Ryan Stewart
Ryan Stewart

Reputation: 128829

Are there "rules" for Ruby syntactic sugar?

I'm learning the basics of Ruby (just starting out), and I came across the Hash.[] method. It was introduced with

a = ["foo", 1, "bar", 2]
=> ["foo", 1, "bar", 2]
Hash[*a]
=> {"foo"=>1, "bar"=>2}

With a little thought, I figured out that Hash[*a] is equivalent to Hash.[](*a) or Hash.[] *a. My question is why that's the case. What is it that lets you put the *a inside the square brackets, and is there some kind of rule for where and when else "it" can be used?

Edit: My wording seems to be causing some confusion. I'm not asking about the array expansion. I get that. My question is basically: if [] is a method name, why is it okay to put arguments inside the brackets? It seems almost--but not quite--like saying that if you have a method Foo.dood, and you wanted to pass the string "hey" to it, then you could write Foo.do"hey"od.

Upvotes: 5

Views: 2181

Answers (4)

Andrew Grimm
Andrew Grimm

Reputation: 81510

I think that Ruby's syntax is defined in parse.y for YARV Ruby.

Upvotes: 2

Paweł Obrok
Paweł Obrok

Reputation: 23164

There are a couple methods that ruby lets you call in a special way. These are the [] as you mentioned, the +, -, == and the like as someone else mentioned. Another important example are methods of the form something=(value) which can be called with object.something = value and allow you to create accessors.

Edit:

Fun fact 1: if you define a + method you get += for free.

Fun fact 2: if you define a <=> you get all comparison methods, courtesy of Comparable

Upvotes: 3

knut
knut

Reputation: 27855

The *<Array> method tells ruby not to take the array as array, but to use the 'expanded' array.

Example:

def test(*argv)
  p argv
end

a = [1,2,3]
test(a) #-> [[1, 2, 3]]
test(*a) #-> [1, 2, 3]    

With test(a) the array a is the one and only parameter.

With test(*a) a is used as a list of parameters.


In your case

a = ["foo", 1, "bar", 2]
Hash[*a]

is similar to

Hash["foo", 1, "bar", 2]

Hash[*a] would be

Hash[["foo", 1, "bar", 2]]

Upvotes: 0

August Lilleaas
August Lilleaas

Reputation: 54593

Hash["a", "b", "c", "d"] is equivalent to Hash.[]("a", "b", "c", "d"). Almost everything in Ruby is a method call. 5 + 5 is equivalent to 5.+(5).

Given a = ["a", "b", "c", "d"] Hash[*a] is equivalent to Hash["a", "b", "c", "d"], which in turn is equivalent to Hash.[]("a", "b", "c", "d"). Similarly, foo(*a) is equivalent to foo("a", "b", "c", "d") This is called the explode operator, and allows sending an array to a method and have each item in the array count as one argument to the method, instead of sending the array to the method as the first argument.


To specifically answer your update, there's nothing special that lets you put *a inside the brackets. The brackets is just sugar for a normal method call. The only "special" thing here is that you can send *a to any method.

Upvotes: 4

Related Questions