Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby public_send method with hash params where applicable

Tags:

methods

ruby

Tldr: I am trying to use public_send to call methods but some of these methods require arguments as well. How to check which requires arguments and add those as arguments and include them in the call

I have an array of methods in a class like this
class_methods = [:first, :second, :third, :fourth] ...

I defined a can_execute method to check if the class has the method, if so it will execute.

def can_execute (class, method_name)
  if class.respond_to?(method_name.to_sym) && class.class_methods.include?(method_name.to_sym)
    class.public_send(method_name)
  end
end

When user supplies any of those class_method as an argument, I can call them like this
can_execute(class, method_name)

Problem is some of those methods accepts hash as arguments, like
class.first(Value: true) or
class.second(Id: 0, Value: "string")

But some dont
class.third

I am not sure how to include the params hash some of these class_methods require?

I do have the option to check what arguments these methods require by calling, method_args on them, like

class.method_args(:first)
-> [:Value]

class.method_args(:second)
=> [:Id, :Value]

class.method_args(:third)
=> []
like image 497
arjun Avatar asked Oct 24 '25 19:10

arjun


1 Answers

You'll need to pass the arguments to can_execute so it can pass them to public_send. The splat operator is your friend here. When used as parameter, it will wrap any number of arguments into an array with it's name. When used on an array, it breaks the array down into arguments to pass to a method.

In addition to that, class is a keyword. The convention is to call it klass, but it can be whatever you want (other than class)

With that in mind, our new method looks like this:

def can_execute (klass, method_name, *args)
  if klass.respond_to?(method_name.to_sym) && klass.class_methods.include?(method_name.to_sym)
    klass.public_send(method_name, *args)
  end
end

Then to call, it can have parameters or not. No need to check first:

can_execute('teststring', :slice, 1, 5) # => "ests"
can_execute('teststring', :upcase) # => "TESTSTRING"

If you have another reason to want to check the params, you can use Method#arity or Method#parameters. Something like this with results for #slice

klass.method(method_name.to_sym).arity # => -1
klass.method(method_name.to_sym).parameters # => [[:rest]]
like image 95
iCodeSometime Avatar answered Oct 27 '25 09:10

iCodeSometime