4

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.

2
  • Why not just use a splat? Commented Oct 29, 2015 at 22:50
  • Sorry, what do you mean? I don't understand... Oh! Got it! with *args, &block. Yes, but I would prefer to define a method with no arguments, in order to avoid having an args instance which would be equal to en empty array. Commented Oct 29, 2015 at 22:50

1 Answer 1

1

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
Sign up to request clarification or add additional context in comments.

6 Comments

Yes, that's true. But I would like to define a method with no arguments at all, when args is empty...
I don't understand exactly, sorry. Maybe specifying a default value [] for an array?
Your solution is passing, but for 2 cases. Is there a global way to define params? I mean, in order to handle cases such as: (), (arg), (arg1, arg2), (arg, *args), (arg, *args, &block), (arg, *args, **options, &block), etc. Maybe it's impossible, I don't know. Also, it would be awesome without using class_eval.
@Zagzag.., updated. my_method should be available globally.
as well as method1 and method2
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.