Metaprogramming problem

C

Clifford Heath

I'm trying to define s.t. like attr_accessor, but one that takes
an optional block defining a function that filters the value on
the setter. Perhaps that will be clear if I show you the snippet:

class Object
def add_property(sym, &block)
n = sym.id2name
code = %Q{
def #{n}()
@#{n} ||= nil
end
def #{n}=(value)
@#{n} = block ? block.call(value) : value
end
}
eval(code)
end
end

# A test object:
d = 3

# Add a getter and custom setter to 3:
d.add_property:)do_it) {|v|
# Custom setter method
puts "d.do_it here, v = #{v.inspect}"
v # No filtering this time, just return the value.
}

# Assign the property:
d.do_it = "a value"

Ok, I can see why "block" isn't defined. How can I pass add_property's
block in as a block to be used *inside* the evaluated code?

Clifford Heath.
 
R

Robert Klemme

Clifford said:
I'm trying to define s.t. like attr_accessor, but one that takes
an optional block defining a function that filters the value on
the setter. Perhaps that will be clear if I show you the snippet:

class Object
def add_property(sym, &block)
n = sym.id2name
code = %Q{
def #{n}()
@#{n} ||= nil
end
def #{n}=(value)
@#{n} = block ? block.call(value) : value
end
}
eval(code)
end
end

# A test object:
d = 3

# Add a getter and custom setter to 3:
d.add_property:)do_it) {|v|
# Custom setter method
puts "d.do_it here, v = #{v.inspect}"
v # No filtering this time, just return the value.
}

# Assign the property:
d.do_it = "a value"

Ok, I can see why "block" isn't defined. How can I pass add_property's
block in as a block to be used *inside* the evaluated code?

You can use define_method:

class Module
def add_property(sym,&test)
define_method("#{sym}=") do |val|
test && test[val]
instance_variable_set("@#{sym}", val)
end

define_method(sym) do |val|
instance_variable_get("@#{sym}")
end
end
end

class Foo
add_property :age do |x|
raise "Illegal negative" unless x >= 0
end
end
RuntimeError: Illegal negative
from (irb):55
from (irb):54:in `[]'
from (irb):43:in `age='
from (irb):42:in `age='
from (irb):59=> 0

Kind regards

robert
 
C

Clifford Heath

Robert said:
You can use define_method:

Doh! I went searching for that, since it wasn't in my
(ruby 1.6) HTML manual and I expected it to have been
added in 1.8 :)... But I tried

p Object.methods
p Class.methods
p Module.methods
p Kernel.methods

without success, so I stopped looking :-(

Thanks for the help. I have the 1.8 book, both paper
and PDF, but the HTML is so convenient :).

Clifford Heath.
 
G

Gavin Kistner

--Apple-Mail-2-649870537
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
delsp=yes;
format=flowed

Ok, I can see why "block" isn't defined. How can I pass add_property's
block in as a block to be used *inside* the evaluated code?

Here's *a* working solution. The big string + eval feels like a
serious hack, but I'm not cool enough to know how to deal with it
properly.

class Object
def add_property(sym, &block)
n = sym.id2name
(@_property_callbacks||={})[ n ] = block
code = %Q{
def #{n}()
@#{n} ||= nil
end
def #{n}=(value)
if block = @_property_callbacks[ '#{n}' ]
@#{n} = block.call(value)
else
@#{n} = value
end
end
}
eval(code)
end
end

# A test object:
d = 3

# Add a getter and custom setter to 3:
d.add_property:)do_it) {|v|
# Custom setter method
puts "d.do_it here, v = #{v.inspect}"
v # No filtering this time, just return the value.
}

# Assign the property:
d.do_it = "a value"



--Apple-Mail-2-649870537--
 
R

Robert Klemme

Clifford said:
Doh! I went searching for that, since it wasn't in my
(ruby 1.6) HTML manual and I expected it to have been
added in 1.8 :)... But I tried

p Object.methods
p Class.methods
p Module.methods
p Kernel.methods

without success, so I stopped looking :-(

Thanks for the help. I have the 1.8 book, both paper
and PDF, but the HTML is so convenient :).

Clifford Heath.

An additional remark: you can improve performance if you extract the test
for the block's presence from the method and use your approach of code
generation for the getter and for the setter (for the case where there is
no block).

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top