steveyang
steveyang

Reputation: 9298

what's the meaning when passing an object to Hash.new

I've encountered this code when tweaking the ghi, and I cannot figure out the meaning for passing an object to the ALIASES object. Could anyone help to explain the [key] if /^\d+$/ === key line in the following code?

ALIASES = Hash.new { |_, key|
  [key] if /^\d+$/ === key
}.update({...})

https://github.com/yangchenyun/ghi/blob/reading/lib/ghi.rb#L119-138

Upvotes: 0

Views: 96

Answers (4)

doesterr
doesterr

Reputation: 3965

This code sets a default value, that is returned when a not-existing key is accessed.

In this specific case, the default is set to return the given key inside an Array, if the given key is a String representation of a integer number.

hash = Hash.new do |_, key|
  [key] if /^\d+$/ === key
end

hash["foo"].inspect  # => nil
hash[123].inspect    # => nil
hash["123"].inspect  # => ["123"]

Some examples for the regex matching:

/^\d+$/ === 123     # => false
/^\d+$/ === "a123"  # => false
/^\d+$/ === "123a"  # => false
/^\d+$/ === "1.23"  # => false
/^\d+$/ === "123"   # => true

And another (simpler) example for a default value:

hash = Hash.new { |_, key| "this key does not exist" }

hash["foo"]           # => "this key does not exist"
hash["foo"] = "bar"
hash["foo"]           # => "bar"

About the block parameter naming: You could name the first parameter anything you like, but some developers like to name a unused block operator _. This way it is clear at the first glance, that you don't care about this parameter.

Upvotes: 3

Matt
Matt

Reputation: 5398

Here's an excerpt from Ruby documentation for Hash::new:

If obj is specified, this single object will be used for all default values. If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block’s responsibility to store the value in the hash if required.

In your case it's a block, which defines a default value that will be returned when a key is not found. In this case it'll return it only if the key matches given regular expression /^\d+$/, and [key] means it will be returned inside an array.

Upvotes: 0

Marcin Wyszynski
Marcin Wyszynski

Reputation: 2258

Please have a look at the Hash::new documentation here. It says:

Returns a new, empty hash. If this hash is subsequently accessed by a key that doesn’t correspond to a hash entry, the value returned depends on the style of new used to create the hash. If a block is specified, it will be called with the hash object and the key, and should return the default value.

So "_" is the value of the object being set, and the author does not care about it. The middle line just checks whether key consists only of numbers and if not, it assigns the key value to an array with this key value. If the key consists only of numbers, it is disregarded.

Ruby's Regexp#=== is just an alias for Regexp#=~.

Just a note - this is a horrible, unreadable piece of code. Just because you can write things like that does not mean you should. Please don't get inspired.

Upvotes: 0

steenslag
steenslag

Reputation: 80095

The [key] if /^\d+$/ === key is the default_proc. It runs everytime when a key is not found in the hash.ALIASES["123"] would return ["123"] if "123" is not an existing key.

Upvotes: 2

Related Questions