Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use class constant as Ruby hash key

I know I can use class as Hash key, but is it a good practice? Is there any drawbacks in terms of performance or testing?

{
  SomeClassA: 'hash value',
  AnotherClass: 'hash value'
}
like image 227
user1883793 Avatar asked Oct 22 '25 03:10

user1883793


1 Answers

{
  SomeClassA: 'hash value',
  AnotherClass: 'hash value'
}

Is actually equivalent to:

{
  :SomeClassA => 'hash value',
  :AnotherClass => 'hash value'
}

The keys are symbols. In the "new" literal hash syntax keys are just treated as literals which are cast into symbols (provided they are valid syntax).

To use constants, ranges or any other type of object you can dream up as keys you need to use hashrockets:

{
  SomeClassA => 'hash value',
  AnotherClass => 'hash value'
}

Is it a good practice?

Its a technique that could be used in few limited cases. For example to replace a series of if statements.

def foo(bar)
  if bar.is_a? SomeClassA
    'hash value'
  end
  if bar.is_a? AnotherClass
    'another value'
  end
end

def foo(bar)
  {
    SomeClassA => 'hash value',
    AnotherClass => 'another value'
  }[bar]
end

But I would rather use a case statement there anyways as its clearer in intent and more flexible.

Are there any drawbacks in terms of performance or testing?

Each hash you create would have keys that point to the exact same objects in memory just like if you where using symbols.

One big gotcha is that Rails monkey-patches const_missing to autoload files - when you reference a class name rails will load the file from the file system into memory. This is why you declare associations with:

class Foo < ApplicationRecord
  belongs_to :bar, class_name: "Baz"
end

It lets Rails instead lazy load Baz when needed. You would do the same with the example above by:

def foo(bar)
  {
    'SomeClassA' => 'hash value',
    'AnotherClass' => 'another value'
  }[bar.name]
end
like image 158
max Avatar answered Oct 24 '25 17:10

max