On 13/02/2011, at 1:03 AM, Hans Dockter wrote:
>
>
> On Thu, Feb 10, 2011 at 4:10 AM, Adam Murdoch <[email protected]> wrote:
> Hi,
>
> At the moment, you can add properties to projects and tasks (and
> dependencies, source sets, and a few other things) dynamically, simply by
> assigning a value for the property:
>
> someProp = 'value'
> assert project.hasProperty('someProp')
>
> jar.someProp = 'value'
> assert jar.hasProperty('someProp')
>
> This is all nice and convenient. However, it also causes some problems. Here
> are some examples:
>
> A typo in a property name:
>
> jar {
> basename = 'someValue' // should be baseName
> }
>
> This adds a new property 'basename' instead of setting the value of
> 'baseName'. Instead, it probably should give you an error (and suggest that
> you try 'baseName' instead).
>
> Another problem is when you use convention properties before you apply the
> corresponding plugin:
>
> sourceCompatibility = 1.6
> apply plugin: 'java'
>
> In this case, we end up with 2 properties called 'sourceCompatibility', each
> of which is used in different places. This, of course, can be extremely
> confusing.
>
> To me, this implicit definition of properties is a nasty source of confusion,
> even to those who know Gradle well. I keep getting bitten by it, even now.
>
> So, I'd like to get rid of it, and require instead that dynamic properties
> are declared explicitly.
>
> Absolutely. I think this is pretty high priority.
>
>
> One question is how this should look. We already have one way to extend an
> object, using the convention object mechanism. This works for both projects
> and tasks:
>
> class MyConfigBean {
> String someProp
> List<File> someOtherProp = []
> File someFile() { .... }
> }
>
> convention.plugins.myproperties = new MyConfigBean()
>
> // The properties and methods of MyConfigBean are mixed in as properties of
> the project
> someOtherProp << someFile()
> println someProp
>
> This is kind of interesting as a way to declare dynamic properties, for a few
> reasons:
>
> * Plugins and build scripts would use the same mechanism
> * Bean properties can be annotated with all kinds of meta-data, such as
> validation constraints, or mappings to command-line options.
> * Bean properties can have javadoc attached, so that build documentation can
> be generated.
> * It allows both properties and methods to be defined.
> * It works well for all types of objects which need to be extended.
> * It could provide namespacing, as you could group related properties and
> methods into separate classes.
>
> The syntax is a little awkward, but might be good enough.
>
> We should definitely rethink the syntax. The '.plugins' bit is really
> confusing for our scenario here.
Absolutely. I think we should make the actual target object more explicit:
myTask.extendWith(MyTaskExtension.class)
extendWith(MyProjectExtension.class) // implicit project.
Or maybe something more like the apply statement:
extend withType: MyProjectExtension
myTask {
extend withType: MyTaskExtension
}
dependencies.all { extend withType: MyDependencyExtension }
Or even reuse (abuse?) the apply statement:
apply type: MyProjectExtension
Also, I wonder if we should use the term 'Extension' for this capability,
rather than 'Convention'. Certainly, our conventions happen to be implemented
using extensions to our domain objects. But, you can use the extensions to do
things other than implementing a convention.
--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz