Donovan Thomson
Donovan Thomson

Reputation: 2525

Select on hash with indifferent access not working

I am trying to deal with inconsistent keys (Strings/Symbols) in hashes. I thought that HashWithIndifferentAccess would be the answer but I am getting some slightly confusing results when trying to do some basic operations on these hashes

For example I have the following HashWithIndifferentAccess

(rdb:1) metadata
{"indexes"=>["respondent", "brand"], "columns"=>["rating"], 
 "value_labels"=>{}, "column_labels"=>{}}
(rdb:1) metadata.class
ActiveSupport::HashWithIndifferentAccess

when I try the following select I get an empty hash

(rdb:1) metadata.select{ |k, v| [:indexes, :columns, :value_labels, :column_labels]
.include? k }
 {}

Are all common hash operations available with HashWithIndifferentAccess ? Why is this operation returning an empty hash

Upvotes: 1

Views: 2678

Answers (2)

Shadwell
Shadwell

Reputation: 34774

All you really get with HashWithIndifferentAccess is the ability to set and get values using either a string or a key. Once you start using other reading methods on the hash you move to objects that are not indifferent to strings or symbols.

However, HashWithIndifferentAccess does help you because:

Internally symbols are mapped to strings when used as keys in the entire writing interface (calling []=, merge, etc)

....

You are guaranteed that the key is returned as a string

This means that you're always going to get a string for keys with methods like select:

> h = { sym_key: 'sym_value', 'string_key' => 'string_value' }.with_indifferent_access
> h.keys
=> ["sym_key", "string_key"]

Upvotes: 6

Amadan
Amadan

Reputation: 198438

Indifferent access means HashWithIndifferentAccess#[] will check both strings and keys. However, there is no such patch done on Array#include?, which you are using to filter your data. Easy fix:

[:indexes, :columns, :value_labels, :column_labels].include? k.to_sym

Upvotes: 3

Related Questions