From: Trans Date: 2007-11-14T20:45:34+09:00 Subject: Re: "once" meta-method without "module_eval" (Pickaxe) On Nov 14, 1:23 am, Greg Weeks wrote: > My impression is that Ruby meta-programming used to lean heavily on > evaluating strings as code, but is moving away from that. (Good!) In > that spirit, it would be nice to replace this example from Chapter 24, > Classes and Objects: > > class Date > class < def once(*ids) # :nodoc: > for id in ids > module_eval <<-"end;" > alias_method :__#{id.to_i}__, :#{id.to_s} > private :__#{id.to_i}__ > def #{id.to_s}(*args, &block) > (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0] > end > end; > end > end > end > ... > once :as_string, :as_YMD > end > > "once" replaces a specified method with a method that caches the return > value on the first call. > > The example above served to illustrate the use of class instance > variables. However, the replacement that comes to mind does not: > > class < def once(*ids) > values = {} > for id in ids > new_id = "__#{id.to_i}__".to_sym > alias_method new_id, id > private new_id > define_method (id) do |*args| > (values[id] ||= [ method(new_id).call(*args) ])[0] > end > end > end > end > > Is there some way to avoid evals and still use class instance variables? instance_variable_get/set > Is there some way to avoid evals and still handle the "&block" argument? Wait for 1.9. > Is there a natural alternative to the local hash variable? instance_variable_get/set if you want to do it like the original, but your local might be better. > Am I right to think that eval-ing strings is retro? I'm not sure there's anything really wrong with eval. Often the code looks cleaner compared to these long winded meta-methods. T.