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