Flowdock
define_method(...) public

Defines an instance method in the receiver. The method parameter can be a Proc or Method object. If a block is specified, it is used as the method body. This block is evaluated using instance_eval, a point that is tricky to demonstrate because define_method is private. (This is why we resort to the send hack in this example.)

   class A
     def fred
       puts "In Fred"
     end
     def create_method(name, &block)
       self.class.send(:define_method, name, &block)
     end
     define_method(:wilma) { puts "Charge it!" }
   end
   class B < A
     define_method(:barney, instance_method(:fred))
   end
   a = B.new
   a.barney
   a.wilma
   a.create_method(:betty) { p self }
   a.betty

produces:

   In Fred
   Charge it!
   #<B:0x401b39e8>
Show source
Register or log in to add new notes.
November 5, 2009
10 thanks

define_method with parameters

Just to be clear, you can do this:

define_method(:my_method) do |foo, bar| # or even |*args|
  # do something
end

This means same as:

def my_method(foo, bar)
  # do something
end

If you want to define method with parameters that have default values, you need to get a bit more creative and do something like this:

define_method(:my_method) do |foo, bar|
  bar ||= {}
  # do something
end
August 3, 2015
1 thank

define_method with default parameters

To define a method with a default parameter the usual notation can be used:

define_method("example") do |fixed, default = {}|
  # something
end
May 5, 2010
0 thanks

Avoiding the "multiple values for a block parameter" warning

As pointed out below, you can also have optional parameters. But you will get something like “warning: multiple values for a block parameter (0 for 1)” if you omit them.

You can avoid those warnings by passing *args and picking the parameters yourself:

define_method :that_method do |*args|

  foo = args[0] || 'my default'
  # ...
end

Now the warning will be gone. Just make sure you fetch your parameters from *args and assign a default value (unless you want them to default to nil).

August 7, 2018
0 thanks

define_method with blocks works differently

As it is already stated that block is evaluated using instance_exec/instance_eval, so let me give you an example.

module Service
  module ClassMethods
    def endpoint_instance_exec(name, &block)
      define_method name do
        instance_exec(&block)
      end
    end

    def endpoint_block_call(name, &block)
      define_method name, &block
    end

    def endpoint_block_improper_call(name, &block)
      define_method name do
        # In this case, we called the block without "instance_eval" that
        # means block was called in the context of class MyService.
        block.call
      end
    end
  end

  def self.included(klass)
    klass.extend ClassMethods
  end

  private

    def hello
      puts 'world'
    end
end

class MyService
  include Service

  endpoint_instance_exec :foo do
    hello
  end

  endpoint_block_call :bar do
    hello
  end

  endpoint_block_improper_call :foobar do
    hello
  end
end

Now, understand how can we execute the code and understand the working of define_method and instance_exec.

MyService.new.foo # => "hello"
MyService.new.bar # => "hello"
MyService.new.foobar # => undefined local variable or method `hello' for MyService:Class