evalhook 0.3.1 → 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/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
|