1

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.

4 Answers 4

1

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
Sign up to request clarification or add additional context in comments.

7 Comments

above, I used only two params but I've actually 4 paramas in that method. so you mean to say if I do like this par1 = [] par2 = [] par3 = [] par4 = [] par1 = h[1].values_at("value") if h[0] par2 = h[1].values_at("value") if h[1] par3 = h[2].values_at("value") if h[2] par4 = h[3].values_at("value") if h[3] method(par1,par2,par3,par4) it will take care whether those params are thereor not. i'vent tried yet i'll try now and post the result
If you have 4 parameters, doing it this way will be a maintenance hassle. I would suggest method *(h[0..3].map{|i|i.values_at("x")}) - this expands into however many arguments you have defined, and lets the function defaults take care of the rest.
Thanks a lot to all for the answers. method *(h.map{|i|i.values_at("x")}) is working too. But I couldn't understand what does map actually doing. Tried to search , but didnt really get the answer. Can someone please point me where map is explained properly. Thanks again.
There are two stars. in def xx(*args) it is saying: Give me as much parameters as you want, I store the in the Array args. so xx( 1,2,3 ) results in [1,2,3]. The star in the method call makes the opposit. Imagin you have an array arr = [1,2,3]. You want to call xx with this parameter list. xx(arr) would call xx with one parameter (the array). You may call it with xx(arr[0], arr[1], arr[2]). But thats annoying. So you can use xx(*arr). You may find more about this with the keyword splat
Sorry, I'm reading the posts in the wrong order ;). map or collect loop on the array and call the block for each element of the block. The result of the block is stored in an array. this array is the result of the method map. See also ruby-doc.org/core-1.9.3/Array.html#method-i-map
|
1

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")})

Comments

0

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'

Comments

0

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]
    

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.