binding_of_caller 0.6.3-universal-rubinius

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gemtest +0 -0
  2. data/.gitignore +7 -0
  3. data/.yardopts +1 -0
  4. data/HISTORY +0 -0
  5. data/LICENSE +25 -0
  6. data/README.md +86 -0
  7. data/Rakefile +112 -0
  8. data/examples/example.rb +41 -0
  9. data/ext/binding_of_caller/binding_of_caller.c +220 -0
  10. data/ext/binding_of_caller/extconf.rb +13 -0
  11. data/ext/binding_of_caller/ruby_headers/192/debug.h +36 -0
  12. data/ext/binding_of_caller/ruby_headers/192/dln.h +41 -0
  13. data/ext/binding_of_caller/ruby_headers/192/eval_intern.h +232 -0
  14. data/ext/binding_of_caller/ruby_headers/192/gc.h +77 -0
  15. data/ext/binding_of_caller/ruby_headers/192/id.h +173 -0
  16. data/ext/binding_of_caller/ruby_headers/192/iseq.h +104 -0
  17. data/ext/binding_of_caller/ruby_headers/192/method.h +103 -0
  18. data/ext/binding_of_caller/ruby_headers/192/node.h +483 -0
  19. data/ext/binding_of_caller/ruby_headers/192/regenc.h +211 -0
  20. data/ext/binding_of_caller/ruby_headers/192/regint.h +841 -0
  21. data/ext/binding_of_caller/ruby_headers/192/regparse.h +354 -0
  22. data/ext/binding_of_caller/ruby_headers/192/thread_pthread.h +27 -0
  23. data/ext/binding_of_caller/ruby_headers/192/thread_win32.h +33 -0
  24. data/ext/binding_of_caller/ruby_headers/192/timev.h +21 -0
  25. data/ext/binding_of_caller/ruby_headers/192/transcode_data.h +109 -0
  26. data/ext/binding_of_caller/ruby_headers/192/version.h +63 -0
  27. data/ext/binding_of_caller/ruby_headers/192/vm_core.h +703 -0
  28. data/ext/binding_of_caller/ruby_headers/192/vm_exec.h +184 -0
  29. data/ext/binding_of_caller/ruby_headers/192/vm_insnhelper.h +208 -0
  30. data/ext/binding_of_caller/ruby_headers/192/vm_opts.h +51 -0
  31. data/ext/binding_of_caller/ruby_headers/193/addr2line.h +21 -0
  32. data/ext/binding_of_caller/ruby_headers/193/atomic.h +56 -0
  33. data/ext/binding_of_caller/ruby_headers/193/constant.h +34 -0
  34. data/ext/binding_of_caller/ruby_headers/193/debug.h +41 -0
  35. data/ext/binding_of_caller/ruby_headers/193/dln.h +50 -0
  36. data/ext/binding_of_caller/ruby_headers/193/encdb.h +167 -0
  37. data/ext/binding_of_caller/ruby_headers/193/eval_intern.h +234 -0
  38. data/ext/binding_of_caller/ruby_headers/193/gc.h +98 -0
  39. data/ext/binding_of_caller/ruby_headers/193/id.h +175 -0
  40. data/ext/binding_of_caller/ruby_headers/193/internal.h +227 -0
  41. data/ext/binding_of_caller/ruby_headers/193/iseq.h +125 -0
  42. data/ext/binding_of_caller/ruby_headers/193/method.h +105 -0
  43. data/ext/binding_of_caller/ruby_headers/193/node.h +503 -0
  44. data/ext/binding_of_caller/ruby_headers/193/parse.h +186 -0
  45. data/ext/binding_of_caller/ruby_headers/193/regenc.h +219 -0
  46. data/ext/binding_of_caller/ruby_headers/193/regint.h +851 -0
  47. data/ext/binding_of_caller/ruby_headers/193/regparse.h +362 -0
  48. data/ext/binding_of_caller/ruby_headers/193/revision.h +1 -0
  49. data/ext/binding_of_caller/ruby_headers/193/thread_pthread.h +51 -0
  50. data/ext/binding_of_caller/ruby_headers/193/thread_win32.h +40 -0
  51. data/ext/binding_of_caller/ruby_headers/193/timev.h +21 -0
  52. data/ext/binding_of_caller/ruby_headers/193/transcode_data.h +117 -0
  53. data/ext/binding_of_caller/ruby_headers/193/transdb.h +189 -0
  54. data/ext/binding_of_caller/ruby_headers/193/version.h +52 -0
  55. data/ext/binding_of_caller/ruby_headers/193/vm_core.h +755 -0
  56. data/ext/binding_of_caller/ruby_headers/193/vm_exec.h +184 -0
  57. data/ext/binding_of_caller/ruby_headers/193/vm_insnhelper.h +220 -0
  58. data/ext/binding_of_caller/ruby_headers/193/vm_opts.h +51 -0
  59. data/lib/binding_of_caller.bundle +0 -0
  60. data/lib/binding_of_caller.rb +82 -0
  61. data/lib/binding_of_caller/version.rb +3 -0
  62. data/lib/tester.rb +15 -0
  63. data/test/test.rb +91 -0
  64. metadata +121 -0
