Reputation: 13811
I got confused with this two lines of coding :
this.class.methods.name
This is called Gpath (Am I right?). Now consider this code :
count = 0
def a = [1,2,3,4,5,5,51,2]
a.findAll { it == 5 }.each { count ++ }
println count
The line:
a.findAll { it == 5 }.each { count ++ }
is called as a method chaining or Gpath?
Literally, I got struck with these two meanings. It will be nice if some one explains the difference between these two.
Thanks in advance.
Upvotes: 0
Views: 845
Reputation: 19229
I'm not sure if I understand the question correctly.
As I see it, in both examples you are using method chaining, simply because you are calling a method in the object that is returned by another method. But, as Arturo mentions, some people confuse method chaining and fluent interfaces. A fluent interface is indeed quite handy if you want to chain methods.
In Groovy, however, you may, instead of coding a fluent interface yourself, use the with
method in any object. For example, using the same Person
and Address
classes that Arturo defined, you can do:
def person = new Person()
person.with {
name = 'John'
age = 25
address = new Address('Boulevard St')
}
assert person.name == 'John' &&
person.age == 25 &&
person.address.name == 'Boulevard St'
Now, GPath, as I understand, is just a way of accessing the properties of an object. For example, if you have the class:
class Foo {
def bar
}
The GPath mechanism in Groovy lets you do things like:
def foo = new Foo(bar: 42)
assert foo.bar == 42
Instead of accessing the bar property with its getter, like foo.getBar()
. Nothing too fancy. But other classes in Groovy also have some GPath magic and there is where things get more interesting. For example, lists let you access properties in their elements the same way you'd access normal properties:
def foos = (1..5).collect { new Foo(bar: it) } // Five Foos.
assert foos.bar == [1, 2, 3, 4, 5]
As you can see, accessing the bar property on a list of objects that have that property will result in a list with the values of that property for each object in the list. But if you access a property that the elements of the list don't have, e.g. foos.baz
, it will throw a MissingPropertyException.
This is exactly what is happening in:
this.class.methods.name
I, however, consider this behavior to be a little too magic for my taste (unless you are parsing XML, in which case is totally fine). Notice that if the collection returned by the methods
method would be some weird collection that had a name
property, methods.name
would result in that name instead of the names of each method in the collection. In these cases I prefer to use the (IMO) more explicit version:
this.class.methods*.name
Wich will give you the same result, but it's just syntax sugar for:
this.class.methods.collect { it.name }
... and let's the intention of the expression to be more clear (i.e. "I want the names of each method in methods
").
Finally, and this is quite off-topic, the code:
count = 0
def a = [1,2,3,4,5,5,51,2]
a.findAll { it == 5 }.each { count ++ }
println count
can be rewritten as:
def a = [1,2,3,4,5,5,51,2]
def count = a.count { it == 5 }
println count
:)
Upvotes: 3
Reputation: 13122
I think that your code is an example of method chaining.
GPath is a path expression language integrated into Groovy which allows to navigate in XML or POJOs. You can perform nested property access in objects.
Method chaining is a technique for invoking multiple method calls in object-oriented programming languages. Each method returns an object (possibly the current object itself), allowing the calls to be chained together in a single statement.
I'm going to use an example with TupleConstructor to assist in the creation of the object.
import groovy.transform.TupleConstructor
@TupleConstructor
class Address {
String name
}
@TupleConstructor
class Person {
String name
Integer age
Address address
}
def person = new Person('John', 25, new Address('Boulevard St'))
Ok, you are right, this access is called GPath:
assert person.address.name == 'Boulevard St'
A getter access could be named method chaining:
assert person.getAddress().getName() == 'Boulevard St'
But what happens if I can do something like this:
person.setName('Louise')
.setAge(40)
.setAddress(new Address('Main St'))
I need to create a fluent API, an method chaining is the way, the idea is to let methods return this
rather than void
.
@TupleConstructor
class Person {
String name
Integer age
Address address
def setName(name) {
this.name = name
return this
}
def setAge(age) {
this.age = age
return this
}
}
Upvotes: 2