evalhook 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/Rakefile +4 -4
- data/lib/evalhook/redirect_helper.rb +15 -0
- data/lib/evalhook/tree_processor.rb +279 -0
- data/lib/evalhook.rb +50 -2
- data/spec/hook_handler/hook_handler_defaults_spec.rb +199 -18
- data/spec/hook_handler/hook_handler_hook_spec.rb +136 -0
- data/spec/hook_handler/hook_handler_visitor_spec.rb +57 -0
- metadata +9 -9
- data/lib/evalhook/hook_context.rb +0 -144
data/CHANGELOG
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
0.4.0 Removed evalmimic dependency
|
2
|
+
|
3
|
+
Implemented hooking of super as methods calls
|
4
|
+
|
5
|
+
Added hooking for colon2 namespace access (handle_colon2)
|
6
|
+
|
7
|
+
Added hooking for global variable read acess (handle_gvar)
|
8
|
+
|
9
|
+
Added hooking for constant read access (handle_const)
|
10
|
+
|
11
|
+
Refactor of AST processing code (using SexpProcessor)
|
12
|
+
|
1
13
|
0.3.1 Fixed bug when use reflection on call handler (thanks jembezmamy for the feedback!)
|
2
14
|
|
3
15
|
0.3.0 Refactor: removed C extension for hooking and use partialruby instead
|
data/Rakefile
CHANGED
@@ -6,18 +6,18 @@ require 'rake/gempackagetask'
|
|
6
6
|
|
7
7
|
spec = Gem::Specification.new do |s|
|
8
8
|
s.name = 'evalhook'
|
9
|
-
s.version = '0.
|
9
|
+
s.version = '0.4.0'
|
10
10
|
s.author = 'Dario Seminara'
|
11
11
|
s.email = 'robertodarioseminara@gmail.com'
|
12
12
|
s.platform = Gem::Platform::RUBY
|
13
13
|
s.summary = 'Alternate eval which hook all methods executed in the evaluated code'
|
14
14
|
s.homepage = "http://github.com/tario/evalhook"
|
15
|
-
s.add_dependency "partialruby", ">= 0.
|
15
|
+
s.add_dependency "partialruby", ">= 0.2.0"
|
16
16
|
s.add_dependency "ruby_parser", ">= 2.0.6"
|
17
17
|
s.has_rdoc = true
|
18
18
|
s.extra_rdoc_files = [ 'README' ]
|
19
19
|
s.rdoc_options << '--main' << 'README'
|
20
|
-
s.files = Dir.glob("{examples,lib,spec}/**/*.rb") +
|
20
|
+
s.files = Dir.glob("{examples,lib,spec}/**/*.rb") +
|
21
21
|
[ 'LICENSE', 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
|
22
22
|
end
|
23
23
|
|
@@ -33,7 +33,7 @@ end
|
|
33
33
|
desc 'Generate RDoc'
|
34
34
|
Rake::RDocTask.new :rdoc do |rd|
|
35
35
|
rd.rdoc_dir = 'doc'
|
36
|
-
rd.rdoc_files.add 'lib', '
|
36
|
+
rd.rdoc_files.add 'lib', 'README'
|
37
37
|
rd.main = 'README'
|
38
38
|
end
|
39
39
|
|
@@ -73,6 +73,21 @@ module RedirectHelper
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
class Value
|
77
|
+
attr_reader :value
|
78
|
+
def initialize(value)
|
79
|
+
@value = value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def global_value(value)
|
84
|
+
Value.new(value)
|
85
|
+
end
|
86
|
+
|
87
|
+
def const_value(value)
|
88
|
+
Value.new(value)
|
89
|
+
end
|
90
|
+
|
76
91
|
def redirect_method(*args)
|
77
92
|
Redirect.new(*args)
|
78
93
|
end
|
@@ -0,0 +1,279 @@
|
|
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 "ruby_parser"
|
22
|
+
require "partialruby"
|
23
|
+
require "sexp_processor"
|
24
|
+
|
25
|
+
module EvalHook
|
26
|
+
|
27
|
+
|
28
|
+
class TreeProcessor < SexpProcessor
|
29
|
+
def initialize(hook_handler)
|
30
|
+
super()
|
31
|
+
@hook_handler = hook_handler
|
32
|
+
@def_scope = Array.new
|
33
|
+
self.require_empty = false
|
34
|
+
end
|
35
|
+
|
36
|
+
def const_path_emul(code)
|
37
|
+
if code.instance_of? Array
|
38
|
+
if (code.size == 1)
|
39
|
+
s(:const, code[-1].to_sym)
|
40
|
+
else
|
41
|
+
s(:colon2, const_path_emul(code[0..-2]), code[-1].to_sym)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
const_path_emul code.split("::")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def hook_handler_reference
|
49
|
+
# create a global_variable name
|
50
|
+
unless @hh_ref_global_name
|
51
|
+
global_variable_name = "$hook_handler_" + rand(10000000000).to_s
|
52
|
+
eval("#{global_variable_name} = @hook_handler")
|
53
|
+
|
54
|
+
@hh_ref_global_name = global_variable_name.to_sym
|
55
|
+
end
|
56
|
+
|
57
|
+
s(:gvar, @hh_ref_global_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def process_gasgn(tree)
|
61
|
+
|
62
|
+
args1 = s(:arglist, s(:lit, tree[1]))
|
63
|
+
args2 = s(:arglist, process(tree[2]))
|
64
|
+
|
65
|
+
firstcall = s(:call, hook_handler_reference, :hooked_gasgn, args1)
|
66
|
+
|
67
|
+
s(:call, firstcall, :set_value, args2)
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def process_call(tree)
|
73
|
+
|
74
|
+
original_receiver = tree[1]
|
75
|
+
|
76
|
+
receiver = process(original_receiver|| s(:self))
|
77
|
+
|
78
|
+
args1 = s(:arglist, s(:lit, tree[2]), s(:call, nil, :binding, s(:arglist)))
|
79
|
+
args2 = s(:arglist, hook_handler_reference)
|
80
|
+
|
81
|
+
firstcall = nil
|
82
|
+
secondcall = nil
|
83
|
+
|
84
|
+
if original_receiver
|
85
|
+
firstcall = s(:call, receiver, :local_hooked_method, args1)
|
86
|
+
secondcall = s(:call, firstcall, :set_hook_handler, args2)
|
87
|
+
else
|
88
|
+
firstcall = s(:call, receiver, :hooked_method, args1)
|
89
|
+
secondcall = s(:call, firstcall, :set_hook_handler, args2)
|
90
|
+
end
|
91
|
+
|
92
|
+
s(:call, secondcall, :call, process(tree[3]))
|
93
|
+
end
|
94
|
+
|
95
|
+
def process_cdecl(tree)
|
96
|
+
|
97
|
+
const_tree = tree[1]
|
98
|
+
value_tree = tree[2]
|
99
|
+
|
100
|
+
base_class_tree = nil
|
101
|
+
const_id = nil
|
102
|
+
|
103
|
+
unless const_tree.instance_of? Symbol
|
104
|
+
if const_tree[0] == :colon2
|
105
|
+
base_class_tree = const_tree[1]
|
106
|
+
const_id = const_tree[2]
|
107
|
+
elsif const_tree[0] == :colon3
|
108
|
+
base_class_tree = s(:lit, Object)
|
109
|
+
const_id = const_tree[1]
|
110
|
+
end
|
111
|
+
else
|
112
|
+
base_class_tree = s(:lit, Object)
|
113
|
+
const_id = const_tree
|
114
|
+
end
|
115
|
+
|
116
|
+
args1 = s(:arglist, base_class_tree)
|
117
|
+
args2 = s(:arglist, s(:lit, const_id))
|
118
|
+
args3 = s(:arglist, process(value_tree))
|
119
|
+
|
120
|
+
firstcall = s(:call, hook_handler_reference, :hooked_cdecl, args1 )
|
121
|
+
secondcall = s(:call, firstcall, :set_id, args2)
|
122
|
+
|
123
|
+
s(:call, secondcall, :set_value, args3)
|
124
|
+
end
|
125
|
+
|
126
|
+
def process_dxstr(tree)
|
127
|
+
dstr_tree = tree.dup
|
128
|
+
dstr_tree[0] = :dstr
|
129
|
+
|
130
|
+
args = s(:arglist, process(dstr_tree) )
|
131
|
+
s(:call, hook_handler_reference, :hooked_xstr, args)
|
132
|
+
end
|
133
|
+
|
134
|
+
def process_xstr(tree)
|
135
|
+
args = s(:arglist, s(:lit, tree[1]) )
|
136
|
+
s(:call, hook_handler_reference, :hooked_xstr, args)
|
137
|
+
end
|
138
|
+
|
139
|
+
def process_module(tree)
|
140
|
+
module_name_tree = tree[1]
|
141
|
+
if module_name_tree.instance_of? Sexp
|
142
|
+
if module_name_tree.first == :colon3
|
143
|
+
module_name_tree = process_colon3(module_name_tree)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class_scope(nil) {
|
148
|
+
s(:module, module_name_tree, process(tree[2]))
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
def class_scope(class_name)
|
153
|
+
@def_scope.push(class_name)
|
154
|
+
ret = yield
|
155
|
+
@def_scope.pop
|
156
|
+
ret
|
157
|
+
end
|
158
|
+
|
159
|
+
def process_class(tree)
|
160
|
+
class_name_tree = tree[1]
|
161
|
+
if class_name_tree.instance_of? Sexp
|
162
|
+
if class_name_tree.first == :colon3
|
163
|
+
class_name_tree = process_colon3(class_name_tree)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
if tree[2]
|
168
|
+
class_scope(tree[1]) do
|
169
|
+
s(:class, class_name_tree, process(tree[2]), process(tree[3]))
|
170
|
+
end
|
171
|
+
else
|
172
|
+
class_scope(tree[1]) do
|
173
|
+
s(:class, class_name_tree, nil, process(tree[3]))
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def process_colon2(tree)
|
179
|
+
name = tree[2].to_s
|
180
|
+
args = s(:arglist, process(tree[1]), s(:str, name))
|
181
|
+
s(:call, hook_handler_reference, :hooked_colon2, args)
|
182
|
+
end
|
183
|
+
|
184
|
+
def process_colon3(tree)
|
185
|
+
if @hook_handler.base_namespace
|
186
|
+
s(:colon2, const_path_emul(@hook_handler.base_namespace.to_s), tree[1])
|
187
|
+
else
|
188
|
+
s(:colon3, tree[1])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def process_gvar(tree)
|
193
|
+
name = tree[1]
|
194
|
+
|
195
|
+
args = s(:arglist, s(:lit, name))
|
196
|
+
s(:call, hook_handler_reference, :hooked_gvar, args)
|
197
|
+
end
|
198
|
+
|
199
|
+
def process_const(tree)
|
200
|
+
name = tree[1].to_s
|
201
|
+
args = s(:arglist, s(:str, name))
|
202
|
+
s(:call, hook_handler_reference, :hooked_const, args)
|
203
|
+
end
|
204
|
+
|
205
|
+
def process_defn(tree)
|
206
|
+
@last_args = tree[2]
|
207
|
+
@last_method_name = tree[1]
|
208
|
+
|
209
|
+
s(tree[0],tree[1],tree[2],process(tree[3]))
|
210
|
+
end
|
211
|
+
|
212
|
+
def superclass_call_tree
|
213
|
+
current_class_call = nil
|
214
|
+
|
215
|
+
def_class = @def_scope.last
|
216
|
+
if def_class.instance_of? Symbol
|
217
|
+
current_class_call = s(:const, def_class)
|
218
|
+
s(:call, current_class_call, :superclass, s(:arglist))
|
219
|
+
elsif def_class.instance_of? Sexp
|
220
|
+
current_class_call = def_class
|
221
|
+
s(:call, current_class_call, :superclass, s(:arglist))
|
222
|
+
elsif def_class.instance_of? String
|
223
|
+
s(:call, s(:self), :class, s(:arglist))
|
224
|
+
else
|
225
|
+
current_class_call = s(:call, nil, :raise, s(:arglist, s(:const, :SecurityError)))
|
226
|
+
s(:call, current_class_call, :superclass, s(:arglist))
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def process_super(tree)
|
231
|
+
|
232
|
+
receiver = s(:self)
|
233
|
+
|
234
|
+
args1 = s(:arglist, s(:lit, @last_method_name), s(:call, nil, :binding, s(:arglist)))
|
235
|
+
args2 = s(:arglist, hook_handler_reference)
|
236
|
+
|
237
|
+
firstcall = s(:call, receiver, :local_hooked_method, args1)
|
238
|
+
secondcall = s(:call, firstcall, :set_hook_handler, args2)
|
239
|
+
thirdcall = s(:call,secondcall,:set_class,s(:arglist, superclass_call_tree))
|
240
|
+
|
241
|
+
# pass the args passed to super
|
242
|
+
s(:call, thirdcall, :call, s(:arglist, *tree[1..-1]))
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
def process_defs(tree)
|
247
|
+
block_tree = class_scope( "" ) {
|
248
|
+
process(tree[4])
|
249
|
+
}
|
250
|
+
s(:defs, process(tree[1]), tree[2], tree[3], block_tree)
|
251
|
+
end
|
252
|
+
|
253
|
+
def process_zsuper(tree)
|
254
|
+
|
255
|
+
receiver = s(:self)
|
256
|
+
|
257
|
+
args1 = s(:arglist, s(:lit, @last_method_name), s(:call, nil, :binding, s(:arglist)))
|
258
|
+
args2 = s(:arglist, hook_handler_reference)
|
259
|
+
|
260
|
+
firstcall = s(:call, receiver, :local_hooked_method, args1)
|
261
|
+
secondcall = s(:call, firstcall, :set_hook_handler, args2)
|
262
|
+
thirdcall = s(:call,secondcall,:set_class,s(:arglist, superclass_call_tree))
|
263
|
+
|
264
|
+
# pass the args of the current defn
|
265
|
+
|
266
|
+
args = s(:arglist)
|
267
|
+
@last_args[1..-1].each do |arg_sym|
|
268
|
+
if arg_sym.to_s[0] == "*"
|
269
|
+
args << s(:splat, s(:lvar, arg_sym.to_s[1..-1].to_sym))
|
270
|
+
else
|
271
|
+
args << s(:lvar, arg_sym)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
s(:call, thirdcall, :call, args)
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|
data/lib/evalhook.rb
CHANGED
@@ -22,7 +22,8 @@ require "partialruby"
|
|
22
22
|
require "evalhook/redirect_helper"
|
23
23
|
require "evalhook/multi_hook_handler"
|
24
24
|
require "evalhook/hook_handler"
|
25
|
-
require "evalhook/
|
25
|
+
require "evalhook/tree_processor"
|
26
|
+
|
26
27
|
begin
|
27
28
|
require "evalmimic"
|
28
29
|
$evalmimic_defined = true
|
@@ -182,6 +183,36 @@ module EvalHook
|
|
182
183
|
end
|
183
184
|
end
|
184
185
|
|
186
|
+
# used internally
|
187
|
+
def hooked_gvar(global_id)
|
188
|
+
ret = handle_gvar(global_id)
|
189
|
+
if ret
|
190
|
+
ret.value
|
191
|
+
else
|
192
|
+
eval(global_id.to_s)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# used internally
|
197
|
+
def hooked_const(name)
|
198
|
+
ret = handle_const(name)
|
199
|
+
if ret
|
200
|
+
ret.value
|
201
|
+
else
|
202
|
+
Object.const_get(name)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# used internally
|
207
|
+
def hooked_colon2(context,name)
|
208
|
+
ret = handle_colon2(context, name)
|
209
|
+
if ret
|
210
|
+
ret.value
|
211
|
+
else
|
212
|
+
context.const_get(name)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
185
216
|
# used internally
|
186
217
|
def hooked_cdecl(context)
|
187
218
|
HookCdecl.new(context,self)
|
@@ -217,6 +248,20 @@ module EvalHook
|
|
217
248
|
nil
|
218
249
|
end
|
219
250
|
|
251
|
+
# Overwrite to handle const read access
|
252
|
+
def handle_const(name)
|
253
|
+
nil
|
254
|
+
end
|
255
|
+
|
256
|
+
def handle_colon2(context,name)
|
257
|
+
nil
|
258
|
+
end
|
259
|
+
|
260
|
+
# Overwrite to handle global variable read access
|
261
|
+
def handle_gvar(global_id)
|
262
|
+
nil
|
263
|
+
end
|
264
|
+
|
220
265
|
# used internally
|
221
266
|
def hooked_super(*args)
|
222
267
|
hm = caller_obj(2).hooked_method(caller_method(2))
|
@@ -243,7 +288,10 @@ module EvalHook
|
|
243
288
|
|
244
289
|
tree = RubyParser.new.parse code
|
245
290
|
|
246
|
-
context =
|
291
|
+
context = PartialRuby::PureRubyContext.new
|
292
|
+
|
293
|
+
tree = EvalHook::TreeProcessor.new(self).process(tree)
|
294
|
+
|
247
295
|
emulationcode = context.emul tree
|
248
296
|
|
249
297
|
eval emulationcode, b_, name, line
|
@@ -23,7 +23,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
23
23
|
hook_handler = EvalHook::HookHandler.new
|
24
24
|
|
25
25
|
expected = eval(expr)
|
26
|
-
hook_handler.evalhook(expr).should be == expected
|
26
|
+
hook_handler.evalhook(expr, binding).should be == expected
|
27
27
|
|
28
28
|
end
|
29
29
|
end
|
@@ -32,14 +32,14 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
32
32
|
hook_handler = EvalHook::HookHandler.new
|
33
33
|
|
34
34
|
$global_variable_test = 5
|
35
|
-
hook_handler.evalhook("$global_variable_test").should be == $global_variable_test
|
35
|
+
hook_handler.evalhook("$global_variable_test", binding).should be == $global_variable_test
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should allow reference to constants" do
|
39
39
|
hook_handler = EvalHook::HookHandler.new
|
40
40
|
|
41
41
|
CONSTANTTEST = 5
|
42
|
-
hook_handler.evalhook("CONSTANTTEST").should be == CONSTANTTEST
|
42
|
+
hook_handler.evalhook("CONSTANTTEST", binding).should be == CONSTANTTEST
|
43
43
|
end
|
44
44
|
|
45
45
|
it "should allow reference to local variables" do
|
@@ -71,7 +71,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
71
71
|
|
72
72
|
it "should allow method calls" do
|
73
73
|
hook_handler = EvalHook::HookHandler.new
|
74
|
-
hook_handler.evalhook("X.new.foo").should be X.new.foo
|
74
|
+
hook_handler.evalhook("X.new.foo", binding).should be X.new.foo
|
75
75
|
end
|
76
76
|
|
77
77
|
it "should capture method calls" do
|
@@ -80,14 +80,14 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
80
80
|
hook_handler.should_receive(:handle_method).with(X.class,X,:new)
|
81
81
|
hook_handler.should_receive(:handle_method).with(X,anything(),:foo)
|
82
82
|
|
83
|
-
hook_handler.evalhook("X.new.foo")
|
83
|
+
hook_handler.evalhook("X.new.foo", binding)
|
84
84
|
end
|
85
85
|
|
86
86
|
it "should capture constant assignment" do
|
87
87
|
hook_handler = EvalHook::HookHandler.new
|
88
88
|
|
89
89
|
hook_handler.should_receive(:handle_cdecl).with(Object,:TEST_CONSTANT,4)
|
90
|
-
hook_handler.evalhook("TEST_CONSTANT = 4")
|
90
|
+
hook_handler.evalhook("TEST_CONSTANT = 4", binding)
|
91
91
|
|
92
92
|
end
|
93
93
|
|
@@ -95,7 +95,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
95
95
|
hook_handler = EvalHook::HookHandler.new
|
96
96
|
|
97
97
|
hook_handler.should_receive(:handle_gasgn).with(:$test_global_variable,4)
|
98
|
-
hook_handler.evalhook("$test_global_variable = 4")
|
98
|
+
hook_handler.evalhook("$test_global_variable = 4", binding)
|
99
99
|
|
100
100
|
end
|
101
101
|
|
@@ -103,7 +103,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
103
103
|
hook_handler = EvalHook::HookHandler.new
|
104
104
|
|
105
105
|
hook_handler.should_receive(:handle_xstr).with("echo test")
|
106
|
-
hook_handler.evalhook("`echo test`")
|
106
|
+
hook_handler.evalhook("`echo test`", binding)
|
107
107
|
|
108
108
|
end
|
109
109
|
|
@@ -111,7 +111,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
111
111
|
hook_handler = EvalHook::HookHandler.new
|
112
112
|
|
113
113
|
hook_handler.should_receive(:handle_xstr).with("echo test")
|
114
|
-
hook_handler.evalhook("`echo \#{}test`")
|
114
|
+
hook_handler.evalhook("`echo \#{}test`", binding)
|
115
115
|
|
116
116
|
end
|
117
117
|
|
@@ -119,7 +119,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
119
119
|
hook_handler = EvalHook::HookHandler.new
|
120
120
|
|
121
121
|
hook_handler.should_receive(:handle_xstr).with("echo test")
|
122
|
-
hook_handler.evalhook("%x[echo test]")
|
122
|
+
hook_handler.evalhook("%x[echo test]", binding)
|
123
123
|
end
|
124
124
|
|
125
125
|
|
@@ -139,14 +139,14 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
139
139
|
hook_handler = EvalHook::HookHandler.new
|
140
140
|
|
141
141
|
hook_handler.base_namespace = :A
|
142
|
-
hook_handler.evalhook("::B").should be == A::B
|
142
|
+
hook_handler.evalhook("::B", binding).should be == A::B
|
143
143
|
end
|
144
144
|
|
145
145
|
it "should allow define base_namespace (const)" do
|
146
146
|
hook_handler = EvalHook::HookHandler.new
|
147
147
|
|
148
148
|
hook_handler.base_namespace = A
|
149
|
-
hook_handler.evalhook("::B").should be == A::B
|
149
|
+
hook_handler.evalhook("::B", binding).should be == A::B
|
150
150
|
end
|
151
151
|
|
152
152
|
class C1
|
@@ -170,7 +170,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
170
170
|
def foo
|
171
171
|
'A1::C1#foo at evalhook'
|
172
172
|
end
|
173
|
-
end")
|
173
|
+
end" , binding)
|
174
174
|
|
175
175
|
C1.new.foo.should be == "C1#foo" # C1#foo class remains unchanged
|
176
176
|
A1::C1.new.foo.should be == "A1::C1#foo at evalhook" # A1::C1#foo changes
|
@@ -196,7 +196,7 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
196
196
|
end
|
197
197
|
|
198
198
|
end
|
199
|
-
")
|
199
|
+
", binding)
|
200
200
|
|
201
201
|
C2.new.foo.should be == "::C2#foo at evalhook"
|
202
202
|
end
|
@@ -216,15 +216,14 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
216
216
|
def foo
|
217
217
|
'A1::A2::C1#foo at evalhook'
|
218
218
|
end
|
219
|
-
end")
|
219
|
+
end", binding)
|
220
220
|
|
221
221
|
C1.new.foo.should be == "C1#foo" # C1#foo class remains unchanged
|
222
222
|
A1::A2::C1.new.foo.should be == "A1::A2::C1#foo at evalhook" # A1::C1#foo changes
|
223
223
|
end
|
224
224
|
|
225
|
-
it "should
|
226
|
-
|
227
|
-
EvalHook::HookHandler.new.evalhook("a").should be == 9
|
225
|
+
it "should allow declaring classes with ::" do
|
226
|
+
EvalHook::HookHandler.new.evalhook("class Fixnum::TestClass12345; end", binding)
|
228
227
|
end
|
229
228
|
|
230
229
|
module TestInheritedClassMethodError
|
@@ -243,5 +242,187 @@ describe EvalHook::HookHandler, "hook handler defaults" do
|
|
243
242
|
hh.evalhook('TestInheritedClassMethodError::B.foo', binding)
|
244
243
|
end
|
245
244
|
|
245
|
+
it "should allow declaring modules with ::" do
|
246
|
+
EvalHook::HookHandler.new.evalhook("module Fixnum::TestModule12345; end", binding)
|
247
|
+
end
|
248
|
+
|
249
|
+
module TestModule12347
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should allow assignment of constants nested on modules" do
|
253
|
+
EvalHook::HookHandler.new.evalhook("TestModule12347::A = 9", binding)
|
254
|
+
end
|
255
|
+
|
256
|
+
class XTEST44
|
257
|
+
def foo(a)
|
258
|
+
a+1
|
259
|
+
end
|
260
|
+
end
|
261
|
+
it "should pass arguments on super" do
|
262
|
+
EvalHook::HookHandler.new.evalhook('
|
263
|
+
class YTEST44 < XTEST44
|
264
|
+
def foo(a)
|
265
|
+
super
|
266
|
+
end
|
267
|
+
end
|
268
|
+
YTEST44.new.foo(9)
|
269
|
+
', binding).should be == 10
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should pass arguments on super (explicitly)" do
|
273
|
+
EvalHook::HookHandler.new.evalhook('
|
274
|
+
class YTEST45 < XTEST44
|
275
|
+
def foo(a)
|
276
|
+
super(a)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
YTEST45.new.foo(9)
|
280
|
+
', binding).should be == 10
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should pass arguments on super with three levels" do
|
284
|
+
EvalHook::HookHandler.new.evalhook('
|
285
|
+
class YTEST46 < XTEST44
|
286
|
+
def foo(a)
|
287
|
+
super(a)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
class ZTEST46 < YTEST46
|
292
|
+
def foo(a)
|
293
|
+
super(a)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
ZTEST46.new.foo(9)
|
297
|
+
', binding).should be == 10
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should raise SecurityError when use super outside a class" do
|
302
|
+
|
303
|
+
lambda {
|
304
|
+
|
305
|
+
EvalHook::HookHandler.new.evalhook('
|
306
|
+
module MODULETEST48
|
307
|
+
def foo(a)
|
308
|
+
super(a)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class XTEST48 < XTEST44
|
313
|
+
include MODULETEST48
|
314
|
+
end
|
315
|
+
XTEST48.new.foo(9)
|
316
|
+
', binding)
|
317
|
+
|
318
|
+
}.should raise_error(SecurityError)
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should raise SecurityError when use super inside a module nested on class" do
|
323
|
+
|
324
|
+
lambda {
|
325
|
+
|
326
|
+
EvalHook::HookHandler.new.evalhook('
|
327
|
+
|
328
|
+
class CLASSTEST49
|
329
|
+
module MODULETEST49
|
330
|
+
def foo(a)
|
331
|
+
super(a)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
class YTEST49 < XTEST44
|
337
|
+
include CLASSTEST49::MODULETEST49
|
338
|
+
end
|
339
|
+
YTEST49.new.foo(9)
|
340
|
+
', binding)
|
341
|
+
|
342
|
+
}.should raise_error(SecurityError)
|
343
|
+
|
344
|
+
end
|
345
|
+
|
346
|
+
it "should pass arguments on super with no arguments throught three levels" do
|
347
|
+
EvalHook::HookHandler.new.evalhook('
|
348
|
+
class YTEST50 < XTEST44
|
349
|
+
def foo(a)
|
350
|
+
super
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
class ZTEST50 < YTEST50
|
355
|
+
def foo(a)
|
356
|
+
super
|
357
|
+
end
|
358
|
+
end
|
359
|
+
ZTEST50.new.foo(9)
|
360
|
+
', binding).should be == 10
|
361
|
+
|
362
|
+
end
|
363
|
+
|
364
|
+
it "should raise SecurityError when use super with no arguments outside a class" do
|
365
|
+
|
366
|
+
lambda {
|
367
|
+
|
368
|
+
EvalHook::HookHandler.new.evalhook('
|
369
|
+
module MODULETEST51
|
370
|
+
def foo(a)
|
371
|
+
super
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
class XTEST51 < XTEST44
|
376
|
+
include MODULETEST51
|
377
|
+
end
|
378
|
+
XTEST51.new.foo(9)
|
379
|
+
', binding)
|
380
|
+
|
381
|
+
}.should raise_error(SecurityError)
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
it "should raise SecurityError when use super with no arguments inside a module nested on class" do
|
386
|
+
|
387
|
+
lambda {
|
388
|
+
|
389
|
+
EvalHook::HookHandler.new.evalhook('
|
390
|
+
|
391
|
+
class CLASSTEST52
|
392
|
+
module MODULETEST52
|
393
|
+
def foo(a)
|
394
|
+
super
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
class YTEST52 < XTEST44
|
400
|
+
include CLASSTEST52::MODULETEST52
|
401
|
+
end
|
402
|
+
YTEST52.new.foo(9)
|
403
|
+
', binding)
|
404
|
+
|
405
|
+
}.should raise_error(SecurityError)
|
406
|
+
|
407
|
+
end
|
408
|
+
|
409
|
+
it "should execute super call from singleton methods" do
|
410
|
+
EvalHook::HookHandler.new.evalhook('
|
411
|
+
|
412
|
+
class CLASSTEST53
|
413
|
+
def bar(a)
|
414
|
+
a+1
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
obj = CLASSTEST53.new
|
419
|
+
|
420
|
+
def obj.bar(a)
|
421
|
+
super(a+1)
|
422
|
+
end
|
423
|
+
obj.bar(10)
|
424
|
+
', binding).should be == 12
|
425
|
+
end
|
426
|
+
|
246
427
|
end
|
247
428
|
|
@@ -43,4 +43,140 @@ describe EvalHook::HookHandler, "hook handler hooks" do
|
|
43
43
|
TEST_CONSTANT.should be == 7
|
44
44
|
end
|
45
45
|
|
46
|
+
it "should intercept constant access" do
|
47
|
+
hh = EvalHook::HookHandler.new
|
48
|
+
def hh.handle_const(name)
|
49
|
+
const_value(77)
|
50
|
+
end
|
51
|
+
|
52
|
+
TEST_CONSTANT_12345 = 8
|
53
|
+
hh.evalhook("TEST_CONSTANT_12345").should be == 77
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should allow change constant values using hooking" do
|
57
|
+
hh = EvalHook::HookHandler.new
|
58
|
+
def hh.handle_colon2(context, name)
|
59
|
+
const_value(77)
|
60
|
+
end
|
61
|
+
|
62
|
+
TEST_CONSTANT_12346 = 8
|
63
|
+
hh.evalhook("Object::TEST_CONSTANT_12346").should be == 77
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should allow change global variable values using hooking" do
|
67
|
+
hh = EvalHook::HookHandler.new
|
68
|
+
def hh.handle_gvar(global_id)
|
69
|
+
global_value(88)
|
70
|
+
end
|
71
|
+
|
72
|
+
$test_global_12345 = 9
|
73
|
+
hh.evalhook("$test_global_12345").should be == 88
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should intercept constant access" do
|
77
|
+
hh = EvalHook::HookHandler.new
|
78
|
+
|
79
|
+
hh.should_receive(:handle_const).with("A")
|
80
|
+
|
81
|
+
hh.evalhook("A")
|
82
|
+
end
|
83
|
+
|
84
|
+
module TestModule321
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should intercept nested constant access" do
|
88
|
+
hh = EvalHook::HookHandler.new
|
89
|
+
|
90
|
+
hh.should_receive(:handle_const).once.with("TestModule321")
|
91
|
+
hh.should_receive(:handle_colon2).once.with(TestModule321,"B")
|
92
|
+
|
93
|
+
hh.evalhook("TestModule321::B")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should intercept global_variable access" do
|
97
|
+
hh = EvalHook::HookHandler.new
|
98
|
+
|
99
|
+
hh.should_receive(:handle_gvar).with(:$global_variable_test)
|
100
|
+
|
101
|
+
hh.evalhook("$global_variable_test")
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
class X
|
106
|
+
def foo
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class Y < X
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should intercept super as a method call" do
|
114
|
+
h = EvalHook::HookHandler.new
|
115
|
+
|
116
|
+
# reference to X for inheritance
|
117
|
+
h.should_receive(:handle_const).with("X")
|
118
|
+
|
119
|
+
# reference to Y
|
120
|
+
h.should_receive(:handle_const).with("Y")
|
121
|
+
|
122
|
+
# call to new
|
123
|
+
h.should_receive(:handle_method).with(Y.class,Y,:new)
|
124
|
+
|
125
|
+
# first Y#foo call
|
126
|
+
h.should_receive(:handle_method).with(Y,anything(),:foo)
|
127
|
+
|
128
|
+
# super call
|
129
|
+
h.should_receive(:handle_method).with(X,anything(),:foo)
|
130
|
+
|
131
|
+
h.evalhook('
|
132
|
+
|
133
|
+
class Y < X
|
134
|
+
def foo
|
135
|
+
super
|
136
|
+
end
|
137
|
+
end
|
138
|
+
Y.new.foo
|
139
|
+
|
140
|
+
', binding)
|
141
|
+
end
|
142
|
+
|
143
|
+
class X2
|
144
|
+
def foo(a)
|
145
|
+
a+1
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class Y2 < X2
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should intercept super with explicit arguments as a method call" do
|
153
|
+
h = EvalHook::HookHandler.new
|
154
|
+
|
155
|
+
# reference to X for inheritance
|
156
|
+
h.should_receive(:handle_const).with("X2")
|
157
|
+
|
158
|
+
# reference to Y
|
159
|
+
h.should_receive(:handle_const).with("Y2")
|
160
|
+
|
161
|
+
# call to new
|
162
|
+
h.should_receive(:handle_method).with(Y2.class,Y2,:new)
|
163
|
+
|
164
|
+
# first Y#foo call
|
165
|
+
h.should_receive(:handle_method).with(Y2,anything(),:foo)
|
166
|
+
|
167
|
+
# super call
|
168
|
+
h.should_receive(:handle_method).with(X2,anything(),:foo)
|
169
|
+
|
170
|
+
h.evalhook('
|
171
|
+
|
172
|
+
class Y2 < X2
|
173
|
+
def foo(a)
|
174
|
+
super(a)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
Y2.new.foo(9)
|
178
|
+
|
179
|
+
', binding).should be == 10
|
180
|
+
end
|
181
|
+
|
46
182
|
end
|
@@ -7,6 +7,10 @@ describe EvalHook::HookHandler, "hook handler visitor" do
|
|
7
7
|
def foo
|
8
8
|
|
9
9
|
end
|
10
|
+
|
11
|
+
def bar(*x)
|
12
|
+
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
16
|
def self.visitor_it(code, name)
|
@@ -100,4 +104,57 @@ describe EvalHook::HookHandler, "hook handler visitor" do
|
|
100
104
|
|
101
105
|
end
|
102
106
|
|
107
|
+
it "should capture inside parameters" do
|
108
|
+
x = X.new
|
109
|
+
hh = EvalHook::HookHandler.new
|
110
|
+
|
111
|
+
hh.should_receive(:handle_method).with(X,x,:foo)
|
112
|
+
hh.should_receive(:handle_method).with(X,x,:bar)
|
113
|
+
|
114
|
+
c = nil
|
115
|
+
hh.evalhook("
|
116
|
+
x.bar(x.foo)
|
117
|
+
", binding
|
118
|
+
)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should capture in global assignment" do
|
122
|
+
x = X.new
|
123
|
+
hh = EvalHook::HookHandler.new
|
124
|
+
|
125
|
+
hh.should_receive(:handle_method).with(X,x,:foo)
|
126
|
+
|
127
|
+
c = nil
|
128
|
+
hh.evalhook("
|
129
|
+
$a = x.foo
|
130
|
+
", binding
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should capture in constant assignment" do
|
135
|
+
x = X.new
|
136
|
+
hh = EvalHook::HookHandler.new
|
137
|
+
|
138
|
+
hh.should_receive(:handle_method).with(X,x,:foo)
|
139
|
+
|
140
|
+
c = nil
|
141
|
+
hh.evalhook("
|
142
|
+
TESTCONSTANTA = x.foo
|
143
|
+
", binding
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should capture in dxstr system calls" do
|
148
|
+
x = X.new
|
149
|
+
hh = EvalHook::HookHandler.new
|
150
|
+
|
151
|
+
hh.should_receive(:handle_method).with(X,x,:foo)
|
152
|
+
|
153
|
+
c = nil
|
154
|
+
hh.evalhook("
|
155
|
+
`\#{x.foo}`
|
156
|
+
", binding
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
103
160
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evalhook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Dario Seminara
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-28 00:00:00 -03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -26,12 +26,12 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 23
|
30
30
|
segments:
|
31
31
|
- 0
|
32
|
-
-
|
32
|
+
- 2
|
33
33
|
- 0
|
34
|
-
version: 0.
|
34
|
+
version: 0.2.0
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
@@ -65,9 +65,9 @@ files:
|
|
65
65
|
- examples/example4.rb
|
66
66
|
- examples/example2.rb
|
67
67
|
- lib/evalhook/multi_hook_handler.rb
|
68
|
+
- lib/evalhook/tree_processor.rb
|
68
69
|
- lib/evalhook/hook_handler.rb
|
69
70
|
- lib/evalhook/redirect_helper.rb
|
70
|
-
- lib/evalhook/hook_context.rb
|
71
71
|
- lib/evalhook.rb
|
72
72
|
- spec/hook_handler/hook_handler_arguments_spec.rb
|
73
73
|
- spec/hook_handler/hook_handler_hook_spec.rb
|
@@ -1,144 +0,0 @@
|
|
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 "ruby_parser"
|
22
|
-
require "partialruby"
|
23
|
-
|
24
|
-
module EvalHook
|
25
|
-
class HookContext < PartialRuby::PureRubyContext
|
26
|
-
|
27
|
-
def initialize(hook_handler)
|
28
|
-
@hook_handler = hook_handler
|
29
|
-
end
|
30
|
-
|
31
|
-
def const_path_emul(code)
|
32
|
-
if code.instance_of? Array
|
33
|
-
if (code.size == 1)
|
34
|
-
s(:const, code[-1].to_sym)
|
35
|
-
else
|
36
|
-
s(:colon2, const_path_emul(code[0..-2]), code[-1].to_sym)
|
37
|
-
end
|
38
|
-
else
|
39
|
-
const_path_emul code.split("::")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def ruby_emul_colon3(tree)
|
44
|
-
if @hook_handler.base_namespace
|
45
|
-
emul s(:colon2, const_path_emul(@hook_handler.base_namespace.to_s), tree[1])
|
46
|
-
else
|
47
|
-
super tree
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def ruby_emul_call(tree)
|
52
|
-
|
53
|
-
method_name = tree[2]
|
54
|
-
|
55
|
-
if tree.respond_to?(:is_marked?)
|
56
|
-
return super(tree)
|
57
|
-
end
|
58
|
-
|
59
|
-
args1 = s(:arglist, s(:lit, method_name), marked(s(:call, nil, :binding, s(:arglist))))
|
60
|
-
|
61
|
-
args2 = s(:arglist, s(:lit, @hook_handler))
|
62
|
-
|
63
|
-
receiver = tree[1] || s(:self)
|
64
|
-
|
65
|
-
firstcall = nil
|
66
|
-
secondcall = nil
|
67
|
-
|
68
|
-
if tree[1]
|
69
|
-
firstcall = marked(s(:call, receiver, :local_hooked_method, args1))
|
70
|
-
secondcall = marked(s(:call, firstcall, :set_hook_handler, args2))
|
71
|
-
else
|
72
|
-
firstcall = marked(s(:call, receiver, :hooked_method, args1))
|
73
|
-
secondcall = marked(s(:call, firstcall, :set_hook_handler, args2))
|
74
|
-
end
|
75
|
-
|
76
|
-
super marked(s(:call, secondcall, :call, tree[3]))
|
77
|
-
end
|
78
|
-
|
79
|
-
def ruby_emul_dxstr(tree)
|
80
|
-
|
81
|
-
dstr_tree = tree.dup
|
82
|
-
dstr_tree[0] = :dstr
|
83
|
-
|
84
|
-
args = s(:arglist, dstr_tree )
|
85
|
-
|
86
|
-
emul marked(s(:call, s(:lit, @hook_handler), :hooked_xstr, args))
|
87
|
-
end
|
88
|
-
|
89
|
-
def ruby_emul_xstr(tree)
|
90
|
-
args = s(:arglist, s(:lit, tree[1]) )
|
91
|
-
|
92
|
-
emul marked(s(:call, s(:lit, @hook_handler), :hooked_xstr, args))
|
93
|
-
end
|
94
|
-
|
95
|
-
def ruby_emul_cdecl(tree)
|
96
|
-
const_tree = tree[1]
|
97
|
-
value_tree = tree[2]
|
98
|
-
|
99
|
-
base_class_tree = nil
|
100
|
-
const_id = nil
|
101
|
-
|
102
|
-
unless const_tree.instance_of? Symbol
|
103
|
-
if const_tree[0] == :colon2
|
104
|
-
base_class_tree = const_tree[1]
|
105
|
-
const_id = const_tree[2]
|
106
|
-
elsif const_tree[0] == :colon3
|
107
|
-
base_class_tree = s(:lit, Object)
|
108
|
-
const_id = const_tree[1]
|
109
|
-
end
|
110
|
-
else
|
111
|
-
base_class_tree = s(:lit, Object)
|
112
|
-
const_id = const_tree
|
113
|
-
end
|
114
|
-
|
115
|
-
args1 = s(:arglist, base_class_tree)
|
116
|
-
args2 = s(:arglist, s(:lit, const_id))
|
117
|
-
args3 = s(:arglist, value_tree)
|
118
|
-
|
119
|
-
firstcall = marked(s(:call, s(:lit, @hook_handler), :hooked_cdecl, args1 ))
|
120
|
-
secondcall = marked(s(:call, firstcall, :set_id, args2))
|
121
|
-
thirdcall = marked(s(:call, secondcall, :set_value, args3))
|
122
|
-
|
123
|
-
emul thirdcall
|
124
|
-
end
|
125
|
-
|
126
|
-
def ruby_emul_gasgn(tree)
|
127
|
-
args1 = s(:arglist, s(:lit, tree[1]))
|
128
|
-
args2 = s(:arglist, tree[2] )
|
129
|
-
|
130
|
-
firstcall = marked(s(:call, s(:lit, @hook_handler), :hooked_gasgn, args1))
|
131
|
-
secondcall = marked(s(:call, firstcall, :set_value, args2))
|
132
|
-
emul secondcall
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
def marked(ast)
|
138
|
-
def ast.is_marked?
|
139
|
-
true
|
140
|
-
end
|
141
|
-
ast
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|