2

I have a scenario that when I try to access a hash key using a symbol it doesn't work, but when I access it with a string it works fine. It is my understanding that symbols are recommended over strings, so I am trying to clean my script. I am using hash symbols elsewhere in my script, it is just this specific scenario that does not work.

Here is the snippet:

account_params ={}
File.open('file', 'r') do |f|
  f.each_line do |line|
    hkey, hvalue = line.chomp.split("=")
    account_params[hkey] = hvalue
  end
end

account_scope = account_params["scope"]

This works, however if I use a symbol it doesn't, as shown below:

account_scope = account_params[:scope]

When I use a symbol I get:

can't convert nil into String (TypeError)

I am not sure if it matters, but the contents of this specific hash value looks something like this:

12345/ABCD123/12345
sawa
  • 165,429
  • 45
  • 277
  • 381
fattastic
  • 927
  • 1
  • 7
  • 10

2 Answers2

3

The key you're reading in from the file is a string. In fact, everything you're reading in from the file is a string. If you want the keys in your hash to be symbols, you could update the script the do this instead:

account_params[hkey.to_sym] = hvalue

This will turn "hkey" into a symbol instead of using the string value.

Ruby provides a variety of these types of methods which will coerce the value into a different type. For instance: to_i will take it to an integer, to_f to a float, and to_s will take something back to a string value.

Pete
  • 17,885
  • 4
  • 32
  • 30
  • Thanks for the fast response. Is changing these all to symbols a good practice? The values are all a mix of characters. Thanks again! – fattastic Apr 11 '12 at 02:12
  • By the way, this did indeed fix my problem. Thank you again! – fattastic Apr 11 '12 at 02:15
  • Personally, I tend to prefer symbols as keys to hashes where it makes sense (no odd characters involved, etc) as they do feel a bit cleaner. That said, there is no rule saying that you should always use symbols or anything of that sort. In fact in Rails, there is a class which treats symbols and strings the same way as keys to avoid this sort of annoyance so you don't have to ensure the type of your keys coming in: http://as.rubyonrails.org/classes/HashWithIndifferentAccess.html – Pete Apr 11 '12 at 02:16
  • converting a regular Hash into a HashWithIndifferentAccess normally requires you to duplicate the Hash. Check the answer below, to add the behavior without creating a copy. – Tilo Sep 24 '12 at 21:11
0

you can use this Mix-In: https://gist.github.com/3778285

This will add "Hash With Indifferent Access" behavior to an existing single Hash instance, without copying or duplicating that hash instance. This can be useful in your case, when reading from File, or also when reading a parameter hash from Redis.

See comments inside Gist for more details.

require 'hash_extensions' # Source: https://gist.github.com/3778285

account_params = {'name' => 'Tom' } # a regular Hash

class << account_params
  include Hash::Extensions::IndifferentAccess  # mixing-in Indifferent Access on the fly
end

account_params[:name] 
 => 'Tom'
account_params.create_symbols_only # (optional) new keys will be created as symbols
account_params['age'] = 22
 => 22
account_params.keys
 => ['name',:age]
Tilo
  • 33,354
  • 5
  • 79
  • 106