views:

883

answers:

4

In ruby, is there a way to "undefine" a variable or constant once it's been defined?

In our rails environemnts, we define one of three contants to be true, depending on the environment: TESTING, DEVELOPMENT, or PRODUCTION. Then, in controller code, we use defined? to see if what environment we're in, ie: defined? PRODUCTION.

Now, I want to unit test some of that environment-specific behavior. My initial attempt was to just set the appropriate constant in my test, and then reset them in teardown. However, I can't figure out how to reset DEVELOPMENT and PRODUCTION such that defined? returns false.

Obviously, a solution would be to just check to see if the appropriate constant is also true in addition to checking if it's defined, but this will result in having to touch a fair amount of existing code.

EDIT: I realize this is definitely NOT the right way to do things. Alas, changing it is a nontrivial task, so I'm looking for an easy way to just unit test what's there now. Plus, I'm also just curious about the lower level language question of whether it's possible to undefine a variable/constant.

+1  A: 

Instead of checking each constant, why not do something like:

environment = :TESTING

if(environment == :TESTING)
grepsedawk
+3  A: 

It makes little sense to use three true/false variables for conditions that are mutually exclusive. What happens, for example, if both DEVELOPMENT and PRODUCTION are set at the same time.

Instead, have a single variable which indicates which environment you're in, setting ENVIRON to one of the set (DEV,TEST,PROD) or something similar.

Then you can just compare ENVIRON to one of the three for each action you want to perform.

paxdiablo
+5  A: 

Well I'm guessing because this is tagged with RubyOnRails that we are talking about Rails here... the environment is stored in RAILS_ENV already so doing something like works just fine...

if (RAILS_ENV == "production") ...

I guess you could also write it like:

RAILS_ENV.include?("development")
Tim K.
+2  A: 

I found this answer

Object.send(:remove_const, "TESTING")

If I remember correctly, using send here is kind of a hack, because remove_const is really a private method. You want to ask yourself why you need to define constants PRODUCTION, DEVELOPMENT and TESTING at the same time while they really are mutually exclusive ; that's why I upvoted grepsedawk's answer.

vincent
This is exactly what I was looking for, hacky or not (it's unit test code, so I'm not terribly worried that it's private). Thanks!
Scotty Allen