Question about array of hashes

I’m looking at Page 39 of Why’s (poignant) Guide to Ruby (
http://www.rubyinside.com/media/poignant-guide.pdf ) and I see

[:shape => ‘sock’, :fabric => ‘cashmere’] +
[:shape => ‘mouse’, :fabric => ‘calico’] +
[:shape => ‘eggroll’, :fabric => ‘chenille’]

The result of this is (irb 1.9.2)

irb(main):001:0> kitty_toys =
irb(main):002:0* [:shape => ‘sock’, :fabric => ‘cashmere’] +
irb(main):003:0* [:shape => ‘mouse’, :fabric => ‘calico’] +
irb(main):004:0* [:shape => ‘eggroll’, :fabric => ‘chenille’]
=> [{:shape=>“sock”, :fabric=>“cashmere”}, {:shape=>“mouse”,
:fabric=>“calico”}, {:shape=>“eggroll”, :fabric=>“chenille”}]
irb(main):024:0> kitty_toys.size
=> 3

That is, it is an array of 3 hashes

But the lexically similar

irb(main):001:0> x=
irb(main):002:0* [1, :fabric => ‘cashmere’] +
irb(main):003:0* [2, :fabric => ‘calico’] +
irb(main):004:0* [3, :fabric => ‘chenille’]
=> [1, {:fabric=>“cashmere”}, 2, {:fabric=>“calico”}, 3,
{:fabric=>“chenille”}]
irb(main):005:0> x.size
=> 6

produces what is to me a surprisingly different result.

Clearly, ruby has flattened things for x and yet … it seems to have
kept the hashes together for kitty_toys

I would have expected

irb(main):006:0> y = [[1, {:fabric=>“cashmere”}], [2,
{:fabric=>“calico”}], [3, {:fabric=>“chenille”}]]
=> [[1, {:fabric=>“cashmere”}], [2, {:fabric=>“calico”}], [3,
{:fabric=>“chenille”}]]
irb(main):007:0> y.size
=> 3

In fact, the more I stare at it, the more I think that the correct
syntax should be

doggy_toys =
[{:shape => ‘sock’, :fabric => ‘cashmere’}] +
[{:shape => ‘mouse’, :fabric => ‘calico’}] +
[{:shape => ‘eggroll’, :fabric => ‘chenille’}]

Why is the kitty_toys syntax even legal?

I see that using the new 1.9 syntax for creating hash tables also works
the same way.

irb(main):018:0> birdy_toys =
irb(main):019:0* [shape:‘sock’, fabric:‘cashmere’] +
irb(main):020:0* [shape:‘mouse’, fabric:‘calico’] +
irb(main):021:0* [shape:‘eggroll’, fabric:‘chenille’]
=> [{:shape=>“sock”, :fabric=>“cashmere”}, {:shape=>“mouse”,
:fabric=>“calico”}, {:shape=>“eggroll”, :fabric=>“chenille”}]
irb(main):022:0> doggy_toys == birdy_toys
=> true

So what are the rules for “implied hash table”? Where would I find that
documented?

Ralph S.

On Mon, Apr 30, 2012 at 10:52 PM, Ralph S. [email protected]
wrote:

irb(main):003:0* [:shape => ‘mouse’, :fabric => ‘calico’] +
irb(main):004:0* [:shape => ‘eggroll’, :fabric => ‘chenille’]
=> [{:shape=>“sock”, :fabric=>“cashmere”}, {:shape=>“mouse”, :fabric=>“calico”},
{:shape=>“eggroll”, :fabric=>“chenille”}]
irb(main):024:0> kitty_toys.size
=> 3

That is, it is an array of 3 hashes

But the lexically similar

Similar but not identical.

irb(main):001:0> x=
irb(main):002:0* [1, :fabric => ‘cashmere’] +
irb(main):003:0* [2, :fabric => ‘calico’] +
irb(main):004:0* [3, :fabric => ‘chenille’]
=> [1, {:fabric=>“cashmere”}, 2, {:fabric=>“calico”}, 3, {:fabric=>“chenille”}]
irb(main):005:0> x.size
=> 6

produces what is to me a surprisingly different result.

Why are you surprised that a different input gives a different output?

Clearly, ruby has flattened things for x and yet … it seems to have kept the
hashes together for kitty_toys

No, it hasn’t flattened anything. Note what you have:

irb(main):007:0> [1, :fabric => ‘cashmere’]
=> [1, {:fabric=>“cashmere”}]

This is an Array with a Fixnum and a Hash. And Array#+ creates a new
Array with the content of both arguments concatenated:

irb(main):010:0> [1,2] + [4,5]
=> [1, 2, 4, 5]

I would have expected

irb(main):006:0> y = [[1, {:fabric=>“cashmere”}], [2, {:fabric=>“calico”}], [3,
{:fabric=>“chenille”}]]
=> [[1, {:fabric=>“cashmere”}], [2, {:fabric=>“calico”}], [3,
{:fabric=>“chenille”}]]
irb(main):007:0> y.size
=> 3

I am not sure why you expect that. No nested Arrays are created.

In fact, the more I stare at it, the more I think that the correct syntax should
be

doggy_toys =
[{:shape => ‘sock’, :fabric => ‘cashmere’}] +
[{:shape => ‘mouse’, :fabric => ‘calico’}] +
[{:shape => ‘eggroll’, :fabric => ‘chenille’}]

Why is the kitty_toys syntax even legal?

It’s Ruby’s way to be nice to the user. You can also use this for
method arguments:

irb(main):008:0> p(:foo => 1, :bar => 2)
{:foo=>1, :bar=>2}
=> {:foo=>1, :bar=>2}

And there are even Keyword arguments, which are translated to a Hash as
well:

irb(main):009:0> p(foo: 3, bar: 4)
{:foo=>3, :bar=>4}
=> {:foo=>3, :bar=>4}

I see that using the new 1.9 syntax for creating hash tables also works the same
way.

Exactly.

irb(main):018:0> birdy_toys =
irb(main):019:0* [shape:‘sock’, fabric:‘cashmere’] +
irb(main):020:0* [shape:‘mouse’, fabric:‘calico’] +
irb(main):021:0* [shape:‘eggroll’, fabric:‘chenille’]
=> [{:shape=>“sock”, :fabric=>“cashmere”}, {:shape=>“mouse”, :fabric=>“calico”},
{:shape=>“eggroll”, :fabric=>“chenille”}]
irb(main):022:0> doggy_toys == birdy_toys
=> true

So what are the rules for “implied hash table”? Where would I find that
documented?

I am sure “The Well-Grounded Rubyist” covers this. Section 9.3, I
believe.
http://www.amazon.com/dp/1933988657

Kind regards

robert

On Mon, Apr 30, 2012 at 1:52 PM, Ralph S. [email protected]
wrote:

irb(main):001:0> kitty_toys =
irb(main):002:0* [:shape => ‘sock’, :fabric => ‘cashmere’] +
irb(main):003:0* [:shape => ‘mouse’, :fabric => ‘calico’] +
irb(main):004:0* [:shape => ‘eggroll’, :fabric => ‘chenille’]
=> [{:shape=>“sock”, :fabric=>“cashmere”}, {:shape=>“mouse”, :fabric=>“calico”},
{:shape=>“eggroll”, :fabric=>“chenille”}]
irb(main):024:0> kitty_toys.size
=> 3

Why is the kitty_toys syntax even legal?

If a series of key:value pairs are the last elements in an argument
list, they get collected into a single hash. It’s basically the method
call hash argument collection, being applied to the [] method here.
See
http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_methods.html

martin