[Note: parts of this message were removed to make it a legal post.]
I am reading up in other areas, and it occurs to me much of the items I
have as class and object variables really should be constants, but ideally
still in the class or object context. Is there a way to do this?
xc
Variables that begin with capital letters are constants
initial_constants = Module.constants
class MyClass
MY_FAVOURITE_NUMBER = 12
MyFavouriteNumber = 12
end
Module.constants - initial_constants # => [:MyClass]
MyClass.constants # => [:MY_FAVOURITE_NUMBER, :MyFavouriteNumber]
So you can see that classes are already constants, and an example of how to
create constants within a class.
In Ruby, this really means that the reference may not be changed (or at
least you will be warned if you try to do so), not that the object being
referenced may not be mutated.
class MyClass
MyFavouriteNumber = 12
MyFavouriteNumber = 13 # !> already initialized constant MyFavouriteNumber
MyFavouriteNumber # => 13
end
If you change your constant, you will know, it will warn you (ie, it won't
happen by accident). If your code breaks because of this... well... you'll
have a pretty good idea where to look. While Ruby is dynamic enough to make
such a change, it is not something you should do. If you need to change your
constants, then they shouldn't be constants.
If you really need your data to not change, to the point where you don't
even want to allow yourself the opportunity to do so, you can freeze it, and
it will throw an exception
class MyClass
MyFavouriteWord = "ambivalent"
MyFavouriteWord << 'l'
MyFavouriteWord # => "ambivalentl"
MyFavouriteWord.freeze
MyFavouriteWord << 'y'
MyFavouriteWord # =>
end
# ~> -:6:in `<class:MyClass>': can't modify frozen string (RuntimeError)
# ~> from -:1:in `<main>'
But as far as I am aware, there is no way to recursively free any references
it has (probably a good thing, you could recursively freeze your entire
program)
class MyClass
SomeArray = [ 'abc' , 'def' ].freeze
SomeArray # => ["abc", "def"]
begin
SomeArray << 'ghi'
rescue => e
e # => #<RuntimeError: can't modify frozen array>
end
SomeArray.last # => "def"
SomeArray.last << 'ghi'
SomeArray.last # => "defghi"
end
Generally, constants are used for data that should be hard coded in, you use
a constant so that you can easily change it later, like using a macro in C.
You can then drop it into your code, and it is replaced with the actual
value (you can redefine macros too). And they are also used for keeping
important references, like the constant STDIN. We can change the global we
use as stdin, but we don't want to lose track the actual stdin, so we keep
it in the constant.
STDIN # => #<IO:<STDIN>>
$stdin # => #<IO:<STDIN>>
$stdin = DATA # => #<File:untitled>
gets # => "this is the data\n"
$stdin = STDIN # => #<IO:<STDIN>>
__END__
this is the data