From: Marc Heiler Date: 2013-02-03T18:03:40+09:00 Subject: Re: Easy way to handle positional and hashed parameters on a method? > Ideally, I'd like to be able to offer either of these > on an API I'm creating: > my_method('a','b','c') You already gave an example of how to do this. It is via the splat operator in ruby. You can test this in IRB: require 'pp' def foo(*i) pp i end foo('a','b','c') You can see that this will return an array: ["a", "b", "c"] That way you can have as many arguments to a method as you like - they will all be collected into the variable name you wrote down in the method definition. So far, so good. Now to the other question you have: > my_method(first: 'a', second: 'b', third: 'c') Ok, let's first break down what happens here. I will replace "my_method" with "foo", I like foo() as demo-name for methods. So we have: my_method(first: 'a', second: 'b', third: 'c') which is: foo(first: 'a', second: 'b', third: 'c') which actually is this here: foo({first: 'a', second: 'b', third: 'c'}) In other words, this is a hash. To make this compatible with Ruby 1.8.x, let's make it even more clear: foo({:first => 'a', :second => 'b', :third => 'c'}) Now, if you look at what this code above returns in IRB (test it please!), you will notice it will return this here: [{:third=>"c", :second=>"b", :first=>"a"}] In other words, it has simply put the hash that you passed here into the first element of an array. So you still have an array! With splat operator, it seems as if you will always have an array. :) Now you could, within the method definition, check whether you have a hash. if i.is_a? Array if i[0].is_a? Hash # do something special here Ok? You just check whether your first element contains a hash or not. If it does contain a hash, you can act on this information, inside your method! > I know I can construct the method definition as: > def my_method(*args) > ... > end Yes, the splat operator. > and whatever way they pass things in will get there. Yes, collected into an array! args in your example will be an array. > But how can I easily merge them into a hash for use > in the rest of the method? Simple. Check the given argument for .is_a? and when you find a hash, reconstruct the method and the variable. It is your method, you are in full control of what it does and what it will return! Input, Modify, Output - that is a the basic of any function (or method in ruby, as functions are attached to objects). > I want the end result to look like: > {:first => 'a', :second => 'b', :third => 'c'} You already have this! It just resides as the first element of your array! In fact, if you would have tested in IRB, you could have seen it :D (Btw I just noticed that you used the new hash syntax. I recommend to use the old hash syntax, for CONSISTENCY. Right now you seem to switch beween the two, I don't think this is good at all.) > no matter how they enter them. Hmmmmmm. I am not sure if it is easily possible to get the same input as output as far as the new hash syntax is concerned. I would, right now, simply claim that this is not possible. > And could you deal with something where a hash > is entered as a positional parameter, and > trailing hash values as well?? Like: > mymethod(({z: 1, x: 2}),'bazinga!', third: 17) > to end up with: > {:first => {:z => 1, :x => 2}, :second => 'basinga!', :third => 17} No, you can not. There is no way for ruby to make a real difference between the two different syntaxes on the AST. Perhaps matz could say something about this - I myself would not need what you need, because I will forever more use the old way to use a hash ;) but if others really need the same input as the same output, well then why not. But internally, I think it is ALL converted into the same internal representation, it just seems syntactic sugar to squeeze away a few extra characters. -- Posted via http://www.ruby-forum.com/.