blob: d9413c913497216f253785e3552c611ea65a066c [file] [log] [blame]
Refactorings / Tidying things up
=================================
* refactor InvokerException & related exceptions to be groovy.lang
- better name for InvokerException?
- maybe root GroovyRuntimeException
* refactor MetaClass to GroovyClass?
* maybe refactor ScriptContext into GroovyShell?
* groovy.model -> groovy.mvc?
* groovy.gdo -> groovy.sql?
Things to Test
==============
* home page tester
* do wiki plugin to auto-test the examples
* test synchronized statement
* export script variables when using the console
* test do while
* test compiler errors when
- duplicate methods test
- duplicate class in module
* duplicate class definition: ClosureMethodTest$4
<bob> java.lang.LinkageError: duplicate class definition: ClosureMethodTest$4
<bob> at java.lang.ClassLoader.defineClass0(Native Method)
<bob> at java.lang.ClassLoader.defineClass(ClassLoader.java:502)
<bob> at java.lang.ClassLoader.defineClass(ClassLoader.java:431)
<bob> at groovy.lang.GroovyClassLoader.onClassNode(GroovyClassLoader.java:108)
<bob> at org.codehaus.groovy.classgen.TestSupport$1.onClassNode(TestSupport.java:96)
* test date range using Range object
* test max, min, sort with closure comparator
- min/max/sort to allow closures for comparators
foo.max { a, b | a.length <=> b.length }
- ClosureComparator
* test Button(actionPerformed:{event| event.println() }
* remove dependency on asm-util on the compiler
Core Groovy Tasks
=================
* allow maps to be created using identifiers?
{name:'James', address:'London'}
only issue is the identifiers could conflict.
* 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
- Object.getMetaClass()
- Object.eachProperty
- Object.eachPropertyName { object.getProperty(it) }
- Object.setProperties(foo:'abc', x:123)
- removeIf { x | x > 0 }
- List.first, List.last, pop
- List.eachWithindex { item, idx | ... }
- reverseEach { ... }
- Map.eachKey, eachValue
- Map.index, Map.indexes
- Object.display (rather than toConsoleOutput)
- grep(pattern) { closure }
where pattern = range / regexp
- eval("....")
- gets
- load(...)
- File.eachByte
- 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?
- Map.get(key, defaultValue)
- Map.setDefault(key, defaultValue) for things like
map.setDefault(key, []).add(newValue)
- list.sortBy { [it.name, it.location] }
- list.sort { a, b | a.name <=> b.name }
to ensure the map has a list of things
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
* << for list append and for output to streams
maybe other optional IO methods like gets?
* 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
* .@ support on W3C DOM trees...
though we might wanna use @ to refer to attributes?
* 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
* bug - x = methodName fails, but x = this.methodName works
* groovy thread...
foo = new GroovyThread(args) { closure }
* doc to write
- using beans + listeners
- expression language
* allow constructors to have optional trailing closure...
new JFrame() { text = 'hello'; size = [1, 2] }
closure on construction of beans?
new JTable() {....}
invokes the closure with the new object as delegate for setting properties etc
* support -ve indices on subscript operator
* foo[1, 2] versus foo[1..2] etc
* 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
* maybe add python's * and ** for any number of args or maps in method decl
* use *args in method invocation to expand a list as argument values
* 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
* test [] on lists & maps?
* should we implement + and - for collections and maps?
l = [1, 2] + [3, 4];
assert l := [1, 2, 3, 4];
* test use of overloaded setter methods & use of property notation
so that the use of properties within a class should use setteres / getters.
* test the use of PropertyExpression
a.b = c.d
* 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?
* maybe use * to represent fields if we need to differentiate properties & fields?
* 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