Practical Use of Binding in Ruby

Let's write our own version of IRB to apply the concept of binding to a real world problem. Simple one liner REPL:

loop { p eval gets }

This can execute one line programs only.

$ ruby one.rb
1 + 1
2
self
main
self.class
Object
def test
one.rb:1:in `eval': (eval):1: syntax error, unexpected end-of-input (SyntaxError)
    from one.rb:1:in `block in <main>'
    from one.rb:1:in `loop'
    from one.rb:1:in `<main>'

It fails if you try to define a method. It also cannot remember the local variables you used.

$ ruby one.rb
x = 1
1
x
one.rb:1:in `eval': undefined local variable or method `x' for main:Object (NameError)
    from one.rb:1:in `eval'
    from one.rb:1:in `block in <main>'
    from one.rb:1:in `loop'
    from one.rb:1:in `<main>'

It printed the value the first time. The second time it results in an error. We can fix this by executing the eval in the top level context.

myirb_binding = binding()

loop do
  print ">> "
  input = gets.chomp!
  result = myirb_binding.eval(input)
  p result
end

Now we can persist the local variable in the REPL session.

$ ruby two.rb
>> x = 10
10
>> x
10
>> x
10

We can exit gracefully when we hit control+c by rescuing the Interrupt.

myirb_binding = binding()

begin
  loop do
    print ">> "
    input = gets.chomp!
    result = myirb_binding.eval(input)
    p result
  end
rescue Interrupt
  exit
end

References


Related Articles


Create your own user feedback survey