Verifying keyword arguments

E

Eli Bendersky

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
 
E

Eli Bendersky

Eli said:
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

Is this topic of no interest to anyone but me ? :-/
 
R

Ross Bamford

Eli said:
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
?

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

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 = { :eek:ne => 'two', :three => 'four' }
# => {:three=>"four", :eek:ne=>"two"}

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

h[:eek:ne]
# => "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.
 
E

Eli Bendersky

Ross said:
Eli said:
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
?

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

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 = { :eek:ne => 'two', :three => 'four' }
# => {:three=>"four", :eek:ne=>"two"}

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

h[:eek:ne]
# => "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.

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

Joel VanderWerf

Ross Bamford wrote:
...
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 = { :eek:ne => 'two', :three => 'four' }
# => {:three=>"four", :eek:ne=>"two"}

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

h[:eek:ne]
# => "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.

What about using rescue for optional arguments? It might be slower though.
 
E

Eli Bendersky

Joel said:
Ross Bamford wrote:
..
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 = { :eek:ne => 'two', :three => 'four' }
# => {:three=>"four", :eek:ne=>"two"}

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

h[:eek:ne]
# => "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.

What about using rescue for optional arguments? It might be slower though.

What do you mean ? Can you provide an example ?
 
J

Joel VanderWerf

Eli said:
Joel said:
Ross Bamford wrote:
..
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 = { :eek:ne => 'two', :three => 'four' }
# => {:three=>"four", :eek:ne=>"two"}

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

h[:eek:ne]
# => "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.
What about using rescue for optional arguments? It might be slower though.

What do you mean ? Can you provide an example ?

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

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

h[:eek:ne]
# => "two"

h[:three]
# => "four"

v = h[:two] rescue "this string is the default for 'two'"
p v
# => "this string is the default for 'two'"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top