Forum: Ruby Verifying keyword arguments

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Eli B. (Guest)
on 2006-03-24 08:23
(Received via mailing list)
Hello all,

I'm now writing my first real Ruby module, and on the second function I
already run into a pattern that seems to be very common.
I like using keyword arguments for methods, as follows:

def method(args)
  ...
end

And then call:

method(:arg1 => value1, :arg2 => value2)

And so on.
Now, often some arguments are compulsory, so I wrote the following code
to verify it:

def method(args)
  [:username, :password, :url].each do |arg|
    raise(ArgumentError, "Argument :#{arg} is compulsory" unless
args.has_key?(arg)
  end

  ...
end

I have two questions:
1) Is this the right/idiomatic/best way to achieve what I'm attempting
?
2) Is there a library that encapsulates this capability, or is everyone
writing one of his own ? Because if I don't find any, I surely will
write one... It should be enough saying:

verify_args(:username, :password, :url)

Instead of the .each do iteration everywhere

Eli
unknown (Guest)
on 2006-03-24 16:37
(Received via mailing list)
On Fri, 24 Mar 2006, Eli B. wrote:

> And then call:
> args.has_key?(arg)
> write one... It should be enough saying:
>
> verify_args(:username, :password, :url)
>
> Instead of the .each do iteration everywhere
>
> Eli

http://codeforpeople.com/lib/ruby/
http://codeforpeople.com/lib/ruby/parseargs/parsea...

regards.

-a
Eli B. (Guest)
on 2006-03-25 07:04
(Received via mailing list)
Eli B. wrote:
> And then call:
> args.has_key?(arg)
> write one... It should be enough saying:
>
> verify_args(:username, :password, :url)
>
> Instead of the .each do iteration everywhere
>
> Eli

Is this topic of no interest to anyone but me ? :-/
Ross B. (Guest)
on 2006-03-25 12:03
(Received via mailing list)
On Sat, 2006-03-25 at 14:03 +0900, Eli B. wrote:
> >
> >     raise(ArgumentError, "Argument :#{arg} is compulsory" unless
> > args.has_key?(arg)
> >   end
> >
> >   ...
> > end
> >
> > I have two questions:
> > 1) Is this the right/idiomatic/best way to achieve what I'm attempting
> > ?

It works, and strikes me as more compact and elegant than a simple
'raise unless args[:username] && args[:password] && ...'.

> > 2) Is there a library that encapsulates this capability, or is everyone
> > writing one of his own ? Because if I don't find any, I surely will
> > write one... It should be enough saying:
> >
> > verify_args(:username, :password, :url)
> >
> > Instead of the .each do iteration everywhere
> >

Not sure about libraries (though I'm sure they are out there, check RAA
and Rubyforge) but here's a little trick I've used before:

args = { :one => 'two', :three => 'four' }
# => {:three=>"four", :one=>"two"}

h = Hash.new { |h,k| raise ArgumentError, "#{k}" }.merge(args)
# => {:three=>"four", :one=>"two"}

h[:one]
# => "two"

h[:three]
# => "four"

h[:two]
ArgumentError: two
        from (irb):5
        from (irb):11

This way, you never actually check the arguments explicitly, but you'll
be told if your method uses one that wasn't passed. Obviously for
optional arguments you go to the original hash.
Eli B. (Guest)
on 2006-03-25 16:09
(Received via mailing list)
Ross B. wrote:
> > > end
> > >   [:username, :password, :url].each do |arg|
>
> > >
> h[:one]
> This way, you never actually check the arguments explicitly, but you'll
> be told if your method uses one that wasn't passed. Obviously for
> optional arguments you go to the original hash.
>

This is a nice trick that can be used to handle optional keyword
variables with default values, and indeed it helps detect unwanted
variables.
I think it can be somehow combined with the method I presented - the
aim of which is to detect if any compulsory argument wasn't passed in.
After all, there are arguments for which a default value is
meaningless.

Eli -- (http://eliben.blogspot.com)
Joel VanderWerf (Guest)
on 2006-03-25 23:08
(Received via mailing list)
Ross B. wrote:
...
> # => "two"
> be told if your method uses one that wasn't passed. Obviously for
> optional arguments you go to the original hash.
>

What about using rescue for optional arguments? It might be slower
though.
Eli B. (Guest)
on 2006-03-26 21:29
(Received via mailing list)
Joel VanderWerf wrote:
> >
> >
> > This way, you never actually check the arguments explicitly, but you'll
> > be told if your method uses one that wasn't passed. Obviously for
> > optional arguments you go to the original hash.
> >
>
> What about using rescue for optional arguments? It might be slower though.
>

What do you mean ? Can you provide an example ?
Joel VanderWerf (Guest)
on 2006-03-26 23:29
(Received via mailing list)
Eli B. wrote:
>>> # => {:three=>"four", :one=>"two"}
>>>         from (irb):11
>>>
>>> This way, you never actually check the arguments explicitly, but you'll
>>> be told if your method uses one that wasn't passed. Obviously for
>>> optional arguments you go to the original hash.
>>>
>> What about using rescue for optional arguments? It might be slower though.
>>
>
> What do you mean ? Can you provide an example ?
>

args = { :one => 'two', :three => 'four' }
# => {:three=>"four", :one=>"two"}

h = Hash.new { |h,k| raise ArgumentError, "#{k}" }.merge(args)
# => {:three=>"four", :one=>"two"}

h[:one]
# => "two"

h[:three]
# => "four"

v = h[:two] rescue "this string is the default for 'two'"
p v
# => "this string is the default for 'two'"
This topic is locked and can not be replied to.