assert2 0.3.4 → 0.3.6
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/lib/assert2.rb +10 -7
- data/lib/assert2.rb~ +344 -0
- data/lib/assert2/rubynode_reflector.rb +815 -815
- metadata +6 -6
- data/lib/assert2/null_reflector.rb +0 -0
data/lib/assert2.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
|
3
3
|
# FIXME the first failing assertion of a batch should suggest you get with Ruby1.9...
|
4
|
-
# TODO install Coulor
|
4
|
+
# TODO install Coulor (flibberty)
|
5
5
|
# TODO add :verbose => option to assert{}
|
6
6
|
# TODO pay for Staff Benda Bilili ALBUM: Tr�s Tr�s Fort (Promo Sampler) !
|
7
7
|
# TODO evaluate parts[3]
|
@@ -19,7 +19,7 @@ require 'test/unit'
|
|
19
19
|
#~ end
|
20
20
|
|
21
21
|
if RUBY_VERSION < '1.9.0'
|
22
|
-
require 'assert2/rubynode_reflector'
|
22
|
+
require 'assert2/rubynode_reflector'
|
23
23
|
else
|
24
24
|
require 'assert2/ripper_reflector'
|
25
25
|
end
|
@@ -35,7 +35,7 @@ module Test; module Unit; module Assertions
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def add_diagnostic(whatever = nil, &block)
|
38
|
-
@__additional_diagnostics ||= []
|
38
|
+
@__additional_diagnostics ||= [] # TODO move that inside the reflector object, and persist it thru a test case event
|
39
39
|
|
40
40
|
if whatever == :clear
|
41
41
|
@__additional_diagnostics = []
|
@@ -115,7 +115,7 @@ module Test; module Unit; module Assertions
|
|
115
115
|
include Coulor
|
116
116
|
|
117
117
|
def split_and_read(called)
|
118
|
-
if called =~ /([^:]+):(\d+):/
|
118
|
+
if called + ':' =~ /([^:]+):(\d+):/
|
119
119
|
file, line = $1, $2.to_i
|
120
120
|
return File.readlines(file)[line - 1 .. -1]
|
121
121
|
end
|
@@ -204,7 +204,10 @@ module Test; module Unit; module Assertions
|
|
204
204
|
options[:keep_diagnostics] or add_diagnostic :clear
|
205
205
|
|
206
206
|
begin
|
207
|
-
got = block.call(*options[:args])
|
207
|
+
if got = block.call(*options[:args])
|
208
|
+
add_assertion
|
209
|
+
return got
|
210
|
+
end
|
208
211
|
rescue FlunkError
|
209
212
|
raise # asserts inside assertions that fail do not decorate the outer assertion
|
210
213
|
rescue => got
|
@@ -235,7 +238,7 @@ module Test; module Unit; module Assertions
|
|
235
238
|
options[:keep_diagnostics] or add_diagnostic :clear
|
236
239
|
|
237
240
|
begin
|
238
|
-
got = block.call(*options[:args]) or (add_assertion
|
241
|
+
got = block.call(*options[:args]) or (add_assertion ; return true)
|
239
242
|
rescue FlunkError
|
240
243
|
raise
|
241
244
|
rescue => got
|
@@ -251,7 +254,7 @@ module Test; module Unit; module Assertions
|
|
251
254
|
options[:keep_diagnostics] or add_diagnostic :clear
|
252
255
|
|
253
256
|
begin
|
254
|
-
got = block.call(*options[:args]) or (add_assertion
|
257
|
+
got = block.call(*options[:args]) or (add_assertion ; return true)
|
255
258
|
rescue FlunkError
|
256
259
|
raise
|
257
260
|
rescue => got
|
data/lib/assert2.rb~
ADDED
@@ -0,0 +1,344 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
# FIXME the first failing assertion of a batch should suggest you get with Ruby1.9...
|
4
|
+
# TODO install Coulor (flibberty)
|
5
|
+
# TODO add :verbose => option to assert{}
|
6
|
+
# TODO pay for Staff Benda Bilili ALBUM: Tr�s Tr�s Fort (Promo Sampler) !
|
7
|
+
# TODO evaluate parts[3]
|
8
|
+
# ERGO if the block is a block, decorate with do-end
|
9
|
+
# ERGO decorate assert_latest's block at fault time
|
10
|
+
|
11
|
+
#~ if RUBY_VERSION > '1.8.6'
|
12
|
+
#~ puts "\nWarning: This version of assert{ 2.0 } requires\n" +
|
13
|
+
#~ "RubyNode, which only works on Ruby versions < 1.8.7.\n" +
|
14
|
+
#~ "Upgrade to Ruby1.9, and try 'gem install assert21'\n\n"
|
15
|
+
#~ end
|
16
|
+
|
17
|
+
#~ def colorize(whatever)
|
18
|
+
#~ # FIXME stop ignoring this and start colorizing v2.1!
|
19
|
+
#~ end
|
20
|
+
|
21
|
+
if RUBY_VERSION < '1.9.0'
|
22
|
+
require 'assert2/rubynode_reflector'
|
23
|
+
else
|
24
|
+
require 'assert2/ripper_reflector'
|
25
|
+
end
|
26
|
+
|
27
|
+
# CONSIDER fix if an assertion contains more than one command - reflect it all!
|
28
|
+
|
29
|
+
module Test; module Unit; module Assertions
|
30
|
+
|
31
|
+
FlunkError = if defined? Test::Unit::AssertionFailedError
|
32
|
+
Test::Unit::AssertionFailedError
|
33
|
+
else
|
34
|
+
MiniTest::Assertion
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_diagnostic(whatever = nil, &block)
|
38
|
+
@__additional_diagnostics ||= [] # TODO move that inside the reflector object, and persist it thru a test case event
|
39
|
+
|
40
|
+
if whatever == :clear
|
41
|
+
@__additional_diagnostics = []
|
42
|
+
whatever = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
@__additional_diagnostics += [whatever, block] # note .compact will take care of them if they don't exist
|
46
|
+
end
|
47
|
+
|
48
|
+
def assert(*args, &block)
|
49
|
+
# This assertion calls a block, and faults if it returns
|
50
|
+
# +false+ or +nil+. The fault diagnostic will reflect the
|
51
|
+
# assertion's complete source - with comments - and will
|
52
|
+
# reevaluate the every variable and expression in the
|
53
|
+
# block.
|
54
|
+
#
|
55
|
+
# The first argument can be a diagnostic string:
|
56
|
+
#
|
57
|
+
# assert("foo failed"){ foo() }
|
58
|
+
#
|
59
|
+
# The fault diagnostic will print that line.
|
60
|
+
#
|
61
|
+
# The next time you think to write any of these assertions...
|
62
|
+
#
|
63
|
+
# - +assert+
|
64
|
+
# - +assert_equal+
|
65
|
+
# - +assert_instance_of+
|
66
|
+
# - +assert_kind_of+
|
67
|
+
# - +assert_operator+
|
68
|
+
# - +assert_match+
|
69
|
+
# - +assert_not_nil+
|
70
|
+
#
|
71
|
+
# use <code>assert{ 2.1 }</code> instead.
|
72
|
+
#
|
73
|
+
# If no block is provided, the assertion calls +assert_classic+,
|
74
|
+
# which simulates RubyUnit's standard <code>assert()</code>.
|
75
|
+
if block
|
76
|
+
assert_ *args, &block
|
77
|
+
else
|
78
|
+
assert_classic *args
|
79
|
+
end
|
80
|
+
return true # or die trying ;-)
|
81
|
+
end
|
82
|
+
|
83
|
+
module Coulor #:nodoc:
|
84
|
+
def colorize(we_color)
|
85
|
+
@@we_color = we_color
|
86
|
+
end
|
87
|
+
unless defined? BOLD
|
88
|
+
BOLD = "\e[1m"
|
89
|
+
CLEAR = "\e[0m"
|
90
|
+
end # ERGO modularize these; anneal with Win32
|
91
|
+
def colour(text, colour_code)
|
92
|
+
return colour_code + text + CLEAR if colorize?
|
93
|
+
return text
|
94
|
+
end
|
95
|
+
def colorize? # ERGO how other libraries set these options transparent??
|
96
|
+
we_color = (@@we_color rescue true) # ERGO parens needed?
|
97
|
+
return false if ENV['EMACS'] == 't'
|
98
|
+
return (we_color == :always or we_color && $stdout.tty?)
|
99
|
+
end
|
100
|
+
def bold(text)
|
101
|
+
return BOLD + text + CLEAR if colorize?
|
102
|
+
return text
|
103
|
+
end
|
104
|
+
def green(text); colour(text, "\e[32m"); end
|
105
|
+
def red(text); colour(text, "\e[31m"); end
|
106
|
+
def magenta(text); colour(text, "\e[35m"); end
|
107
|
+
def blue(text); colour(text, "\e[34m"); end
|
108
|
+
def orange(text); colour(text, "\e[3Bm"); end
|
109
|
+
end
|
110
|
+
|
111
|
+
class RubyReflector
|
112
|
+
attr_accessor :captured_block_vars,
|
113
|
+
:args
|
114
|
+
|
115
|
+
include Coulor
|
116
|
+
|
117
|
+
def split_and_read(called)
|
118
|
+
if called + ':' =~ /([^:]+):(\d+):/
|
119
|
+
file, line = $1, $2.to_i
|
120
|
+
return File.readlines(file)[line - 1 .. -1]
|
121
|
+
end
|
122
|
+
|
123
|
+
return nil
|
124
|
+
end
|
125
|
+
|
126
|
+
def __evaluate_diagnostics
|
127
|
+
@__additional_diagnostics.each_with_index do |d, x|
|
128
|
+
@__additional_diagnostics[x] = d.call if d.respond_to? :call
|
129
|
+
end
|
130
|
+
end # CONSIDER pass the same args as blocks take?
|
131
|
+
|
132
|
+
def __build_message(reflection)
|
133
|
+
__evaluate_diagnostics
|
134
|
+
return (@__additional_diagnostics.uniq + [reflection]).compact.join("\n")
|
135
|
+
end # TODO move this fluff to the ruby_reflector!
|
136
|
+
|
137
|
+
def format_inspection(inspection, spaces)
|
138
|
+
spaces = ' ' * spaces
|
139
|
+
inspection = inspection.gsub('\n'){ "\\n\" +\n \"" } if inspection =~ /^".*"$/
|
140
|
+
inspection = inspection.gsub("\n"){ "\n" + spaces }
|
141
|
+
return inspection.lstrip
|
142
|
+
end
|
143
|
+
|
144
|
+
def format_assertion_result(assertion_source, inspection)
|
145
|
+
spaces = " --> ".length
|
146
|
+
inspection = format_inspection(inspection, spaces)
|
147
|
+
return assertion_source.rstrip + "\n --> #{inspection.lstrip}\n"
|
148
|
+
end
|
149
|
+
|
150
|
+
def format_capture(width, snip, value)
|
151
|
+
return "#{ format_snip(width, snip) } --> #{ format_value(width, value) }"
|
152
|
+
end
|
153
|
+
|
154
|
+
def format_value(width, value) # TODO width is a de-facto instance variable
|
155
|
+
width += 4
|
156
|
+
source = value.pretty_inspect.rstrip
|
157
|
+
return format_inspection(source, width)
|
158
|
+
end
|
159
|
+
|
160
|
+
def measure_capture(kap)
|
161
|
+
return kap.split("\n").inject(0){|x, v| v.strip.length > x ? v.strip.length : x } if kap.match("\n")
|
162
|
+
kap.length
|
163
|
+
# TODO need the if?
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
def colorize(to_color)
|
169
|
+
RubyReflector.new.colorize(to_color)
|
170
|
+
end
|
171
|
+
|
172
|
+
# TODO work with raw MiniTest
|
173
|
+
|
174
|
+
# This is a copy of the classic assert, so your pre-existing
|
175
|
+
# +assert+ calls will not change their behavior
|
176
|
+
#
|
177
|
+
if defined? MiniTest::Assertion
|
178
|
+
def assert_classic(test, msg=nil)
|
179
|
+
msg ||= "Failed assertion, no message given."
|
180
|
+
self._assertions += 1
|
181
|
+
unless test then
|
182
|
+
msg = msg.call if Proc === msg
|
183
|
+
raise MiniTest::Assertion, msg
|
184
|
+
end
|
185
|
+
true
|
186
|
+
end
|
187
|
+
|
188
|
+
def add_assertion
|
189
|
+
self._assertions += 1
|
190
|
+
end
|
191
|
+
else
|
192
|
+
def assert_classic(boolean, message=nil)
|
193
|
+
#_wrap_assertion do
|
194
|
+
assert_block("assert<classic> should not be called with a block.") { !block_given? }
|
195
|
+
assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
|
196
|
+
#end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# The new <code>assert()</code> calls this to interpret
|
201
|
+
# blocks of assertive statements.
|
202
|
+
#
|
203
|
+
def assert_(diagnostic = nil, options = {}, &block)
|
204
|
+
options[:keep_diagnostics] or add_diagnostic :clear
|
205
|
+
|
206
|
+
begin
|
207
|
+
if got = block.call(*options[:args])
|
208
|
+
add_assertion
|
209
|
+
return got
|
210
|
+
end
|
211
|
+
rescue FlunkError
|
212
|
+
raise # asserts inside assertions that fail do not decorate the outer assertion
|
213
|
+
rescue => got
|
214
|
+
add_exception got
|
215
|
+
end
|
216
|
+
|
217
|
+
flunk diagnose(diagnostic, got, caller[1], options, block)
|
218
|
+
end
|
219
|
+
|
220
|
+
def add_exception(ex)
|
221
|
+
ex.backtrace[0..10].each do |line|
|
222
|
+
add_diagnostic ' ' + line
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# This assertion replaces:
|
227
|
+
#
|
228
|
+
# - +assert_nil+
|
229
|
+
# - +assert_no_match+
|
230
|
+
# - +assert_not_equal+
|
231
|
+
#
|
232
|
+
# It faults, and prints its block's contents and values,
|
233
|
+
# if its block returns non-+false+ and non-+nil+.
|
234
|
+
#
|
235
|
+
def deny(diagnostic = nil, options = {}, &block)
|
236
|
+
# "None shall pass!" --the Black Knight
|
237
|
+
|
238
|
+
options[:keep_diagnostics] or add_diagnostic :clear
|
239
|
+
|
240
|
+
begin
|
241
|
+
got = block.call(*options[:args]) or (add_assertion and return true)
|
242
|
+
rescue FlunkError
|
243
|
+
raise
|
244
|
+
rescue => got
|
245
|
+
add_exception got
|
246
|
+
end
|
247
|
+
|
248
|
+
flunk diagnose(diagnostic, got, caller[0], options, block)
|
249
|
+
end # "You're a looney!" -- King Arthur
|
250
|
+
|
251
|
+
def deny_(diagnostic = nil, options = {}, &block)
|
252
|
+
# "None shall pass!" --the Black Knight
|
253
|
+
|
254
|
+
options[:keep_diagnostics] or add_diagnostic :clear
|
255
|
+
|
256
|
+
begin
|
257
|
+
got = block.call(*options[:args]) or (add_assertion and return true)
|
258
|
+
rescue FlunkError
|
259
|
+
raise
|
260
|
+
rescue => got
|
261
|
+
add_exception got
|
262
|
+
end
|
263
|
+
|
264
|
+
flunk diagnose(diagnostic, got, caller[0], options, block)
|
265
|
+
end # "You're a looney!" -- King Arthur
|
266
|
+
|
267
|
+
# FIXME document why this deny_ is here, and how to alias it back to deny
|
268
|
+
|
269
|
+
alias denigh deny # to line assert{ ... } and
|
270
|
+
# denigh{ ... } statements up neatly!
|
271
|
+
|
272
|
+
#~ def __reflect_assertion(called, options, block, got)
|
273
|
+
#~ effect = RubyReflector.new(called)
|
274
|
+
#~ effect.args = *options[:args]
|
275
|
+
#~ return effect.reflect_assertion(block, got)
|
276
|
+
#~ end
|
277
|
+
|
278
|
+
#~ def __reflect_assertion(called, options, block, got)
|
279
|
+
#~ effect = RubyReflector.new(called)
|
280
|
+
#~ effect.args = *options[:args]
|
281
|
+
#~ effect.block = block
|
282
|
+
#~ return effect.reflect_assertion(block, got) # TODO merge this and its copies into assert2_utilities
|
283
|
+
#~ end
|
284
|
+
|
285
|
+
#!doc!
|
286
|
+
def diagnose(diagnostic = nil, got = nil, called = caller[0],
|
287
|
+
options = {}, block = nil) # TODO make this directly callable
|
288
|
+
rf = RubyReflector.new
|
289
|
+
rf.diagnose(diagnostic, got, called, options, block, @__additional_diagnostics)
|
290
|
+
#~ options = { :args => [] }.merge(options)
|
291
|
+
#~ # CONSIDER only capture the block_vars if there be args?
|
292
|
+
#~ @__additional_diagnostics.unshift diagnostic
|
293
|
+
#~ return __build_message(__reflect_assertion(called, options, block, got))
|
294
|
+
end
|
295
|
+
|
296
|
+
if RubyReflector::HAS_RUBYNODE
|
297
|
+
# wrap this common idiom:
|
298
|
+
# foo = assemble()
|
299
|
+
# deny{ foo.bar() }
|
300
|
+
# foo.activate()
|
301
|
+
# assert{ foo.bar() }
|
302
|
+
#
|
303
|
+
# that becomes:
|
304
|
+
# foo = assemble()
|
305
|
+
#
|
306
|
+
# assert_yin_yang proc{ foo.bar() } do
|
307
|
+
# foo.activate()
|
308
|
+
# end
|
309
|
+
#
|
310
|
+
def assert_yin_yang(*args, &block)
|
311
|
+
# prock(s), diagnostic = nil, &block)
|
312
|
+
procks, diagnostic = args.partition{|p| p.respond_to? :call }
|
313
|
+
block ||= procks.shift
|
314
|
+
source = reflect_source(&block)
|
315
|
+
fuss = [diagnostic, "fault before calling:", source].compact.join("\n")
|
316
|
+
procks.each do |prock| deny(fuss, &prock); end
|
317
|
+
block.call
|
318
|
+
fuss = [diagnostic, "fault after calling:", source].compact.join("\n")
|
319
|
+
procks.each do |prock| assert(fuss, &prock); end
|
320
|
+
end
|
321
|
+
|
322
|
+
# the prock assertion must pass on both sides of the called block
|
323
|
+
#
|
324
|
+
def deny_yin_yang(*args, &block)
|
325
|
+
# prock(s), diagnostic = nil, &block)
|
326
|
+
procks, diagnostic = args.partition{|p| p.respond_to? :call }
|
327
|
+
block ||= procks.shift
|
328
|
+
source = reflect_source(&block)
|
329
|
+
fuss = [diagnostic, "fault before calling:", source].compact.join("\n")
|
330
|
+
procks.each do |prock| assert(fuss, &prock); end
|
331
|
+
block.call
|
332
|
+
fuss = [diagnostic, "fault after calling:", source].compact.join("\n")
|
333
|
+
procks.each do |prock| assert(fuss, &prock); end
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
end ; end ; end
|
339
|
+
|
340
|
+
class File
|
341
|
+
def self.write(filename, contents)
|
342
|
+
open(filename, 'w'){|f| f.write(contents) }
|
343
|
+
end
|
344
|
+
end
|
@@ -1,76 +1,75 @@
|
|
1
|
-
require 'pp'
|
2
|
-
|
3
|
-
|
4
|
-
module Test; module Unit; module Assertions
|
5
|
-
|
6
|
-
# ERGO
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
|
30
|
-
# This +reflect+s a block of code, by evaluating it, reflecting its
|
31
|
-
# source, and reflecting all its intermediate values
|
32
|
-
#
|
33
|
-
def reflect(&block)
|
34
|
-
result = block.call
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
|
4
|
+
module Test; module Unit; module Assertions
|
5
|
+
|
6
|
+
# ERGO
|
7
|
+
# :bmethod => [:cval],
|
8
|
+
# :cfunc => [:argc, :cfnc],
|
9
|
+
# :cref => [:next, :clss],
|
10
|
+
# :defs => [:mid, :defn, :recv],
|
11
|
+
# :dmethod => [:cval],
|
12
|
+
# :dot2 => [:beg, :end],
|
13
|
+
# :dot3 => [:beg, :end],
|
14
|
+
# :dregx_once => [:next, :lit, :cflag],
|
15
|
+
# :fbody => [:orig, :mid, :head],
|
16
|
+
# :flip2 => [:cnt, :beg, :end],
|
17
|
+
# :flip3 => [:cnt, :beg, :end],
|
18
|
+
# :gasgn => [:vid, :value], # entry not supported
|
19
|
+
# :ifunc => [:tval, :state, :cfnc],
|
20
|
+
# :lasgn => [:vid, :cnt, :value],
|
21
|
+
# :last => [],
|
22
|
+
# :match => [:lit],
|
23
|
+
# :memo => {:u1_value=>:u1_value}, # different uses in enum.c, variabe.c and eval.c ...
|
24
|
+
# :method => [:body, :noex, :cnt], # cnt seems to be always 0 in 1.8.4
|
25
|
+
# :module => [:cpath, :body],
|
26
|
+
# :next => [:stts],
|
27
|
+
# :opt_n => [:body],
|
28
|
+
# :to_ary => [:head],
|
29
|
+
|
30
|
+
# This +reflect+s a block of code, by evaluating it, reflecting its
|
31
|
+
# source, and reflecting all its intermediate values
|
32
|
+
#
|
33
|
+
def reflect(&block)
|
34
|
+
result = block.call
|
35
35
|
rf = RubyReflector.new
|
36
|
-
rf.block = block
|
37
|
-
|
38
|
-
begin
|
39
|
-
waz = rf.colorize?
|
40
|
-
rf.colorize(false)
|
41
|
-
return rf.result + rf.arrow_result(result) + "\n" + rf.format_evaluations
|
42
|
-
ensure
|
43
|
-
rf.colorize(waz)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# This +reflect+s a block of code, /without/ evaluating it.
|
48
|
-
# The function only compiles the source and reflects it as
|
49
|
-
# a string of disassembled Ruby
|
50
|
-
#
|
51
|
-
def reflect_source(&block)
|
36
|
+
rf.block = block
|
37
|
+
|
38
|
+
begin
|
39
|
+
waz = rf.colorize?
|
40
|
+
rf.colorize(false)
|
41
|
+
return rf.result + rf.arrow_result(result) + "\n" + rf.format_evaluations
|
42
|
+
ensure
|
43
|
+
rf.colorize(waz)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# This +reflect+s a block of code, /without/ evaluating it.
|
48
|
+
# The function only compiles the source and reflects it as
|
49
|
+
# a string of disassembled Ruby
|
50
|
+
#
|
51
|
+
def reflect_source(&block)
|
52
52
|
rf = RubyReflector.new(nil, false)
|
53
53
|
rf.block = block
|
54
|
-
return rf.result
|
55
|
-
end
|
56
|
-
|
57
|
-
# This compiles a string and +reflect+s its source...
|
58
|
-
# as another string.
|
59
|
-
#
|
54
|
+
return rf.result
|
55
|
+
end
|
56
|
+
|
57
|
+
# This compiles a string and +reflect+s its source...
|
58
|
+
# as another string.
|
59
|
+
#
|
60
60
|
def reflect_string(string)
|
61
61
|
rf = RubyReflector.new # def initialize
|
62
62
|
rf.block = proc{}
|
63
|
-
rf.reflect_values = false
|
64
|
-
# pp string.parse_to_nodes.transform
|
65
|
-
got = rf.reflect_nodes(string.parse_to_nodes)
|
66
|
-
return got
|
67
|
-
end
|
68
|
-
|
63
|
+
rf.reflect_values = false
|
64
|
+
# pp string.parse_to_nodes.transform
|
65
|
+
got = rf.reflect_nodes(string.parse_to_nodes)
|
66
|
+
return got
|
67
|
+
end
|
68
|
+
|
69
69
|
class RubyReflector # this class turns hamburger back into live cattle
|
70
70
|
HAS_RIPPER = false
|
71
|
-
|
71
|
+
|
72
72
|
begin
|
73
|
-
raise LoadError, 'whatever' if ENV['TEST_ASSERT_2_IN_1_8_7_MODE'] == 'true'
|
74
73
|
require 'rubygems'
|
75
74
|
require 'rubynode'
|
76
75
|
HAS_RUBYNODE = true
|
@@ -78,744 +77,745 @@ module Test; module Unit; module Assertions
|
|
78
77
|
HAS_RUBYNODE = false
|
79
78
|
end
|
80
79
|
|
81
|
-
attr_reader :evaluations,
|
82
|
-
:result,
|
83
|
-
:transformation
|
84
|
-
attr_writer :block,
|
85
|
-
:reflect_values
|
86
|
-
|
80
|
+
attr_reader :evaluations,
|
81
|
+
:result,
|
82
|
+
:transformation
|
83
|
+
attr_writer :block,
|
84
|
+
:reflect_values
|
85
|
+
|
87
86
|
def initialize(called = nil, yo_block = nil, reflect_values = true) # note that a block, from your context, is not optional
|
88
|
-
# FIXME these args are bogus use or lose
|
89
|
-
@reflect_values = reflect_values
|
90
|
-
@evaluations = []
|
91
|
-
@result = ''
|
92
|
-
@line = 0
|
93
|
-
self.block = yo_block
|
94
|
-
end
|
95
|
-
|
87
|
+
# FIXME these args are bogus use or lose
|
88
|
+
@reflect_values = reflect_values
|
89
|
+
@evaluations = []
|
90
|
+
@result = ''
|
91
|
+
@line = 0
|
92
|
+
self.block = yo_block
|
93
|
+
end
|
94
|
+
|
96
95
|
def block=(yo_block)
|
97
|
-
@block = yo_block and
|
98
|
-
reflect_nodes(@block.body_node)
|
99
|
-
end
|
100
|
-
|
101
|
-
def reflect_nodes(body_node)
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
prettier
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
# ERGO
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
already[line]
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
return
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
exp
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
def
|
218
|
-
def
|
219
|
-
def
|
220
|
-
def
|
221
|
-
def
|
222
|
-
def
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
#
|
233
|
-
#
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
@
|
238
|
-
@
|
239
|
-
@
|
240
|
-
@
|
241
|
-
@
|
242
|
-
@
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
@expression <<
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
@expression <<
|
258
|
-
@
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
@expression << @
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
@
|
269
|
-
@
|
270
|
-
@
|
271
|
-
@
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
@
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
exp
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
expression
|
364
|
-
expression <<
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
def
|
384
|
-
def
|
385
|
-
def
|
386
|
-
def
|
387
|
-
def
|
388
|
-
def
|
389
|
-
def
|
390
|
-
def
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
exp
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
expression
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
def
|
433
|
-
def
|
434
|
-
def
|
435
|
-
def
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
expression <<
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
eval_parenz{
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
def
|
462
|
-
def
|
463
|
-
def
|
464
|
-
def
|
465
|
-
def
|
466
|
-
def
|
467
|
-
def
|
468
|
-
def
|
469
|
-
def
|
470
|
-
def
|
471
|
-
def
|
472
|
-
def
|
473
|
-
def
|
474
|
-
def
|
475
|
-
def
|
476
|
-
def
|
477
|
-
def
|
478
|
-
def
|
479
|
-
def
|
480
|
-
def
|
481
|
-
def
|
482
|
-
def
|
483
|
-
def
|
484
|
-
def
|
485
|
-
def
|
486
|
-
def
|
487
|
-
def
|
488
|
-
def
|
489
|
-
def
|
490
|
-
def
|
491
|
-
def
|
492
|
-
def
|
493
|
-
def
|
494
|
-
def
|
495
|
-
def
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
p node
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
#
|
507
|
-
#
|
508
|
-
#
|
509
|
-
#
|
510
|
-
#
|
511
|
-
#
|
512
|
-
#
|
513
|
-
#
|
514
|
-
# [:vcall, {:mid=>:
|
515
|
-
# [:vcall, {:mid=>:
|
516
|
-
# :
|
517
|
-
# :
|
518
|
-
#
|
519
|
-
#
|
520
|
-
#
|
521
|
-
# [:dasgn_curr, {:value=>false, :vid=>:
|
522
|
-
# [:dasgn_curr, {:value=>false, :vid=>:
|
523
|
-
# [:dasgn_curr, {:value=>false, :vid=>:
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
return exp + ', *' +
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
lit.gsub
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
return
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
_send(args.last.
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
#
|
634
|
-
# :
|
635
|
-
# :
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
expression
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
'
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
nest_if(
|
667
|
-
'
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
exp
|
675
|
-
exp
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
expression << '
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
@expression <<
|
720
|
-
@expression <<
|
721
|
-
@ref.
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
@expression <<
|
735
|
-
@expression <<
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
@ref.
|
751
|
-
@
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
@
|
757
|
-
@
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
@ref.
|
770
|
-
exp2
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
exp
|
785
|
-
exp <<
|
786
|
-
exp <<
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
exp << '
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
96
|
+
@block = yo_block and @block.respond_to?(:body_node) and
|
97
|
+
reflect_nodes(@block.body_node)
|
98
|
+
end
|
99
|
+
|
100
|
+
def reflect_nodes(body_node)
|
101
|
+
if body_node
|
102
|
+
@transformation = body_node.transform(:include_node => true)
|
103
|
+
return @result = _send(@transformation)
|
104
|
+
end
|
105
|
+
rescue
|
106
|
+
puts "\nOffending line: #{ @line }"
|
107
|
+
raise
|
108
|
+
end
|
109
|
+
|
110
|
+
def absorb_block_args(code_fragments) # CONSIDER a suckier way of detecting
|
111
|
+
@captured_block_vars = nil # the block args is indeed remotely possible...
|
112
|
+
if code_fragments.first =~ /\|(.*)\|/ or code_fragments[1].to_s =~ /\|(.*)\|/
|
113
|
+
@captured_block_vars = $1
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def detect(expression)
|
118
|
+
expr = expression
|
119
|
+
$__args = nil
|
120
|
+
if @args and @captured_block_vars
|
121
|
+
expr = "#{@captured_block_vars} = $__args.kind_of?(Array) && $__args.length == 1 ? $__args.first : $__args\n" +
|
122
|
+
expr
|
123
|
+
$__args = @args
|
124
|
+
end
|
125
|
+
|
126
|
+
begin
|
127
|
+
intermediate = eval(expr, @block.binding)
|
128
|
+
@evaluations << [expression, intermediate, nil]
|
129
|
+
rescue SyntaxError => e
|
130
|
+
if e.message.index('syntax error, unexpected \',\'') and expression !~ /\[ /
|
131
|
+
return detect('[ ' + expression + ' ]')
|
132
|
+
end # faint prayer to infinite recursion diety here! (-;
|
133
|
+
|
134
|
+
@evaluations << [expression, nil, e.message]
|
135
|
+
rescue => e
|
136
|
+
@evaluations << [expression, nil, e.message]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def eval_intermediate(expression)
|
141
|
+
detect(expression) if @reflect_values
|
142
|
+
return expression
|
143
|
+
end
|
144
|
+
|
145
|
+
def short_inspect(intermediate)
|
146
|
+
pretty = intermediate.inspect
|
147
|
+
# ERGO Proc is prob'ly rare here!
|
148
|
+
pretty = { '#<Proc' => '<Proc>' }.fetch(pretty.split(':').first, pretty)
|
149
|
+
prettier = pretty[0..90]
|
150
|
+
prettier << '*** ' unless prettier == pretty
|
151
|
+
return prettier
|
152
|
+
end
|
153
|
+
private :short_inspect
|
154
|
+
|
155
|
+
# ERGO spew the backrefs (?) any regular expression matchers may emit!
|
156
|
+
# ERGO don't eval the caller of a block without its block!
|
157
|
+
|
158
|
+
def format_evaluations
|
159
|
+
max_line = @evaluations.map{|exp, val, prob| exp.length}.sort.last
|
160
|
+
already = {}
|
161
|
+
lines = []
|
162
|
+
|
163
|
+
@evaluations.each do |exp, val, prob|
|
164
|
+
line = " #{ exp.center(max_line) } "
|
165
|
+
|
166
|
+
line << if prob then
|
167
|
+
orange('--? ' + prob)
|
168
|
+
else
|
169
|
+
green('--> ') + bold(short_inspect(val))
|
170
|
+
end
|
171
|
+
|
172
|
+
lines << line unless already[line] == true
|
173
|
+
already[line] = true
|
174
|
+
end
|
175
|
+
|
176
|
+
return lines.compact.join("\n")
|
177
|
+
end
|
178
|
+
|
179
|
+
def _send(node, thence = '')
|
180
|
+
return '' unless node
|
181
|
+
return node.to_s + thence if node.class == Symbol
|
182
|
+
target = :"_#{ node.first }"
|
183
|
+
last = node.last
|
184
|
+
(@line = last[:node].line) rescue nil
|
185
|
+
exp = send(target, last)
|
186
|
+
exp << thence if exp.length > 0
|
187
|
+
return exp
|
188
|
+
end
|
189
|
+
|
190
|
+
%w( args beg body cond cpath defn else end ensr
|
191
|
+
first head iter ivar lit mid next second
|
192
|
+
stts recv resq rest value var vid ).each do |sender|
|
193
|
+
define_method sender + '_' do |node, *args|
|
194
|
+
return _send(node[sender.to_sym], *args)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
########################################################
|
199
|
+
#### structures
|
200
|
+
|
201
|
+
def _block(node)
|
202
|
+
return node.map{|n| _send(n, "\n") }.join
|
203
|
+
end
|
204
|
+
|
205
|
+
def _module(node, what = 'module')
|
206
|
+
return what + ' ' + cpath_(node) + "\n" +
|
207
|
+
body_(node) +
|
208
|
+
"\nend\n"
|
209
|
+
end
|
210
|
+
|
211
|
+
def _method(node)
|
212
|
+
p node
|
213
|
+
return ''
|
214
|
+
end
|
215
|
+
|
216
|
+
def _class(node); _module(node, 'class'); end
|
217
|
+
def _self(node); 'self'; end
|
218
|
+
def _defn(node); _defs(node); end
|
219
|
+
def _super(node); 'super(' + args_(node) + ')'; end
|
220
|
+
def _zsuper(node); 'super'; end
|
221
|
+
def _begin(node); "begin\n" + body_(node) + "\nend\n"; end
|
222
|
+
def _ensure(node); head_(node) + "\nensure\n" + ensr_(node); end
|
223
|
+
|
224
|
+
def _sclass(node)
|
225
|
+
return 'class << ' + recv_(node) +
|
226
|
+
head_body(node) +
|
227
|
+
"end\n"
|
228
|
+
end
|
229
|
+
|
230
|
+
class ScopeMethod #:nodoc:
|
231
|
+
# this is complex because Ruby gloms several different
|
232
|
+
# kinds of variables into one "scope" token, and they
|
233
|
+
# don't directly match their layout in the source code
|
234
|
+
|
235
|
+
def _scopic(ref, node)
|
236
|
+
@ref = ref
|
237
|
+
@node = node
|
238
|
+
@expression = ''
|
239
|
+
@previously = false
|
240
|
+
@block_arg = false
|
241
|
+
@splat_arg = false
|
242
|
+
@previous_splat = false
|
243
|
+
|
244
|
+
if @node[:tbl]
|
245
|
+
@expression << '('
|
246
|
+
render_argument_list
|
247
|
+
@expression << ')'
|
248
|
+
end
|
249
|
+
|
250
|
+
@expression << "\n"
|
251
|
+
@expression << @ref.next_(@node)
|
252
|
+
return @expression
|
253
|
+
end
|
254
|
+
|
255
|
+
def ulterior_comma(token)
|
256
|
+
@expression << ', ' if @index > 0
|
257
|
+
@expression << token
|
258
|
+
@index = 0
|
259
|
+
end
|
260
|
+
|
261
|
+
def possible_comma(token)
|
262
|
+
@expression << ', ' if @index > 0
|
263
|
+
@expression << @ref._send(token)
|
264
|
+
end
|
265
|
+
|
266
|
+
def render_argument_list
|
267
|
+
@nekst = @node[:next]
|
268
|
+
@block = @nekst.last if @nekst && @nekst.first == :block
|
269
|
+
@args = @block.first.last if @block && @block.first.first == :args
|
270
|
+
@rest = @args[:rest] if @args
|
271
|
+
@opt = @args[:opt] if @args
|
272
|
+
|
273
|
+
@node[:tbl].each_with_index do |_n, _index|
|
274
|
+
@n, @index = _n, _index
|
275
|
+
render_argument
|
276
|
+
break if @block_arg
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def render_argument
|
281
|
+
@splat_arg = @block_arg = false
|
282
|
+
|
283
|
+
if @rest and @rest.first == :lasgn and
|
284
|
+
(@n == nil or @rest.last[:vid] == @n)
|
285
|
+
ulterior_comma('*')
|
286
|
+
@splat_arg = true
|
287
|
+
end
|
288
|
+
|
289
|
+
if @block and (ba = @block[1]) and
|
290
|
+
ba.first == :block_arg and ba.last[:vid] == @n
|
291
|
+
ulterior_comma('&')
|
292
|
+
@block_arg = true
|
293
|
+
end
|
294
|
+
|
295
|
+
# ERGO Ruby 1.9 changes these rules!!
|
296
|
+
|
297
|
+
if !@previous_splat or @block_arg
|
298
|
+
if @opt and @opt.first == :block and # ERGO why a @block??
|
299
|
+
(lasgn = @opt.last.first).first == :lasgn and
|
300
|
+
lasgn.last[:vid] == @n
|
301
|
+
@previously = true
|
302
|
+
possible_comma(@opt.last.first)
|
303
|
+
else
|
304
|
+
possible_comma(@n)
|
305
|
+
@expression << ' = nil' if @previously and !@block_arg and !@splat_arg
|
306
|
+
end
|
307
|
+
|
308
|
+
@previous_splat ||= @splat_arg
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def _scope(node)
|
314
|
+
return ScopeMethod.new._scopic(self, node)
|
315
|
+
end
|
316
|
+
|
317
|
+
def _defs(node)
|
318
|
+
return 'def ' + recv_(node, '.') + mid_(node) +
|
319
|
+
defn_(node) +
|
320
|
+
"end\n"
|
321
|
+
end
|
322
|
+
|
323
|
+
def _rescue(node)
|
324
|
+
if node[:else] == false and node[:head] and
|
325
|
+
node[:resq] and node[:head].first == :vcall
|
326
|
+
return head_(node) + ' rescue ' + resq_(node)
|
327
|
+
else
|
328
|
+
exp = head_(node) +
|
329
|
+
else_(node) +
|
330
|
+
"rescue"
|
331
|
+
if node[:resq] and node[:resq].first == :resbody
|
332
|
+
body = node[:resq].last
|
333
|
+
exp << ' ' + args_(body) if body and body[:args]
|
334
|
+
end
|
335
|
+
return exp + "\n" + resq_(node)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
def _resbody(node)
|
340
|
+
return body_(node)
|
341
|
+
# already emitted: head_(node) + ' ' + args_(node)
|
342
|
+
end
|
343
|
+
|
344
|
+
def _yield(node)
|
345
|
+
exp = 'yield'
|
346
|
+
exp << '(' + head_(node) + ')' if node[:head]
|
347
|
+
return exp
|
348
|
+
end
|
349
|
+
|
350
|
+
def _alias(node)
|
351
|
+
return "alias #{ lit_(node[:new].last) } #{ lit_(node[:old].last) }"
|
352
|
+
end
|
353
|
+
|
354
|
+
def _valias(node)
|
355
|
+
return "alias #{ node[:new] } #{ node[:old] }"
|
356
|
+
end
|
357
|
+
|
358
|
+
########################################################
|
359
|
+
#### control flow
|
360
|
+
|
361
|
+
def _if(node)
|
362
|
+
expression = '( if ' + eval_parenz{cond_(node)} + ' then '
|
363
|
+
expression << eval_parenz{body_(node)} if node[:body]
|
364
|
+
expression << ' else ' +
|
365
|
+
eval_parenz{else_(node)} if node[:else]
|
366
|
+
expression << ' end )'
|
367
|
+
return expression
|
368
|
+
end
|
369
|
+
|
370
|
+
def _while(node, concept = 'while')
|
371
|
+
return '( ' + concept + ' ' + cond_(node) +
|
372
|
+
head_body(node) +
|
373
|
+
"\nend )"
|
374
|
+
end
|
375
|
+
|
376
|
+
def _for(node)
|
377
|
+
return '( for ' + var_(node) + ' in ' + iter_(node) + "\n" +
|
378
|
+
body_(node) + "\n" +
|
379
|
+
'end )'
|
380
|
+
end
|
381
|
+
|
382
|
+
def _args(node); return ''; end # _call and _fcall insert the real args
|
383
|
+
def _until(node); _while(node, 'until'); end
|
384
|
+
def _break(node); 'break'; end
|
385
|
+
def _next(node); 'next' ; end
|
386
|
+
def _case(node); '( case ' + head_body(node) + "\nend )"; end
|
387
|
+
def _when(node); 'when ' + head_body(node) + "\n" + next_(node); end
|
388
|
+
def _retry(node); 'retry'; end
|
389
|
+
def _redo(node); 'redo'; end
|
390
|
+
def head_body(node); head_(node) + "\n" + body_(node); end
|
391
|
+
|
392
|
+
def _return(node)
|
393
|
+
exp = 'return'
|
394
|
+
return exp unless stts = node[:stts]
|
395
|
+
exp << ' '
|
396
|
+
|
397
|
+
if stts.first == :array
|
398
|
+
exp << '[' + stts_(node) + ']'
|
399
|
+
elsif stts.first == :svalue
|
400
|
+
exp << stts_(node)
|
401
|
+
else
|
402
|
+
exp << eval_parenz{stts_(node)}
|
403
|
+
end
|
404
|
+
|
405
|
+
return exp
|
406
|
+
end
|
407
|
+
|
408
|
+
def _postexe(node)
|
409
|
+
raise '_postexe called with unexpected arguments' unless node == {} or node.keys == [:node]
|
410
|
+
return 'END'
|
411
|
+
end
|
412
|
+
|
413
|
+
# :argscat => [:body, :head],
|
414
|
+
|
415
|
+
########################################################
|
416
|
+
#### assignments
|
417
|
+
|
418
|
+
def _dasgn_curr(node)
|
419
|
+
expression = vid_(node)
|
420
|
+
return expression unless value = node[:value]
|
421
|
+
expression << ' = '
|
422
|
+
we_b_array = value.first == :array
|
423
|
+
expression << nest_if(we_b_array, '[', ']'){ value_(node) }
|
424
|
+
return expression
|
425
|
+
end
|
426
|
+
|
427
|
+
def _cdecl(node)
|
428
|
+
return _send(node[ node[:vid] == 0 ? :else : :vid ]) + ' = ' + value_(node)
|
429
|
+
end
|
430
|
+
|
431
|
+
def _dasgn(node); _dasgn_curr(node); end
|
432
|
+
def _iasgn(node); _dasgn_curr(node); end
|
433
|
+
def _gasgn(node); _dasgn_curr(node); end
|
434
|
+
def _lasgn(node); _dasgn_curr(node); end
|
435
|
+
def _cvasgn(node); _dasgn_curr(node); end
|
436
|
+
|
437
|
+
def _op_asgn2(node)
|
438
|
+
expression = ''
|
439
|
+
|
440
|
+
if node[:recv].first == :self
|
441
|
+
expression << 'self'
|
442
|
+
else
|
443
|
+
expression << recv_(node)
|
444
|
+
end
|
445
|
+
|
446
|
+
expression << '.'
|
447
|
+
expression << vid_(node[:next].last) + ' ||= ' + value_(node)
|
448
|
+
return expression
|
449
|
+
end
|
450
|
+
|
451
|
+
########################################################
|
452
|
+
#### operators
|
453
|
+
|
454
|
+
def _and(node, und = 'and')
|
455
|
+
return eval_intermediate( '( ' +
|
456
|
+
eval_parenz{ first_(node)} + ' ' + und + ' ' +
|
457
|
+
eval_parenz{second_(node)} + ' )' )
|
458
|
+
end
|
459
|
+
|
460
|
+
def _back_ref(node); '$' + node[:nth].chr; end
|
461
|
+
def _colon2(node); head_(node, '::') + mid_(node); end
|
462
|
+
def _colon3(node); '::' + mid_(node); end
|
463
|
+
def _cvar(node); _lvar(node); end
|
464
|
+
def _cvdecl(node); vid_(node) + ' = ' + value_(node); end
|
465
|
+
def _defined(node); 'defined? ' + head_(node); end
|
466
|
+
def _dot2(node); '( ' + beg_(node) + ' .. ' + end_(node) + ' )'; end
|
467
|
+
def _dot3(node); '( ' + beg_(node) + ' ... ' + end_(node) + ' )'; end
|
468
|
+
def _dregx(node); _dstr(node, '/'); end
|
469
|
+
def _dregx_once(node); _dstr(node, '/'); end
|
470
|
+
def _dsym(node); ':' + _lit(node[:lit]) + ' ' + rest_(node); end
|
471
|
+
def _dvar(node); eval_intermediate(vid_(node)); end
|
472
|
+
def _dxstr(node); _dstr(node, '`'); end
|
473
|
+
def eval_parenz; eval_intermediate('( ' + yield + ' )'); end
|
474
|
+
def _evstr(node); body_(node); end
|
475
|
+
def _false(nada); 'false'; end
|
476
|
+
def _gvar(node); vid_(node); end
|
477
|
+
def _ivar(node); _dvar(node); end
|
478
|
+
def _lit(node); node[:lit].inspect; end
|
479
|
+
def _lvar(node); eval_intermediate(vid_(node)); end
|
480
|
+
def _match(node); node[:lit].inspect; end
|
481
|
+
def neg_one(node); node == -1 ? '' : _send(node); end
|
482
|
+
def _nil(nada); 'nil' ; end
|
483
|
+
def _not(node); '(not(' + body_(node) + '))'; end
|
484
|
+
def _nth_ref(node); "$#{ node[:nth] }"; end # ERGO eval it?
|
485
|
+
def _op_asgn_and(node); _op_asgn_or(node, ' &&= '); end
|
486
|
+
def _or(node); _and(node, 'or'); end
|
487
|
+
def _str(node); _lit(node); end
|
488
|
+
def _svalue(node); head_(node); end
|
489
|
+
def _to_ary(node); head_(node); end
|
490
|
+
def _true(nada); 'true' ; end
|
491
|
+
def _undef(node); 'undef ' + mid_(node); end
|
492
|
+
def _vcall(node); mid_(node); end
|
493
|
+
def we_b(node); node.first.first; end
|
494
|
+
def _xstr(node); '`' + scrape_literal(node) + '`'; end
|
495
|
+
def _zarray(node); return '[]'; end
|
496
|
+
|
497
|
+
def _flip2(node) # ERGO what the heck is this??
|
498
|
+
p node
|
499
|
+
p node.keys
|
500
|
+
return ''
|
501
|
+
end
|
502
|
+
|
503
|
+
def _masgn(node)
|
504
|
+
|
505
|
+
#{:value=>
|
506
|
+
# [:splat,
|
507
|
+
# {:head=>
|
508
|
+
# [:fcall,
|
509
|
+
# {:mid=>:calc_stack,
|
510
|
+
# :args=>
|
511
|
+
# [:array,
|
512
|
+
# [[:vcall, {:mid=>:insn}],
|
513
|
+
# [:vcall, {:mid=>:from}],
|
514
|
+
# [:vcall, {:mid=>:after}],
|
515
|
+
# [:vcall, {:mid=>:opops}]]]}]}],
|
516
|
+
# :args=>false,
|
517
|
+
# :head=>
|
518
|
+
# [:array,
|
519
|
+
# [[:dasgn_curr, {:value=>false, :vid=>:name}],
|
520
|
+
# [:dasgn_curr, {:value=>false, :vid=>:pops}],
|
521
|
+
# [:dasgn_curr, {:value=>false, :vid=>:rets}],
|
522
|
+
# [:dasgn_curr, {:value=>false, :vid=>:pushs1}],
|
523
|
+
# [:dasgn_curr, {:value=>false, :vid=>:pushs2}]]]}
|
524
|
+
|
525
|
+
value, head, args = node.values_at(:value, :head, :args)
|
526
|
+
|
527
|
+
if value
|
528
|
+
return '( ' + head_(node) + ' = *' + head_(value.last) + ' )' if value.first == :splat
|
529
|
+
|
530
|
+
if head and args
|
531
|
+
exp = head_(node)
|
532
|
+
return exp + ', * = ' + value_(node) if args == -1
|
533
|
+
return exp + ', *' + args_(node) + ' = ' + value_(node)
|
534
|
+
end
|
535
|
+
|
536
|
+
return '( ' + head_(node) + ' = ' + value_(node) + ' )' if args == false
|
537
|
+
end
|
538
|
+
|
539
|
+
if value == false and head == false and args
|
540
|
+
return '*' + neg_one(args)
|
541
|
+
end
|
542
|
+
|
543
|
+
if head.kind_of?(Array) and head.first == :array
|
544
|
+
return head.last.map{|n|
|
545
|
+
nest_if(n.first == :masgn, '(', ')'){ _send(n) }
|
546
|
+
}.join(', ')
|
547
|
+
end
|
548
|
+
|
549
|
+
if head == false and args and value
|
550
|
+
return '*' + args_(node) + ' = ' + value_(node)
|
551
|
+
end
|
552
|
+
|
553
|
+
return head_(node)
|
554
|
+
end
|
555
|
+
|
556
|
+
def _splat(node)
|
557
|
+
if (head = node[:head]) and
|
558
|
+
((we_b_array = head.first == :array) or head.first == :lvar)
|
559
|
+
return '*' + nest_if(we_b_array, '[', ']'){ head_(node) }
|
560
|
+
end
|
561
|
+
|
562
|
+
return '*' + head_(node)
|
563
|
+
end # ERGO raise if any other key!
|
564
|
+
|
565
|
+
def _const(node)
|
566
|
+
expression = vid_(node)
|
567
|
+
q = eval(expression, @block.binding)
|
568
|
+
eval_intermediate(expression) unless q.kind_of?(Module)
|
569
|
+
return expression
|
570
|
+
rescue # ERGO will someone need to see whatever this was?
|
571
|
+
return expression
|
572
|
+
end
|
573
|
+
|
574
|
+
def scrape_literal(node, regex = false)
|
575
|
+
lit = node[:lit].inspect.gsub(/^"/, '').gsub(/"$/, '')
|
576
|
+
lit.gsub!('\\\\', '\\') if regex
|
577
|
+
return lit
|
578
|
+
end
|
579
|
+
|
580
|
+
def _dstr(node, delim = '"')
|
581
|
+
regex = delim == '/'
|
582
|
+
expression = delim + scrape_literal(node, regex)
|
583
|
+
|
584
|
+
if node[:next] and node[:next].first == :array
|
585
|
+
(node[:next].last || []).each do |n|
|
586
|
+
expression << if n.first == :str
|
587
|
+
scrape_literal(n.last, regex)
|
588
|
+
else
|
589
|
+
'#{ ' + _send(n) + ' }'
|
590
|
+
end
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
return eval_intermediate(expression + delim)
|
595
|
+
end
|
596
|
+
|
597
|
+
def _retry(node)
|
598
|
+
raise '_retry called with unexpected arguments' unless node == {} or node.keys == [:node]
|
599
|
+
return 'retry'
|
600
|
+
end
|
601
|
+
|
602
|
+
def recv_zero_self(node, plus = '')
|
603
|
+
recv = node[:recv]
|
604
|
+
return 'self' + plus if recv == 0
|
605
|
+
return recv_(node, plus)
|
606
|
+
end
|
607
|
+
|
608
|
+
def _attrasgn(node)
|
609
|
+
recv, args = node.values_at(:recv, :args)
|
610
|
+
|
611
|
+
if args
|
612
|
+
if args.first == :array
|
613
|
+
if node[:mid].class == Symbol
|
614
|
+
if node[:mid] == :'[]='
|
615
|
+
return recv_zero_self(node) + '[' +
|
616
|
+
_send(args.last.first) + '] = ' +
|
617
|
+
_send(args.last.last)
|
618
|
+
end
|
619
|
+
return recv_zero_self(node, '.') + mid_(node) + '(' + _send(args.last.last) + ')'
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
return recv_zero_self(node) +
|
624
|
+
'[' + head_(args.last) + '] = ' +
|
625
|
+
body_(args.last)
|
626
|
+
end
|
627
|
+
|
628
|
+
return recv_zero_self(node, '.') + node[:mid].to_s.gsub(/=$/, '')
|
629
|
+
end
|
630
|
+
|
631
|
+
def _op_asgn_or(node, op = ' ||= ')
|
632
|
+
# CONSIDER what be :aid?
|
633
|
+
#{:value=>[:lasgn, {:value=>[:str, {:lit=>"vm_opts.h"}], :cnt=>2, :vid=>:file}],
|
634
|
+
# :aid=>0,
|
635
|
+
# :head=>[:lvar, {:cnt=>2, :vid=>:file}]}
|
636
|
+
return head_(node) + op + value_(node[:value].last)
|
637
|
+
end
|
638
|
+
|
639
|
+
def fcall_args(node = nil, methodic = false)
|
640
|
+
expression = ''
|
641
|
+
return expression unless node
|
642
|
+
expression << ' ' unless methodic
|
643
|
+
return expression + nest_if(methodic, '(', ')'){ _send(node) }
|
644
|
+
end
|
645
|
+
|
646
|
+
def _fcall(node)
|
647
|
+
exp = mid_(node) + fcall_args(node[:args], true)
|
648
|
+
eval_intermediate(exp) unless %w(lambda proc).include?(exp)
|
649
|
+
return exp
|
650
|
+
end
|
651
|
+
|
652
|
+
def _block_pass(node)
|
653
|
+
fcall = node[:iter].last
|
654
|
+
return eval_intermediate(recv_(fcall, '.') +
|
655
|
+
mid_(fcall) + '(' + args_(fcall, ', ') +
|
656
|
+
'&' + body_(node) + ')' )
|
657
|
+
end
|
658
|
+
|
659
|
+
def _iter(node)
|
660
|
+
var = node[:var]
|
661
|
+
|
662
|
+
return eval_intermediate(
|
663
|
+
iter_(node) +
|
664
|
+
'{' +
|
665
|
+
nest_if(var != false, '|', '|'){ var_(node) unless var == 0 } +
|
666
|
+
nest_if(node[:body] , ' ', ' '){ body_(node) } +
|
667
|
+
'}')
|
668
|
+
end
|
669
|
+
|
670
|
+
def _array(node)
|
671
|
+
nest_if we_b(node) == :array, '[', ']' do
|
672
|
+
node.map{ |z|
|
673
|
+
exp = _send(z)
|
674
|
+
exp << ', ' unless z.object_id == node.last.object_id
|
675
|
+
exp
|
676
|
+
}.join
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
def _hash(node)
|
681
|
+
return '{}' unless node[:head] and (array = node[:head].last)
|
682
|
+
expression = '{ '
|
683
|
+
|
684
|
+
array.in_groups_of 2 do |key, value|
|
685
|
+
expression << _send(key) + ' => ' + _send(value)
|
686
|
+
expression << ', ' if value != array.last
|
687
|
+
end
|
688
|
+
|
689
|
+
return expression + ' }'
|
690
|
+
end
|
691
|
+
|
692
|
+
def _match2(node)
|
693
|
+
# ERGO should this work like match3?
|
694
|
+
return recv_(node) + ' =~ ' + value_(node)
|
695
|
+
end
|
696
|
+
|
697
|
+
def we_b_op(node)
|
698
|
+
return node[:mid] && node[:mid].to_s !~ /^[a-z]/i
|
699
|
+
end
|
700
|
+
|
701
|
+
def _match3(node)
|
702
|
+
# ERGO do :lit and :value exclude each other?
|
703
|
+
return recv_(node) + ' =~ ' + _send(node[:lit] || node[:value])
|
704
|
+
end
|
705
|
+
|
706
|
+
def _block_arg(node) # is this ever called?
|
707
|
+
return '' # note that _scope should not take care of this
|
708
|
+
end
|
709
|
+
|
710
|
+
class CallMethod
|
711
|
+
def bracket_args
|
712
|
+
return false unless @mid == '[]'
|
713
|
+
@expression << '[' + @ref.args_(@node) + ']'
|
714
|
+
return true
|
715
|
+
end
|
716
|
+
|
717
|
+
def insert_method_call
|
718
|
+
@expression << '.'
|
719
|
+
@expression << @mid
|
720
|
+
@expression << '(' + @ref.args_(@node) + ')'
|
721
|
+
@ref.eval_intermediate(@expression) if @methodic
|
722
|
+
end
|
723
|
+
|
724
|
+
def operator_and_arguments
|
725
|
+
@mid = @ref.mid_(@node)
|
726
|
+
|
727
|
+
unless bracket_args
|
728
|
+
@methodic = @mid =~ /[a-z]/i
|
729
|
+
|
730
|
+
if @methodic
|
731
|
+
insert_method_call
|
732
|
+
else
|
733
|
+
@expression << ' '
|
734
|
+
@expression << @mid
|
735
|
+
@expression << ' '
|
736
|
+
nest_args
|
737
|
+
end
|
738
|
+
end
|
739
|
+
end
|
740
|
+
|
741
|
+
def nest_args
|
742
|
+
return unless @args = @node[:args]
|
743
|
+
|
744
|
+
nest_me = @args.first == :array &&
|
745
|
+
@args.last.length == 1 &&
|
746
|
+
(call = @args.last.first).first == :call &&
|
747
|
+
@ref.we_b_op(call.last)
|
748
|
+
|
749
|
+
exp = @ref.nest_if(nest_me, '( ', ' )'){ @ref.args_(@node) }
|
750
|
+
@ref.eval_intermediate(exp) if nest_me
|
751
|
+
@expression << exp
|
752
|
+
end
|
753
|
+
|
754
|
+
def caller(ref, node)
|
755
|
+
@ref, @node = ref, node
|
756
|
+
@expression = ''
|
757
|
+
@recv = @node[:recv]
|
758
|
+
|
759
|
+
if @recv.first == :block_pass
|
760
|
+
@expression << @ref.recv_(@node)
|
761
|
+
operator_and_arguments
|
762
|
+
else
|
763
|
+
nest_me = @recv.first == :call && @ref.we_b_op(@recv.last)
|
764
|
+
|
765
|
+
exp = if @recv.first == :array
|
766
|
+
@ref.nest_if(true, '[ ', ' ]'){ @ref.recv_(node) }
|
767
|
+
else
|
768
|
+
exp2 = @ref.nest_if(nest_me, '( ', ' )'){ @ref.recv_(node) }
|
769
|
+
@ref.eval_intermediate(exp2) if nest_me
|
770
|
+
exp2
|
771
|
+
end
|
772
|
+
|
773
|
+
@expression << exp
|
774
|
+
operator_and_arguments
|
775
|
+
end
|
776
|
+
return @expression
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
780
|
+
def _call(node); CallMethod.new.caller(self, node); end
|
781
|
+
|
782
|
+
def nest_if(condition, before, after, &block)
|
783
|
+
exp = ''
|
784
|
+
exp << before if condition
|
785
|
+
exp << (block.call || '')
|
786
|
+
exp << after if condition
|
787
|
+
return exp
|
788
|
+
end
|
789
|
+
|
790
|
+
def _op_asgn1(node) # ERGO just look up the list of these?
|
791
|
+
return '' unless args = node[:args]
|
792
|
+
exp = recv_(node)
|
793
|
+
|
794
|
+
if [:'-', :'+', :'*', :'**', :'/', :^, :|, :&,
|
795
|
+
:'<<', :'>>',
|
796
|
+
].include?(node[:mid]) and
|
797
|
+
node[:recv] and args.first == :argscat
|
798
|
+
|
799
|
+
return exp +
|
800
|
+
"[#{ body_(args.last) }] #{ node[:mid] }= " + head_(args.last)
|
801
|
+
end
|
802
|
+
|
803
|
+
raise "unexpected mid value #{ node[:mid].inspect } in opcode for X= " unless node[:mid] == 0
|
804
|
+
|
805
|
+
if args.first == :argscat and args.last[:body]
|
806
|
+
exp << '[' + body_(args.last) + ']'
|
807
|
+
exp << ' ||= ' + head_(args.last)
|
808
|
+
else
|
809
|
+
raise "unexpected arguments in opcode for ||= "
|
810
|
+
end
|
811
|
+
|
812
|
+
return exp
|
813
|
+
end
|
814
|
+
|
815
|
+
def _argscat(node)
|
816
|
+
return head_(node) + ', *' +
|
817
|
+
nest_if(node[:body].first == :array, '[', ']'){ body_(node) }
|
818
|
+
end
|
819
819
|
|
820
820
|
def diagnose(diagnostic, result, called, options, block, additional_diagnostics)
|
821
821
|
@__additional_diagnostics = additional_diagnostics
|
@@ -843,18 +843,18 @@ p node
|
|
843
843
|
def arrow_result(result) #:nodoc:
|
844
844
|
return "\t--> #{ result.inspect }"
|
845
845
|
end
|
846
|
-
|
847
|
-
end
|
848
|
-
|
849
|
-
end; end; end
|
850
|
-
|
851
|
-
unless [].respond_to? :in_groups_of
|
852
|
-
class Array
|
853
|
-
def in_groups_of(number, fill_with = nil, &block)
|
854
|
-
require 'enumerator'
|
855
|
-
collection = dup
|
856
|
-
collection << fill_with until collection.size.modulo(number).zero?
|
857
|
-
collection.each_slice(number, &block)
|
858
|
-
end
|
859
|
-
end
|
860
|
-
end
|
846
|
+
|
847
|
+
end
|
848
|
+
|
849
|
+
end; end; end
|
850
|
+
|
851
|
+
unless [].respond_to? :in_groups_of
|
852
|
+
class Array
|
853
|
+
def in_groups_of(number, fill_with = nil, &block)
|
854
|
+
require 'enumerator'
|
855
|
+
collection = dup
|
856
|
+
collection << fill_with until collection.size.modulo(number).zero?
|
857
|
+
collection.each_slice(number, &block)
|
858
|
+
end
|
859
|
+
end
|
860
|
+
end
|