On 02.05.2009 15:33, Thomas H. wrote:
self.class.class_eval{ define_method(:lookup){ |k| h[k] } }
end
Once define_lookup'' has been called, the method
lookup’’ is
defined and will act in a lazy manner. Just call lookup'' as often as you need, but only for the first time the expensive operation (e.g. dealing with files) will be performed. Due to duck typing no condition needs to be checked: for the first call
h[k]’’ implies calling the
lambda, for the next times ``h[k]’’ implies accessing the hash.
(Tried with Ruby 1.8.6.)
Sorry to sound discouraging but there is memoize already. The
difference is that not the whole Hash is filled but only the one that
you need for the argument list provided which seems potentially more
efficient.
define_lookup should probably be a class method but in that case having
a single Hash for all instances is problematic.
Note, that you can use Hash’s default_proc to achieve something similar
very elegantly:
class Foo
def initialize(some, args)
@some = some
@args = args
@lookup = Hash.new {|h,k| h[k] = do_lookup(k)}
end
def lookup(a,b)
@lookup[[a,b]]
end
private
def do_lookup(args)
puts “calculating…”
sleep 2
args.first + args.last + @some + @args
end
end
Note that you do not need a separate method but if the calculation is
complex code might be more readable with another method.
irb(main):059:0> f = Foo.new 1,2
=> #<Foo:0x101b3ce8 @some=1, @args=2, @lookup={}>
irb(main):060:0> f.lookup 3,4
calculating…
=> 10
irb(main):061:0> f.lookup 3,4
=> 10
irb(main):062:0>
In case you want to fill the Hash completely you can just replace the
calculation code to assign multiple values.
OTOH, often a single Hash with a default_proc is sufficient already,
e.h.
irb(main):064:0> foo = Hash.new {|h,k| h[k] = k + 1 + 3}
=> {}
irb(main):065:0> foo[3]
=> 7
irb(main):066:0> foo
=> {3=>7}
Kind regards
robert