Henley Wing Chiu
Henley Wing Chiu

Reputation: 22535

Ruby - how to pass a single argument to a method with long list of arguments?

Is there a way to pass a single argument to a ruby function that has only optional parameters?

For instance, I want to pass ignoreAlreadyCrawled = true in the method below, and use the default parameter values for everything else. But since it's the last parameter, I have to do call crawl(nil, nil, nil, false, nil, false, nil, false, [], true), which is verbose, and ugly.

Method:

def crawl(url = nil, proxy = nil, userAgent = nil, post = false, postData = nil, image = false, imageFilename = nil, forceNoUserAgent = false, ignoreSubDomains = [], ignoreAlreadyCrawled = false)   
        #..logic here
    end      

Upvotes: 0

Views: 728

Answers (2)

Max Williams
Max Williams

Reputation: 32955

When you have more than two or three arguments, the preferred pattern is to use a Hash of options instead.

I would redefine this method as follows: this is similar to Pawel's but more readable, i think:

def crawl(options={})
  defaults = { url: nil, 
               proxy: nil, 
               userAgent: nil, 
               post: false, 
               postData: nil, 
               image: false, 
               imageFilename: nil, 
               forceNoUserAgent: false, 
               ignoreSubDomains: [], 
               ignoreAlreadyCrawled: false
             }
    options = defaults.merge(options)
    #..logic here

end

You could omit from defaults all options that have nil as their default, as an undefined option will come out as nil anyway. But, having them there acts as documentation for which options can be passed.

Upvotes: 1

Paweł Dawczak
Paweł Dawczak

Reputation: 9649

This is possible for ruby >= 2.0 with keyword arguments. In that case, you have to modify the method signature as follows (basically change = to :):

def crawl(url: nil, proxy: nil, userAgent: nil, post: false, postData: nil, image: false, imageFilename: nil, forceNoUserAgent: false, ignoreSubDomains: [], ignoreAlreadyCrawled: false)   
    #..logic here
end

And it will work as expected:

crawl(ignoreAlreadyCrawled: true)

Please see article for more examples: https://robots.thoughtbot.com/ruby-2-keyword-arguments

Upvotes: 8

Related Questions