Faking named parameters and enforcing required params

G

Greg Willits

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
 
R

Robert Dober

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=3D{}
defaults.each_pair{ |nk,nv|
self[nk]=3Dnv unless has_key? nk
}
end
end

def whatever params=3D{}
params.require :size, :age
params.provide_defaults :language =3D> "en", :id =3D> 42

end

HTH

Robert

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

---
Les m=EAmes questions qu'on se pose
On part vers o=F9 et vers qui
Et comme indice pas grand-chose
Des roses et des orties.
-
Francis Cabrel
 
R

Roger Pack

Greg said:
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],
{:eek:ptional1 => 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, :eek:ptional1 => 4
or
method1 1, 2, :eek:ptional1 => 4
whichever floats your boat.

Try it out, let me know if it works.

the file is

http://code.google.com/p/ruby-roger...rowse/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
 
R

Roger Pack

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
 
R

Roger Pack

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 :)
-R
 
R

Roger Pack

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 :eek:riginal_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
 

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,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top