Merging hashes using both symbols and strings as keys

I'm trying to merge to hashes, one using symbols as keys (the defined
default values for my class) and the other using strings as keys
(taken from the params hash).

default = { :name => "Joe", :age => 50 }

params = { "name" => "Bill" }

new_hash = default.merge(params)

{ :name => "Joe", :age => 50, "name" => "Bill }

What's the Ruby way to handle this so that it overwrites :name with
"name"? Do I need to implement a stringify_keys or symbolize_keys
method like in Rails? I'd like to avoid using strings as the keys in
my default hash.

Any help greatly appreciated.

Stu

shenry wrote:

I'm trying to merge to hashes, one using symbols as keys (the defined
default values for my class) and the other using strings as keys
(taken from the params hash).

default = { :name => "Joe", :age => 50 }

params = { "name" => "Bill" }

new_hash = default.merge(params)

{ :name => "Joe", :age => 50, "name" => "Bill }

What's the Ruby way to handle this so that it overwrites :name with
"name"? Do I need to implement a stringify_keys or symbolize_keys
method like in Rails? I'd like to avoid using strings as the keys in
my default hash.

I would think it would be easiest to use something like symbolize_keys.
Or just lift the whole HashWithIndifferentAccess class from Rails.

Any help greatly appreciated.

Stu

Best,

···

--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
--
Posted via http://www.ruby-forum.com/\.

shenry wrote:

I'd like to avoid using strings as the keys in
my default hash.

h1 = { :name => "Joe", :age => 50 }
h2 = { "name" => "Bill", :phone => "123-4567"}

h2.each do |key, val|
  h1[key.to_sym] = val
end

p h1

--output:--
{:age=>50, :phone=>"123-4567", :name=>"Bill"}

···

--
Posted via http://www.ruby-forum.com/\.

require 'facets/hash/rekey'

  default.merge(params.rekey)

rekey takes a block, without a block it is the same as:

  rekey(&:to_sym)

···

On Oct 30, 12:10 pm, shenry <stuarthe...@gmail.com> wrote:

I'm trying to merge to hashes, one using symbols as keys (the defined
default values for my class) and the other using strings as keys
(taken from the params hash).

default = { :name => "Joe", :age => 50 }

params = { "name" => "Bill" }

new_hash = default.merge(params)

