From: Robert Klemme Date: 2010-10-07T23:49:42+09:00 Subject: Re: named parameters in ruby? On Wed, Oct 6, 2010 at 6:05 PM, xiMera wrote: > Hi all, > > Ruby does not support named parameter for now as all of you know. > There is really three solutions for this > * hash as parameter > * class as parameter > * bindings > > Hash parameters: > > def do_some( params ) >  a = params[ :a ] >  b = params[ :b ] > end > > do_some :a => 1, :b =>2 That's really the best solution available today. > Class parameters (ugly, written in couple minutes) > > class A >    def metaclass >        class << self; self; end >    end > >    def set_var( name, val ) >        eval "@#{name} = val", binding >        self.metaclass.send( :define_method, name ) do >            eval "@#{name}" >        end >    end >    def set_vars( params ) >        params.each{ |key,val| self.set_var( key, val ) } >    end > end > > > def do_some( params ) >  a = params.a >  b = params.b > end > > A.new Where do you store result of A.new? > a.set_vars( :a => 1. :b =>2 ) > do_some a I don't think anybody would do this, after all it's much too convoluted. Also, why do you (ab)use a class for storing temporary state? You could as well do A = Struct.new :a, b: do_some A[1,2] or do_some OpenStruct.new(:a=>1,:b=>2) But even that is much more complicated than the Hash version. Plus, you do not get rid of the assignment in the block which you call "ugly" further on. > Bindings way: > > def do_block( &block ) >   eval "a=1", block.binding >   eval "b=2", block.binding > end > > do_block( params ){ >  a = eval 'a' >  b = eval 'b' > } Local assignments in the block are even worse. Also, this won't run because you pass one argument while the method expects none. > As we can see there is overtyping in all cases. We always need to map > incoming variables into locals or write ugly accessor every time. > > So My question is: >   Is there any way to set local variables for blocks outside of block > scope? > > IMHO nice solution will looks like this: Frankly, I can't see what's nice about this approach. > def do_some( &block ) >  block.binding.set_var( 'a', 1 ) >  block.binding.set_var( 'b', 2 ) >  block.call > end > > do_some{ >   puts a >   puts b > } And what do you need that for? You can do this already today: def do_some yield 1,2 end do_some do |a,b| puts a puts b end Your solution with the "injection" of local variables cannot work because the variables are not known inside the block so Ruby will error out. Also, it is not obvious where the values are coming from so reading this code will be made harder. I think your alternative solutions need a bit more polishing. :-) Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/