binding_of_caller 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -3,25 +3,56 @@ binding_of_caller
3
3
 
4
4
  (C) John Mair (banisterfiend) 2011
5
5
 
6
- FIXME: _tagline_
6
+ _Retrieve the binding of a method's caller in MRI 1.9.2_
7
7
 
8
- FIXME: _description goes here_
8
+ The `binding_of_caller` gem provides the `Binding#of_caller` method.
9
+
10
+ Using `binding_of_caller` we can grab bindings from higher up the call
11
+ stack and evaluate code in that context. Allows access to bindings arbitrarily far up the
12
+ call stack, not limited to just the immediate caller.
13
+
14
+ **Recommended for use only in debugging situations. Do not use this in production apps.**
15
+
16
+ **Only works in MRI Ruby 1.9.2**
9
17
 
10
18
  * Install the [gem](https://rubygems.org/gems/binding_of_caller): `gem install binding_of_caller`
11
- * Read the [documentation](http://rdoc.info/github/banister/binding_of_caller/master/file/README.markdown)
12
19
  * See the [source code](http://github.com/banister/binding_of_caller)
13
20
 
14
- Example: Example description
21
+ Example: Modifying a local inside the caller of a caller
15
22
  --------
16
23
 
17
- Example preamble
24
+ ```ruby
25
+ def a
26
+ var = 10
27
+ b
28
+ puts var
29
+ end
30
+
31
+ def b
32
+ c
33
+ end
34
+
35
+ def c
36
+ binding.of_caller(2).eval('var = :hello')
37
+ end
38
+
39
+ a()
40
+
41
+ # OUTPUT
42
+ # => hello
43
+ ```
44
+
45
+ Spinoff project
46
+ -------
18
47
 
19
- puts "example code"
48
+ This project is a spinoff from the [Pry REPL project.](http://pry.github.com)
20
49
 
21
50
  Features and limitations
22
51
  -------------------------
23
52
 
24
- Feature List Preamble
53
+ * Only works with MRI 1.9.2
54
+ * Broken in 1.9.3, support will hopefully be provided in the near future.
55
+ * Does not work in 1.8.7, but there is a well known (continuation-based) hack to get a `Binding#of_caller` there.
25
56
 
26
57
  Contact
27
58
  -------
@@ -32,7 +63,7 @@ Problems or questions contact me at [github](http://github.com/banister)
32
63
  License
33
64
  -------
34
65
 
35
- (The MIT License)
66
+ (The MIT License)
36
67
 
37
68
  Copyright (c) 2011 (John Mair)
38
69
 
data/Rakefile CHANGED
@@ -52,7 +52,7 @@ namespace :ruby do
52
52
  end
53
53
  end
54
54
 
55
- desc "build the biinaries"
55
+ desc "build the binaries"
56
56
  task :compile do
57
57
  chdir "./ext/#{PROJECT_NAME}/" do
58
58
  sh "ruby extconf.rb"
@@ -72,7 +72,7 @@ task :rmgems => ["ruby:clobber_package"]
72
72
 
73
73
  desc "build and push latest gems"
74
74
  task :pushgems => :gems do
75
- chdir("#{direc}/pkg") do
75
+ chdir("./pkg") do
76
76
  Dir["*.gem"].each do |gemfile|
77
77
  sh "gem push #{gemfile}"
78
78
  end
@@ -0,0 +1,41 @@
1
+ unless Object.const_defined? :BindingOfCaller
2
+ $:.unshift File.expand_path '../../lib', __FILE__
3
+ require 'binding_of_caller'
4
+ require 'binding_of_caller/version'
5
+ end
6
+
7
+ outer = 10
8
+
9
+ class Z
10
+ def z
11
+ u = 10
12
+ A.new.a
13
+ end
14
+ end
15
+
16
+ class A
17
+ def a
18
+ y = 10
19
+ B.new.b
20
+ end
21
+ end
22
+
23
+ class B
24
+ def b
25
+ x = 10
26
+ puts binding.of_caller(0).eval('local_variables')
27
+ puts binding.of_caller(1).eval('local_variables')
28
+ puts binding.of_caller(2).eval('local_variables')
29
+ puts binding.of_caller(3).eval('local_variables')
30
+ puts binding.of_caller(400).eval('local_variables')
31
+ end
32
+ end
33
+
34
+ Z.new.z
35
+
36
+ # output:
37
+ # => x
38
+ # => y
39
+ # => u
40
+ # => outer
41
+ # Exception
@@ -2,10 +2,10 @@
2
2
 
3
3
  #include <ruby.h>
4
4
 
5
- # include <ruby/io.h>
6
- # include <ruby/re.h>
7
- # include "vm_core.h"
8
- # include "gc.h"
5
+ #include <ruby/io.h>
6
+ #include <ruby/re.h>
7
+ #include "vm_core.h"
8
+ #include "gc.h"
9
9
 
10
10
  typedef enum { false, true } bool;
11
11
 
@@ -58,24 +58,25 @@ binding_alloc(VALUE klass)
58
58
  return obj;
59
59
  }
60
60
 
61
- static bool valid_frame_p(rb_control_frame_t * cfp) {
61
+ static bool valid_frame_p(rb_control_frame_t * cfp, rb_control_frame_t * limit_cfp) {
62
+ if (cfp > limit_cfp)
63
+ rb_raise(rb_eRuntimeError, "Invalid frame, gone beyond end of stack!");
64
+
62
65
  return cfp->iseq && !NIL_P(cfp->self);
63
66
  }
64
67
 
65
- static rb_control_frame_t * find_valid_frame(rb_control_frame_t * cfp) {
68
+ static rb_control_frame_t * find_valid_frame(rb_control_frame_t * cfp, rb_control_frame_t * limit_cfp) {
66
69
  int error_count = 0;
67
70
 
68
71
  while (error_count <= max_frame_errors) {
69
72
  cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
70
73
 
71
- if (valid_frame_p(cfp))
74
+ if (valid_frame_p(cfp, limit_cfp))
72
75
  return cfp;
73
76
  else
74
77
  error_count += 1;
75
78
  }
76
79
 
77
- rb_raise(rb_eRuntimeError, "No valid stack frame found.");
78
-
79
80
  // never reached
80
81
  return 0;
81
82
  }
@@ -84,15 +85,17 @@ static VALUE binding_of_caller(VALUE self, VALUE rb_level)
84
85
  {
85
86
  rb_thread_t *th = GET_THREAD();
86
87
  rb_control_frame_t *cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
88
+ rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
87
89
  int level = FIX2INT(rb_level);
88
90
 
89
91
  // attempt to locate the nth parent control frame
90
- for (int i = 0; i < level; i++)
92
+ for (int i = 0; i < level; i++) {
91
93
  cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
92
94
 
93
- // if did not find a valid one, then search for a valid one
94
- if (!valid_frame_p(cfp))
95
- cfp = find_valid_frame(cfp);
95
+ // skip invalid frames
96
+ if (!valid_frame_p(cfp, limit_cfp))
97
+ cfp = find_valid_frame(cfp, limit_cfp);
98
+ }
96
99
 
97
100
  VALUE bindval = binding_alloc(rb_cBinding);
98
101
  rb_binding_t *bind;
@@ -1,3 +1,3 @@
1
1
  module BindingOfCaller
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: binding_of_caller
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.0
5
+ version: 0.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - John Mair (banisterfiend)
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-10-18 00:00:00 Z
13
+ date: 2011-10-20 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bacon
@@ -39,9 +39,8 @@ files:
39
39
  - LICENSE
40
40
  - README.md
41
41
  - Rakefile
42
+ - examples/example.rb
42
43
  - ext/binding_of_caller/binding_of_caller.c
43
- - ext/binding_of_caller/compat.h
44
- - ext/binding_of_caller/example.rb
45
44
  - ext/binding_of_caller/extconf.rb
46
45
  - ext/binding_of_caller/ruby_headers/192/debug.h
47
46
  - ext/binding_of_caller/ruby_headers/192/dln.h
@@ -1,57 +0,0 @@
1
- /* contains basic macros to facilitate ruby 1.8 and ruby 1.9 compatibility */
2
-
3
- #ifndef GUARD_COMPAT_H
4
- #define GUARD_COMPAT_H
5
-
6
- #include <ruby.h>
7
-
8
- /* test for 1.9 */
9
- #if !defined(RUBY_19) && defined(ROBJECT_EMBED_LEN_MAX)
10
- # define RUBY_19
11
- #endif
12
-
13
- /* macros for backwards compatibility with 1.8 */
14
- #ifndef RUBY_19
15
- # define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
16
- # define RCLASS_SUPER(c) (RCLASS(c)->super)
17
- # define RCLASS_IV_TBL(c) (RCLASS(c)->iv_tbl)
18
- # define OBJ_UNTRUSTED OBJ_TAINTED
19
- # include "st.h"
20
- #endif
21
-
22
- #ifdef RUBY_19
23
- inline static VALUE
24
- class_alloc(VALUE flags, VALUE klass)
25
- {
26
- rb_classext_t *ext = ALLOC(rb_classext_t);
27
- NEWOBJ(obj, struct RClass);
28
- OBJSETUP(obj, klass, flags);
29
- obj->ptr = ext;
30
- RCLASS_IV_TBL(obj) = 0;
31
- RCLASS_M_TBL(obj) = 0;
32
- RCLASS_SUPER(obj) = 0;
33
- RCLASS_IV_INDEX_TBL(obj) = 0;
34
- return (VALUE)obj;
35
- }
36
- #endif
37
-
38
- inline static VALUE
39
- create_class(VALUE flags, VALUE klass)
40
- {
41
- #ifdef RUBY_19
42
- VALUE new_klass = class_alloc(flags, klass);
43
- #else
44
- NEWOBJ(new_klass, struct RClass);
45
- OBJSETUP(new_klass, klass, flags);
46
- #endif
47
-
48
- return (VALUE)new_klass;
49
- }
50
-
51
- # define FALSE 0
52
- # define TRUE 1
53
-
54
- /* a useful macro. cannot use ordinary CLASS_OF as it does not return an lvalue */
55
- #define KLASS_OF(c) (RBASIC(c)->klass)
56
-
57
- #endif
@@ -1,39 +0,0 @@
1
- require './binding_of_caller'
2
-
3
- outer = 10
4
-
5
- class Z
6
- def z
7
- u = 10
8
- A.new.a
9
- end
10
- end
11
-
12
- class A
13
- def a
14
- y = 10
15
- B.new.b
16
- end
17
- end
18
-
19
- class B
20
- def b
21
- x = 10
22
- puts binding_of_caller(0).eval('local_variables')
23
- puts binding_of_caller(1).eval('local_variables')
24
- puts binding_of_caller(2).eval('local_variables')
25
- puts binding_of_caller(3).eval('local_variables')
26
- puts binding_of_caller(400).eval('local_variables')
27
- end
28
- end
29
-
30
- def a; b; end; def b; binding_of_caller(10); end; a;
31
-
32
- # Z.new.z
33
-
34
- # output:
35
- # => x
36
- # => y
37
- # => u
38
- # => outer
39
- # Exception