evalhook 0.1.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/AUTHORS +1 -0
- data/CHANGELOG +12 -0
- data/README +108 -0
- data/Rakefile +48 -0
- data/TODO +2 -0
- data/examples/example1.rb +12 -0
- data/examples/example2.rb +21 -0
- data/examples/example3.rb +28 -0
- data/ext/evalhook_base/evalhook_base.c +679 -0
- data/ext/evalhook_base/extconf.rb +7 -0
- data/lib/evalhook/redirect_helper.rb +54 -0
- data/lib/evalhook.rb +219 -0
- metadata +79 -0
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
evalhook de tario <rseminara@hotmail.com>
|
data/CHANGELOG
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
0.1.0 Created RDOC
|
2
|
+
|
3
|
+
Implemented use examples
|
4
|
+
|
5
|
+
Fixed functionality for shikashi sandbox
|
6
|
+
|
7
|
+
added method hook tree no hook the tree of a ruby method
|
8
|
+
|
9
|
+
implemented hook of global vars assignments
|
10
|
+
|
11
|
+
implemented hook of constant assigment (handle_cdecl)
|
12
|
+
|
data/README
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
= evalhook - Alternate eval which hook all methods (and more) in the evaluated code
|
2
|
+
|
3
|
+
== Installation
|
4
|
+
|
5
|
+
=== Gem installation
|
6
|
+
|
7
|
+
Run in the terminal:
|
8
|
+
|
9
|
+
sudo gem install evalhook
|
10
|
+
|
11
|
+
OR
|
12
|
+
|
13
|
+
* Download the last version of the gem from http://github.com/tario/evalhook/downloads
|
14
|
+
* Install the gem with the following;
|
15
|
+
|
16
|
+
sudo gem install evalhook-X.X.X.gem.
|
17
|
+
|
18
|
+
== Documentation
|
19
|
+
|
20
|
+
Full API documentation can be found on:
|
21
|
+
http://tario.github.com/evalhook/doc/
|
22
|
+
|
23
|
+
== Usage
|
24
|
+
|
25
|
+
This examples and more can be found in examples directory
|
26
|
+
|
27
|
+
=== Basic Example
|
28
|
+
|
29
|
+
Hook of method calls
|
30
|
+
|
31
|
+
require "rubygems"
|
32
|
+
require "evalhook"
|
33
|
+
|
34
|
+
class Hook < EvalHook::HookHandler
|
35
|
+
def handle_method(klass, recv, method_name)
|
36
|
+
print "called #{klass}##{method_name} over #{recv}\n"
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
h = Hook.new
|
42
|
+
h.evalhook('print "hello world\n"')
|
43
|
+
|
44
|
+
=== Basic Example 2
|
45
|
+
|
46
|
+
Hook of global variables and constants
|
47
|
+
|
48
|
+
require "rubygems"
|
49
|
+
require "evalhook"
|
50
|
+
|
51
|
+
class Hook < EvalHook::HookHandler
|
52
|
+
# global variable assignment/creation
|
53
|
+
def handle_gasgn( global_name, new_value)
|
54
|
+
print "assignment of #{global_name} = #{new_value}\n"
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# constant assignment/creation
|
59
|
+
def handle_cdecl( container, const_name, new_value)
|
60
|
+
print "assignment of #{container}::#{const_name} = #{new_value}\n"
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
h = Hook.new
|
66
|
+
h.evalhook('
|
67
|
+
$a = 4
|
68
|
+
A = 4', binding)
|
69
|
+
|
70
|
+
|
71
|
+
=== Basic Example 3
|
72
|
+
|
73
|
+
Redirect of method calls
|
74
|
+
|
75
|
+
require "rubygems"
|
76
|
+
require "evalhook"
|
77
|
+
|
78
|
+
class Hook < EvalHook::HookHandler
|
79
|
+
|
80
|
+
include RedirectHelper
|
81
|
+
|
82
|
+
def handle_method(klass, recv, method_name)
|
83
|
+
print "called #{klass}##{method_name} over #{recv}\n"
|
84
|
+
|
85
|
+
if method_name == :print
|
86
|
+
# change the method_name to alternative_print
|
87
|
+
Redirect.new(klass, recv, "alternative_print")
|
88
|
+
else
|
89
|
+
nil # do nothing
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
module Kernel
|
96
|
+
def alternative_print(*args)
|
97
|
+
print "alternative ", *args
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
h = Hook.new
|
102
|
+
h.evalhook('print "hello world\n"')
|
103
|
+
|
104
|
+
|
105
|
+
== Copying
|
106
|
+
|
107
|
+
Copyright (c) 2010 Dario Seminara, released under the GPL License (see LICENSE)
|
108
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = 'evalhook'
|
9
|
+
s.version = '0.1.0'
|
10
|
+
s.author = 'Dario Seminara'
|
11
|
+
s.email = 'robertodarioseminara@gmail.com'
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.summary = 'Alternate eval which hook all methods executed in the evaluated code'
|
14
|
+
s.homepage = "http://github.com/tario/evalhook"
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.extra_rdoc_files = [ 'README' ]
|
17
|
+
s.rdoc_options << '--main' << 'README'
|
18
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
19
|
+
s.files = Dir.glob("{examples,lib,test}/**/*.rb") + Dir.glob("ext/**/*.c") + Dir.glob("ext/**/*.h") + Dir.glob("ext/**/extconf.rb") +
|
20
|
+
[ 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Run tests'
|
24
|
+
task :default => [ :test ]
|
25
|
+
|
26
|
+
Rake::TestTask.new('test') do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = '{test}/**/test_*.rb'
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Generate RDoc'
|
33
|
+
Rake::RDocTask.new :rdoc do |rd|
|
34
|
+
rd.rdoc_dir = 'doc'
|
35
|
+
rd.rdoc_files.add 'lib', 'ext', 'README'
|
36
|
+
rd.main = 'README'
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Build Gem'
|
40
|
+
Rake::GemPackageTask.new spec do |pkg|
|
41
|
+
pkg.need_tar = true
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'Clean up'
|
45
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
46
|
+
|
47
|
+
desc 'Clean up'
|
48
|
+
task :clobber => [ :clean ]
|
data/TODO
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "evalhook"
|
3
|
+
|
4
|
+
class Hook < EvalHook::HookHandler
|
5
|
+
# global variable assignment/creation
|
6
|
+
def handle_gasgn( global_name, new_value)
|
7
|
+
print "assignment of #{global_name} = #{new_value}\n"
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
|
11
|
+
# constant assignment/creation
|
12
|
+
def handle_cdecl( container, const_name, new_value)
|
13
|
+
print "assignment of #{container}::#{const_name} = #{new_value}\n"
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
h = Hook.new
|
19
|
+
h.evalhook('
|
20
|
+
$a = 4
|
21
|
+
A = 4', binding)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "evalhook"
|
3
|
+
|
4
|
+
class Hook < EvalHook::HookHandler
|
5
|
+
|
6
|
+
include RedirectHelper
|
7
|
+
|
8
|
+
def handle_method(klass, recv, method_name)
|
9
|
+
print "called #{klass}##{method_name} over #{recv}\n"
|
10
|
+
|
11
|
+
if method_name == :print
|
12
|
+
# change the method_name to alternative_print
|
13
|
+
Redirect.new(klass, recv, "alternative_print")
|
14
|
+
else
|
15
|
+
nil # do nothing
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Kernel
|
22
|
+
def alternative_print(*args)
|
23
|
+
print "alternative ", *args
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
h = Hook.new
|
28
|
+
h.evalhook('print "hello world\n"')
|
@@ -0,0 +1,679 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the evalhook project, http://github.com/tario/evalhook
|
4
|
+
|
5
|
+
Copyright (c) 2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
evalhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
evalhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with evalhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <ruby.h>
|
23
|
+
#include <env.h>
|
24
|
+
#include <node.h>
|
25
|
+
|
26
|
+
VALUE m_EvalHook ;
|
27
|
+
VALUE c_HookHandler;
|
28
|
+
|
29
|
+
#define nd_3rd u3.node
|
30
|
+
|
31
|
+
ID method_call;
|
32
|
+
ID method_hooked_method;
|
33
|
+
ID method_local_hooked_method;
|
34
|
+
ID method_private_hooked_method;
|
35
|
+
ID method_public_hooked_method;
|
36
|
+
ID method_protected_hooked_method;
|
37
|
+
ID method_public, method_private, method_protected;
|
38
|
+
|
39
|
+
ID method_set_hook_handler;
|
40
|
+
|
41
|
+
struct BLOCK {
|
42
|
+
NODE *var;
|
43
|
+
NODE *body;
|
44
|
+
VALUE self;
|
45
|
+
struct FRAME frame;
|
46
|
+
struct SCOPE *scope;
|
47
|
+
VALUE klass;
|
48
|
+
NODE *cref;
|
49
|
+
int iter;
|
50
|
+
int vmode;
|
51
|
+
int flags;
|
52
|
+
int uniq;
|
53
|
+
struct RVarmap *dyna_vars;
|
54
|
+
VALUE orig_thread;
|
55
|
+
VALUE wrapper;
|
56
|
+
VALUE block_obj;
|
57
|
+
struct BLOCK *outer;
|
58
|
+
struct BLOCK *prev;
|
59
|
+
};
|
60
|
+
|
61
|
+
struct METHOD {
|
62
|
+
VALUE klass, rklass;
|
63
|
+
VALUE recv;
|
64
|
+
ID id, oid;
|
65
|
+
int safe_level;
|
66
|
+
NODE *body;
|
67
|
+
};
|
68
|
+
|
69
|
+
|
70
|
+
void process_node(NODE* node, VALUE handler);
|
71
|
+
|
72
|
+
void patch_local_call_node(NODE* node, VALUE handler) {
|
73
|
+
NODE* args1 = NEW_LIST(NEW_LIT(ID2SYM(node->nd_mid)));
|
74
|
+
NODE* args2 = NEW_LIST(NEW_LIT(handler));
|
75
|
+
|
76
|
+
node->nd_recv = NEW_CALL(NEW_SELF(), method_local_hooked_method, args1);
|
77
|
+
node->nd_recv = NEW_CALL(node->nd_recv, method_set_hook_handler, args2);
|
78
|
+
node->nd_mid = method_call;
|
79
|
+
|
80
|
+
nd_set_type(node, NODE_CALL);
|
81
|
+
}
|
82
|
+
|
83
|
+
void patch_call_node(NODE* node, VALUE handler) {
|
84
|
+
NODE* args1 = NEW_LIST(NEW_LIT(ID2SYM(node->nd_mid)));
|
85
|
+
NODE* args2 = NEW_LIST(NEW_LIT(handler));
|
86
|
+
|
87
|
+
node->nd_recv = NEW_CALL(node->nd_recv, method_hooked_method, args1);
|
88
|
+
node->nd_recv = NEW_CALL(node->nd_recv, method_set_hook_handler, args2);
|
89
|
+
|
90
|
+
node->nd_mid = method_call;
|
91
|
+
}
|
92
|
+
|
93
|
+
struct global_entry {
|
94
|
+
struct global_variable *var;
|
95
|
+
ID id;
|
96
|
+
};
|
97
|
+
|
98
|
+
void process_individual_node(NODE* node, VALUE handler) {
|
99
|
+
ID id = node->nd_mid;
|
100
|
+
|
101
|
+
switch (nd_type(node)) {
|
102
|
+
case NODE_COLON3: {
|
103
|
+
rb_raise(rb_eSecurityError, "Forbidden node type colon3 (reference to global namespace)");
|
104
|
+
}
|
105
|
+
/* case NODE_LASGN:
|
106
|
+
case NODE_IASGN:
|
107
|
+
case NODE_DASGN:
|
108
|
+
case NODE_CVASGN:
|
109
|
+
case NODE_CVDECL:*/
|
110
|
+
case NODE_GASGN: {
|
111
|
+
NODE* args1 = NEW_LIST(NEW_LIT(ID2SYM(node->nd_entry->id)));
|
112
|
+
NODE* args2 = NEW_LIST(node->nd_value);
|
113
|
+
|
114
|
+
node->nd_recv = NEW_CALL(NEW_LIT(handler), rb_intern("hooked_gasgn"), args1);
|
115
|
+
node->nd_mid = rb_intern("set_value");
|
116
|
+
node->nd_args = args2;
|
117
|
+
|
118
|
+
nd_set_type(node, NODE_CALL);
|
119
|
+
break;
|
120
|
+
}
|
121
|
+
case NODE_CDECL: {
|
122
|
+
|
123
|
+
NODE* else_node = node->nd_else;
|
124
|
+
NODE* head_node = node->nd_head;
|
125
|
+
NODE* base_class;
|
126
|
+
|
127
|
+
ID vid;
|
128
|
+
|
129
|
+
if (node->nd_vid == 0) {
|
130
|
+
base_class = else_node;
|
131
|
+
vid = node->nd_else->nd_mid;
|
132
|
+
} else {
|
133
|
+
base_class = NEW_LIT( (ruby_cref->nd_clss));
|
134
|
+
vid = node->nd_vid;
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
NODE* args1 = NEW_LIST(base_class);
|
139
|
+
NODE* args2 = NEW_LIST(NEW_LIT(ID2SYM(vid)));
|
140
|
+
NODE* args3 = NEW_LIST(node->nd_value);
|
141
|
+
|
142
|
+
node->nd_recv = NEW_CALL(NEW_LIT(handler), rb_intern("hooked_cdecl"), args1);
|
143
|
+
node->nd_recv = NEW_CALL(node->nd_recv, rb_intern("set_id"), args2);
|
144
|
+
node->nd_mid = rb_intern("set_value");
|
145
|
+
node->nd_args = args3;
|
146
|
+
|
147
|
+
nd_set_type(node, NODE_CALL);
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
|
151
|
+
|
152
|
+
case NODE_SUPER:
|
153
|
+
case NODE_ZSUPER: {
|
154
|
+
node->nd_mid = rb_intern("hooked_super");
|
155
|
+
node->nd_recv = NEW_LIT(handler);
|
156
|
+
nd_set_type(node, NODE_CALL);
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
case NODE_FCALL: {
|
160
|
+
if (id == method_public) break;
|
161
|
+
if (id == method_private) break;
|
162
|
+
if (id == method_protected) break;
|
163
|
+
|
164
|
+
patch_local_call_node(node, handler);
|
165
|
+
break;
|
166
|
+
}
|
167
|
+
|
168
|
+
case NODE_CALL: {
|
169
|
+
patch_call_node(node, handler);
|
170
|
+
break;
|
171
|
+
|
172
|
+
}
|
173
|
+
case NODE_VCALL: {
|
174
|
+
if (id == method_public) break;
|
175
|
+
if (id == method_private) break;
|
176
|
+
if (id == method_protected) break;
|
177
|
+
|
178
|
+
patch_local_call_node(node, handler);
|
179
|
+
|
180
|
+
break;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
void process_recursive_node(NODE* node, VALUE handler ) {
|
186
|
+
|
187
|
+
switch (nd_type(node)) {
|
188
|
+
|
189
|
+
case NODE_BLOCK:
|
190
|
+
{
|
191
|
+
while (node) {
|
192
|
+
process_node(node->nd_head, handler);
|
193
|
+
node = node->nd_next;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
break;
|
197
|
+
|
198
|
+
case NODE_FBODY:
|
199
|
+
case NODE_DEFINED:
|
200
|
+
case NODE_COLON2:
|
201
|
+
process_node(node->nd_head, handler);
|
202
|
+
break;
|
203
|
+
|
204
|
+
case NODE_MATCH2:
|
205
|
+
case NODE_MATCH3:
|
206
|
+
process_node(node->nd_recv, handler);
|
207
|
+
process_node(node->nd_value, handler);
|
208
|
+
break;
|
209
|
+
|
210
|
+
case NODE_BEGIN:
|
211
|
+
case NODE_OPT_N:
|
212
|
+
case NODE_NOT:
|
213
|
+
process_node(node->nd_body, handler);
|
214
|
+
break;
|
215
|
+
|
216
|
+
case NODE_IF:
|
217
|
+
process_node(node->nd_cond, handler);
|
218
|
+
if (node->nd_body) {
|
219
|
+
process_node(node->nd_body, handler);
|
220
|
+
}
|
221
|
+
if (node->nd_else) {
|
222
|
+
process_node(node->nd_else, handler);
|
223
|
+
}
|
224
|
+
break;
|
225
|
+
|
226
|
+
case NODE_CASE:
|
227
|
+
if (node->nd_head != NULL) {
|
228
|
+
process_node(node->nd_head, handler);
|
229
|
+
}
|
230
|
+
node = node->nd_body;
|
231
|
+
while (node) {
|
232
|
+
process_node(node, handler);
|
233
|
+
if (nd_type(node) == NODE_WHEN) { /* when */
|
234
|
+
node = node->nd_next;
|
235
|
+
} else {
|
236
|
+
break; /* else */
|
237
|
+
}
|
238
|
+
}
|
239
|
+
break;
|
240
|
+
|
241
|
+
case NODE_WHEN:
|
242
|
+
process_node(node->nd_head, handler);
|
243
|
+
if (node->nd_body) {
|
244
|
+
process_node(node->nd_body, handler);
|
245
|
+
}
|
246
|
+
break;
|
247
|
+
|
248
|
+
case NODE_WHILE:
|
249
|
+
case NODE_UNTIL:
|
250
|
+
process_node(node->nd_cond, handler);
|
251
|
+
if (node->nd_body) {
|
252
|
+
process_node(node->nd_body, handler);
|
253
|
+
}
|
254
|
+
break;
|
255
|
+
|
256
|
+
case NODE_BLOCK_PASS:
|
257
|
+
process_node(node->nd_body, handler);
|
258
|
+
process_node(node->nd_iter, handler);
|
259
|
+
break;
|
260
|
+
|
261
|
+
case NODE_ITER:
|
262
|
+
case NODE_FOR:
|
263
|
+
process_node(node->nd_iter, handler);
|
264
|
+
if (node->nd_var != (NODE *)1
|
265
|
+
&& node->nd_var != (NODE *)2
|
266
|
+
&& node->nd_var != NULL) {
|
267
|
+
process_node(node->nd_var, handler);
|
268
|
+
}
|
269
|
+
process_node(node->nd_body, handler);
|
270
|
+
break;
|
271
|
+
|
272
|
+
case NODE_BREAK:
|
273
|
+
case NODE_NEXT:
|
274
|
+
if (node->nd_stts)
|
275
|
+
process_node(node->nd_stts, handler);
|
276
|
+
|
277
|
+
break;
|
278
|
+
|
279
|
+
case NODE_YIELD:
|
280
|
+
if (node->nd_stts)
|
281
|
+
process_node(node->nd_stts, handler);
|
282
|
+
|
283
|
+
break;
|
284
|
+
|
285
|
+
case NODE_RESCUE:
|
286
|
+
process_node(node->nd_1st, handler);
|
287
|
+
process_node(node->nd_2nd, handler);
|
288
|
+
process_node(node->nd_3rd, handler);
|
289
|
+
break;
|
290
|
+
|
291
|
+
/*
|
292
|
+
// rescue body:
|
293
|
+
// begin stmt rescue exception => var; stmt; [rescue e2 => v2; s2;]* end
|
294
|
+
// stmt rescue stmt
|
295
|
+
// a = b rescue c
|
296
|
+
*/
|
297
|
+
|
298
|
+
case NODE_RESBODY:
|
299
|
+
if (node->nd_3rd) {
|
300
|
+
process_node(node->nd_3rd, handler);
|
301
|
+
}
|
302
|
+
process_node(node->nd_2nd, handler);
|
303
|
+
process_node(node->nd_1st, handler);
|
304
|
+
break;
|
305
|
+
|
306
|
+
case NODE_ENSURE:
|
307
|
+
process_node(node->nd_head, handler);
|
308
|
+
if (node->nd_ensr) {
|
309
|
+
process_node(node->nd_ensr, handler);
|
310
|
+
}
|
311
|
+
break;
|
312
|
+
|
313
|
+
case NODE_AND:
|
314
|
+
case NODE_OR:
|
315
|
+
process_node(node->nd_1st, handler);
|
316
|
+
process_node(node->nd_2nd, handler);
|
317
|
+
break;
|
318
|
+
|
319
|
+
case NODE_FLIP2:
|
320
|
+
case NODE_FLIP3:
|
321
|
+
process_node(node->nd_beg, handler);
|
322
|
+
process_node(node->nd_end, handler);
|
323
|
+
break;
|
324
|
+
|
325
|
+
case NODE_DOT2:
|
326
|
+
case NODE_DOT3:
|
327
|
+
process_node(node->nd_beg, handler);
|
328
|
+
process_node(node->nd_end, handler);
|
329
|
+
break;
|
330
|
+
|
331
|
+
case NODE_RETURN:
|
332
|
+
if (node->nd_stts)
|
333
|
+
process_node(node->nd_stts, handler);
|
334
|
+
break;
|
335
|
+
|
336
|
+
case NODE_ARGSCAT:
|
337
|
+
case NODE_ARGSPUSH:
|
338
|
+
process_node(node->nd_head, handler);
|
339
|
+
process_node(node->nd_body, handler);
|
340
|
+
break;
|
341
|
+
|
342
|
+
case NODE_CALL:
|
343
|
+
case NODE_FCALL:
|
344
|
+
case NODE_VCALL:
|
345
|
+
if (nd_type(node) != NODE_FCALL) {
|
346
|
+
if (node->nd_recv) process_node(node->nd_recv, handler);
|
347
|
+
}
|
348
|
+
if (node->nd_args || nd_type(node) != NODE_FCALL) {
|
349
|
+
if (node->nd_args) process_node(node->nd_args, handler);
|
350
|
+
}
|
351
|
+
break;
|
352
|
+
|
353
|
+
case NODE_SUPER:
|
354
|
+
process_node(node->nd_args, handler);
|
355
|
+
break;
|
356
|
+
|
357
|
+
case NODE_BMETHOD:
|
358
|
+
{
|
359
|
+
struct BLOCK *data;
|
360
|
+
Data_Get_Struct(node->nd_cval, struct BLOCK, data);
|
361
|
+
|
362
|
+
if (data->var == 0 || data->var == (NODE *)1 || data->var == (NODE *)2) {
|
363
|
+
} else {
|
364
|
+
process_node(data->var, handler);
|
365
|
+
}
|
366
|
+
process_node(data->body, handler);
|
367
|
+
}
|
368
|
+
break;
|
369
|
+
|
370
|
+
#if RUBY_VERSION_CODE < 190
|
371
|
+
case NODE_DMETHOD:
|
372
|
+
{
|
373
|
+
struct METHOD *data;
|
374
|
+
Data_Get_Struct(node->nd_cval, struct METHOD, data);
|
375
|
+
process_node(data->body, handler);
|
376
|
+
|
377
|
+
break;
|
378
|
+
}
|
379
|
+
#endif
|
380
|
+
|
381
|
+
case NODE_METHOD:
|
382
|
+
// You should not ever get here. parse_tree_for_meth passes nd_body
|
383
|
+
process_node(node->nd_body, handler);
|
384
|
+
break;
|
385
|
+
|
386
|
+
case NODE_SCOPE:
|
387
|
+
process_node(node->nd_next, handler);
|
388
|
+
break;
|
389
|
+
|
390
|
+
case NODE_OP_ASGN1:
|
391
|
+
process_node(node->nd_recv, handler);
|
392
|
+
#if RUBY_VERSION_CODE < 185
|
393
|
+
process_node(node->nd_args->nd_next, handler);
|
394
|
+
#else
|
395
|
+
process_node(node->nd_args->nd_2nd, handler);
|
396
|
+
#endif
|
397
|
+
process_node(node->nd_args->nd_head, handler);
|
398
|
+
break;
|
399
|
+
|
400
|
+
case NODE_OP_ASGN2:
|
401
|
+
process_node(node->nd_recv, handler);
|
402
|
+
process_node(node->nd_value, handler);
|
403
|
+
break;
|
404
|
+
|
405
|
+
case NODE_OP_ASGN_AND:
|
406
|
+
case NODE_OP_ASGN_OR:
|
407
|
+
process_node(node->nd_head, handler);
|
408
|
+
process_node(node->nd_value, handler);
|
409
|
+
break;
|
410
|
+
|
411
|
+
case NODE_MASGN:
|
412
|
+
if (node->nd_head) {
|
413
|
+
process_node(node->nd_head, handler);
|
414
|
+
}
|
415
|
+
if (node->nd_args) {
|
416
|
+
if (node->nd_args != (NODE *)-1) {
|
417
|
+
process_node(node->nd_args, handler);
|
418
|
+
}
|
419
|
+
}
|
420
|
+
if (node->nd_value) {
|
421
|
+
process_node(node->nd_value, handler);
|
422
|
+
}
|
423
|
+
break;
|
424
|
+
|
425
|
+
case NODE_LASGN:
|
426
|
+
case NODE_IASGN:
|
427
|
+
case NODE_DASGN:
|
428
|
+
case NODE_CVASGN:
|
429
|
+
case NODE_CVDECL:
|
430
|
+
case NODE_GASGN:
|
431
|
+
process_node(node->nd_value, handler);
|
432
|
+
break;
|
433
|
+
|
434
|
+
case NODE_CDECL:
|
435
|
+
if (node->nd_vid) {
|
436
|
+
} else {
|
437
|
+
process_node(node->nd_else, handler);
|
438
|
+
}
|
439
|
+
process_node(node->nd_value, handler);
|
440
|
+
break;
|
441
|
+
|
442
|
+
case NODE_DASGN_CURR:
|
443
|
+
if (node->nd_value) {
|
444
|
+
process_node(node->nd_value, handler);
|
445
|
+
}
|
446
|
+
break;
|
447
|
+
|
448
|
+
case NODE_ALIAS: /* u1 u2 (alias :blah :blah2) */
|
449
|
+
#if RUBY_VERSION_CODE < 185
|
450
|
+
#else
|
451
|
+
process_node(node->nd_1st, handler);
|
452
|
+
process_node(node->nd_2nd, handler);
|
453
|
+
#endif
|
454
|
+
break;
|
455
|
+
|
456
|
+
case NODE_UNDEF: /* u2 (undef name, ...) */
|
457
|
+
#if RUBY_VERSION_CODE < 185
|
458
|
+
#else
|
459
|
+
process_node(node->nd_value, handler);
|
460
|
+
#endif
|
461
|
+
break;
|
462
|
+
|
463
|
+
case NODE_HASH:
|
464
|
+
{
|
465
|
+
NODE *list;
|
466
|
+
|
467
|
+
list = node->nd_head;
|
468
|
+
while (list) {
|
469
|
+
process_node(list->nd_head, handler);
|
470
|
+
list = list->nd_next;
|
471
|
+
}
|
472
|
+
}
|
473
|
+
break;
|
474
|
+
|
475
|
+
case NODE_ARRAY:
|
476
|
+
while (node) {
|
477
|
+
process_node(node->nd_head, handler);
|
478
|
+
node = node->nd_next;
|
479
|
+
}
|
480
|
+
break;
|
481
|
+
|
482
|
+
case NODE_DSTR:
|
483
|
+
case NODE_DSYM:
|
484
|
+
case NODE_DXSTR:
|
485
|
+
case NODE_DREGX:
|
486
|
+
case NODE_DREGX_ONCE:
|
487
|
+
{
|
488
|
+
NODE *list = node->nd_next;
|
489
|
+
while (list) {
|
490
|
+
if (list->nd_head) {
|
491
|
+
process_node(list->nd_head, handler);
|
492
|
+
}
|
493
|
+
list = list->nd_next;
|
494
|
+
}
|
495
|
+
}
|
496
|
+
break;
|
497
|
+
|
498
|
+
case NODE_DEFN:
|
499
|
+
case NODE_DEFS:
|
500
|
+
if (node->nd_defn) {
|
501
|
+
if (nd_type(node) == NODE_DEFS)
|
502
|
+
process_node(node->nd_recv, handler);
|
503
|
+
|
504
|
+
process_node(node->nd_defn, handler);
|
505
|
+
}
|
506
|
+
break;
|
507
|
+
|
508
|
+
case NODE_CLASS:
|
509
|
+
case NODE_MODULE:
|
510
|
+
if (nd_type(node->nd_cpath) == NODE_COLON2 && ! node->nd_cpath->nd_vid) {
|
511
|
+
} else {
|
512
|
+
process_node(node->nd_cpath, handler);
|
513
|
+
}
|
514
|
+
|
515
|
+
if (nd_type(node) == NODE_CLASS) {
|
516
|
+
if (node->nd_super) {
|
517
|
+
process_node(node->nd_super, handler);
|
518
|
+
}
|
519
|
+
}
|
520
|
+
process_node(node->nd_body, handler);
|
521
|
+
break;
|
522
|
+
|
523
|
+
case NODE_SCLASS:
|
524
|
+
process_node(node->nd_recv, handler);
|
525
|
+
process_node(node->nd_body, handler);
|
526
|
+
break;
|
527
|
+
|
528
|
+
case NODE_ARGS: {
|
529
|
+
NODE *optnode;
|
530
|
+
optnode = node->nd_opt;
|
531
|
+
if (optnode) {
|
532
|
+
process_node(node->nd_opt, handler);
|
533
|
+
}
|
534
|
+
} break;
|
535
|
+
|
536
|
+
case NODE_NEWLINE:
|
537
|
+
process_node(node->nd_next, handler);
|
538
|
+
break;
|
539
|
+
|
540
|
+
case NODE_SPLAT:
|
541
|
+
case NODE_TO_ARY:
|
542
|
+
case NODE_SVALUE: /* a = b, c */
|
543
|
+
process_node(node->nd_head, handler);
|
544
|
+
break;
|
545
|
+
|
546
|
+
case NODE_ATTRASGN: /* literal.meth = y u1 u2 u3 */
|
547
|
+
/* node id node */
|
548
|
+
if (node->nd_1st == RNODE(1)) {
|
549
|
+
// add_to_parse_tree(self, current, NEW_SELF(), locals);
|
550
|
+
} else {
|
551
|
+
process_node(node->nd_1st, handler);
|
552
|
+
}
|
553
|
+
process_node(node->nd_3rd, handler);
|
554
|
+
break;
|
555
|
+
|
556
|
+
case NODE_EVSTR:
|
557
|
+
process_node(node->nd_2nd, handler);
|
558
|
+
break;
|
559
|
+
|
560
|
+
|
561
|
+
#if RUBY_VERSION_CODE >= 190
|
562
|
+
case NODE_ERRINFO:
|
563
|
+
case NODE_VALUES:
|
564
|
+
case NODE_PRELUDE:
|
565
|
+
case NODE_LAMBDA:
|
566
|
+
puts("no worky in 1.9 yet");
|
567
|
+
break;
|
568
|
+
#endif
|
569
|
+
|
570
|
+
/* Nodes we found but have yet to decypher */
|
571
|
+
/* I think these are all runtime only... not positive but... */
|
572
|
+
case NODE_MEMO: /* enum.c zip */
|
573
|
+
case NODE_CREF:
|
574
|
+
/* #defines: */
|
575
|
+
/* case NODE_LMASK: */
|
576
|
+
/* case NODE_LSHIFT: */
|
577
|
+
default:
|
578
|
+
break;
|
579
|
+
}
|
580
|
+
}
|
581
|
+
|
582
|
+
void process_node(NODE* node, VALUE handler) {
|
583
|
+
if (node) {
|
584
|
+
process_recursive_node(node, handler);
|
585
|
+
process_individual_node(node, handler);
|
586
|
+
}
|
587
|
+
}
|
588
|
+
|
589
|
+
VALUE hook_method_tree(VALUE self, VALUE rb_method) {
|
590
|
+
|
591
|
+
struct METHOD* method;
|
592
|
+
Data_Get_Struct(rb_method,struct METHOD,method);
|
593
|
+
|
594
|
+
NODE* node = method->body->nd_defn;
|
595
|
+
process_node(node, self);
|
596
|
+
|
597
|
+
return Qnil;
|
598
|
+
}
|
599
|
+
|
600
|
+
|
601
|
+
VALUE hook_block(VALUE self, VALUE handler) {
|
602
|
+
process_node(ruby_frame->node->nd_recv, handler);
|
603
|
+
}
|
604
|
+
|
605
|
+
VALUE caller_method(VALUE self, VALUE rblevel) {
|
606
|
+
int level = FIX2INT(rblevel);
|
607
|
+
|
608
|
+
struct FRAME* frame = ruby_frame;
|
609
|
+
while(level--) frame = frame->prev;
|
610
|
+
|
611
|
+
return ID2SYM(frame->orig_func);
|
612
|
+
}
|
613
|
+
|
614
|
+
VALUE caller_class(VALUE self, VALUE rblevel) {
|
615
|
+
int level = FIX2INT(rblevel);
|
616
|
+
|
617
|
+
struct FRAME* frame = ruby_frame;
|
618
|
+
while(level--) frame = frame->prev;
|
619
|
+
|
620
|
+
return frame->last_class;
|
621
|
+
}
|
622
|
+
|
623
|
+
VALUE caller_obj(VALUE self, VALUE rblevel) {
|
624
|
+
int level = FIX2INT(rblevel);
|
625
|
+
|
626
|
+
struct FRAME* frame = ruby_frame;
|
627
|
+
while(level--) frame = frame->prev;
|
628
|
+
|
629
|
+
return frame->self;
|
630
|
+
}
|
631
|
+
|
632
|
+
|
633
|
+
extern void Init_evalhook_base() {
|
634
|
+
m_EvalHook = rb_define_module("EvalHook");
|
635
|
+
|
636
|
+
/*
|
637
|
+
Class to create hook instances for specific handling of method calls and/or const and global assignment
|
638
|
+
|
639
|
+
=== Example:
|
640
|
+
|
641
|
+
Hook of method calls
|
642
|
+
|
643
|
+
require "rubygems"
|
644
|
+
require "evalhook"
|
645
|
+
|
646
|
+
class Hook < EvalHook::HookHandler
|
647
|
+
def handle_method(klass, recv, method_name)
|
648
|
+
print "called #{klass}##{method_name} over #{recv}\n"
|
649
|
+
nil
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
h = Hook.new
|
654
|
+
h.evalhook('print "hello world\n"')
|
655
|
+
|
656
|
+
|
657
|
+
|
658
|
+
|
659
|
+
See README for more examples
|
660
|
+
|
661
|
+
*/
|
662
|
+
c_HookHandler = rb_define_class_under(m_EvalHook, "HookHandler", rb_cObject);
|
663
|
+
|
664
|
+
rb_define_singleton_method(m_EvalHook, "hook_block", hook_block, 1);
|
665
|
+
|
666
|
+
rb_define_method(c_HookHandler, "hook_method_tree", hook_method_tree, 1);
|
667
|
+
|
668
|
+
rb_define_method(c_HookHandler, "caller_method", caller_method, 1);
|
669
|
+
rb_define_method(c_HookHandler, "caller_class", caller_class, 1);
|
670
|
+
rb_define_method(c_HookHandler, "caller_obj", caller_obj, 1);
|
671
|
+
|
672
|
+
method_local_hooked_method = rb_intern("local_hooked_method");
|
673
|
+
method_hooked_method = rb_intern("hooked_method");
|
674
|
+
method_call = rb_intern("call");
|
675
|
+
method_private = rb_intern("private");
|
676
|
+
method_public = rb_intern("public");
|
677
|
+
method_protected = rb_intern("protected");
|
678
|
+
method_set_hook_handler = rb_intern("set_hook_handler");
|
679
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the evalhook project, http://github.com/tario/evalhook
|
4
|
+
|
5
|
+
Copyright (c) 2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
evalhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
evalhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with evalhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
module RedirectHelper
|
22
|
+
module MethodRedirect
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
#Internal class used for return method redirection messages
|
27
|
+
#Example:
|
28
|
+
# ...
|
29
|
+
# class X
|
30
|
+
# def foo
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
# def handle_method
|
34
|
+
# return RedirectHelper::Redirect.new(X, X.new, :foo)
|
35
|
+
# end
|
36
|
+
|
37
|
+
class Redirect
|
38
|
+
include MethodRedirect
|
39
|
+
|
40
|
+
attr_reader :klass
|
41
|
+
attr_reader :recv
|
42
|
+
|
43
|
+
def method_name
|
44
|
+
@method
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(klass, recv, m, unhook = nil)
|
48
|
+
@klass = klass
|
49
|
+
@recv = recv
|
50
|
+
@method = m
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/evalhook.rb
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the evalhook project, http://github.com/tario/evalhook
|
4
|
+
|
5
|
+
Copyright (c) 2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
evalhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
evalhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with evalhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "evalhook"
|
22
|
+
require "evalhook_base"
|
23
|
+
require "evalhook/redirect_helper"
|
24
|
+
|
25
|
+
|
26
|
+
class Object
|
27
|
+
def local_hooked_method(mname)
|
28
|
+
EvalHook::HookedMethod.new(self,mname,true)
|
29
|
+
end
|
30
|
+
def hooked_method(mname)
|
31
|
+
EvalHook::HookedMethod.new(self,mname,false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module EvalHook
|
36
|
+
|
37
|
+
# used internally
|
38
|
+
class HookedMethod
|
39
|
+
|
40
|
+
def initialize(recv, m,localcall)
|
41
|
+
@recv = recv
|
42
|
+
@m = m
|
43
|
+
@localcall = localcall
|
44
|
+
end
|
45
|
+
|
46
|
+
# used internally
|
47
|
+
def set_hook_handler(method_handler)
|
48
|
+
@method_handler = method_handler
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
# used internally
|
53
|
+
def set_class(klass)
|
54
|
+
@klass = klass
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
# used internally
|
59
|
+
def call(*args)
|
60
|
+
method_handler = @method_handler
|
61
|
+
ret = nil
|
62
|
+
|
63
|
+
klass = @klass || @recv.method(@m).owner
|
64
|
+
method_name = @m
|
65
|
+
recv = @recv
|
66
|
+
|
67
|
+
if method_handler
|
68
|
+
ret = method_handler.handle_method(klass, recv, method_name )
|
69
|
+
end
|
70
|
+
|
71
|
+
if ret.kind_of? RedirectHelper::MethodRedirect
|
72
|
+
klass = ret.klass
|
73
|
+
method_name = ret.method_name
|
74
|
+
recv = ret.recv
|
75
|
+
end
|
76
|
+
|
77
|
+
if block_given?
|
78
|
+
klass.instance_method(method_name).bind(recv).call(*args) do |*x|
|
79
|
+
yield(*x)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
klass.instance_method(method_name).bind(recv).call(*args)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# used internally
|
88
|
+
class FakeEvalHook
|
89
|
+
def self.hook_block(*args)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class HookHandler
|
94
|
+
|
95
|
+
# used internally
|
96
|
+
class HookCdecl
|
97
|
+
def initialize(klass, hook_handler)
|
98
|
+
@klass = klass
|
99
|
+
@hook_handler = hook_handler
|
100
|
+
end
|
101
|
+
|
102
|
+
def set_id(const_id)
|
103
|
+
@const_id = const_id
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
def set_value(value)
|
108
|
+
klass = @klass
|
109
|
+
const_id = @const_id
|
110
|
+
|
111
|
+
ret = @hook_handler.handle_cdecl( @klass, @const_id, value )
|
112
|
+
|
113
|
+
if ret then
|
114
|
+
klass = ret.klass
|
115
|
+
const_id = ret.const_id
|
116
|
+
value = ret.value
|
117
|
+
end
|
118
|
+
|
119
|
+
klass.const_set(const_id, value)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# used internally
|
124
|
+
class HookGasgn
|
125
|
+
def initialize(global_id, hook_handler)
|
126
|
+
@global_id = global_id
|
127
|
+
@hook_handler = hook_handler
|
128
|
+
end
|
129
|
+
|
130
|
+
def set_value(value)
|
131
|
+
global_id = @global_id
|
132
|
+
|
133
|
+
ret = @hook_handler.handle_gasgn(@global_id, value)
|
134
|
+
|
135
|
+
if ret then
|
136
|
+
global_id = ret.global_id
|
137
|
+
value = ret.value
|
138
|
+
end
|
139
|
+
|
140
|
+
eval("#{global_id} = value")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# used internally
|
145
|
+
def hooked_cdecl(context)
|
146
|
+
HookCdecl.new(context,self)
|
147
|
+
end
|
148
|
+
|
149
|
+
# used internally
|
150
|
+
def hooked_gasgn(global_id)
|
151
|
+
HookGasgn.new(global_id,self)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Overwrite to handle the assignment/creation of global variables. By default do nothing but assign the variable. See examples
|
155
|
+
def handle_gasgn(*args)
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
|
159
|
+
# Overwrite to handle the assignment/creation of constants. By default do nothing but assign the variable. See examples
|
160
|
+
def handle_cdecl(*args)
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
# Overwrite to handle the method calls. By default do nothing and the methods are called normally
|
165
|
+
def handle_method(klass,recv,method_name)
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
|
169
|
+
def hooked_super(*args)
|
170
|
+
hm = caller_obj(2).hooked_method(caller_method(2))
|
171
|
+
hm.set_class(caller_class(2).superclass)
|
172
|
+
hm.set_hook_handler(self)
|
173
|
+
|
174
|
+
if block_given?
|
175
|
+
hm.call(*args) do |*x|
|
176
|
+
yield(*x)
|
177
|
+
end
|
178
|
+
else
|
179
|
+
hm.call(*args)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def evalhook(*args)
|
184
|
+
|
185
|
+
EvalHook.method_handler = self
|
186
|
+
|
187
|
+
args[0] = "
|
188
|
+
retvalue = nil
|
189
|
+
EvalHook.double_run do |run|
|
190
|
+
( if (run)
|
191
|
+
retvalue = begin
|
192
|
+
#{args[0]}
|
193
|
+
end
|
194
|
+
EvalHook::FakeEvalHook
|
195
|
+
else
|
196
|
+
EvalHook
|
197
|
+
end ).hook_block(ObjectSpace._id2ref(#{object_id}))
|
198
|
+
end
|
199
|
+
retvalue
|
200
|
+
"
|
201
|
+
eval(*args)
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
module ModuleMethods
|
207
|
+
|
208
|
+
attr_accessor :method_handler
|
209
|
+
|
210
|
+
def double_run
|
211
|
+
yield(false)
|
212
|
+
yield(true)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
class << self
|
217
|
+
include ModuleMethods
|
218
|
+
end
|
219
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evalhook
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dario Seminara
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-30 00:00:00 -03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email: robertodarioseminara@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions:
|
27
|
+
- ext/evalhook_base/extconf.rb
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README
|
30
|
+
files:
|
31
|
+
- examples/example1.rb
|
32
|
+
- examples/example3.rb
|
33
|
+
- examples/example2.rb
|
34
|
+
- lib/evalhook/redirect_helper.rb
|
35
|
+
- lib/evalhook.rb
|
36
|
+
- ext/evalhook_base/evalhook_base.c
|
37
|
+
- ext/evalhook_base/extconf.rb
|
38
|
+
- AUTHORS
|
39
|
+
- CHANGELOG
|
40
|
+
- README
|
41
|
+
- Rakefile
|
42
|
+
- TODO
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/tario/evalhook
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --main
|
50
|
+
- README
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
hash: 3
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.7
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Alternate eval which hook all methods executed in the evaluated code
|
78
|
+
test_files: []
|
79
|
+
|