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 2005-11-14 22:29
on 2005-11-14 22:47
On 11/14/05, Robert Evans <robert.evans@acm.org> 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
on 2005-11-14 22:59
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 Evans
on 2005-11-14 23:17
On Tue, Nov 15, 2005 at 06:56:59AM +0900, Robert Evans 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 2005-11-14 23:20
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)
on 2005-11-14 23:23
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.
on 2005-11-14 23:26
On 11/14/05, Robert Evans <robert.evans@acm.org> 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 2005-11-15 00:08
Thanks for all responses. I think I can work something out based on these. I'll post my answer. Bob
on 2005-11-15 02:48
On 11/14/05, Mauricio Fernández <mfp@acm.org> 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
on 2005-11-15 06:18
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 Evans
on 2005-11-15 10:22
On Tue, Nov 15, 2005 at 10:44:48AM +0900, Mark Hubbart wrote: > On 11/14/05, Mauricio Fernández <mfp@acm.org> 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, http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l11
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.