data/.gemtest ADDED
File without changes
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ Makefile
2
+ *.so
3
+ *.o
4
+ *.def
5
+ doc/
6
+ pkg/
7
+ .yardoc/
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown
data/HISTORY ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ License
2
+ -------
3
+
4
+ (The MIT License)
5
+
6
+ Copyright (c) 2011 John Mair (banisterfiend)
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining
9
+ a copy of this software and associated documentation files (the
10
+ 'Software'), to deal in the Software without restriction, including
11
+ without limitation the rights to use, copy, modify, merge, publish,
12
+ distribute, sublicense, and/or sell copies of the Software, and to
13
+ permit persons to whom the Software is furnished to do so, subject to
14
+ the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be
17
+ included in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ binding_of_caller
2
+ ===========
3
+
4
+ (C) John Mair (banisterfiend) 2011
5
+
6
+ _Retrieve the binding of a method's caller in MRI 1.9.2_
7
+
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 and 1.9.3**
17
+
18
+ * Install the [gem](https://rubygems.org/gems/binding_of_caller): `gem install binding_of_caller`
19
+ * See the [source code](http://github.com/banister/binding_of_caller)
20
+
21
+ Example: Modifying a local inside the caller of a caller
22
+ --------
23
+
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
+ -------
47
+
48
+ This project is a spinoff from the [Pry REPL project.](http://pry.github.com)
49
+
50
+ Features and limitations
51
+ -------------------------
52
+
53
+ * Only works with MRI 1.9.2 and 1.9.3
54
+ * Does not work in 1.8.7, but there is a well known (continuation-based) hack to get a `Binding#of_caller` there.
55
+
56
+ Contact
57
+ -------
58
+
59
+ Problems or questions contact me at [github](http://github.com/banister)
60
+
61
+
62
+ License
63
+ -------
64
+
65
+ (The MIT License)
66
+
67
+ Copyright (c) 2011 (John Mair)
68
+
69
+ Permission is hereby granted, free of charge, to any person obtaining
70
+ a copy of this software and associated documentation files (the
71
+ 'Software'), to deal in the Software without restriction, including
72
+ without limitation the rights to use, copy, modify, merge, publish,
73
+ distribute, sublicense, and/or sell copies of the Software, and to
74
+ permit persons to whom the Software is furnished to do so, subject to
75
+ the following conditions:
76
+
77
+ The above copyright notice and this permission notice shall be
78
+ included in all copies or substantial portions of the Software.
79
+
80
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
81
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
82
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
83
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
84
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
85
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
86
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,112 @@
1
+ dlext = Config::CONFIG['DLEXT']
2
+ direc = File.dirname(__FILE__)
3
+
4
+ $:.unshift 'lib'
5
+
6
+ PROJECT_NAME = "binding_of_caller"
7
+
8
+ require 'rake/clean'
9
+ require 'rubygems/package_task'
10
+
11
+ require "#{PROJECT_NAME}/version"
12
+
13
+ CLOBBER.include("**/*.#{dlext}", "**/*~", "**/*#*", "**/*.log", "**/*.o")
14
+ CLEAN.include("ext/**/*.#{dlext}", "ext/**/*.log", "ext/**/*.o",
15
+ "ext/**/*~", "ext/**/*#*", "ext/**/*.obj", "**/*#*", "**/*#*.*",
16
+ "ext/**/*.def", "ext/**/*.pdb", "**/*_flymake*.*", "**/*_flymake", "**/*.rbc")
17
+
18
+ def apply_spec_defaults(s)
19
+ s.name = PROJECT_NAME
20
+ s.summary = "Retrieve the binding of a method's caller. Can also retrieve bindings even further up the stack. Currently only works for MRI 1.9.2+"
21
+ s.version = BindingOfCaller::VERSION
22
+ s.date = Time.now.strftime '%Y-%m-%d'
23
+ s.author = "John Mair (banisterfiend)"
24
+ s.email = 'jrmair@gmail.com'
25
+ s.description = s.summary
26
+ s.require_path = 'lib'
27
+ s.add_development_dependency("bacon","~>1.1")
28
+ s.homepage = "http://github.com/banister/binding_of_caller"
29
+ s.has_rdoc = 'yard'
30
+ s.files = `git ls-files`.split("\n")
31
+ s.test_files = `git ls-files -- test/*`.split("\n")
32
+ end
33
+
34
+ desc "Run tests"
35
+ task :test do
36
+ sh "bacon -Itest -rubygems test.rb -q"
37
+ end
38
+
39
+ task :pry do
40
+ puts "loading binding_of_caller into pry"
41
+ sh "pry -r ./lib/binding_of_caller"
42
+ end
43
+
44
+ desc "generate gemspec"
45
+ task :gemspec => "ruby:gemspec"
46
+
47
+ namespace :ruby do
48
+ spec = Gem::Specification.new do |s|
49
+ apply_spec_defaults(s)
50
+ s.platform = Gem::Platform::RUBY
51
+ s.extensions = ["ext/#{PROJECT_NAME}/extconf.rb"]
52
+ end
53
+
54
+ Gem::PackageTask.new(spec) do |pkg|
55
+ pkg.need_zip = false
56
+ pkg.need_tar = false
57
+ end
58
+
59
+ desc "Generate gemspec file"
60
+ task :gemspec do
61
+ File.open("#{spec.name}.gemspec", "w") do |f|
62
+ f << spec.to_ruby
63
+ end
64
+ end
65
+ end
66
+
67
+ namespace :rbx do
68
+ spec = Gem::Specification.new do |s|
69
+ apply_spec_defaults(s)
70
+ s.platform = Gem::Platform.new(["universal", "rubinius"])
71
+ end
72
+
73
+ Gem::PackageTask.new(spec) do |pkg|
74
+ pkg.need_zip = false
75
+ pkg.need_tar = false
76
+ end
77
+ end
78
+
79
+ desc "build the binaries"
80
+ task :compile do
81
+ chdir "./ext/#{PROJECT_NAME}/" do
82
+ sh "ruby extconf.rb"
83
+ sh "make clean"
84
+ sh "make"
85
+ sh "cp *.#{dlext} ../../lib/"
86
+ end
87
+ end
88
+
89
+ desc "reinstall gem"
90
+ task :reinstall => :gems do
91
+ sh "gem uninstall binding_of_caller" rescue nil
92
+ sh "gem install #{direc}/pkg/#{PROJECT_NAME}-#{BindingOfCaller::VERSION}.gem"
93
+ end
94
+
95
+ desc "build all platform gems at once"
96
+ task :gems => [:clean, :rmgems, "ruby:gem", "rbx:gem"]
97
+
98
+ task :gem => [:gems]
99
+
100
+ task :rbxgem => "rbx:gem"
101
+
102
+ desc "remove all platform gems"
103
+ task :rmgems => ["ruby:clobber_package"]
104
+
105
+ desc "build and push latest gems"
106
+ task :pushgems => :gems do
107
+ chdir("./pkg") do
108
+ Dir["*.gem"].each do |gemfile|
109
+ sh "gem push #{gemfile}"
110
+ end
111
+ end
112
+ 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
@@ -0,0 +1,220 @@
1
+ /* (c) 2011 John Mair (banisterfiend), MIT license */
2
+
3
+ #include <ruby.h>
4
+ #include "vm_core.h"
5
+ #include "gc.h"
6
+
7
+ typedef enum { false, true } bool;
8
+
9
+ static VALUE
10
+ string2sym(const char * string)
11
+ {
12
+ return ID2SYM(rb_intern(string));
13
+ }
14
+
15
+ static inline const rb_data_type_t *
16
+ threadptr_data_type(void)
17
+ {
18
+ static const rb_data_type_t *thread_data_type;
19
+ if (!thread_data_type) {
20
+ VALUE current_thread = rb_thread_current();
21
+ thread_data_type = RTYPEDDATA_TYPE(current_thread);
22
+ }
23
+ return thread_data_type;
24
+ }
25
+
26
+ #define ruby_thread_data_type *threadptr_data_type()
27
+
28
+ #define ruby_current_thread ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()))
29
+
30
+ static size_t
31
+ binding_memsize(const void *ptr)
32
+ {
33
+ return ptr ? sizeof(rb_binding_t) : 0;
34
+ }
35
+
36
+ static void
37
+ binding_free(void *ptr)
38
+ {
39
+ rb_binding_t *bind;
40
+ RUBY_FREE_ENTER("binding");
41
+ if (ptr) {
42
+ bind = ptr;
43
+ ruby_xfree(ptr);
44
+ }
45
+ RUBY_FREE_LEAVE("binding");
46
+ }
47
+
48
+ static void
49
+ binding_mark(void *ptr)
50
+ {
51
+ rb_binding_t *bind;
52
+ RUBY_MARK_ENTER("binding");
53
+ if (ptr) {
54
+ bind = ptr;
55
+ RUBY_MARK_UNLESS_NULL(bind->env);
56
+
57
+ #ifdef RUBY_192
58
+ RUBY_MARK_UNLESS_NULL(bind->filename);
59
+ #endif
60
+
61
+ }
62
+ RUBY_MARK_LEAVE("binding");
63
+ }
64
+
65
+ static const rb_data_type_t binding_data_type = {
66
+ "binding",
67
+ binding_mark,
68
+ binding_free,
69
+ binding_memsize,
70
+ };
71
+
72
+ static VALUE
73
+ binding_alloc(VALUE klass)
74
+ {
75
+ VALUE obj;
76
+ rb_binding_t *bind;
77
+ obj = TypedData_Make_Struct(klass, rb_binding_t, &binding_data_type, bind);
78
+ return obj;
79
+ }
80
+
81
+ static bool valid_frame_p(rb_control_frame_t * cfp, rb_control_frame_t * limit_cfp) {
82
+ return cfp->iseq && !NIL_P(cfp->self);
83
+ }
84
+
85
+ static rb_control_frame_t * find_valid_frame(rb_control_frame_t * cfp, rb_control_frame_t * limit_cfp) {
86
+ while (cfp < limit_cfp) {
87
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
88
+
89
+ if (cfp >= limit_cfp)
90
+ return NULL;
91
+
92
+ if (valid_frame_p(cfp, limit_cfp))
93
+ return cfp;
94
+ }
95
+
96
+ // beyond end of stack
97
+ return NULL;
98
+ }
99
+
100
+ static VALUE
101
+ frametype_name(VALUE flag)
102
+ {
103
+ switch (flag & VM_FRAME_MAGIC_MASK) {
104
+ case VM_FRAME_MAGIC_METHOD: return string2sym("method");
105
+ case VM_FRAME_MAGIC_BLOCK: return string2sym("block");
106
+ case VM_FRAME_MAGIC_CLASS: return string2sym("class");
107
+ case VM_FRAME_MAGIC_TOP: return string2sym("top");
108
+ case VM_FRAME_MAGIC_FINISH: return string2sym("finish");
109
+ case VM_FRAME_MAGIC_CFUNC: return string2sym("cfunc");
110
+ case VM_FRAME_MAGIC_PROC: return string2sym("proc");
111
+ case VM_FRAME_MAGIC_IFUNC: return string2sym("ifunc");
112
+ case VM_FRAME_MAGIC_EVAL: return string2sym("eval");
113
+ case VM_FRAME_MAGIC_LAMBDA: return string2sym("lambda");
114
+ default:
115
+ rb_raise(rb_eRuntimeError, "Unknown frame type! got flag: %d", FIX2INT(flag));
116
+ }
117
+ }
118
+
119
+ static VALUE binding_of_caller(VALUE self, VALUE rb_level)
120
+ {
121
+ rb_thread_t *th;
122
+ GetThreadPtr(rb_thread_current(), th);
123
+
124
+ rb_control_frame_t *cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
125
+ rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
126
+ int level = FIX2INT(rb_level);
127
+
128
+ // attempt to locate the nth parent control frame
129
+ for (int i = 0; i < level; i++) {
130
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
131
+
132
+ if (cfp >= limit_cfp)
133
+ rb_raise(rb_eRuntimeError, "Invalid frame, gone beyond end of stack!");
134
+
135
+ // skip invalid frames
136
+ if (!valid_frame_p(cfp, limit_cfp))
137
+ cfp = find_valid_frame(cfp, limit_cfp);
138
+ }
139
+
140
+ VALUE bindval = binding_alloc(rb_cBinding);
141
+ rb_binding_t *bind;
142
+
143
+ if (cfp == 0)
144
+ rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber.");
145
+
146
+ GetBindingPtr(bindval, bind);
147
+ bind->env = rb_vm_make_env_object(th, cfp);
148
+ bind->filename = cfp->iseq->filename;
149
+ bind->line_no = rb_vm_get_sourceline(cfp);
150
+
151
+ rb_iv_set(bindval, "@frame_type", frametype_name(cfp->flag));
152
+ rb_iv_set(bindval, "@frame_description", cfp->iseq->name);
153
+
154
+ return bindval;
155
+ }
156
+
157
+ static VALUE
158
+ frame_type(VALUE self)
159
+ {
160
+ return rb_iv_get(self, "@frame_type");
161
+ }
162
+
163
+ static VALUE
164
+ frame_description(VALUE self)
165
+ {
166
+ return rb_iv_get(self, "@frame_description");
167
+ }
168
+
169
+ static VALUE frame_count(VALUE self)
170
+ {
171
+ rb_thread_t *th;
172
+ GetThreadPtr(rb_thread_current(), th);
173
+
174
+ rb_control_frame_t *cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
175
+ rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
176
+
177
+ int i = 1;
178
+ while (cfp < limit_cfp) {
179
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
180
+
181
+ if (cfp >= limit_cfp)
182
+ return INT2FIX(i);
183
+
184
+ // skip invalid frames
185
+ if (!valid_frame_p(cfp, limit_cfp))
186
+ cfp = find_valid_frame(cfp, limit_cfp);
187
+
188
+ if (!cfp)
189
+ break;
190
+
191
+ i++;
192
+ }
193
+
194
+ return INT2FIX(i);
195
+ }
196
+
197
+ static VALUE
198
+ callers(VALUE self)
199
+ {
200
+ VALUE ary = rb_ary_new();
201
+
202
+ for (int i = 0; i < FIX2INT(frame_count(self)); i++)
203
+ rb_ary_push(ary, binding_of_caller(self, INT2FIX(i)));
204
+
205
+ return ary;
206
+ }
207
+
208
+ void
209
+ Init_binding_of_caller()
210
+ {
211
+ VALUE mBindingOfCaller = rb_define_module("BindingOfCaller");
212
+
213
+ rb_define_method(mBindingOfCaller, "of_caller", binding_of_caller, 1);
214
+ rb_define_method(mBindingOfCaller, "frame_count", frame_count, 0);
215
+ rb_define_method(mBindingOfCaller, "frame_type", frame_type, 0);
216
+ rb_define_method(mBindingOfCaller, "frame_description", frame_description, 0);
217
+ rb_define_method(mBindingOfCaller, "callers", callers, 0);
218
+ rb_include_module(rb_cBinding, mBindingOfCaller);
219
+ }
220
+