Reputation: 3253
I've a method like:
def method (a=[],b=[])
...
end
I am calling this method with variables like this:
method(h[0].values_at("value"), h[1].values_at("value"))
where h[0]
and h[1]
are hashes. It works fine.
I dont know if h[1]
is going to be there in the next run, so it's giving me error if hash h[1]
is not there.
How can I modify it so it makes the call dynamically depending on whether h[0]
, h[1]
are there or not, and call the method with the correct number of parameters.
Upvotes: 1
Views: 351
Reputation: 64363
You can change the function signature to accept variable arguments.
def foo(*args)
options = args.extract_options!
p options
p args
end
Invocation without parameters
foo()
{}
[]
Invocation with 2 parameters
foo(1, 2)
{}
[1, 2]
Invocation with 3 parameters
foo(1, 2, 3)
{}
[1, 2, 3]
Invocation with 3 parameters and an option hash
foo(1, 2, 3, :debug => true)
{:debug=>true}
[1, 2, 3]
Upvotes: 0
Reputation: 27845
Hope I understood your problem right:
method(h[0].values_at("value"),
h[1] ? h[1].values_at("value") : []
)
Your problem: if h[1]
does not exist, h[1].values_at
will raise an exception. So you have to test first, if the value is available. In the code snipllet above I used a ternary operator.
An extended version would be:
par2 = []
par2 = h[1].values_at("value") if h[1]
method(h[0].values_at("value"),
par2
)
With my solution you don't need the default values in the method definition.
In your comment you extended your question.
With four parameters you could use it like this:
def method(p1,p2,p3,p4)
#...
end
method(
h[0] ? h[0].values_at("value") : [],
h[1] ? h[1].values_at("value") : [],
h[2] ? h[2].values_at("value") : [],
h[3] ? h[3].values_at("value") : [],
)
But I would recommend a more generic version:
def method(*pars)
#pars is an Array with all values (including empty arrays.
#The next check make only sense, if you need exactly 4 values.
raise "Expected 4 values, get #{pars.size}" unless pars.size == 4
end
method( *(h.map{|i|i.values_at("x")})
And another - probably not so good - idea:
Extend nil (the result of h[1]
if h
has not this element) to return []
for values_at:
class NilClass
def values_at(x)
[]
end
end
Upvotes: 1
Reputation: 2918
If you use Ruby On Rails you are able to execute try
method:
method(h[0].values_at("value"), h[1].try(:values_at, 'value') || [])
Examples for method try
:
nil.try('[]', :x) # => nil
{:x => 't'}.try('[]', :x) # => 't'
Upvotes: 0
Reputation: 35520
The simplest way to do exactly what you ask would be:
if h[1]
method(h[0].values_at("x"), h[1].values_at("x"))
else
method(h[0].values_at("x"))
end
Another idea is to put a default hash in the case where h[1] is nil
method(h[0].values_at("x"), (h[1]||{}).values_at("x") )
If you are sure h
never has more than 2 items, you can do:
method *(h.map{|i|i.values_at("x")})
Upvotes: 1