a startup file to be loaded by RUBYOPT should have minimal side
effects. I guess, this pattern will do it:
class << Object.new
FOO = … # will not override FOO if defined before
BAR = … # will introduce BAR intermediately
…
# Use the constants above to do some wanted side effect on an
# object hold by a global variable, e.g. $LOAD_PATH :
$:.unshift(FOO, …)
end
no more BAR visible here
Is there a canonical way to achive this kind of hygiene?
I guess that using local variables is not exactly the same thing like
class constants,
Of course it’s not the same, but it always depends on the use case.
but it’s close enough that I don’t (yet) notice the
difference when writing Ruby programs which load that startup file:
Does this mean you switched to local variables?
Neither are the variables from outside visible to the loaded startup
file, nor are local variables of the startup file visible from
outside. (That wasn’t the case for uppercase names (constants!), and
so I had to enclose them in a dummy class - or whatever - do you know
a simpler solution to hide constants, BTW?)
The question is: why do you need constants if you want to hide them?
Now it is even less clear to me what you want. All I’ve understood is
that you want to require a file (even if it’s autorequired) and make
sure that particular information does not leak. OTOH I am sure you
want some information to leak so why don’t you use constants for the
things (classes, modules) that need to be known outside and use local
variables for the rest?
Can’t you use local variables to do the same thing?
I can. That’s it, thanks!
Now you made me curious: why?
I guess that using local variables is not exactly the same thing like
class constants, but it’s close enough that I don’t (yet) notice the
difference when writing Ruby programs which load that startup file:
Neither are the variables from outside visible to the loaded startup
file, nor are local variables of the startup file visible from
outside. (That wasn’t the case for uppercase names (constants!), and
so I had to enclose them in a dummy class - or whatever - do you know
a simpler solution to hide constants, BTW?)
The question is: why do you need constants if you want to hide them?
First I defined constants rather than variables simply because each of
them actually is constant rather than variable: the value never
changes after assignment. In C++ I would add a const qualifier to the
local variables, e.g. to prevent from unintentionally overriding it.
In Haskell ther’s no need for a const keyword, because all definitions
are immutable per se, which is regarded a feature in this purely
functional programming language.
But in Ruby there are no local constants analogical to local
variables, so when I simply define constants I unintentionally export
them, too. (Freeze is no option, because it freezes the object hold by
the variable, not the variable itself.)
Every alternative has its own tradeoff:
If I define simple constants, I pollute the namespace of the
loading code.
If I define constants within class << Object.new, the code is
somehow ugly.
If I define local variables, I don’t benefit from the fact that
they are actually constant.
So currently alternative #3 is best for me, but if somebody shows me a
way to make #2 less ugly (get away from class << Object.new), that
would probably my favorite.
Generally, Ruby is less strict with these things (“private” is another
example).
But in Ruby there are no local constants analogical to local
variables, so when I simply define constants I unintentionally export
them, too. (Freeze is no option, because it freezes the object hold by
the variable, not the variable itself.)
Every alternative has its own tradeoff:
If I define simple constants, I pollute the namespace of the
loading code.
If I define constants within class << Object.new, the code is
somehow ugly.
This is also a kind of inappropriate solution because you create an
instance just to get at its singleton class. This is not needed (see
below).
If I define local variables, I don’t benefit from the fact that
they are actually constant.
So currently alternative #3 is best for me, but if somebody shows me a
way to make #2 less ugly (get away from class << Object.new), that
would probably my favorite.
Module.new do
TEST = 123
puts “Test is #{TEST}”
end
puts “Is there TEST?”
puts TEST
EOF
Test is 123
Is there TEST?
-:6:in `’: uninitialized constant TEST (NameError)