>> { :name => "Joe", :age => 50, "name" => "Bill }

What's the Ruby way to handle this so that it overwrites :name with
"name"? Do I need to implement a stringify_keys or symbolize_keys
method like in Rails? I'd like to avoid using strings as the keys in
my default hash.

Any help greatly appreciated.

Hi, I made a small module called SymbolizeKeys that will allow you to extend
the hash you are interested in applying this behaviour to, you can then use
it like this:

default = { :name => "Joe", :age => 50 }.extend(SymbolizeKeys)

params = { "name" => "Bill" }

default.merge(params) # => {:age=>50, :name=>"Bill"}

I'm going through "Ruby Best Practices" right now, which touches on testing
in the first chapter. This seemed like a good opportunity to practice that
(while I eagerly await PragProg's RSpec book), so I'll include the tests I
wrote.

If anyone has relevant thoughts / criticisms, I welcome them (I don't
promise to agree, though). Is extending the object a wise approach? Are my
tests appropriate / follow good testing methodologies? Is there a better way
to implement anything I've done?

# file: symbolize_keys.rb

module SymbolizeKeys

  # converts any current string keys to symbol keys
  def self.extended(hash)
    hash.each do |key,value|
      if key.is_a?(String)
        hash.delete key
        hash[key] = value #through overridden =
      end
    end
  end

  # assigns a new key/value pair
  # converts they key to a symbol if it is a string
  def =(*args)
    args[0] = args[0].to_sym if args[0].is_a?(String)
    super
  end

  # returns new hash which is the merge of self and other hashes
  # the returned hash will also be extended by SymbolizeKeys
  def merge(*other_hashes , &resolution_proc )
    merged = Hash.new.extend SymbolizeKeys
    merged.merge! self , *other_hashes , &resolution_proc
  end

  # merges the other hashes into self
  # if a proc is submitted , it's return will be the value for the key
  def merge!( *other_hashes , &resolution_proc )

    # default resolution: value of the other hash
    resolution_proc ||= proc{ |key,oldval,newval| newval }

    # merge each hash into self
    other_hashes.each do |hash|
      hash.each{ |k,v|
        # assign new k/v into self, resolving conflicts with resolution_proc
        self[k] = self.has_key?(k) ? resolution_proc[k,self[k],v] : v
      }
    end

    self
  end

end

···

On Fri, Oct 30, 2009 at 11:10 AM, shenry <stuarthenry@gmail.com> wrote:

I'm trying to merge to hashes, one using symbols as keys (the defined
default values for my class) and the other using strings as keys
(taken from the params hash).

default = { :name => "Joe", :age => 50 }

params = { "name" => "Bill" }

new_hash = default.merge(params)
>> { :name => "Joe", :age => 50, "name" => "Bill }

What's the Ruby way to handle this so that it overwrites :name with
"name"? Do I need to implement a stringify_keys or symbolize_keys
method like in Rails? I'd like to avoid using strings as the keys in
my default hash.

Any help greatly appreciated.

Stu

--------------------------------------------------

# file: symbolize_keys_test.rb

require 'test/unit'
require 'symbolize_keys'

# this method was written by Gregory Brown
# and comes from

module Test::Unit
  # Used to fix a minor minitest/unit incompatibility in flexmock
  AssertionFailedError = Class.new(StandardError)

  class TestCase

    def self.must(name, &block)
      test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
      defined = instance_method(test_name) rescue false
      raise "#{test_name} is already defined in #{self}" if defined
      if block_given?
        define_method(test_name, &block)
      else
        define_method(test_name) do
          flunk "No implementation provided for #{name}"
        end
      end
    end

  end
end

class ExtendingWithSymbolizeKeysTest < Test::Unit::TestCase
  def setup
    @default = {
      :age => 50 ,
      'initially a string' => 51 ,
      /neither string nor symbol/ => 52 ,
    }
    @default.extend SymbolizeKeys
  end

  must "convert string keys to symbols when extended" do
    assert_nil @default[ 'initially a string']
    assert_equal @default[:'initially a string'] , 51
  end

  must "leave symbol keys as symbols" do
    assert_equal @default[:age] , 50
  end

  must 'leave non symbols / strings as they are' do
    assert_equal @default[/neither string nor symbol/] , 52
  end

end

class SettingKeysWithSymbolizeKeysTest < Test::Unit::TestCase
  def setup
    @default = Hash.new.extend SymbolizeKeys

  end

  must "convert string keys to symbols" do
    @default['foo'] = :bar
    assert_equal @default[:foo] , :bar
  end

  must "leave symbol keys as symbols" do
    @default[:foo] = :bar
    assert_equal @default[:foo] , :bar
  end

  must 'leave non symbols / strings as they are' do
    @default[/foo/] = :bar
    assert_equal @default[/foo/] , :bar
  end

end

class MergingWithSymbolizeKeysTest < Test::Unit::TestCase
  def setup
    @default = {
      :name => 'Joe' ,
      :age => 50 ,
      'initially a string' => 51 ,
      /neither string nor symbol/ => 52 ,
      :'from default' => :default ,
    }
    @params1 = {
      :name => 'Bill' ,
      'alias' => 'Billy' ,
      :'from params1' => :params1 ,
    }
    @params2 = {
      'name' => 'Sam' ,
      'alias' => 'Sammy' ,
      12 => 'favourite number' ,
      :'from params2' => :params2 ,
    }
    @default.extend SymbolizeKeys
  end

  must "retain new keys for merge" do
    merged = @default.merge(@params2)
    assert_equal merged[12] , 'favourite number'
  end

  must "retain new keys for merge!" do
    @default.merge!(@params2)
    assert_equal @default[12] , 'favourite number'
  end

  must "replace current values with new values for merge" do
    merged = @default.merge(@params1)
    assert_equal merged[:name] , 'Bill'
  end

  must "replace current values with new values for merge!" do
    @default.merge!(@params1)
    assert_equal @default[:name] , 'Bill'
  end

  must "not change original hash for merge" do
    @default.merge(@params1)
    assert_equal @default[:name] , 'Joe'
  end

  must "receive [key,oldval,newval] as params to block" do
    h1 = {:no_conflict_1 => 1 , :conflict => 2 }.extend(SymbolizeKeys)
    h2 = {:conflict => 3 , :no_conflict_2 => 4}
    resolution_proc_params = nil
    h1.merge(h2){ |*params| resolution_proc_params = params }
    assert_equal resolution_proc_params , [:conflict,2,3]
  end

  must "replace resolve conflicts with block for merge" do
    merged = @default.merge(@params1){ |key,oldval,newval| oldval }
    assert_equal merged[:name] , 'Joe'

    merged = @default.merge(@params1){ |key,oldval,newval| newval }
    assert_equal merged[:name] , 'Bill'
  end

  must "replace resolve conflicts with block for merge!" do
    @default.merge!(@params1){ |key,oldval,newval| oldval }
    assert_equal @default[:name] , 'Joe'

    @default.merge!(@params1){ |key,oldval,newval| newval }
    assert_equal @default[:name] , 'Bill'
  end

  must "convert string keys to symbols for merge" do
    merged = @default.merge(@params1)
    assert_nil merged['alias']
    assert_equal merged[ :alias] , 'Billy'
  end

  must "convert string keys to symbols for merge!" do
    @default.merge!(@params1)
    assert_nil @default['alias']
    assert_equal @default[ :alias] , 'Billy'
  end

  must "merge with multiple hashes" do
    merged = @default.merge(@params1,@params2)
    assert_equal merged[:'from default'] , :default
    assert_equal merged[:'from params1'] , :params1
    assert_equal merged[:'from params2'] , :params2
  end

  must "merge! with multiple hashes" do
    @default.merge!(@params1,@params2)
    assert_equal @default[:'from default'] , :default
    assert_equal @default[:'from params1'] , :params1
    assert_equal @default[:'from params2'] , :params2
  end

  must "return object that is extended with SymbolizeKeys, for merge" do
    merged = @default.merge(@params1)
    assert_kind_of SymbolizeKeys , merged
  end

  must "not modify original hash, for merge" do
    original = @default.dup
    @default.merge(@params1,@params2)
    assert_equal original , @default
  end

end

I decided that I wasn't happy with the tests, it should be able to access
the same object through either a string or a symbol (previously it just
turned everything into a symbol, then if you tried to access that object w/
the string, it would not find it).

So I overrode and has_key? also, and changed some of the tests.

Here is the updated version

# file: symbolize_keys.rb

module SymbolizeKeys

  # converts any current string keys to symbol keys
  def self.extended(hash)
    hash.each do |key,value|
      if key.is_a?(String)
        hash.delete key
        hash[key] = value #through overridden =
      end
    end
  end

  #considers string keys and symbol keys to be the same
  def (key)
    key = convert_key(key)
    super(key)
  end

  #considers string keys and symbol keys to be the same
  def has_key?(key)
    key = convert_key(key)
    super(key)
  end

  # assigns a new key/value pair
  # converts they key to a symbol if it is a string
  def =(*args)
    args[0] = convert_key(args[0])
    super
  end

  # returns new hash which is the merge of self and other hashes
  # the returned hash will also be extended by SymbolizeKeys
  def merge(*other_hashes , &resolution_proc )
    merged = Hash.new.extend SymbolizeKeys
    merged.merge! self , *other_hashes , &resolution_proc
  end

  # merges the other hashes into self
  # if a proc is submitted , it's return will be the value for the key
  def merge!( *other_hashes , &resolution_proc )

    # default resolution: value of the other hash
    resolution_proc ||= proc{ |key,oldval,newval| newval }

    # merge each hash into self
    other_hashes.each do |hash|
      hash.each{ |k,v|
        # assign new k/v into self, resolving conflicts with resolution_proc
        self[k] = self.has_key?(k) ? resolution_proc[k.to_sym,self[k],v] : v
      }
    end

    self
  end

private

  def convert_key(key)
    key.is_a?(String) ? key.to_sym : key
  end

end

···

On Fri, Oct 30, 2009 at 11:10 AM, shenry <stuarthenry@gmail.com> wrote:

I'm trying to merge to hashes, one using symbols as keys (the defined
default values for my class) and the other using strings as keys
(taken from the params hash).

default = { :name => "Joe", :age => 50 }

params = { "name" => "Bill" }

new_hash = default.merge(params)
>> { :name => "Joe", :age => 50, "name" => "Bill }

What's the Ruby way to handle this so that it overwrites :name with
"name"? Do I need to implement a stringify_keys or symbolize_keys
method like in Rails? I'd like to avoid using strings as the keys in
my default hash.

Any help greatly appreciated.

Stu

--------------------------------------------------

# file: symbolize_keys_test.rb

require 'test/unit'
require 'symbolize_keys'

# this method was written by Gregory Brown
# and comes from

module Test::Unit
  # Used to fix a minor minitest/unit incompatibility in flexmock
  AssertionFailedError = Class.new(StandardError)

  class TestCase

    def self.must(name, &block)
      test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
      defined = instance_method(test_name) rescue false
      raise "#{test_name} is already defined in #{self}" if defined
      if block_given?
        define_method(test_name, &block)
      else
        define_method(test_name) do
          flunk "No implementation provided for #{name}"
        end
      end
    end

  end
end

class ExtendingWithSymbolizeKeysTest < Test::Unit::TestCase
  def setup
    @default = {
      :age => 50 ,
      'initially a string' => 51 ,
      /neither string nor symbol/ => 52 ,
    }
    @default.extend SymbolizeKeys
  end

  must "convert string keys to symbols when extended" do
    assert_equal @default[:'initially a string'] , 51
  end

  must "sym/str keys can access through either, but only one key" do
    assert_equal @default[ 'initially a string'] , 51
    assert_equal @default[:'initially a string'] , 51
    assert_equal @default[:'initially a string'] , @default['initially a
string']
    assert_equal @default.size , 3
  end

  must "leave symbol keys as symbols" do
    assert_equal @default[:age] , 50
  end

  must 'leave non symbols / strings as they are' do
    assert_equal @default[/neither string nor symbol/] , 52
  end

end

class SettingKeysWithSymbolizeKeysTest < Test::Unit::TestCase
  def setup
    @default = Hash.new.extend SymbolizeKeys
  end

  must "enable access to strings through symbols" do
    @default['foo'] = 'bar'
    assert_equal @default[:foo] , 'bar'
    assert_same @default[:foo] , @default['foo']
  end

  must "enable access to symbols through strings" do
    @default[:foo] = 'bar'
    assert_equal @default['foo'] , 'bar'
    assert_same @default[:foo] , @default['foo']
  end

  must 'leave non symbols / strings as they are' do
    @default[/foo/] = :bar
    assert_equal @default[/foo/] , :bar
  end

end

class MergingWithSymbolizeKeysTest < Test::Unit::TestCase
  def setup
    @default = {
      :name => 'Joe' ,
      :age => 50 ,
      'initially a string' => 51 ,
      /neither string nor symbol/ => 52 ,
      :'from default' => :default ,
    }
    @params1 = {
      :name => 'Bill' ,
      'alias' => 'Billy' ,
      :'from params1' => :params1 ,
    }
    @params2 = {
      'name' => 'Sam' ,
      'alias' => 'Sammy' ,
      12 => 'favourite number' ,
      :'from params2' => :params2 ,
    }
    @default.extend SymbolizeKeys
  end

  must "retain new keys for merge" do
    merged = @default.merge(@params2)
    assert_equal merged[12] , 'favourite number'
  end

  must "retain new keys for merge!" do
    @default.merge!(@params2)
    assert_equal @default[12] , 'favourite number'
  end

  must "replace current values with new values for merge" do
    merged = @default.merge(@params1)
    assert_equal merged[:name] , 'Bill'
  end

  must "replace current values with new values for merge!" do
    @default.merge!(@params1)
    assert_equal @default[:name] , 'Bill'
  end

  must "not change original hash for merge" do
    @default.merge(@params1)
    assert_equal @default[:name] , 'Joe'
  end

  must "receive [key,oldval,newval] as params to block" do
    h1 = {:no_conflict_1 => 1 , :conflict => 2 }.extend(SymbolizeKeys)
    h2 = {:conflict => 3 , :no_conflict_2 => 4}
    resolution_proc_params = nil
    h1.merge(h2){ |*params| resolution_proc_params = params }
    assert_equal resolution_proc_params , [:conflict,2,3]
  end

  must "only invoke the resolution proc on conflicts" do
    conflict_count = 0
    conflicts = { :name => false , :alias => false }
    @params1.extend(SymbolizeKeys).merge(@params2) do |k,ov,nv|
      conflict_count += 1
      conflicts[k] = true
    end
    assert_equal conflict_count , 2
    assert conflicts[:name]
    assert conflicts[:alias]
  end

  must "replace resolve conflicts with block for merge" do
    merged = @default.merge(@params1){ |key,oldval,newval| oldval }
    assert_equal merged[:name] , 'Joe'

    merged = @default.merge(@params1){ |key,oldval,newval| newval }
    assert_equal merged[:name] , 'Bill'
  end

  must "replace resolve conflicts with block for merge!" do
    @default.merge!(@params1){ |key,oldval,newval| oldval }
    assert_equal @default[:name] , 'Joe'

    @default.merge!(@params1){ |key,oldval,newval| newval }
    assert_equal @default[:name] , 'Bill'
  end

  must "convert string keys to symbols for merge" do
    unique_keys = @default.keys.map{|k|k.to_s.to_sym} |
@params1.keys.map{|k|k.to_s.to_sym}
    merged = @default.merge(@params1)
    assert_equal merged['alias'] , 'Billy'
    assert_equal merged[ :alias] , 'Billy'
    assert_equal merged.size , unique_keys.size
  end

  must "convert string keys to symbols for merge!" do
    unique_keys = @default.keys.map{|k|k.to_s.to_sym} |
@params1.keys.map{|k|k.to_s.to_sym}
    @default.merge!(@params1)
    assert_equal @default['alias'] , 'Billy'
    assert_equal @default[ :alias] , 'Billy'
    assert_equal @default.size , unique_keys.size
  end

  must "merge with multiple hashes" do
    merged = @default.merge(@params1,@params2)
    assert_equal merged[:'from default'] , :default
    assert_equal merged[:'from params1'] , :params1
    assert_equal merged[:'from params2'] , :params2
  end

  must "merge! with multiple hashes" do
    @default.merge!(@params1,@params2)
    assert_equal @default[:'from default'] , :default
    assert_equal @default[:'from params1'] , :params1
    assert_equal @default[:'from params2'] , :params2
  end

  must "return object that is extended with SymbolizeKeys, for merge" do
    merged = @default.merge(@params1)
    assert_kind_of SymbolizeKeys , merged
  end

  must "not modify original hash, for merge" do
    original = @default.dup
    @default.merge(@params1,@params2)
    assert_equal original , @default
  end

end

Typically you do not want to modify defaults so I'd probably do

irb(main):001:0> default = { :name => "Joe", :age => 50 }.freeze
=> {:name=>"Joe", :age=>50}
irb(main):002:0> params = { "name" => "Bill" }
=> {"name"=>"Bill"}
irb(main):003:0> new_hash = default.dup
=> {:name=>"Joe", :age=>50}
irb(main):004:0> params.each {|k,v| new_hash[k.to_sym]=v}
=> {"name"=>"Bill"}
irb(main):005:0> new_hash
=> {:name=>"Bill", :age=>50}

If you are allowed to change params you could do

irb(main):001:0> default = { :name => "Joe", :age => 50 }.freeze
=> {:name=>"Joe", :age=>50}
irb(main):002:0> params = { "name" => "Bill" }
=> {"name"=>"Bill"}
irb(main):003:0> default.each {|k,v| params[k.to_s] ||= v}
=> {:name=>"Joe", :age=>50}
irb(main):004:0> params
=> {"name"=>"Bill", "age"=>50}

Kind regards

robert

···

2009/10/30 7stud -- <bbxx789_05ss@yahoo.com>:

shenry wrote:

I'd like to avoid using strings as the keys in
my default hash.

h1 = { :name => "Joe", :age => 50 }
h2 = { "name" => "Bill", :phone => "123-4567"}

h2.each do |key, val|
h1[key.to_sym] = val
end

p h1

--output:--
{:age=>50, :phone=>"123-4567", :name=>"Bill"}

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Josh, I believe it's better to create a gist for code of that length
and paste the link only. That makes it easier to follow - especially
since you'll get code highlighting and versioning for free.

Kind regards

robert

···

2009/11/3 Josh Cheek <josh.cheek@gmail.com>:

Here is the updated version

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Hi, Robert, I always thought that too, but I was told I should put them in
the email in case the host site went down (
What is "stack level too deep (SystemStackError)" error - Ruby - Ruby-Forum )

Is there some standard that I can follow, because there seems to be
conflicts of opinion regarding the best approach.

···

On Tue, Nov 3, 2009 at 7:06 AM, Robert Klemme <shortcutter@googlemail.com>wrote:

2009/11/3 Josh Cheek <josh.cheek@gmail.com>:

> Here is the updated version

Josh, I believe it's better to create a gist for code of that length
and paste the link only. That makes it easier to follow - especially
since you'll get code highlighting and versioning for free.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

A big difference here is that a pastie is only available through
pastie.org, a gist is a git repository that can be cloned.

···

On Tue, Nov 3, 2009 at 1:22 PM, Josh Cheek <josh.cheek@gmail.com> wrote:

On Tue, Nov 3, 2009 at 7:06 AM, Robert Klemme <shortcutter@googlemail.com>wrote:

2009/11/3 Josh Cheek <josh.cheek@gmail.com>:

> Here is the updated version

Josh, I believe it's better to create a gist for code of that length
and paste the link only. That makes it easier to follow - especially
since you'll get code highlighting and versioning for free.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Hi, Robert, I always thought that too, but I was told I should put them in
the email in case the host site went down (
What is "stack level too deep (SystemStackError)" error - Ruby - Ruby-Forum )

Is there some standard that I can follow, because there seems to be
conflicts of opinion regarding the best approach.

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

> Here is the updated version

Josh, I believe it's better to create a gist for code of that length
and paste the link only. That makes it easier to follow - especially
since you'll get code highlighting and versioning for free.

Hi, Robert, I always thought that too, but I was told I should put them in
the email in case the host site went down (
What is "stack level too deep (SystemStackError)" error - Ruby - Ruby-Forum )

Well, it seems both sides have valid and good arguments. :slight_smile: The only
footnote I'd put on that statement is: the real disadvantage of
pastebin and similar services is that they are typically intended for
short lived data only and may or actually do delete older content. A
gist on the other hand belongs to an account and lives as long as that
account lives or the gist is deleted. Of course, since this is
separate from the posting the issue remains that the posting can be
available and the code not...

Is there some standard that I can follow, because there seems to be
conflicts of opinion regarding the best approach.

No written standard as far as I know. So you're back to square and
have to decide yourself. :slight_smile:

Kind regards

robert

···

2009/11/3 Josh Cheek <josh.cheek@gmail.com>:

On Tue, Nov 3, 2009 at 7:06 AM, Robert Klemme <shortcutter@googlemail.com>wrote:

2009/11/3 Josh Cheek <josh.cheek@gmail.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Here is the code in a gist symbolize_keys.rb · GitHub

···

On Tue, Nov 3, 2009 at 7:27 AM, Paul Smith <paul@pollyandpaul.co.uk> wrote:

A big difference here is that a pastie is only available through
pastie.org, a gist is a git repository that can be cloned.

It might be of interest to note that this code basically take the
opposite tack from the HashWithIndifferentAccess which is part of
ActiveSupport and therefore Rails.

HashWithIndifferentAccess (which I'll abbreviate to HWIA) converts
symbol keys to strings in the access methods (, = etc.) Contrary
to some people's thinking (including mine when I first encountered it)
the actual keys in the hash are strings, not symbols.

The trade-offs between the two approaches include:

1) Symbols once created can't be garbage collected. Since Rails uses
HWIA for things like the params hash, and the keys come from parts of
arbitrary client provided URIs this could be an opening for a DOS
attack which creates tons of useless extra parameters which result in
non-GCable symbols. Since HWIA uses strings, for the keys, keys
coming from query parameters and the like never get turned into
symbols. The only symbols will be those coming from the application
itself.

2) Using strings for the keys is slightly slower on access because
computing the hash value of a string is O(length of the string) while
the hash value of a symbol is computed once and is O(1) subsequently.
On the other hand this only becomes significant if the same key is
used to access the hash multiple times, since interning a string as a
symbol requires computing the hash of the string anyway.

In practice, and particularly for the typical usage in Rails apps, I
doubt that there's any real effect on performance from storing strings
rather than symbols for the keys. The main advantage of HWIA is that
it allows you to save a keystroke

   params[:id]
vs
  params['id']

and some think the former looks a little bit nicer. Although this is
no doubt a potential source of controversy. I for one have a slight
preference for the :id form, but that might be the result of Stockholm
syndrome having worked on so many Rails apps.

···

On Tue, Nov 3, 2009 at 8:40 AM, Josh Cheek <josh.cheek@gmail.com> wrote:

On Tue, Nov 3, 2009 at 7:27 AM, Paul Smith <paul@pollyandpaul.co.uk> wrote:

A big difference here is that a pastie is only available through
pastie.org, a gist is a git repository that can be cloned.

Here is the code in a gist symbolize_keys.rb · GitHub

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Hi --

···

On Tue, 3 Nov 2009, Rick DeNatale wrote:

  params[:id]
vs
params['id']

and some think the former looks a little bit nicer. Although this is
no doubt a potential source of controversy. I for one have a slight
preference for the :id form, but that might be the result of Stockholm
syndrome having worked on so many Rails apps.

When it involves Rails, we call it "Copenhagen Syndrome" :slight_smile:

David

--
The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com

David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)

I dunno, there IS a bit of Chicago mixed in.

I have to repeat the story I told at the end of my RubyConf
presentation last year, about the classification of OO languages by
geographic origin:

  Smalltalk (which came from Xerox Parc in California) is the surfer's
language, Smalltalk programmers wear baggy swimsuits, and hang loose.

  ObjectiveC (which came from an ITT lab in Connecticut) was a "New
England Yankee" language, it did just what it had to do and nothing
more. (Not sure this is still true)

  Eiffel (the brainchild of Bertrand Meyer) was/is "quintessentially French")

and

  C++ (from Bjarne Stroustrup, a compatriot of DHH, and who at the
time was at Bell/ATT labs) is like Haagen Dazs Ice Cream, you think
it's from Scandanavia, but it's really an industrial product from New
Jersey!

···

On Tue, Nov 3, 2009 at 9:31 AM, David A. Black <dblack@rubypal.com> wrote:

Hi --

On Tue, 3 Nov 2009, Rick DeNatale wrote:

params[:id]
vs
params['id']

and some think the former looks a little bit nicer. Although this is
no doubt a potential source of controversy. I for one have a slight
preference for the :id form, but that might be the result of Stockholm
syndrome having worked on so many Rails apps.

When it involves Rails, we call it "Copenhagen Syndrome" :slight_smile:

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale