Having to prefix the ivar with self. makes the DSL look clunky
I agree, though some experienced Rubyists don't see it that way.
so with this I can write
Box {width 10}
which is acceptable from the DSL view point, but makes the getter
operations more expensive. In the real version a getter operation takes
about 7 statements to allow for evaluation of block if the ivar had been
set to a Proc object and inheritance of values from its parent object (in
a visual hierarchy). The setter operation is often only done when the
object is created but the getter is done very frequently so I want to
move down the route of separate setters and getters rather than combining
them in the one method as an optimization.
If you have some guarantees about the ordering of getters and setters, you
can dynamically (re)define the getter and setter at the instance level. The
attached worked for the case of instance variables being initialized only
once, but being read at any time (the context for this was some kind of lazy
creation of an object graph including forward references). Perhaps some bits
of it will apply to your case.
class Object
def singleton_class
class << self; self; end
end
end
module LazyForwardRef
UNDEFINED = nil
def forward_ref(attr)
getter = attr
setter = (attr.to_s + '=').intern
ivar = ('@' + attr.to_s).intern
suspension = lambda { self.send getter }
self.singleton_class.send :define_method, getter, lambda {
v = instance_variable_get ivar
if v == UNDEFINED
suspension
elsif v.is_a?(Proc)
current = v.call
self.send(setter, current) if current != v
current
else v
end
}
self.singleton_class.send :define_method, setter, lambda {|val|
self.instance_variable_set ivar, val
}
end
end
require 'pp'
x = Object.new
x.extend LazyForwardRef
begin
p x.foo
rescue NoMethodError => detail
pp detail
pp [__LINE__, x, x.methods.sort - Object.instance_methods]
end
x.forward_ref(:foo)
pp [__LINE__, x, x.methods.sort - Object.instance_methods]
x.foo
pp [__LINE__, x, x.foo]
x.foo = 'Something else'
pp [__LINE__, x, x.foo]
y = Object.new
y.extend LazyForwardRef
y.forward_ref(:bar)
pp [__LINE__, y, y.methods.sort - Object.instance_methods]
z = Object.new
z.extend LazyForwardRef
z.forward_ref(:baz)
y.bar = z.baz
pp [__LINE__, x, y, z, x.foo, y.bar, z.baz, x.foo==z.baz]
x.foo = y.bar
pp [__LINE__, x, y, x.foo, y.bar]
z.baz= 10
pp [__LINE__, x, y, z]
pp [__LINE__, x.foo, y.bar, z.baz]
pp [__LINE__, x, y, z]
···
"Dave Baldwin" <dave.baldwin@3dlabs.com> wrote