From: tamouse mailing lists Date: 2013-02-04T17:18:20+09:00 Subject: Re: Easy way to handle positional and hashed parameters on a method? On Sun, Feb 3, 2013 at 3:05 AM, Marc Heiler wrote: > Yes, I just tested in IRB: All my examples were first run through IRB. > > > When I input: > > foo({first: 'a', second: 'b', third: 'c'}) > > It will return the CHANGED version: > > [{:first=>"a", :second=>"b", :third=>"c"}] > > I believe this is a design decision. I'd say it's a backwards-compatibility decision, to make sure both ways still work and not needlessly breaking old code. > Internally, ruby will ALWAYS treat the new > hash syntax as the old hash syntax! So I > recommend to use the old hash syntax, your > brain will be happier in the long run. ;) Not a chance. I much prefer the new way. My brain is quite happy TYVM. :) What you answered was none of what I was actually asking for. ...And I really think I demonstrated I knew how splat works... What I'd like is a DRY and functional way to do this. The question is really, how can I convert an array that may contain ['a', 'b', {:third => 'c'}] to {:first => 'a', :second => 'b', :third => 'c'}, plus all *other* variants of that first form, to the *same* final form, as an arguments hash, in an elegant, functional fashion. I can do it, but it doesn't feel elegant this way. And there *is* a way to convert the last form as well: foo(({z: 1, x: 2}), 'bazinga!', third: 17) comes into *args as: => [{:z=>1, :x=>2}, "bazinga!", {:third=>17}] # brute force conversion: def splatargdeflate(args,argnames) return args unless args.is_a?(Array) return args if args.length < 1 if args.last.is_a?(Hash) last_arg = args.pop else last_arg = {} end arg_hash={} argnames.each_index do |i| arg_hash[argnames[i]] = args.shift end arg_hash.merge!(last_arg) args.unshift arg_hash end def foo(*args) args = splatargdeflate(args,[:first, :second, :third]) puts args.inspect end Here's the output for the example foo call from above: puts foo(({z: 1, x: 2}), 'bazinga!', third: 17) => [{:first=>{:z=>1, :x=>2}, :second=>"bazinga!", :third=>17}] And here's some more, to compare: puts foo => [] puts foo(1) => [{:first=>1, :second=>nil, :third=>nil}] puts foo(1,2) => [{:first=>1, :second=>2, :third=>nil}] puts foo('a', 'b', 'c') => [{:first=>"a", :second=>"b", :third=>"c"}] puts foo('a', 'b', third: 'blah') => [{:first=>"a", :second=>"b", :third=>"blah"}] puts foo('a', 'b', first: 'butno') => [{:first=>"butno", :second=>"b", :third=>nil}] puts foo(nil, nil, nil) => [{:first=>nil, :second=>nil, :third=>nil}] puts foo(1,2,3,4,5,6,7,8,9,10) => [{:first=>1, :second=>2, :third=>3}, 4, 5, 6, 7, 8, 9, 10] And, for more amusement: foo 1, 2, 3, 4, 5, 6, 7, 8, 9, first: 'zip', bazinga: 'owie' => [{:first=>"zip", :second=>2, :third=>3, :bazinga=>"owie"}, 4, 5, 6, 7, 8, 9] The thing I *really* dislike about splatargsdeflate, and why I was asking in the first place, is that it seems so *procedural* and as I said above, brute force. I really wanted something much more functional. I'm just wondering if there's is some cool ruby method that does something akin to this already that I haven't discovered, or if it is something that can be map/reduced somehow. The only place I can see doing that is in the loop through the argnames: arg_hash = argnames.reduce(h={}){|h,n| h[n]=args.shift;h} produces the same arg_hash, at some cost of readability, perhaps. Anyway, thanks for your time and looking.