Skip to content

Instantly share code, notes, and snippets.

@headius
Created February 12, 2013 21:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save headius/4773409 to your computer and use it in GitHub Desktop.
Save headius/4773409 to your computer and use it in GitHub Desktop.
Example of Binding.of_caller in JRuby
ext-jruby-local ~/projects/jruby $ jruby -X-C -S irb
irb(main):001:0> def foo
irb(main):002:1> a = 1
irb(main):003:1> bar
irb(main):004:1> puts a
irb(main):005:1> end
=> nil
irb(main):006:0> def bar
irb(main):007:1> eval 'a = 2', Binding.of_caller(1)
irb(main):008:1> end
=> nil
irb(main):009:0> foo
2
=> nil
diff --git a/src/org/jruby/RubyBinding.java b/src/org/jruby/RubyBinding.java
index 13ee964..6e5d5a5 100644
--- a/src/org/jruby/RubyBinding.java
+++ b/src/org/jruby/RubyBinding.java
@@ -133,4 +133,10 @@ public class RubyBinding extends RubyObject {
return RubyKernel.eval(context, this, newArgs, Block.NULL_BLOCK);
}
+
+ @JRubyMethod(meta = true)
+ public static IRubyObject of_caller(ThreadContext context, IRubyObject self, IRubyObject level) {
+ Binding binding = context.bindingOfCaller((int)level.convertToInteger().getLongValue());
+ return new RubyBinding(context.runtime, (RubyClass)self, binding);
+ }
}
diff --git a/src/org/jruby/runtime/ThreadContext.java b/src/org/jruby/runtime/ThreadContext.java
index b811b3e..dbe0889 100644
--- a/src/org/jruby/runtime/ThreadContext.java
+++ b/src/org/jruby/runtime/ThreadContext.java
@@ -1276,6 +1276,22 @@ public final class ThreadContext {
}
/**
+ * Return a binding representing call state from the specified levels above
+ * the current call. This will generally produce unpredictable results when
+ * JRuby's compiler optimizations are active since compiled calls will omit
+ * some or all of this state.
+ *
+ * @return the binding at the specified level above the current call
+ */
+ public Binding bindingOfCaller(int level) {
+ // FIXME: no bounds check
+ Frame frame = frameStack[frameIndex - level];
+ DynamicScope scope = scopeStack[scopeIndex - level];
+ BacktraceElement element = backtrace[backtraceIndex - level];
+ return new Binding(frame, scope.getStaticScope().getModule(), scope, element.clone());
+ }
+
+ /**
* Return a binding representing the previous call's state but with a specified self
* @param self the self object to use
* @return the current binding, using the specified self
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment