assert2 0.3.4 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|