List of methods: the methods are called always - ruby

How can I make a list of methods without running it and using it latter?
For example
def somedef
(anything)
end
a = [system("echo 'hello'"), 1, somedef]
After you type a=[system("echo 'hello'"), 1, somedef] you get hello and the result of somedef method. But I want to for example concatenate lists with methods within.

Use a proc
a = [Proc.new {system("echo 'hello'")}, Proc.new {1}, Proc.new{somedef}]
Whenever you have to execute the methods execute the call method of the proc.
a[0].call #Output: hello
a[1].call #Output: 1

In Ruby, you can leave out the parentheses when calling a method. (I am quite surprised that you have never seen this before, as it is indeed quite common to do so.) Ergo, what you are doing is simply calling the methods.
If you want to get a reference to the method as an object, you can call the method method, which returns a Method object:
a = [system("echo 'hello'"), 1, method(:somedef)]

Using method():
def hello
system("echo 'hello'")
end
=> nil
a = [method(:hello), 1]
=> [#<Method: Object#hello>, 1]
foo[0].call
hello
=> true

Depending on what your needs are you can also just save symbols and then send them to the appropriate object when necessary. For example:
def some_def
...
end
a = [:some_def]
self.send(a[0])
It's just an alternative to the other good answers on this page. It's a weak contract (you have to know that the object you are sending this messages to will respond to them) but it may be enough for some scenarios.

Related

Calling call() on a function in Ruby

I have code as follows:
def sum(a, b)
a + b
end
puts sum.call 2, 3
I get an error like:
wrong number of arguments (given 0, expected 2) (ArgumentError)
How can I call a function?
EDIT
I want to have a function able to call other one with certain arguments. I've written the code like below but the same error is still displayed.
def sum(a, b)
a + b
end
def kall(func, *args)
send(func, *args)
end
puts kall(sum, 2, 3)
In order to invoke the function sum, just delete the .call call:
def sum(a, b)
a + b
end
sum(1, 2)
# => 3
Other way to call the method is doing:
send(:sum, 1, 2)
Which invokes the method sum on the current context/object with the list of arguments (1, 2).
One more way to call a method is:
method(:sum).call(2, 3)
#=> 5
sum is not a function, it is a method. Methods belong to objects, they aren't objects. Ruby is an object-oriented language, which means you can only store objects in variables, only pass objects as arguments (with the slightly odd exception of blocks), only return objects from methods and only send messages to objects.
You cannot send a message to the sum method, because you can only send messages to objects, and methods aren't objects.
And even if it were possible to send messages to methods, there would still be an ambiguity in your code: Ruby allows you to leave out the argument list to a message send if you don't pass any arguments, therefore
sum
is a valid message send and is (somewhat) equivalent (modulo privacy) to
self.sum()
So, even if it were possible to send messages to methods, Ruby would still think that you try to send the sum message without an argument list.
So, since the problem is that we need an object, there are two things we can do. Firstly, we can use an object to begin with.
You used the term "function" in your question. Well, Ruby doesn't have functions, but it has something close to it: Procs. One solution would be to use a Proc instead of a method:
sum = -> (a, b) { a + b }
sum.(2, 3)
#=> 5
The other solution would be to obtain an object for the method. Ruby's Reflection System has a class called Method which responds to call, instances of which are reflective proxies for methods. You can obtain a Method object by sending the Object#method message to an object, e.g.:
sum = method(:sum)
sum.(2, 3)
#=> 5
You don't need to do .call or anything like that. If the function has no parameters, simply just type the name of the function. And if the function does have parameters, just do myFunction(param1, param2).
def hello
puts 'Hello, World!'
end
def output(string)
puts string
end
# Both of these do the same thing:
hello
hello()
# Doing that with stdout won't work though. It expects one argument, string
output('You can do it with parenthesis')
output 'You can also do it without'

Changing the object identity of a formal parameter

I will try to explain the problem with a simple example:
def enclose(x)
[x]
end
In my application, enclose does something more complex, but in essence it returns an array, the content of which is solely determined by the value of the parameter x. I could it use it like this:
foo = 'abcd'
....
foo = enclose(foo)
Now to my question: Is it possible to write a method enclose!, which simply replaces the parameter by its enclosed version, so that the example could be written as
foo = 'abcd'
....
enclose!(foo)
Since Ruby passes arguments by reference, I thought hat this could maybe be possible. The naive approach,
def enclose!(x)
x = [x]
end
does not work - I think this is because the assignment creates a new object and leaves the actual parameter untouched.
Is there way, that I can achieve my goal? I think in Smallalk, there would be a method become which would change the object identity, but I didn't find something similar in Ruby.
Since Ruby passes arguments by reference, I thought hat this could maybe be possible.
Ruby is pass-by-value, not pass-by-reference, which you have proven yourself, because otherwise your code would have worked.
I think in Smallalk, there would be a method become which would change the object identity, but I didn't find something similar in Ruby.
There isn't. Ruby has neither pass-by-reference nor become:, what you want simply isn't possible.
There's some other interesting posts about how ruby is pass by value, but the values are references.
What it boils down to is, you can modify the variable an object refers to, but you cannot change it to refer to another object.
> a = [1]
=> [1]
> def add_a(array)
> array << "a"
> end
=> :add_a
> add_a a
=> [1, "a"]
> a
=> [1, "a"]
There is a way to sort of accomplish what you are asking for but it's not quite pretty. Ruby has this concept of a binding (http://ruby-doc.org/core-2.2.0/Binding.html), which is like a CallContext in .NET.
You can do something like this:
def enclose(x)
[x]
end
def enclose!(x, binding)
eval("#{x} = [#{x}]", binding)
end
foo = 'abcd'
enclose!(:foo, binding)
=> ["abcd"]
In the script above, the :foo means you are passing the name of the variable, and the binding (context) where to find its value. Then you're dynamically calling eval to evaluate the assignment operation foo = [foo].

Defining method in Ruby with equals

Being new to Ruby, I'm having trouble explaining to myself the behavior around method definitions within Ruby.
The example is noted below...
class Foo
def do_something(action)
action.inspect
end
def do_something_else=action
action.inspect
end
end
?> f.do_something("drive")
=> "\"drive\""
?> f.do_something_else=("drive")
=> "drive"
The first example is self explanatory. What Im trying to understand is the behavior of the second example. Other than what looks to be one producing a string literal and the other is not, what is actually happening? Why would I use one over the other?
Generally, do_something is a getter, and do_something= is a setter.
class Foo
attr_accessor :bar
end
is equivalent to
class Foo
def bar
#bar
end
def bar=(value)
#bar = value
end
end
To answer your question about the difference in behavior, methods that end in = always return the right hand side of the expression. In this case returning action, not action.inspect.
class Foo
def do_something=(action)
"stop"
end
end
?> f = Foo.new
?> f.do_something=("drive")
=> "drive"
Both of your methods are actually being defined and called as methods. Quite a lot of things in Ruby can be defined as methods, even the operators such as +, -, * and /. Ruby allows methods to have three special notational suffixes. I made that phrase up all by myself. What I mean by notational suffixes is that the thing on the end of the method will indicate how that method is supposed to work.
Bang!
The first notational suffix is !. This indicates that the method is supposed to be destructive, meaning that it modifies the object that it's called on. Compare the output of these two scripts:
a = [1, 2, 3]
a.map { |x| x * x }
a
And:
a = [1, 2, 3]
a.map! { |x| x * x }
a
There's a one character difference between the two scripts, but they operate differently! The first one will still go through each element in the array and perform the operation inside the block, but the object in a will still be the same [1,2,3] that you started with.
In the second example, however, the a at the end will instead be [1, 4, 9] because map! modified the object in place!
Query
The second notational suffix is ?, and that indicates that a method is used to query an object about something, and means that the method is supposed to return true, false or in some extreme circumstances, nil.
Now, note that the method doesn't have to return true or false... it's just that it'd be very nice if it did that!
Proof:
def a?
true
end
def b?
"moo"
end
Calling a? will return true, and calling b? will return "moo". So there, that's query methods. The methods that should return true or false but sometimes can return other things because some developers don't like other developers.
Setters!
NOW we get to the meat of your (paraphrased) question: what does = mean on the end of a method?
That usually indicates that a method is going to set a particular value, as Erik already outlined before I finished typing this essay of an answer.
However, it may not set one, just like the query methods may not return true or false. It's just convention.
You can call that setter method like this also:
foo.something_else="value"
Or (my favourite):
foo.something_else = "value"
In theory, you can actually ignore the passed in value, just like you can completely ignore any arguments passed into any method:
def foo?(*args)
"moo"
end
>> foo?(:please, :oh, :please, :why, :"won't", :you, :use, :these, :arguments, :i, :got, :just, :for, :you, :question_mark?)
=> "moo"
Ruby supports all three syntaxes for setter methods, although it's very rare to see the one you used!
Well, I hope this answer's been roughly educational and that you understand more things about Ruby now. Enjoy!
You cannot define a return value for assignment methods. The return value is always the same as the value passed in, so that assignment chains (x = y = z = 3) will always work.
Typically, you would omit the brackets when you invoke the method, so that it behaves like a property:
my_value = f.do_something= "drive"
def do_something_else=action
action.inspect
end
This defines a setter method, so do_something_else appears as though we are initializing a attribute. So the value initialized is directly passed,

How can I get a reference to a method that contains the arguments used for invocations, in Ruby?

Given this code:
a = {1=>2}
m = a.method(:[])
I know that I can now use :
value = m.call(1)
and it will return 2. The thing is, what do I need to change so that I can call the method directly like :
m.call()
and it will get the 1 sent as a parameter? It would be nice to be able to write something like :
m = a.method(:[],1) # where the symbol is the method, and 1 will be the parameter it will be called with
The thing is, I'd like to delay the execution of certain parts of my script until some objects get created, and I'd like to avoid rewriting EVERYTHING to use lambdas.
Basically, what you want is a way to curry the function.
http://en.wikipedia.org/wiki/Curry_function
This can be done in many different ways, one of which:
def curry(method, *params)
lambda { send method, *params }
end
You can add this to Hash's metaclass, or to a module you want to include in some of your objects, etc. Then, calling it becomes the usecase you wanted:
irb(main):001:0> a = {1 => 2}
=> {1=>2}
... # add curry to Hash's metaclass
irb(main):011:0> m = a.curry :[], 1
=> #<Proc:0xb76e2154#(irb):8>
irb(main):012:0> m.call
=> 2
There's more than one way to do it, I'm sure.
a = {1=>2}
class << a
def fetch_what(key)
Proc.new { self[key] }
end
end
....
m = a.fetch_what(1)
m.call() # -> 2
It sounds like you should attach the method parameters to the object you're calling the method on, and have the method access them as instance variables.
In terms of simple refactoring steps:
Introduce new instance variables, one per method parameter.
Introduce new accessors for the instance variables.
Refactor the method to use the instance variables if the parameters are not supplied.
Refactor the calling code to set the instance variables through the accessors, at some point prior to the method call.
Refactor the calling code to pass no parameters in the method call.
As an example, refactor calling code like this:
widget = Widget.new
assembly_method = widget.method(:assemble)
# Time passes...
assembly_method.call(:electric, :smooth)
to work like this:
widget = Widget.new
widget.frombulator = :electric
widget.jazzifier = :smooth
assembly_method = widget.method(:assemble)
# Time passes...
assembly_method.call
It's not sexy or clever, but it will result in code that expresses its intent, and odds are good that it will address the real problem, namely that something is missing from your model.

Changing default Ruby arguments

I want to change the default arguments passed to a Ruby function. For example, instead of each time writing
[1,2,3].do_stuff(:option => ' my option ')
I want to modify the defaults so that I can write
[1,2,3].do_stuff
What is the simplest, cleanest, most Ruby-like way of changing default parameters?
>> [1, 2, 3].do_stuff
=> Result I get
>> [1, 2, 3].do_stuff :an_option => a_value
=> Result I really want, but don't want to specify the argument
I like to use super for this. It allows us to add some functionality to the method apart from just changing default arguments:
class Array
def do_stuff(options = {})
# Verify if caller has not passed the option
options[:argument_i_want_to_change] = default_value_i_want unless options.has_key? :argument_i_want_to_change
# call super
super
end
end
Result:
>> [1, 2, 3].do_stuff
=> Result that I really want
UPDATE: Removed reverse_merge! dependency. (Now looking for a better alternatives to using []= method)
(moved from your original question)
I assume you are talking about a method Array#do_stuff that already exists, but you want to modify it slightly (in your case by changing a default parameter).
A post here gives a nice way of doing it. It doesn't suffer from the same problems as the alias technique, as there isn't a leftover "old" method.
Here how you could use that technique with your example problem (tested with ruby 1.9)
class Array
old_do_stuff = instance_method(:do_stuff)
define_method(:do_stuff) { |options = {}|
options[:option] ||= " option "
old_do_stuff.bind(self).call(options)
}
end
You might also want read up on UnboundMethod if the above code is confusing. Note that old_do_stuff goes out of scope after the end statement, so it isn't a problem for future uses of Array.
Are you wanting a solution for code you didn't write yourself? There are two options I'm aware of.
Code you wrote yourself:
def some_method_you_wrote(options)
becomes:
def some_method_you_wrote(options = { :option1 => 'value' })
(Swanand's answer is nice too)
For code you didn't write, look into aliasing methods. (Rails provides something called alias_method_chain for this purpose, IIRC.)

Resources