views:

256

answers:

3

Hello,

I'd like to store some properties in a static closure and later access them during a method call:

class Person {
static someMap = { key1: "value1", key2: "value2" }
}

So how can I write a method within Person, which retrieves this stored data?

Regards,

Peter

+2  A: 

If they need to be initialized by a closure, instead of a map, then somebody's got to run the closure in order to pick up and record the values as they're set.

Your syntax there isn't valid. Remember closures are just anonymous methods. Your syntax looks like you're trying to define a map, but closures would need to call methods, set variables or return maps. e.g.

static someClosure = { key1 = "value1"; key2 = "value2" } // set variables
static someClosure = { key1 "value1"; key2 = "value2" } // call methods
static someClosure = { [key1: "value1", key2: "value2"] } // return a map

Then of course whoever's running the closure needs to have the right metaprogramming to record the results.

It sounds like what you really want is just to define a map.

static someMap = [key1: "value1", key2: "value2"]
John Stoneham
Thanks a lot for clarifying this issue. A map is definitely helpful and with your help I can actually define and acess one. I got confused by the definition of a GORM domain class, which I think, uses closures. If I wanted to define my data in such a style, how could I read it?
Daniel
The GORM domain class does use closures for things like constraints and database mappings, but it's implemented a DSL to execute and evaluate the closure. This is much more work than simply using a map, but it can be useful if you're trying to DRY up code and give the user the ability to express things in a language more specific to the task than normal groovy.For what you're trying to do, John has it right, just use a map.
Ted Naleid
Wow, fantastic reply, Ted. I didn't have the time to put in the metaprogramming sample code. :)
John Stoneham
+4  A: 

For the simple case, you're better off using a map.

If you really do want to evaluate it as a closure (possibly to create your own DSL), you'll need to change your syntax slightly as John points out. Here's one way to do it using a Builder class to evaluate the "something" closure within whatever is passed to the builder.

It uses groovy metaprogramming to intercept calls with method/property missing and to save them off:

class SomethingBuilder {
    Map valueMap = [:]

    SomethingBuilder(object) {
        def callable = object.something
        callable.delegate = this
        callable.resolveStrategy = Closure.DELEGATE_FIRST
        callable()
    }

    def propertyMissing(String name) {
        return valueMap[name]
    }

    def propertyMissing(String name, value) {
        valueMap[name] = value
    }

    def methodMissing(String name, args) {
        if (args.size() == 1) {
            valueMap[name] = args[0]
        } else {
            valueMap[name] = args
        }
    }
}

class Person {
    static something = {
        key1 "value1"              // calls methodMissing("key1", ["value1"])
        key2("value2")             // calls methodMissing("key2", ["value2"])
        key3 = "value3"            // calls propertyMissing("key3", "value3")
        key4 "foo", "bar", "baz"   // calls methodMissing("key4", ["foo","bar","baz"])
    }
}

def builder = new SomethingBuilder(new Person())

assert "value1" == builder."key1"  // calls propertyMissing("key1")
assert "value2" == builder."key2"  // calls propertyMissing("key2")
assert "value3" == builder."key3"  // calls propertyMissing("key3")
assert ["foo", "bar", "baz"] == builder."key4"  // calls propertyMissing("key4")
Ted Naleid
I also threw a post out on my blog with a slightly more generic solution: http://naleid.com/blog/2010/01/24/interrogating-arbitrary-groovy-closures-for-values/
Ted Naleid
A: 

Thank you very much. You helped a lot

Waxolunist