G
Greg Weeks
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 <<self
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 <<self
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?
Is there some way to avoid evals and still handle the "&block" argument?
Is there a natural alternative to the local hash variable?
Am I right to think that eval-ing strings is retro?
(By the way, neither implementation allows "once" to be called twice
with the same symbol.)
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 <<self
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 <<self
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?
Is there some way to avoid evals and still handle the "&block" argument?
Is there a natural alternative to the local hash variable?
Am I right to think that eval-ing strings is retro?
(By the way, neither implementation allows "once" to be called twice
with the same symbol.)