[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Faking named parameters and enforcing required params

Greg Willits

6/24/2008 6:12:00 AM

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
--
Posted via http://www.ruby-....

6 Answers

Robert Dober

6/24/2008 8:17:00 AM

0

On Tue, Jun 24, 2008 at 8:12 AM, Greg Willits <lists@gregwillits.ws> 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=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.blo...

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

Robert Dober

6/24/2008 8:18:00 AM

0

BTW I guess Facets has things like these already!

Robert

Roger Pack

7/6/2008 5:04:00 AM

0

Greg Willits 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...

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

-R
--
Posted via http://www.ruby-....

Roger Pack

7/8/2008 10:12:00 PM

0

> 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
--
Posted via http://www.ruby-....

Roger Pack

7/9/2008 4:57:00 AM

0


> 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
--
Posted via http://www.ruby-....

Roger Pack

7/9/2008 11:45:00 PM

0

> 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... 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
--
Posted via http://www.ruby-....