Ruby - What is difference between defining constant using 'const_set' and simple capitalize constant name in the class?

2.3k views Asked by At

I am working on a Rails application where in one class, constants are defined using const_set constant_name, value.

I know we can define constants directly in class by just specifying the CAPITALIZE name of the constant with its value like following

class A
 RANDOM_CONSTANT = 1
end

so what is the difference between defining constants using const_set and simply the way I have declared in class A ?

3

There are 3 answers

0
Amadan On BEST ANSWER
class A
  RANDOM_CONSTANT = 1
end

is simpler to write and read. This should be the preferred way to set a constant.

constant_name = 'RANDOM_CONSTANT'
A.const_set(constant_name, 1)

will work when the constant name is dynamically generated, and thus more flexible. You'd typically use it only when you want to do some metaprogramming magic.

Other than that, they are equivalent.

0
Marek Lipka On

As far as I know, there's no difference, so this:

class A; end
A.const_set('RANDOM_CONSTANT', 1)

is equivalent to:

class A
  RANDOM_CONSTANT = 1
end
1
Oleksandr Holubenko On

I can add to the answer from @amadan that this method, like an others, for example const_get, method_missing, define_method etc is part of tools for meta-programming in ruby.

For example:

  1. #const_get

Let's say we have such module Foo with list of constants: BOO, BAR, BAZ

module Foo
  BAR = 1
  BAZ = 2
  BOO = 3
end

now we need to print all of it, we can do it dynamically or manually:

def print_dynamically
  Foo.constants.each do |const| 
    p Foo.const_get(const)
  end
end

def print_manually
  p Foo::BAR
  p Foo::BAZ
  p Foo::BOO
end

> print_dynamically
=> 1
=> 2
=> 3

> print_manually
=> 1
=> 2
=> 3
  1. #method_missing

Let's say we have such class Foo and we want to add some friendly error catching for NoMethodError

class Foo
  def boo
    puts 'boo'
  end

  def method_missing(method_name)
    puts "sorry, method: ##{method_name} not defined."
    puts "Here is a list of public methods:"
    # here we take all defined public methods from class Foo except `#method_missing`
    p public_methods(false).reject { |n| n == :method_missing } 
  end
end

> foo = Foo.new
> foo.boo
=> boo
> foo.bar
=> sorry, method: #bar not defined.
=> Here is a list of public methods:
=> [:boo]
  1. #define_method

Let's say we need to define some list of simple(or not) methods, and we don't want to just copy-paste it:

instead of:

class Foo
  def foo
    puts "foo"
  end
  def boo
    puts "boo"
  end
  def bar
    puts "bar"
  end
end

> foo.foo
=> foo
> foo.boo
=> boo
> foo.bar
=> bar

you can simply write it in his way:

class Foo
  %i[foo boo bar].each do |method_name|
    define_method(method_name) { puts "#{method_name}" }
  end
end

> foo.foo
=> foo
> foo.boo
=> boo
> foo.bar
=> bar

Summary: From examples below you can see that Ruby provide us a lot of tools for dynamically creation of methods, getting of it, getting of constants and setting of it.

P.S. These is far not all the methods, it's just a few of them, but I think it's enough to show that you can do with meta-programming tools in ruby.