blob: 2fe22276b07d0392b0cb6278a7d7504e416cfb1c [file] [log] [blame]
Things to Test
==============
* test synchronized statement
* test compiler errors when
- duplicate methods testno
- duplicate class in module
* test Button(actionPerformed:{event| event.println() }
Core Groovy Tasks
=================
* allow maps to be created using identifiers?
{name:'James', address:'London'}
only issue is the identifiers could conflict.
Could use a helper method?
* handling sequences (0-n, 1-n)
they are Lists & behave like lists, any methods on the items will
be called etc.
however how are they assigned / modified.
foo.customers += customer
foo.customers = [customer1, customer2]
so assignment of sequence fields don't really do an assign; they do a set(List) instead
- should we allow real assignments. e.g.
Address* foo = ...;
foo = [1, 2, 3]
foo keeps its type so its not a List
how about handling mandatory values -
the set we overload to do the non-null checks?
this must be a type. e.g.
String! x = "hello"
x = null // error
* new GroovyMethods to be added
- File.grep(pattern) -> List
- File.grep(pattern) { closure }
allow iteration through a file for each line matching a regex pattern
- Collection.grep(pattern) -> List
- Collection.grep(pattern) { closure }
where pattern = regexp (could maybe be other kinds of patterns like Range?)
- List.first(), List.last(), pop()
- Collection.removeIf { x | x > 0 }
- List.eachWithindex { item, idx | ... }
- List.reverseEach { ... }
- Collection.count(foo) -> returns number of objects that equal foo
- Collection.countIf { it > 5 } -> returns number of objects that match closure predicate
- Map.get(key, defaultValue)
- Map.setDefault(key, defaultValue) for things like
map.setDefault(key, []).add(newValue)
- Object.getMetaClass()
- Object.eachProperty
- Object.eachPropertyName { object.getProperty(it) }
- Object.setProperties(foo:'abc', x:123)
- Map.eachKey, eachValue
- Map.index, Map.indexes
- configure method on beans?
bean.setProperties(name:'James', location:'London')
- some kind of Regexp iterator of strings like Ruby's scan
- maybe support Pythons' zip and reduce functions?
maybe add the various readonly List APIs to Object[] and *[] types
if we ever support the DTD / Xed style type*, type+ then we can do the same
there too
* add doesNotUnderstand() method for catching & handling unknown methods
* is there a better way to add listeners in Groovy. e.g. how to remove added listeners
listener = bean.property + { some closure }
bean.property - listener
* BeanBuilder - builder which creates a tree of beans
builder.bean(class:SomeClass, x:123, b:'hello') {
nestedProperty(a:123)
nestedProperty2(class:DerivedClass, b:43)
}
using adder method as well as setter methods
* MBeanBuilder?
builder.mlet {
mbean(class:SomeClass) {
someAttribute(value)
}
mbean(class:SomeClass, someAttribute:value) {
operation(1, 2)
}
}
* templating - allow looping & conditionals?
text = "
<table>
#for (f in foo)
<tr>
<td>${f.name}
</tr>
#end
</table>
"
* allow if/switch to be the and of a function. i.e.
foo() {
if (x > 1) {
"hello"
}
else {
"cheese"
}
}
ditto for switch? i.e. make return statement optional.
* SQL builder
sql.table("users") {
ÊÊÊ column('user-id') { autoinc(), primaryKey(), references('foo'), initialValue(1234) }
ÊÊÊ column('nickname') { varchar(200) }
column(name:'foo', type:'varchar(200)', references:['a', 'b'], initialValue:1234)
}
}
* using mixin for adding using style behaviour to any object??
mixin Using {
static using(yield) {
object = this.newInstance()
try {
yield(object)
object.close()
}
catch (Exception e) {
try {
object.close()
}
catch (Exception e2)
// ignore e2
throw e
}
}
}
or
using(yield) {
try {
yield(this)
close()
}
catch (Exception e) {
try {
close()
}
catch (Exception e2)
// ignore e2
throw e
}
}
}
}
then use it as
new FileInputStream().using { in |
...
}
* looks like a bug on generated methods, should use param name over any field name
- also it looks like there's various unnecessary stuff (creation of tuples) when invoking
methods
* groovy thread...
foo = new GroovyThread(args) { closure }
* MetaClass -> add getPropertyDescriptor which has methods
- get(), set(), type(), cardinality() etc
could use naming conventions to detect cardinality - e.g. addFoo(), getFoos()
* generate property change listener stuff on properties
* test identity -> hashCode + equals methods
* support for property converters, based on type
* go through all not-working @todo tests in src/test
* to support dynamic mixins we should use dynamic proxies to allow
a groovy object to change metaclass at runtime
* groovy dynamic proxy of any Java object in Java-land?
NullObject pattern
* immutable bean
* MetaClass.deriveMetaClass()
MetaClass.addMixin(mixin)
* constructors with map / tuple expressions, named parameter calling
* default values for parameters
* test try / catch with multiple exception types
* * support static newInstance() method for constructors
* maybe split up ClassGenerator - do code gen & class gen separately
* mixin support...
SomeClass.addMixin(Foo);
MetaClass.addInterceptor( new Interceptor() {
filter(method) {
return method.isPublic();
}
invoke(method, args) {
// do something
method.invoke(args);
}
});
* allow meta classes to be added dynamically using closure syntax?
e.g. Map?
STUFF TO PONDER
===============
* if we allow statements in class declarations, then we could disallow the syntax sugar
for method invocation with closures. i.e. foo { code } would have to be foo ({code})
otherwise it'd be interpeted as a method declaration.
e.g.
module MyValidatingModule
class Cheese {
readOnlyProperty('hello')
validatingProperty('name', { it.length > 0 } )
lazilyCreatedProperty(:cheese, { new MySpecialCheese() })
public(:methodA, :methodB, :methodC)
}
for now we could argue that only methods are allowed to be invoked inside the class declaration.
We could still do markup but just not as nice
class Whatnot {
table( {
foo {
}
whatnot {
}
})
blah = {
a(x:1234, b:942) {
d()
}
}
* Support multiple return values...
String, Number cheese() {
"hello", 7
}
a, b = cheese()
also if we do this we should do assignment / swapping
a, b = 1, 2
a, b = b, a
* maybe use syntax #[1, 2] to create arrays which behave just like immutable lists?
* using macros to avoid dependencies on logging stuff (say)
class GroovyLog {
switch (System.getProperty('groovy.log.impl', 'useCommonsLogging')) {
case 'useCommonsLogging': {
// lets define the new instance method
newInstance() {
return new CommonsLoggingThingy()
}
}
default {
newInstance() {
return new SimpleGroovyLog()
}
}
}
}
doing things like this at compile time means no runtime dependencies. Ditto to do JDK based compiles
UI WORK
=======
* tree demo...
* when named method calls are supported with default values, refactor SwingBuilder
so that all the creations of widgets occur with SwingFactory which would be
useful in and of itself
- plus we should be using normal method call mechanism & for groovy to do the rest to avoid
the long laborious Map coding
* add table layout cell spacing thingy
* FormModel.addPropertyModel(property)
FormModel.addClosureModel(readClosure, writeClosure)
* ListModel is-a List but delegates to an underlying list and has events
* rename tableLayout -> table and table -> grid
* add sortableGrid
* create a GroovyUI
-> interactive script + allows scripts to be run & objects explored
ECLIPSE WORK
============
* Run as JUnit support for Groovy!
* Refactoring support for Groovy and tie it into the Java refactoring
JUNIT WORK
==========
* patch GroovyTestCase so that methods which return Object are included in the test. This avoids us having to
specify void for method return types.This requires a clever static method when we generate the
bytecode which can instantiate a special kind of TestSuite
unless there's another way?
OPTIMISATIONS
=============
* method invocations - if foo instanceof GroovyObject
then generate bytecode
foo.invokeMethod(method, args);
* could code generate the MetaClass with very efficient dynamic dispatch
e.g. could switch() on the method name & then use real method invocation
on the method instance