removing a constant definition from an environment

R

Robert Evans

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
 
R

Ryan Leavengood

I expected the unit test to clean the environment, in lieu of that,
how can I undefined const?

---------------------------------------------------- Module#remove_const
remove_const(sym) =3D> 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
 
R

Robert Evans

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
 
M

Mauricio Fernández

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)

Object.remove_const:)FOO)
 
M

m4dc4p

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.
 
M

Mauricio Fernández

Sorry, I meant=20
Object.send:)remove_const, :FOO)

--=20
Mauricio Fernandez
 
R

Ryan Leavengood

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 =3D "my symbol value"
=3D> "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 =3D "something"
=3D> "something"
irb(main):002:0> Object.const_defined?:)FOO)
=3D> true
irb(main):003:0> Object.send:)remove_const, :FOO)
=3D> "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 =3D "something"
irb(main):007:1> end
=3D> "something"
irb(main):008:0> class Test
irb(main):009:1> FOO =3D "something else"
irb(main):010:1> end
(irb):9: warning: already initialized constant FOO
=3D> "something else"
irb(main):011:0> class Test
irb(main):012:1> remove_const:)FOO)
irb(main):013:1> FOO =3D "yet something else"
irb(main):014:1> end
=3D> "yet something else"

In other words you should call remove_const from inside the class
definition before re-creating it.

Ryan
 
R

Robert Evans

Thanks for all responses. I think I can work something out based on
these. I'll post my answer.

Bob
 
R

Robert Evans

Hey Everybody,

Thanks for your help. I went for Mark's approach of using =20
Object.instance_eval:)remove_const, :FOO).

I want to make sure I understand what is going on, so let me know if =20
I get the reason this works wrong.

This works because: Object includes Kernel which is a Module, so it =20
gets all the methods on Module, which includes remove_const. Is that =20
correct?

Thanks,
Bob Evans
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top