Faking named parameters and enforcing required params

I come from years of using a language with named params. I prefer the
explicitness of it, so I’m tending to do a lot of it in my Ruby code
using a hash to fake it

object.method(:shape=>‘square’, :size=‘medium’)

What I am wondering is whether there’s an idiomatc preference to dealing
with the hash inside the method?

Currently, I just do the prozaic:

def task(parameters)
shape = parameters[:shape]
size = parameters[:size]

Should I be doing something else?

In that other language (Lasso), it also offered a way to declare
required and optional parameters

define_tag:‘task’,
-required = ‘shape’,
-optional = ‘size’;

...blah...

/define_tag;

which then got used like this:

object->task(-shape=‘square’, -size=‘large’) # legal
object->task(-shape=‘square’) # legal
object->task(-size=‘medium’) # failed for lack of required param

The required and optional features combined with some other stuff got
very close to a full design by contract implementation.

Anyway, I figured out I could simulate the assignment side of required
and optional with this:

def task(parameters)
@shape = parameters[:shape]
@size = parameters[:size] ||= ‘medium’

What I have’t figured out is an elegant pattern in Ruby for enforcing
required parameters – other than a bunch of hand written exception
coding.

To summarize my questions:

A) is there something better than x = parameters[:x]?
B) if :x isn’t in (parameters), what’s the best way to complain to the
developer about that?

Many thanks.

– gw

On Tue, Jun 24, 2008 at 8:12 AM, Greg W. [email protected]
wrote:
Maybe something like

class Hash
def require_all_keys *keys
keys.all?{ |k| has_key? k } or raise ArgumentError # better
doing an each here and raise an exception which argument was missing
of course, but I guess you got the idea;)
end
def provide_defaults defaults={}
defaults.each_pair{ |nk,nv|
self[nk]=nv unless has_key? nk
}
end
end

def whatever params={}
params.require :size, :age
params.provide_defaults :language => “en”, :id => 42

end

HTH

Robert


http://ruby-smalltalk.blogspot.com/


Les mêmes questions qu’on se pose
On part vers où et vers qui
Et comme indice pas grand-chose
Des roses et des orties.

Francis Cabrel

BTW I guess Facets has things like these already!

Robert

Greg W. wrote:

I come from years of using a language with named params. I prefer the
explicitness of it, so I’m tending to do a lot of it in my Ruby code
using a hash to fake it

object.method(:shape=>‘square’, :size=‘medium’)

What I am wondering is whether there’s an idiomatc preference to dealing
with the hash inside the method?
object->task(-shape=‘square’, -size=‘large’) # legal
object->task(-shape=‘square’) # legal
object->task(-size=‘medium’) # failed for lack of required param

The required and optional features combined with some other stuff got
very close to a full design by contract implementation.

Interestingly, I have also been working on something very similar to
this recently. [a named parameter parser for ruby]

Basically it parses an array as a parameter list, with some required and
some optional parameters.
ex:

[first remember that you can pass parameters to a method via * for a
variable number of parameters, i.e. def method *args; end passes in args
as an array of all parameters]

the syntax it uses is:

def method1 *as
required1, required2, optional1 = as.args [:required1, :required2],
{:optional1 => 3}
end

and you call it either named or unnamedly, a la:
method1 4, 5, 6
or
method1 4, 5
or
method1 :required1 => 1, :required2 => 2
or
method1 :required1 => 1, :required2 => 2, :optional1 => 4
or
method1 1, 2, :optional1 => 4
whichever floats your boat.

Try it out, let me know if it works.

the file is

http://code.google.com/p/ruby-roger-useful-functions/source/browse/trunk/arg_parser/enhanced_arg_parser.rb

and docs for it http://wilkboardonline.com/roger/arg_parser/doc/ [see
args method for description].
Thanks!

-R

My question is does anybody know the C code for ‘adding’ a variable to
the scope above the current?
something like

scope->prev->local_vars.push(name, object);

Thanks!
-R

It appears impossible [from casual glancing at the code] to add an
arbitrary local variable during runtime. This because it uses a ‘parse
then run’ style execution.
I.e.
a = 3
b
is first translated into
ASSIGN(a, 3)
CALL(b)

and then run consecutively.
And
a = 2
a
is translated into
ASSIGN(a, 2)
VAR_VALUE(a) since a is already defined. Then run.

So it appears that currently the only way to arbitrarily add a local
variable would be to hack the parse tree itself.

Guess I’ll file a requested feature of binding.set_local_variable :slight_smile:
-R

Basically it parses an array as a parameter list, with some required and
some optional parameters.
ex:

[first remember that you can pass parameters to a method via * for a
variable number of parameters, i.e. def method *args; end passes in args
as an array of all parameters]

My question is does anybody know the C code for ‘adding’ a variable to
the scope above the current?
something like

scope->prev->local_vars.push(name, object);

Thanks!
-R

So it appears that currently the only way to arbitrarily add a local
variable would be to hack the parse tree itself.

Appears that ParseTree and ruby2ruby provide this type of functionality
[see http://weblog.raganwald.com/2008/06/not-going-dark.html for an
example].

So my question is
say I’ve got a method
def method1(a, b=3)

end
that I want to allow to accept named parameter [a la method1(2, :b => 3)
or method1(:a => 2]

I could either rewrite the original method’s parse tree to allow for
named parameters [i.e. convert it to]
def method1(*args)
a, b = args.parse [:a], {:b => 3}

end
then ‘eval’ the newly created function, replacing the original with the
new

or I could just write a caller function, a la
alias :original_method1 :method1

def method1(*args)
a, b = args.parse [:a], {:b => 3}
original_method1(a, b)
end

so alias chain kind of.
Any thoughts on which of these would might be preferable?
Thanks!
-R

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs