Changing default Ruby arguments - ruby

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.)

Related

In ruby, is there a method you can call on an object to return that object? [duplicate]

I am doing some reflection, and ran into an unexpected road block.
Is there an object method in ruby (or rails) that returns itself
ruby-1.9.2> o = Object.new
=> #<Object:0x00000104750710>
ruby-1.9.2> o.class
=> Object
ruby-1.9.2> o.send :self
NoMethodError: undefined method `self' for #<Object:0x00000104750710>
What I want
ruby-1.9.2> o.send :self
=> #<Object:0x00000104750710>
Is this built in? Or do I need to extend Object (It always gets me nervous opening up Object):
class Object
def itself
self
end
end
And then so:
ruby-1.9.2> o.send :itself
=> #<Object:0x00000104750710>
Ok, some background on what I am trying to achieve. I have a generic table helper in my rails app, and you call if like so:
render_list #person, [{field: :name, link_to: :itself},
{field: {address: :name}, link_to: :address}]
I was struggling on the right way to call :itself -- but i'm thinking that my patch is the way to go.
Yes! If you have Ruby 2.2.0 or later, you can use the Kernel#itself method.
You can see the extensive discussion of this feature here: https://bugs.ruby-lang.org/issues/6373. The patch was submitted by Rafael França in message #53.
You can see it in the official Ruby source by looking in object.c.
There is a discussion about adding such method: http://bugs.ruby-lang.org/issues/6373
If you are using Ruby version >= 1.9 you can use tap method with empty block:
Object.tap{} => Object
Object.new.tap{} => #<Object:0x5f41334>
self is the object itself, no need to extra fetch it. After your patch, try the following:
>> a=[2,3,4] #=> [2, 3, 4]
>> a == a.itself #=> true
>> a.object_id #=> 71056290
>> a.itself.object_id #=> 71056290
...it is exactly the same
self is a keyword referring to the default receiver. It is not a method. See this page for an example.
Your itself method works fine. You can also say:
o.instance_eval('self')
For a class, use class_eval instead:
Object.class_eval('self')
There is a #yourself method in Smalltalk. It has sense because of the syntax of the language where you can send several messages to the same object and want to get the object itself at the end of the phrase.
aList add: (anObjet doThis; andThat; yourself).
Also in Smalltalk the default return value for a method is self, but in Ruby it's the last instruction's return value (or nil if there is nothing in the method).
Anyway maybe we should all start using explicit returns :)
If for some weird logic reason you have to call a method on some object but what you want is really the object itself, then I don't see why you couldn't extend the Object class to do just that.
There's really no reason why it would break your program unless the method exists somewhere else (did or will exist) and did (or will) do something else. Maybe a slight loss in performance?
Try .presence
>> a=[2,3,4]
=> [2, 3, 4]
>> a == a.presence
=> true

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].

Is there a way to force usage of named parameters instead of your standard function_name(var, var)?

I really like named parameters, as they greatly help with the readability of my code.
Ruby uses pseudo-named parameters with hashes, and I've implemented a few methods using that technique, but adding these three lines to every method with parameters would get cumbersome:
def something_does_something_with(parameters = {})
default_params = {:some => option, :another => something}
parameters = default_params.merge(parameters)
...
end
or the method header could be like this:
def something_does_something_with(parameters = {:some => option, :another => something})
but then I think if I supply any parameters at all, it overrides the entire default hash.
When I worked with Objective-C, named-variables were my favorite thing in the programming universe.
Is there a way to modify the default way Ruby looks at method headers such that named-parameterss are required, or at least easier?
You definitely can not use second example because it will work only in case when you're passing a full set of parameters.
In reference to your first example you could make it short like this:
def something_does_something_with(parameters = {})
parameters = {:some=>option,:another=>something}.merge(parameters)
...
end
And finally, the named parameters is planning to implement in the next version of Ruby - Ruby 2.0

Advantages/disadvantages to using struct as a parameter while defining new API

The APIs that I am writing are for a Ruby class that inherits from ActiveRecord. I am trying to write static methods to avoid leaking the ActiveRecord instance. All the APIs now need tuple to uniquely identify a database row.
Is it a good idea to have APIs of the form:
API1(abc, def, ....)
API2(abc, def, ....)
and so on
or should I define a struct with fields to help with future changes?
Any other ideas are greatly welcome!
Using a struct would be strange in Ruby, a Hash would be normal:
def self.api1(options)
# Look at options[:abc], options[:def], ...
end
And then it could be called using named arguments like this:
C.api1 :abc => 'abc', :def => '...'
Easy to extend, common Ruby practice, and easy to make certain parameters optional.
To continue what mu is describing, a common Ruby idiom you'll see it to have a method set itself some default options and then merge into that hash the options that the method received. This way you can be sure that some minimum list of options always exist:
def self.api1(options={})
default_options = { :foo => 'bar', :baz => nil }
options = default_options.merge options
# Now include your code and you can assume that options[:foo] and options[:bar] are there
end
This comes in handy when your method, for example, outputs the value of :baz. Now you don't need to check that it exists first, you can just output it knowing that it would always exist.

Is there a ruby equivalent to the Scala Option?

How do I model an optional value in ruby? Scala has Option[], which is what I'm looking for in ruby.
There's no equivalent in the standard library. You have to define your own. See this article.
I'm not a Ruby expert, but I don't think there is an Option equivalent. As Ruby is object oriented, nothing stops you from writing your own implementation, but it won't be as useful as in a statically typed language, where the compiler forces you to do a proper check for the empty option, which is one of the main points for using this construct. Of course there are other advantages, like the possibility to chain Option values in several ways.
Have you checked out the Rumonade gem? It gives you an Option class modeled on scala.
require 'rumonade'
[nil, 1, 123].map { |v| Option(v) }
=> [None, #<Rumonade::Some:0x7f2589297768 #value=1>, #<Rumonade::Some:0x7f2589297740 #value=123>]
[nil, 1, 123].map { |v| Option(v).map { |n| n.to_s }.select { |s| s.size > 2 } }.flatten
=> ["123"]
There is an example of a Maybe class in nkpart's adt library under examples/common_adts.rb. There are also other example ADTs and the library makes it easier to define your own.
I have just pushed a gem called nil_be_gone that gives you an Optional that you can wrap objects with. It implements method_missing to check whether the value of the Optional is nil and if so simply return another Optional wrapped nil value, otherwise it calls the method on the object and wraps it again.
nil_be_gone implements bind as and_then which allows you to chain operations on Optional types, it's return methods which retrieves the value from Optional is value and the unit operation which wraps an object in the monad is defined by self.from_value.
I don't know Scala, so I can't assert that's your answer:
In ruby, when you call a method, you can define a default value for a param:
def foo(i_am_mandatory, i_am_optionnal = :banga)
puts i_am_optionnal
end
foo(:pouet, :plip)
=> :plip
foo(:pouet)
=> :banga
In that example, you can omit i_am_optionnal, which has a default value.
HTH.

Resources