[ruby 1.8]
Assume I have:
dummy "string" do
puts "thing"
end
Now, this is a call to a method which has as input arguments one string and one block. Nice.
Now assume I can have a lot of similar calls (different method names, same arguments). Example:
otherdummy "string" do
puts "thing"
end
Now because they do the same thing, and they can be hundreds, I don't want create an instance method for each one in the wanted class. I would like rather find a smart way to define the method dynamically at runtime based on a general rule.
Is that possible? Which techniques are commonly used?
Thanks
I'm particularly fond of using method_missing
, especially when the code you want to use is very similar across the various method calls. Here's an example from this site - whenever somebody calls x.boo
and boo
doesn't exist, method_missing is called with boo
, the arguments to boo
, and (optionally) a block:
class ActiveRecord::Base
def method_missing(meth, *args, &block)
if meth.to_s =~ /^find_by_(.+)$/
run_find_by_method($1, *args, &block)
else
super # You *must* call super if you don't handle the
# method, otherwise you'll mess up Ruby's method
# lookup.
end
end
def run_find_by_method(attrs, *args, &block)
# Make an array of attribute names
attrs = attrs.split('_and_')
# #transpose will zip the two arrays together like so:
# [[:a, :b, :c], [1, 2, 3]].transpose
# # => [[:a, 1], [:b, 2], [:c, 3]]
attrs_with_args = [attrs, args].transpose
# Hash[] will take the passed associative array and turn it
# into a hash like so:
# Hash[[[:a, 2], [:b, 4]]] # => { :a => 2, :b => 4 }
conditions = Hash[attrs_with_args]
# #where and #all are new AREL goodness that will find all
# records matching our conditions
where(conditions).all
end
end
define_method
also looks like it would work for you, but I have less experience with it than method_missing
. Here's the example from the same link:
%w(user email food).each do |meth|
define_method(meth) { @data[meth.to_sym] }
end