57

Let's say I'm using irb, and type a = 5. How do I remove the definition of a so that typing a returns a NameError?

Some context: later I want to do this:

context = Proc.new{}.binding
context.eval 'a = 5'
context.eval 'undef a'  # though this doesn't work.

5 Answers 5

58

There are remove_class_variable, remove_instance_variable and remove_const methods but there is currently no equivalent for local variables.

Sign up to request clarification or add additional context in comments.

4 Comments

hmm, annoying that there aren't any methods like that. I guess I can stick to instance variables for now.
Those links don't look like they are going to the right place anymore.
@jcollum thanks. remove_instance_variable and remove_const are private methods so don't seem to be included in the documentation on ruby-doc.org any more. I've updated the answer to use equivalent links to apidock.com
It's been 6 years. Have there been any developments regarding locals and globals?
29

You can avoid un-declaring the variable by reducing the scope in which the variable exists:

def scope 
  yield
end

scope do 
  b = 1234
end

b  # undefined local variable or method `b' for main:Object

3 Comments

This is the answer I wanted to see.
there is an standard kind of scope function called Proc.new: Proc.new { b = 1 } ; b
Worth noting that Proc.new differs from the given scope in that it doesn't actually call the block. The equivalent would be Proc.new { b = 1 }.call; b. You can also use lambda { b = 1 }.call.
15

You can always 'clear' irb's registry of local variables by invoking an irb subshell. Think of how Bash shells work with respect to unexported environment variables. Since you metioned interactive mode, this solution ought to work for that.

As far as production code, I wouldn't want to undefine local variables as part of a solution - keyed hashes would probably be better for that type of scenario.

Here's what I mean:

$ irb
irb(main):001:0> a = "a"
=> "a"
irb(main):002:0> defined? a
=> "local-variable"
irb(main):003:0> irb # step into subshell with its own locals
irb#1(main):001:0> defined? a
=> nil
irb#1(main):002:0> a
NameError: undefined local variable or method `a' for main:Object
    from /Users/dean/.irbrc:108:in `method_missing'
    from (irb#1):2
irb#1(main):003:0> exit
=> #<IRB::Irb: @context=#<IRB::Context:0x1011b48b8>, @signal_status=:IN_EVAL, @scanner=#<RubyLex:0x1011b3df0>>
irb(main):004:0> a # now we're back and a exists again
=> "a"

1 Comment

that returns: "NotImplementedError: ruby engine can initialize only in the main thread"
0

In the spirit of the question, you could limit the variable to a scope, assuming you are okay with other local variables being locked to the same scope. This is useful particularly if you are defining something in a class and don't want the local variable to stay around in the class declaration.

The only ways I can think to do this is with Integer#times or Array#each like so:

1.times do |a|
  a = 5
  # code…
end

[5].each do |a|
  # code…
end

There are probably other, even cleaner ways to limit to a block besides this. These aren't as clean as I'd like and I'd love to see if someone has a cleaner method to use to do this.

Comments

-2

Currently you have no mean to remove global variables, local variables and class variables. You can remove constants using "remove_const" method though

1 Comment

Not true for class variables - there is remove_class_variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.