I have controller "MyController" which has a class method "my_controller_class_method" which accepts arguments a,b,c
is there a way to pass "MyController.my_controller_class_method" as an argument to another method so I could do something like that:
def use_another_method(other_method,a,b,c)
#invoke method inside
other_method(a,b,c)
end
and then I could run
use_another_method(MyController.my_controller_class_method,a1,b1,c1)
You can use .method to get an object representing that method:
method_object = MyController.method(:my_controller_class_method)
method_object.call(a, b, c)
method_object.(a, b, c) # shorter syntax
That object can then be passed around and used as a function argument, just like any other object.
Related
For learning purposes, I'm exploring if I can convert these three method calls:
Foo::Bar.logger.debug(a)
Foo::Bar.logger.debug(b)
Foo::Bar.logger.debug(c)
into a single-line statement using the shorthand proc &method approach:
[a, b, c].each(&method(:'Foo::Bar.logger.debug'))
.debug does not respond to .to_proc so naturally:
NameError: undefined method `Foo::Bar.logger.debug' for class `#<Class:Foo>'
This does work; however, but isn't as succinct as the former:
logger = Proc.new { |x| Foo::Bar.logger.debug(x) }
[a, b, c].each(&logger)
Is it possible for the former approach to work?
You're using the method method incorrectly. From the fine manual:
method(sym) → method
Looks up the named method as a receiver in obj, returning a Method object (or raising NameError).
You'd usually say
m = some_obj.method(:some_method_name)
and then work with m. Saying:
method(:Foo::Bar.logger.debug)
should be giving you a TypeError because because :Foo is a symbol, not a class or module and trying to apply :: to a symbol makes no sense. I suspect that you're actually saying:
method(':Foo::Bar.logger.debug')
as that will produce the error you're seeing. Assuming that that's the case, then you're actually trying to get a reference to the method named ':Foo::Bar.logger.debug' in the object self.
If you want a reference to the debug method in Foo::Bar.logger then you'd say:
Foo::Bar.logger.method(:debug)
Combining that your to_proc call (via &):
[a, b, c].each(&Foo::Bar.logger.method(:debug))
Given a class that has method which accepts a splat, for example a method you get from ActiveRecord::FinderMethods:
class Settle
def self.find(*args)
end
end
How should I call that method from another method, say another class, so that it has the exact same signature?
class Settler
def self.find(*args)
Settle.find(*args)
end
end
Or
class Settler
def self.find(*args)
Settle.find(args)
end
end
Or something else?
Note that the exact same signature is the important part: Settler.find should work exactly similar to Settle.find.
I am not, however, interested in code that allows the Settler.find signature to magically update whenever Settle.find changes into something completely different, like e.g. .find(scope, *args). In that case, updating the version in Settler is no problem.
It should be
Settle.find(*args)
This way, all the arguments passed into Settler.find, are passed also to Settle.find and stored in args array inside of it. So the args arrays inside of both methods hold the same value.
Passing arguments as 'splat' is quite simple - it's just passing an array as separate arguments. So if you have
ar = [arg1, arg2, arg3, argn]
calling
some_method(*ar)
is equivalent to
some_method(arg1, arg2, arg3, argn)
I'd like to know how to call a method with a varying name. I have:
queries = ['new_teachers']
I'd like to call the method new_teachers on a module DailyQueries using a reference to the array element like DailyQueries[queries[i]], which should be equivalent to DailyQueries.new_teachers. Any help greatly appreciated.
You can use the public_send method to call an arbitrary method on an object. For example, foo.public_send(:bar) is equivalent to foo.bar, and works exactly the same way.
Knowing this you can define an array of symbols, where each symbol is a method you want to call. So:
[:bar, :baz, :qorg].each {|method|
DailyQueries.public_send(method)
end
will work the same as:
DailyQueries.bar
DailyQueries.baz
DailyQueries.qorg
Here's some reading material if you'd like to learn more about the public_send method, and its less privacy-respecting cousin, the send method:
What is the difference between ruby send and ruby public_send method?
What does send() do in Ruby?
Object#public_send on RubyDoc
If you need just a way to call a method if a variable has method name string, then, refer to #sawa's answer. If, for some specific reason, you need to invoke a module method using [] syntax, then, read on.
If you say method is part of module, then, it must be its singleton method as shown below, only then, you can invoke it using DailyQueries.new_teachers syntax
module DailyQueries
def self.new_teachers
["A", "B"]
end
end
You cannot invoke module methods using [] syntax - hence, you may have to add a method to module that does this for you.
module DailyQueries
def self.[] name, *params
method(name)[*params]
end
#... other methods definitions
end
Now, you can do this:
DailyQueries[queries[0]]
If the method had any parameters, you can pass arguments as:
DailyQueries[queries[0], "param1", "param2", :another_param]
DailyQueries.send(queries[i])
....................
I know what this means:
def f(*args)
...
end
But what does this mean and why would you want to use it? Can it appear with named parameters, too?
def f(*)
...
end
def f(*) has the same effect as def f(*args), except that it does not name the globbed argument array. You might use it if you want the function to accept any number of arguments but don't actually need to refer to them within the function -- for example, if you are overriding a method but calling super without passing an explicit argument list, which results in the original arguments being passed to super.
You can write def f(a, b, *) as well.
I know what this means:
def f(*args)
...
end
But what does this mean and why would you want to use it? Can it appear with named parameters, too?
def f(*)
...
end
def f(*) has the same effect as def f(*args), except that it does not name the globbed argument array. You might use it if you want the function to accept any number of arguments but don't actually need to refer to them within the function -- for example, if you are overriding a method but calling super without passing an explicit argument list, which results in the original arguments being passed to super.
You can write def f(a, b, *) as well.