Hi,
I am running unit tests that test the assignment of a constant value
in a “config” file that is actually ruby code, e.g.
VARIABLE=“somevalue”
On subsequent test methods in my unit test, I get a complaint that it
is already assigned.
setup
load const
end
def test_1
do something
end
def test_2
do something else
end
test 2 gets a warning that const has already been defined.
I expected the unit test to clean the environment, in lieu of that,
how can I undefined const?
Thanks,
Bob
On 11/14/05, Robert E. [email protected] wrote:
I expected the unit test to clean the environment, in lieu of that,
how can I undefined const?
---------------------------------------------------- Module#remove_const
remove_const(sym) => obj
Removes the definition of the given constant, returning that
constant's value. Predefined classes and singleton objects (such as
_true_) cannot be removed.
You pass it a symbol: remove_const(:VARIABLE)
Ryan
Hi Ryan,
Thanks for your help.
I tried that, and it didn’t work. Here is my irb transcript trying
that. Is there another way to remove a constant? I thought I had seen
one in the Pickaxe book, but maybe I was thinking of the module method.
irb
irb(main):001:0> FOO = “my symbol value”
=> “my symbol value”
irb(main):002:0> remove_const(FOO)
NoMethodError: undefined method remove_const' for main:Object from (irb):2 irb(main):003:0> remove_const(:FOO) NoMethodError: undefined method
remove_const’ for main:Object
from (irb):3
irb(main):004:0> ??
Any other ideas?
Thanks,
Bob E.
On Tue, Nov 15, 2005 at 06:56:59AM +0900, Robert E. wrote:
=> “my symbol value”
irb(main):002:0> remove_const(FOO)
NoMethodError: undefined method `remove_const’ for main:Object
from (irb):2
irb(main):003:0> remove_const(:FOO)
Object.remove_const(:FOO)
On Tue, Nov 15, 2005 at 07:16:06AM +0900, Mauricio Fernández wrote:
irb(main):001:0> FOO = “my symbol value”
=> “my symbol value”
irb(main):002:0> remove_const(FOO)
NoMethodError: undefined method `remove_const’ for main:Object
from (irb):2
irb(main):003:0> remove_const(:FOO)
Sorry, I meant
Object.send(:remove_const, :FOO)
Ryan,
This is a tricky problem. First, you can’t call remove_const directly
as it’s a private method on the Module class. In the simple case, that
means you have to call it from within the class or module from which
you want to remove a constant. Further, that call must be made from
within a class (as opposed to instance) method. Here is a simple
program which shows a class which can define and undefine a constant.
If you run it with ruby you should see the output in the comments
class Foo
def self.define_constant
class_eval “CONST_VAL = 1”
end
def self.undef_constant
remove_const :CONST_VAL
end
end
puts “CONST_VAL defined?: #{Foo.const_defined?(:CONST_VAL)}”
Foo.define_constant
puts “CONST_VAL defined now?: #{Foo.const_defined?(:CONST_VAL)}”
Foo.undef_constant
puts “CONST_VAL still defined?: #{Foo.const_defined?(:CONST_VAL)}”
output:
#CONST_VAL defined?: false
#CONST_VAL defined now?: true
#CONST_VAL still defined?: false
There are trickier ways to do this with the “send” method but this be
enough should get you started.
Thanks for all responses. I think I can work something out based on
these. I’ll post my answer.
Bob
On 11/14/05, Robert E. [email protected] wrote:
=> “my symbol value”
irb(main):002:0> remove_const(FOO)
NoMethodError: undefined method remove_const' for main:Object from (irb):2 irb(main):003:0> remove_const(:FOO) NoMethodError: undefined method
remove_const’ for main:Object
from (irb):3
irb(main):004:0> ??
Any other ideas?
This is one of those odd methods that is hard to call. It is actually
a private method in Module, which means you must call it on a module
or class, and because it is private you must use send if you want to
call it from outside the class or module:
irb(main):001:0> FOO = “something”
=> “something”
irb(main):002:0> Object.const_defined?(:FOO)
=> true
irb(main):003:0> Object.send(:remove_const, :FOO)
=> “something”
irb(main):004:0> FOO
NameError: uninitialized constant FOO
from (irb):4
But it is better to do something like this:
irb(main):005:0> class Test
irb(main):006:1> FOO = “something”
irb(main):007:1> end
=> “something”
irb(main):008:0> class Test
irb(main):009:1> FOO = “something else”
irb(main):010:1> end
(irb):9: warning: already initialized constant FOO
=> “something else”
irb(main):011:0> class Test
irb(main):012:1> remove_const(:FOO)
irb(main):013:1> FOO = “yet something else”
irb(main):014:1> end
=> “yet something else”
In other words you should call remove_const from inside the class
definition before re-creating it.
Ryan
On 11/14/05, Mauricio Fernández [email protected] wrote:
irb
irb(main):001:0> FOO = “my symbol value”
=> “my symbol value”
irb(main):002:0> remove_const(FOO)
NoMethodError: undefined method `remove_const’ for main:Object
from (irb):2
irb(main):003:0> remove_const(:FOO)
Sorry, I meant
Object.send(:remove_const, :FOO)
I may be wrong, but I think using #send to bypass private method
encapsulation is not future-proof. Instead, you might use
Object.instance_eval{ remove_const :FOO }
This is almost guaranteed to work in the future.
cheers,
Mark
Hey Everybody,
Thanks for your help. I went for Mark’s approach of using
Object.instance_eval(:remove_const, :FOO).
I want to make sure I understand what is going on, so let me know if
I get the reason this works wrong.
This works because: Object includes Kernel which is a Module, so it
gets all the methods on Module, which includes remove_const. Is that
correct?
Thanks,
Bob E.
On Tue, Nov 15, 2005 at 10:44:48AM +0900, Mark H. wrote:
On 11/14/05, Mauricio Fernández [email protected] wrote:
Sorry, I meant
Object.send(:remove_const, :FOO)
I may be wrong, but I think using #send to bypass private method
encapsulation is not future-proof.
Right, eigenclass.org