for instance in python it is possible to assign a method to a variable:
class MyClass
def myMethod(self):
return "Hi"
x = MyClass()
method = x.myMethod
print method() # prints Hi
I know this should be possible in Ruby, but I don't know what's the syntax.
You need to grab the method by using method with the method’s name as an argument. This will return you an instance of type Method, which can be called with call().
class MyClass
def myMethod
"Hi"
end
end
x = MyClass.new
m = x.method(:myMethod)
# => #<Method: MyClass#myMethod>
puts m.call
# You can also do m[] instead of m.call()
Note that any arguments would need to be added to the call method.
In many practical cases, however, there is no need to have the method itself saved to a variable in Ruby; if you just want to dynamically call a method (i.e. send a message to an object) and there is no need to save the method, you could also use the send (or __send__ method in case of name clashes).
x = MyClass.new
puts x.send :myMethod # also possible with a string: m.send "myMethod"
# "Hi"
Any arguments should follow the method name:
puts x.send(:myMethod, arg1, arg2)
To use it like this is probably more Ruby-like, as the concept of Method classes is not as prominent as it is in Python. In Python, you can always think of a two step mechanism when doing something like a_string.split(); first you grab the method with a_string.split and then you call it (either implicitly with () or explicitly with __call__()). So, cutting that two-step mechanism is rather natural to do.
Ruby is more based on message passing and to actually get a method class in Ruby, you’ll have to do some more work, because in some way, the method object will have to be constructed for you at that point. So, unless you really need some Methods object in Ruby, you should rather stick to the message passing abstraction and simply use send.
I think you are looking for Proc or lambda block
x = Proc.new { return "Hello World" }
puts x.call
x = lambda { return "Hello World" }
puts x.call
I would read this short post - there is a slight but significant difference in the way the methods behave
http://samdanielson.com/2007/3/19/proc-new-vs-lambda-in-ruby
Related
This article touches on the issues but doesn't give a solution.
This started when I wanted to write a method and optionally pass it an argument which could be null or a ???? (proc, lambda, method, block, ???). Lets call it, for now, a block because a block works. The block takes one required argument. An example of the method and a call to it would be:
#!/usr/bin/env ruby
def foo(&proc)
puts "before"
if proc
yield "passed to proc"
end
puts "after"
end
def add_message(s)
puts "from add_message #{s}"
end
foo { |s| add_message(s) }
foo
And the output is:
before
from add_message passed to proc
after
before
after
Great. But, what I'd like to do is be able to call foo like this: foo(&:add_message). But I can't. Changing line 15 above I get:
before
./temp.rb:11:in `add_message': wrong number of arguments (given 0, expected 1) (ArgumentError)
from ./temp.rb:6:in `foo'
from ./temp.rb:15:in `<main>'
And, as the article above mentions, the arity is now -2. So, how do I write a simple method like add_message that I can use with &:add_message. OR!!! as is the case 99.99% of the time, please set me on the proper track on how to do this.
The problem is that Symbol#to_proc does not create a proc that calls add_message method correctly.
# `yield` will pass its arguments to proc
>> :add_message.to_proc.call('passed to proc')
# => ArgumentError
This calls 'passed to proc'.add_message, because our method is defined in Object it works when called on String, however it is missing the required argument.
The solution is to make a proc that can accept the same arguments as add_message method and pass them along to that method. We can use Object#method that returns Method object that implements its own to_proc and has the same arity as the method.
>> method(:add_message).to_proc.arity
=> 1
>> method(:add_message).to_proc.call('passed to proc')
from add_message passed to proc
>> foo(&method(:add_message))
before
from add_message passed to proc
after
From the Ruby docs
Conversion of other objects to procs
Any object that implements the to_proc method can be converted into a proc by the & operator, and therefore can be consumed by iterators.
class Greeter
def initialize(greeting)
#greeting = greeting
end
def to_proc
proc {|name| "#{#greeting}, #{name}!" }
end
end
hi = Greeter.new("Hi")
hey = Greeter.new("Hey")
["Bob", "Jane"].map(&hi) #=> ["Hi, Bob!", "Hi, Jane!"]
["Bob", "Jane"].map(&hey) #=> ["Hey, Bob!", "Hey, Jane!"]
Of the Ruby core classes, this method is implemented by Symbol, Method, and Hash.
So when you pass an argument with a unary ampersand before it, to_proc gets called on it. The &: "syntax" is actually & being called on a symbol literal, i.e. &(:foobar), and Symbol.to_proc has the behavior of converting a symbol into a method call on its first argument, i.e. these two are roughly equivalent (modulo named argument forwarding)
:foobar.to_proc
proc { |x, *args| x.foobar(*args) }
Ruby's Method type also implements to_proc, so if you have a standalone method called foobar (on a module, say, Example), then you can call Example.method(:foobar) and get an &-compatible object. If you have a "top-level" method, then it's probably being defined on the main object and calling method with no explicit receiver will work.
The other type mentioned in that quote is hashes, which can be turned into a function mapping their keys to their values (and returning nil if no matching key exists). And, of course, you can always implement a method called to_proc on your own classes and it'll work just as well as any built-in type.
class Integer
def set
return self + 1
end
end
p [1,2,3,4,5,6].map(&:set)
I think when you can use &: syntax that a method have been defined for a class like above
Is there a way to create a object that has properties and can be called using only the notation of a function call? Something equivalent to Python's __call__.
For example:
obj = ExampleClass.new()
obj() # call notation
Alternate approaches are welcome, I need a way for the callable "object" to store its own properties.
What I am trying to do is store a callable "object" in a variable. This object has properties that are associated with it, while at the same time, it can be used exactly like a method.
If you're willing to change the desired syntax a little bit...
class Foo
def call
puts 'called'
end
end
f = Foo.new
f.()
# >> called
The exact syntax, as in your question, is not possible in ruby, because parentheses are optional and, therefore, f() is the same as f. Which, in the case of a callable object is ambiguous. Do you want to perform the call or only reference the callable object? Explicit call (with the dot syntax) removes the ambiguity.
You can't make an object callable, as far as I know that's reserved for method calls, but you can do it with a bit of a hack using an alternate notation:
class ExampleClass
def []
:callable
end
end
Where now you can do:
example = ExampleClass.new
example[]
This is similar to how you can call a Proc:
proc = Proc.new { :return_value }
proc[]
# => :return_value
It's not perfect, but it'll work.
Note that normally you can side-step a lot of this mess by architecting your API around these limitations.
One thing that u can do is simple create an class and a function with the same name:
class Thing
end
def Thing()
end
Thing.new
Thing()
I've been writing a DSL, and I'm trying to get a dynamically defined method to be accessible from a lambda. This works fine unless you try to do a setter something= in which case the lambda invocation just sets a local variable instead.
A simplified example:
class Caller
attr_accessor :cmd
def callme
self.class.send(:define_method, "something") { puts "Retrieve Something" }
self.class.send(:define_method, "something=") {|val| puts "Set Something = #{val}" }
instance_exec &cmd
end
end
c = Caller.new
c.cmd = lambda { something = 1 }
c.callme
This also works fine if I use self.something=. However that's less than ideal in the case of a DSL.
Is it possible to get this to work without self. in front of the method?
This has absolutely nothing to do with blocks or dynamically defined methods. It's just simple basic Ruby syntax:
foo = bar
is local variable assignment. Always.
self.foo = bar
is a method call.
Is it possible to get this to work without self. in front of the method?
No.
This is just basic Ruby syntax. The define_method metaprogramming, the instance_exec, the blocks in your code sample are just a red herring, the problem can be demonstrated with a much simpler example:
def foo=(*)
puts 'I was called!'
end
foo=('bar') # even removing spaces and adding parentheses won't help!
self.foo = 'bar'
# I was called!
Note also that foo= is private but was actually called with an explicit receiver (which is illegal for private methods). That's a special exception for setter methods in the rule for private methods, because they otherwise couldn't be called at all, precisely because they would always be interpreted as a local variable assignment.
I understand that method_missing is something of a last resort when Ruby is processing messages. My understanding is that it goes up the Object hierarchy looking for a declared method matching the symbol, then back down looking for the lowest declared method_missing. This is much slower than a standard method call.
Is it possible to intercept sent messages before this point? I tried overriding send, and this works when the call to send is explicit, but not when it is implicit.
Not that I know of.
The most performant bet is usually to use method_missing to dynamically add the method being to a called to the class so that the overhead is only ever incurred once. From then on it calls the method like any other method.
Such as:
class Foo
def method_missing(name, str)
# log something out when we call method_missing so we know it only happens once
puts "Defining method named: #{name}"
# Define the new instance method
self.class.class_eval <<-CODE
def #{name}(arg1)
puts 'you passed in: ' + arg1.to_s
end
CODE
# Run the instance method we just created to return the value on this first run
send name, str
end
end
# See if it works
f = Foo.new
f.echo_string 'wtf'
f.echo_string 'hello'
f.echo_string 'yay!'
Which spits out this when run:
Defining method named: echo_string
you passed in: wtf
you passed in: hello
you passed in: yay!
I want to store several different methods in an array in Ruby. Suppose I want to store the type method twice:
[type, type]
doesn't store two entries of type in an array; it executes type twice, and stores the results in the array. how do I refer explicitly to the method object itself?
(this is just a simplified version of what I really want.)
EDIT: on second thoughts, it bothers me that the solution proposed below avoids the problem by passing the name of the method. how do you pass the method object itself? for example, what if you pass [:type, :type] to a method that has an alternative resolution for type? how can you pass the type method object itself?
If you want to store a method rather than the result of calling a method or just the message you'd send to invoke it, you need to use the method method on the owning object. So for example
"hello".method(:+)
will return the + method of the object "hello", so that if you call it with the argument " world", you'll get "hello world".
helloplus = "hello".method(:+)
helloplus.call " world" # => "hello world"
If you're thinking about doing method references in Ruby, you're doing it wrong.
There is a built-in method in Ruby called method. It will return a proc version of the method. It is not a reference to the original method, though; every call to method will create a new proc. Changing the method won't affect the proc, for example.
def my_method
puts "foo"
end
copy = method(:my_method)
# Redefining
def my_method
puts "bar"
end
copy.call
# => foo
When you want to store pieces of code, and don't want to use regular methods, use procs.
stack = [proc { do_this }, proc { do_that }]
stack.each {|s| s.call }
[:type, :type].collect { |method_name| self.send(method_name) }
Alternatively, if the method is part of an object:
method = obj.method(:type)
values = [method.call, method.call]