A lot of the magic you see in Rubyland has to do with metaprogramming, which is simply writing code that writes code for you. Ruby's attr_accessor, attr_reader, and attr_writer are all simple metaprogramming, in that they create two methods in one line, following a standard pattern. Rails does a whole lot of metaprogramming with their relationship-management methods like has_one and belongs_to.
But it's pretty simple to create your own metaprogramming tricks using class_eval to execute dynamically-written code.
The following example allows a wrapper object to forwards certain methods along to an internal object:
class Wrapper
attr_accessor :internal
def self.forwards(*methods)
[*methods]methods.each do |method|
class_eval("
define_method method defdo #{method}(*args|*arguments, &blk)&block|
self.internal.send(#{ method.to_sym.inspect}, *args*arguments, &blk)&block
end
")
end
end
forwards :to_i, :length, :split
end
w = Wrapper.new
w.internal = "12 13 14"
w.to_i # => 12
w.length # => 8
w.split('1') # => ["", "2 ", "3 ", "4"]
Note the use ofThe method [*methods]Wrapper.forwards (pointed out elsewheretakes symbols for the names of methods and stores them in this thread) to enumerate over the arguments givenmethods array. Then, for each of those given, we use class_evaldefine_method to create a new method whose job it is to send the message along, including all arguments and blocks.
A great resource for metaprogramming issues is Why the Lucky Stiff's "Seeing Metaprogramming Clearly".