article originally published here : https://www.bootrails.com/blog/ruby-constants/
Motivation
We don't have a lot of Ruby constants in the bootrAils starter. However, it's always good to know how they work when the need arises.
"Constants" are variables that are not meant to be changed. Let's see how. In this article we will use the ruby console, if you are in a Rails environment, you can get it by typing bin/rails console
.
How to define a Ruby constant
Constants begin with an uppercase letter.
Example :
Boiling = 100 # valid
BOILING = 100 # valid
boiling = 100 # invalid
Constants defined within a class or module can be directly accessed from the inside. Those defined outside a class or module can still be accessed globally.
Example :
class Water
ICE = 0
BOIL = 100
def show
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
As you can notice, ICE and BOIL are freely accessed from the class where they are defined. From the outside :
Water::ICE
# => 0
Water::BOIL
# => 100
Water.new.show
# => Celsius temperature for becoming ice is 0
# => Celsius temperature for becoming steam is 100
Ruby constants that will fail
Constants cannot be defined inside a method.
Example :
class Water
def show
ICE = 0
BOIL = 100
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
# Traceback (most recent call last):
# SyntaxError ((irb):117: dynamic constant assignment)
# ICE = 0
Constants cannot start with a lower case.
class Water
ice = 0 # ! fail ! Constant cannot start with lowercase
boil = 100 # ! fail ! Constant cannot start with lowercase
def show
puts "Celsius temperature for becoming ice is #{ice}"
puts "Celsius temperature for becoming steam is #{boil}"
end
end
This will produce the following error on call :
Water::ice
Traceback (most recent call last):
1: from (irb):87:in `<main>'
NoMethodError (undefined method `ice' for Water:Class)
Uninitialized Constant Error
This kind of error will often happen if you code with Ruby-on-Rails or any other framework. It often means a class or constant inside a module wasn't found. You can easily recreate this error on your computer :
class Water
ICE = 0
BOIL = 100
def show
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
And then try simply to access a constant that doesn't exists :
irb(main):131:0> Water::ICE
0
irb(main):132:0> Water::UNEXISTING
Traceback (most recent call last):
1: from (irb):132:in `<main>'
NameError (uninitialized constant Water::UNEXISTING)
Changing... A Ruby constant
This is something disturbing if you come from another language : Ruby constants can be changed without the raise of any error.
Water::ICE = 42
# => warning: already initialized constant Water::ICE
Water::ICE
# => 42
A warning is raised, but the program still continues.
If you want to avoid this default behaviour, you have to freeze
your constant.
For this example, I'm going to freeze... the ice.
class Water
ICE = 0.freeze
BOIL = 100.freeze
def show
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
It doesn't really work, because you can still make Water::ICE = 42
and have a simple warning.
A Ruby constant isn't actually immutable, and you can't freeze a variable.
See this excellent StackOverflow answer to circumvent this problem : https://stackoverflow.com/a/26542453/2595513
Top comments (0)