After discussing with Adam, here's the proposal.

We add something like:

public interface DynamicExtension {
    /**
     * Registers a new property with the given name and initial value.
     */
    void add(String name, Object value);

    /**
     * Returns the value for the registered property with the given name.
     */
    Object get(String name);

    /**
     * Updates the value for the registered property with the given name to the 
given value.
     */
    void set(String name, Object value);
}

We also add the following to ExtensionContainer: 

DynamicExtension addDynamic(String name, Action<DynamicExtension> configure = 
null)

The basic idea is that we drive everything through the extension mechanism, but 
provide a lightweight extension impl that users can use for adhoc state. 
DynamicExtension objects will also of course act like maps, in that you can 
read/write registered properties via standard groovy property notation.


From there we do some more with this machinery, maybe as a transitional measure 
or maybe as a long term measure. We will pre-populate all extension containers 
with a special dynamic extension named something like “mine”, “user” or “ext”. 
This extension will also promote it's properties into the top level element. 
Assuming it's called “ext”, the following would work…

project.ext.add("foo", "bar")
assert project.foo == "bar"

This would not (with clean slate):

project.extensions.addDynamic("custom")
project.custom.add("foo", "bar")
assert project.foo == "bar"

but this would:

assert project.custom.foo == "bar"
 
The link between the “special” dynamic extension is bidirectional…

project.ext.add("foo", "bar")
project.foo = "abc"
assert project.ext.foo == "abc"


With the introduction of this, the following would give you a deprecation 
warning:

task foo {
  newProperty = "value"
}

It will suggest you either do `ext.add("newProperty", "value")` or add your own 
new namespaced extension. 


It's not clear yet whether the behaviour of promoting properties out of a 
special namespace up to the top level is something that we want to support long 
term or not. There are no plans in this round of work to emit any kind of 
warning when reading/writing top level dynamic properties provided they have 
been declared. We can potentially do that later.

One of the reasons for pushing towards namespacing the dynamic properties is 
that it provides a better migration path for builds. Using dynamic extensions 
are a lightweight way to extend objects. As needs get more advanced, the 
dynamic extension can be swapped for a real one with real methods and setters 
etc. without changing it's public DSL API. For example, someone might start out 
doing this…

configurations.all { 
  dependencies.all {
    it.extensions.addDynamic("maven") { add "optional", false }
  }
}

Then later…

class MavenDependencyExtension {
  Dependency dependency
  boolean optional
}

configurations.all { 
  dependencies.all {
    it.extensions.add("maven", MavenDependencyExtension, [dependency: it])
  }
}


There's also an argument to be made for safety, but at the cost of convenience. 
If all “added” stuff is in a namespace, it's easier to tell at a glance that 
it's added. 


I'm feeling pretty good about most of that as the idea of dynamic extensions is 
pretty good I think and something that should be there. The only real 
contentious decision that we need to make now is if we allow new properties to 
be _registered_ on the top level object, which really comes down to making some 
kind of commitment to namespaces. That is, between something like…

project.addProperty("foo", "bar")
 
and…

project.ext.add("foo", "bar")

If we go the latter, we can resolve later whether or not to deprecate the 
promotion to top level or not. I think this is the right path.

-- 
Luke Daley
Principal Engineer, Gradleware 
http://gradleware.com


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply via email to