method

define_method

v1_8_6_287 - Show latest stable - Class: Module
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>

4Notes

define_method with parameters

Oleg · Nov 5, 200910 thanks

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

define_method with default parameters

fgasperi · Aug 3, 20151 thank

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

define_method("example") do |fixed, default = {}|
# something
end

Avoiding the "multiple values for a block parameter" warning

Foobear · May 5, 2010

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

define_method with blocks works differently

kuldeepaggarwal · Aug 7, 2018

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