Zag zag..
Zag zag..

Reputation: 6231

Define method parameters for meta programming in Ruby

In Ruby, we can define instance methods with meta-programming like:

define_method(:hi) { 'Hello, SO world!' } # => :hi
hi                                        # => "Hello, SO world!"

This way, it is possible to define a method with a dynamic name:

dynamic_name = :hi                                 # => :hi
define_method(dynamic_name) { 'Hello, SO world!' } # => :hi
hi                                                 # => "Hello, SO world!"

We can also inject arguments in to a dynamic method:

dynamic_name = :hi # => :hi
define_method(dynamic_name) do |arg1, arg2, &block|
  'Hello, SO world!'
end                # => :hi
hi(42, 42) { 42 }  # => "Hello, SO world!"

So far, so good.

But how could we do to inject dynamic arguments? Would it be possible to replace arg1, arg2, &block by a dynamic notation?

Thanks for any tips, best practices, or even ideas.

Edit:

In other words, I would like to dynamically also define the parameters and the block of an instance method.

However, I would like to do so with a particular number of parameters (which could be 0), an array in option, and to finish the block of the method.

This way, I could avoid having methods such as:

dynamic_name = :hi      # => :hi
define_method(dynamic_name) do |*args, &block|
  'f'
end                     # => :hi
hi                      # => "f"
hi(:foo)                # => "f"
hi(:foo, :fooo)         # => "f"
hi(:foo, :fooo, :foooo) # => "f"

...which is a nonsense, because here we can give to the method an infinite number of unused parameters. I would like to avoid this situation.

Edit 2:

The reason is the following:

In Ruby, when we need a method which do not need any parameters, we can simply do:

def my_method
  "Hello, SO world!"
end

However, if instead I do this:

def my_method(*args)
  "Hello, SO world!"
end

...the result is still the same, but because the parameter (the array args) is useless, it would be better to keep it simple by removing it from the method.

Upvotes: 4

Views: 1214

Answers (1)

Incerteza
Incerteza

Reputation: 34934

Try passing an array or dictionary.

UPDATE:

if condition1
  class_eval <<-EVAL
    def #{"my_method"}(arg1)
    end
  EVAL
else  
    class_eval <<-EVAL
      def #{"my_method"}
      end
  EVAL
end

UPDATE2:

if condition1
  self.instance_eval <<-EVAL
    def #{"my_method"}(arg1)
    end
  EVAL
else  
    self.instance_eval <<-EVAL
      def #{"my_method"}
      end
  EVAL
end

UPDATE3:

# or
self.instance_eval("def method1(arg1) puts 'hellowa' + arg1.to_s; end")
self.instance_eval("def method2() puts 'hellowa2'; end")

# and then
method1(33) # => hellowa33
method2 # => hellowa2

Upvotes: 1

Related Questions