Skip to main content
Simplified `[*methods]` to `methods`; changed `class_eval` to `define_method`
Source Link

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".

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].each do |method|
      class_eval("
        def #{method}(*args, &blk)
          self.internal.send(#{method.to_sym.inspect}, *args, &blk)
        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 of [*methods] (pointed out elsewhere in this thread) to enumerate over the arguments given. Then, for each of those given, we use class_eval 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".

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.each do |method|
      define_method method do |*arguments, &block|
        internal.send method, *arguments, &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"]

The method Wrapper.forwards takes symbols for the names of methods and stores them in the methods array. Then, for each of those given, we use define_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".

changed last three lines of example code to show values
Source Link
the Tin Man
  • 160.9k
  • 44
  • 222
  • 308

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].each do |method|
      class_eval("
        def #{method}(*args, &blk)
          self.internal.send(#{method.to_sym.inspect}, *args, &blk)
        end
      ")
    end
  end

  forwards :to_i, :length, :split
end

w = Wrapper.new
w.internal = "12 13 14"
puts w.to_i
puts        # => 12
w.length
puts      # => 8
w.split('1')  # => ["", "2 ", "3 ", "4"]

Note the use of [*methods] (pointed out elsewhere in this thread) to enumerate over the arguments given. Then, for each of those given, we use class_eval 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 Stuff's "Seeing Metaprogramming Clearly"Why the Lucky Stiff's "Seeing Metaprogramming Clearly".

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].each do |method|
      class_eval("
        def #{method}(*args, &blk)
          self.internal.send(#{method.to_sym.inspect}, *args, &blk)
        end
      ")
    end
  end

  forwards :to_i, :length, :split
end

w = Wrapper.new
w.internal = "12 13 14"
puts w.to_i
puts w.length
puts w.split('1')

Note the use of [*methods] (pointed out elsewhere in this thread) to enumerate over the arguments given. Then, for each of those given, we use class_eval 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 Stuff's "Seeing Metaprogramming Clearly".

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].each do |method|
      class_eval("
        def #{method}(*args, &blk)
          self.internal.send(#{method.to_sym.inspect}, *args, &blk)
        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 of [*methods] (pointed out elsewhere in this thread) to enumerate over the arguments given. Then, for each of those given, we use class_eval 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".

Post Made Community Wiki
Source Link
TALlama
  • 16.5k
  • 8
  • 41
  • 47

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].each do |method|
      class_eval("
        def #{method}(*args, &blk)
          self.internal.send(#{method.to_sym.inspect}, *args, &blk)
        end
      ")
    end
  end

  forwards :to_i, :length, :split
end

w = Wrapper.new
w.internal = "12 13 14"
puts w.to_i
puts w.length
puts w.split('1')

Note the use of [*methods] (pointed out elsewhere in this thread) to enumerate over the arguments given. Then, for each of those given, we use class_eval 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 Stuff's "Seeing Metaprogramming Clearly".