New model confusion

I’m sure this not going to be the first confused post :slight_smile:
Let’s say I have the following setup.

@Managed 
interface Foo {
  String getBar()
  void setBar(String bar)
}

class FooRules extends RuleSource {
  @Model 
  void myFooModel( Foo f ) {} 
}

apply plugin : FooRules

I now create a model

model {
  myFoo(Foo) {
    bar = '123'  // I expect this to work
    blahblahblah = 123 // I would expect this to fail, but it does not
  }
}

What is happening with blahblahblah ?

Here is another point that I cannot get my head around. The documentation states that @Mutate rules can have additional parameters, but there are no examples. Assume that I have a rule source such as below
, how would mutateWithExtraMethod get invoked in the model DSL?

class RuleRules extends RuleSource {
  @Model 
  void myFooModel( Foo f ) {}

  @Mutate mutateWithExtraMethod( Foo f, def input1 ) {
  }
}

For your second question, the first argument is the target of the mutation, i.e. the object to be modified. The additional optional arguments are normally other model or extension objects that are or should be considered read-only. The software model documentation does describe this, I recommend reading the latest version again, and trying out the examples there.

@axl, I get stuff like

@Mutate addTasks( ModelMap<Task> t, Foo f)

because I think that it states that if a managed object of type Foo is added to the model, then it will affect the list of tasks associated with the model (or project to be pragmatic). However, if I follow the same reasoning then

@Mutate mutateWithExtraMethod( Foo f, def input1 ) {
}

does not make sense, neither would something like

@Mutate mutateWithExtraMethod( Foo f, String input1 ) {
}

However, if as you said “optional arguments are normally other model or extension objects”, then

@Mutate mutateWithExtraMethod( Foo f, Bar input1 ) {
}

says, that if a domain object of type Bar is added, this will affect a domain object of type Foo.

This still leaves me with ro wonder about the validaity of this all as I still have not found anything in the docs that explicitly states that the additional arguments have to be managed/model/extension objects.

Right, the documentation does leave a few bits out :slight_smile: As far as I have understood it, the only inputs, i.e. arguments 2 and up, you can have on a rule method are things that can be referenced through the model somehow. Any random data, or project property that is not accessible through the model, cannot be passed in.

Some things can be referenced using the @Path(“dotted.path”) syntax, and some must be referenced as collections, ModelMap, but it’s quite unclear to me exactly what are valid paths, or when one must use collections vs objects.

I’ve written a rather complex plugin and spent a lot of time reading the source code to figure out the gritty details, most of which are still in heavy motion. I usually have to rewrite several sections for each upgrade, which is fine, it’s usually for the better.

The “fact” that you cannot pass random things into rules have caused me some problems before, but I got around most of them by adding an extension object, which has access to the project object, and which can then be added as a model element, and used as a sort of proxy. I’m not sure how well that is in line with the design and intentions of the software model, but it lets me move along for now.

I would definitely be interested in seeing what you have done and on your feedback in general with working on the new model. The fact that you have spent a lot of time reading source code, trying to figure out what to do is not something everything plugin author would be able to do or in fact, should not need to do.

Part of writing Vol 2 of Idiomatic Gradle includes clearing up a lot of the confusion. Feedback and input such as yours is extremely helpful.

Sure. My plugin is not yet public, and would be of little use to most people at the moment, but I can definitely share my experiences. Please PM me and we can figure something out.

1 Like

Two more complaints: No decent description of @Finalize and @Validate

(Edit: The linked topics have good answers).

Today’s confusion: Obtaining the name of the current component.

It is not clear how to obtain the name of the component within a rule, or whether the Named interface is a prerequisite.

Creating default implementations

This is relatively easy to get working

@Managed
interface MyComponent extends ComponentSpec {
}

class Rules extends RuleSource {
  @ComponentSpec
 void register( TypeBuilder<MyComponent> builder ) {}
}

But try doing

class DefaultMyCompoent implements MyComponent { ... }

class Rules extends RuleSource {
  @ComponentSpec
  void register( TypeBuilder<MyComponent>builder ) {
    build.defaultImplementation(DefaultMyComponent)
  }
}

and it wil fail with No factory registered to create an instance of implementation classDefaultMyComponent’