Throw exception when re-assigning a constant in Ruby?
I've long been aware that "constants" in Ruby (i.e., variable names that are capitalized) aren't really constant. Li开发者_StackOverflow中文版ke other programming languages, a reference to an object is the only thing stored in the variable/constant. (Sidebar: Ruby does have the facility to "freeze" referenced objects from being modified, which as far as I know, isn't an ability offered in many other languages.)
So here's my question: when you re-assign a value into a constant, you get a warning like so:
>> FOO = 'bar'
=> "bar"
>> FOO = 'baz'
(irb):2: warning: already initialized constant FOO
=> "baz"
Is there a way to force Ruby to throw an exception instead of printing a warning? It's tough to figure out why reassignments happen sometimes.
Look at Can you ask ruby to treat warnings as errors? to see how it is possible in some cases to treat warnings as errors.
Otherwise I guess you'd have to write a custom method to assign constants and raise the exception if already assigned.
If you know that a reassignment happens to a specific constant, you can also add a sanity check just before the assignment.
You can't intercept it directly, no.
If you really need to do this, I can think of a very dirty hack, though. You could redirect the standard error IO to a custom IO object. The write
method could then check for what is being written; if it contains "warning: already initialized constant"
, then you raise, otherwise you forward the call to the standard error's write
.
If the constant is within a class or a module, then you could freeze
the class or module:
# Normal scenario
$VERBOSE = true
class Foo
BAR = 1
end
Foo::BAR = 2 # warning: already initialized constant BAR
# Using freeze
Foo.freeze
Foo::BAR = 3
RuntimeError: can't modify frozen Class
from (irb):8
from /Users/agrimm/.rbenv/versions/1.9.3-p194/bin/irb:12:in `<main>'
For your scenario, you could freeze Object
, but that sounds kind of scary.
精彩评论