ripper_ruby_parser 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,73 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+ require 'ruby_parser'
3
+
4
+ describe "Using RipperRubyParser and RubyParser" do
5
+ def to_comments exp
6
+ inner = exp.map do |sub_exp|
7
+ if sub_exp.is_a? Sexp
8
+ to_comments sub_exp
9
+ else
10
+ sub_exp
11
+ end
12
+ end
13
+
14
+ if exp.comments.nil?
15
+ s(*inner)
16
+ else
17
+ s(:comment, exp.comments, s(*inner))
18
+ end
19
+ end
20
+
21
+ let :newparser do
22
+ RipperRubyParser::Parser.new
23
+ end
24
+
25
+ let :oldparser do
26
+ RubyParser.new
27
+ end
28
+
29
+ describe "for a program with quite some comments" do
30
+ let :program do
31
+ <<-END
32
+ # Foo
33
+ class Foo
34
+ # The foo
35
+ # method
36
+ def foo
37
+ bar # bar
38
+ # internal comment
39
+ end
40
+
41
+ def bar
42
+ baz
43
+ end
44
+ end
45
+ # Quux
46
+ module Qux
47
+ class Quux
48
+ def bar
49
+ end
50
+ def baz
51
+ end
52
+ end
53
+ end
54
+ END
55
+ end
56
+
57
+ let :original do
58
+ oldparser.parse program
59
+ end
60
+
61
+ let :imitation do
62
+ newparser.parse program
63
+ end
64
+
65
+ it "gives the same result" do
66
+ imitation.must_equal original
67
+ end
68
+
69
+ it "gives the same result with comments" do
70
+ to_comments(imitation).must_equal to_comments(original)
71
+ end
72
+ end
73
+ end
@@ -52,5 +52,65 @@ describe "Using RipperRubyParser and RubyParser" do
52
52
  end
53
53
  end
54
54
 
55
+ describe "for an example with yield from Reek" do
56
+ let :program do
57
+ 'def fred() yield(3) if block_given?; end'
58
+ end
59
+
60
+ it "gives the same result" do
61
+ original = oldparser.parse program
62
+ imitation = newparser.parse program
63
+
64
+ imitation.must_equal original
65
+ end
66
+ end
67
+
68
+ describe "for an example with floats from Reek" do
69
+ let :program do
70
+ <<-END
71
+ def total_envy
72
+ fred = @item
73
+ total = 0
74
+ total += fred.price
75
+ total += fred.tax
76
+ total *= 1.15
77
+ end
78
+ END
79
+ end
80
+
81
+ it "gives the same result" do
82
+ original = oldparser.parse program
83
+ imitation = newparser.parse program
84
+
85
+ formatted(imitation).must_equal formatted(original)
86
+ end
87
+ end
88
+
89
+ describe "for a example with operators and explicit block parameter from Reek" do
90
+ let :program do
91
+ <<-END
92
+ def parse(arg, argv, &error)
93
+ if !(val = arg) and (argv.empty? or /\\A-/ =~ (val = argv[0]))
94
+ return nil, block, nil
95
+ end
96
+ opt = (val = parse_arg(val, &error))[1]
97
+ val = conv_arg(*val)
98
+ if opt and !arg
99
+ argv.shift
100
+ else
101
+ val[0] = nil
102
+ end
103
+ val
104
+ end
105
+ END
106
+ end
107
+
108
+ it "gives the same result" do
109
+ original = oldparser.parse program
110
+ imitation = newparser.parse program
111
+
112
+ formatted(imitation).must_equal formatted(original)
113
+ end
114
+ end
55
115
  end
56
116
 
@@ -0,0 +1,63 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+ require 'ruby_parser'
3
+
4
+ describe "Using RipperRubyParser and RubyParser" do
5
+ def to_line_numbers exp
6
+ exp.map! do |sub_exp|
7
+ if sub_exp.is_a? Sexp
8
+ to_line_numbers sub_exp
9
+ else
10
+ sub_exp
11
+ end
12
+ end
13
+
14
+ if exp.sexp_type == :scope
15
+ exp
16
+ else
17
+ s(:line_number, exp.line, exp)
18
+ end
19
+ end
20
+
21
+ let :newparser do
22
+ RipperRubyParser::Parser.new
23
+ end
24
+
25
+ let :oldparser do
26
+ RubyParser.new
27
+ end
28
+
29
+ describe "for a multi-line program" do
30
+ let :program do
31
+ <<-END
32
+ class Foo
33
+ def foo()
34
+ bar()
35
+ baz(qux)
36
+ end
37
+ end
38
+
39
+ module Bar
40
+ @@baz = {}
41
+ end
42
+ END
43
+ end
44
+
45
+ let :original do
46
+ oldparser.parse program
47
+ end
48
+
49
+ let :imitation do
50
+ newparser.parse program
51
+ end
52
+
53
+ it "gives the same result" do
54
+ imitation.must_equal original
55
+ end
56
+
57
+ it "gives the same result with line numbers" do
58
+ formatted(to_line_numbers(imitation)).
59
+ must_equal formatted(to_line_numbers(original))
60
+ end
61
+ end
62
+ end
63
+
data/test/test_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'simplecov'
2
- SimpleCov.start
1
+ if ENV["SIMPLECOV"]
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ end
3
5
  require 'minitest/spec'
4
6
  require 'minitest/autorun'
5
7
 
@@ -7,6 +9,16 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
9
 
8
10
  require 'ripper_ruby_parser'
9
11
 
10
- def formatted exp
11
- exp.to_s.gsub /\), /, "),\n"
12
+ class MiniTest::Unit::TestCase
13
+ def formatted exp
14
+ exp.to_s.gsub(/\), /, "),\n")
15
+ end
16
+
17
+ def suppress_warnings
18
+ old_verbose = $VERBOSE
19
+ $VERBOSE = nil
20
+ result = yield
21
+ $VERBOSE = old_verbose
22
+ result
23
+ end
12
24
  end
@@ -0,0 +1,75 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+
3
+ describe RipperRubyParser::CommentingSexpBuilder do
4
+ def parse_with_builder str
5
+ builder = RipperRubyParser::CommentingSexpBuilder.new str
6
+ builder.parse
7
+ end
8
+
9
+ describe "handling comments" do
10
+ it "produces a comment node surrounding a commented def" do
11
+ result = parse_with_builder "# Foo\ndef foo; end"
12
+ result.must_equal [:program,
13
+ [[:comment,
14
+ "# Foo\n",
15
+ [:def,
16
+ [:@ident, "foo", [2, 4]],
17
+ [:params, nil, nil, nil, nil, nil],
18
+ [:bodystmt, [[:void_stmt]], nil, nil, nil]]]]]
19
+ end
20
+
21
+ it "produces a blank comment node surrounding a def that has no comment" do
22
+ result = parse_with_builder "def foo; end"
23
+ result.must_equal [:program,
24
+ [[:comment,
25
+ "",
26
+ [:def,
27
+ [:@ident, "foo", [1, 4]],
28
+ [:params, nil, nil, nil, nil, nil],
29
+ [:bodystmt, [[:void_stmt]], nil, nil, nil]]]]]
30
+ end
31
+
32
+ it "produces a comment node surrounding a commented class" do
33
+ result = parse_with_builder "# Foo\nclass Foo; end"
34
+ result.must_equal [:program,
35
+ [[:comment,
36
+ "# Foo\n",
37
+ [:class,
38
+ [:const_ref, [:@const, "Foo", [2, 6]]],
39
+ nil,
40
+ [:bodystmt, [[:void_stmt]], nil, nil, nil]]]]]
41
+ end
42
+
43
+ it "produce a blank comment node surrounding a class that has no comment" do
44
+ result = parse_with_builder "class Foo; end"
45
+ result.must_equal [:program,
46
+ [[:comment,
47
+ "",
48
+ [:class,
49
+ [:const_ref, [:@const, "Foo", [1, 6]]],
50
+ nil,
51
+ [:bodystmt, [[:void_stmt]], nil, nil, nil]]]]]
52
+ end
53
+
54
+ it "produces a comment node surrounding a commented module" do
55
+ result = parse_with_builder "# Foo\nmodule Foo; end"
56
+ result.must_equal [:program,
57
+ [[:comment,
58
+ "# Foo\n",
59
+ [:module,
60
+ [:const_ref, [:@const, "Foo", [2, 7]]],
61
+ [:bodystmt, [[:void_stmt]], nil, nil, nil]]]]]
62
+ end
63
+
64
+ it "produces a blank comment node surrounding a module that has no comment" do
65
+ result = parse_with_builder "module Foo; end"
66
+ result.must_equal [:program,
67
+ [[:comment,
68
+ "",
69
+ [:module,
70
+ [:const_ref, [:@const, "Foo", [1, 7]]],
71
+ [:bodystmt, [[:void_stmt]], nil, nil, nil]]]]]
72
+ end
73
+ end
74
+ end
75
+
@@ -19,6 +19,25 @@ describe RipperRubyParser::Parser do
19
19
  sexp_p.verify
20
20
  end
21
21
 
22
+ describe "for a class declaration" do
23
+ it "works with a namespaced class name" do
24
+ result = parser.parse "class Foo::Bar; end"
25
+ result.must_equal s(:class,
26
+ s(:colon2, s(:const, :Foo), :Bar),
27
+ nil,
28
+ s(:scope))
29
+ end
30
+ end
31
+
32
+ describe "for a module declaration" do
33
+ it "works with a namespaced module name" do
34
+ result = parser.parse "module Foo::Bar; end"
35
+ result.must_equal s(:module,
36
+ s(:colon2, s(:const, :Foo), :Bar),
37
+ s(:scope))
38
+ end
39
+ end
40
+
22
41
  describe "for if" do
23
42
  it "works in the postfix case" do
24
43
  result = parser.parse "foo if bar"
@@ -28,6 +47,14 @@ describe RipperRubyParser::Parser do
28
47
  nil)
29
48
  end
30
49
 
50
+ it "works in the block case" do
51
+ result = parser.parse "if foo; bar; end"
52
+ result.must_equal s(:if,
53
+ s(:call, nil, :foo, s(:arglist)),
54
+ s(:call, nil, :bar, s(:arglist)),
55
+ nil)
56
+ end
57
+
31
58
  it "works with an else clause" do
32
59
  result = parser.parse "if foo; bar; else; baz; end"
33
60
  result.must_equal s(:if,
@@ -132,33 +159,219 @@ describe RipperRubyParser::Parser do
132
159
  result.must_equal s(:return,
133
160
  s(:call, nil, :foo, s(:arglist)))
134
161
  end
162
+
163
+ it "works with a splat argument" do
164
+ result = parser.parse "return *foo"
165
+ result.must_equal s(:return,
166
+ s(:svalue,
167
+ s(:splat,
168
+ s(:call, nil, :foo, s(:arglist)))))
169
+ end
170
+
171
+ it "works with multiple arguments" do
172
+ result = parser.parse "return foo, bar"
173
+ result.must_equal s(:return,
174
+ s(:array,
175
+ s(:call, nil, :foo, s(:arglist)),
176
+ s(:call, nil, :bar, s(:arglist))))
177
+ end
178
+
179
+ it "works with a regular argument and a splat argument" do
180
+ result = parser.parse "return foo, *bar"
181
+ result.must_equal s(:return,
182
+ s(:array,
183
+ s(:call, nil, :foo, s(:arglist)),
184
+ s(:splat,
185
+ s(:call, nil, :bar, s(:arglist)))))
186
+ end
135
187
  end
136
188
 
137
189
  describe "for the until statement" do
138
- it "works with do" do
190
+ it "works in the prefix block case with do" do
139
191
  result = parser.parse "until foo do; bar; end"
140
192
  result.must_equal s(:until,
141
193
  s(:call, nil, :foo, s(:arglist)),
142
194
  s(:call, nil, :bar, s(:arglist)), true)
143
195
  end
144
196
 
145
- it "works without do" do
197
+ it "works in the prefix block case without do" do
146
198
  result = parser.parse "until foo; bar; end"
147
199
  result.must_equal s(:until,
148
200
  s(:call, nil, :foo, s(:arglist)),
149
201
  s(:call, nil, :bar, s(:arglist)), true)
150
202
  end
203
+
204
+ it "works in the single-line postfix case" do
205
+ result = parser.parse "foo until bar"
206
+ result.must_equal s(:until,
207
+ s(:call, nil, :bar, s(:arglist)),
208
+ s(:call, nil, :foo, s(:arglist)), true)
209
+ end
210
+
211
+ it "works in the block postfix case" do
212
+ result = parser.parse "begin; foo; end until bar"
213
+ result.must_equal s(:until,
214
+ s(:call, nil, :bar, s(:arglist)),
215
+ s(:call, nil, :foo, s(:arglist)), false)
216
+ end
151
217
  end
152
218
 
153
- describe "for identifiers" do
154
- it "works for an ivar" do
155
- result = parser.parse "@foo"
156
- result.must_equal s(:ivar, :@foo)
219
+ describe "for the while statement" do
220
+ it "works with do" do
221
+ result = parser.parse "while foo do; bar; end"
222
+ result.must_equal s(:while,
223
+ s(:call, nil, :foo, s(:arglist)),
224
+ s(:call, nil, :bar, s(:arglist)), true)
157
225
  end
158
226
 
159
- it "works for self" do
160
- result = parser.parse "self"
161
- result.must_equal s(:self)
227
+ it "works without do" do
228
+ result = parser.parse "while foo; bar; end"
229
+ result.must_equal s(:while,
230
+ s(:call, nil, :foo, s(:arglist)),
231
+ s(:call, nil, :bar, s(:arglist)), true)
232
+ end
233
+ end
234
+
235
+ describe "for the for statement" do
236
+ it "works with do" do
237
+ result = suppress_warnings {
238
+ parser.parse "for foo in bar do; baz; end" }
239
+ result.must_equal s(:for,
240
+ s(:call, nil, :bar, s(:arglist)),
241
+ s(:lasgn, :foo),
242
+ s(:call, nil, :baz, s(:arglist)))
243
+ end
244
+
245
+ it "works without do" do
246
+ result = suppress_warnings {
247
+ parser.parse "for foo in bar; baz; end" }
248
+ result.must_equal s(:for,
249
+ s(:call, nil, :bar, s(:arglist)),
250
+ s(:lasgn, :foo),
251
+ s(:call, nil, :baz, s(:arglist)))
252
+ end
253
+ end
254
+
255
+ describe "for a begin..end block" do
256
+ it "works with no statements" do
257
+ result = parser.parse "begin; end"
258
+ result.must_equal s(:nil)
259
+ end
260
+
261
+ it "works with one statement" do
262
+ result = parser.parse "begin; foo; end"
263
+ result.must_equal s(:call, nil, :foo, s(:arglist))
264
+ end
265
+
266
+ it "works with multiple statements" do
267
+ result = parser.parse "begin; foo; bar; end"
268
+ result.must_equal s(:block,
269
+ s(:call, nil, :foo, s(:arglist)),
270
+ s(:call, nil, :bar, s(:arglist)))
271
+ end
272
+ end
273
+
274
+ describe "for the rescue statement" do
275
+ it "works with single statement main and rescue bodies" do
276
+ result = parser.parse "begin; foo; rescue; bar; end"
277
+ result.must_equal s(:rescue,
278
+ s(:call, nil, :foo, s(:arglist)),
279
+ s(:resbody,
280
+ s(:array),
281
+ s(:call, nil, :bar, s(:arglist))))
282
+ end
283
+
284
+ it "works with multi-statement main and rescue bodies" do
285
+ result = parser.parse "begin; foo; bar; rescue; baz; qux; end"
286
+ result.must_equal s(:rescue,
287
+ s(:block,
288
+ s(:call, nil, :foo, s(:arglist)),
289
+ s(:call, nil, :bar, s(:arglist))),
290
+ s(:resbody,
291
+ s(:array),
292
+ s(:block,
293
+ s(:call, nil, :baz, s(:arglist)),
294
+ s(:call, nil, :qux, s(:arglist)))))
295
+ end
296
+
297
+ it "works with assignment to an error variable" do
298
+ result = suppress_warnings {
299
+ parser.parse "begin; foo; rescue => e; bar; end" }
300
+ result.must_equal s(:rescue,
301
+ s(:call, nil, :foo, s(:arglist)),
302
+ s(:resbody,
303
+ s(:array, s(:lasgn, :e, s(:gvar, :$!))),
304
+ s(:call, nil, :bar, s(:arglist))))
305
+ end
306
+
307
+ it "works with filtering of the exception type" do
308
+ result = parser.parse "begin; foo; rescue Bar; baz; end"
309
+ result.must_equal s(:rescue,
310
+ s(:call, nil, :foo, s(:arglist)),
311
+ s(:resbody,
312
+ s(:array, s(:const, :Bar)),
313
+ s(:call, nil, :baz, s(:arglist))))
314
+ end
315
+
316
+ it "works with filtering of the exception type and assignment to an error variable" do
317
+ result = suppress_warnings {
318
+ parser.parse "begin; foo; rescue Bar => e; baz; end" }
319
+ result.must_equal s(:rescue,
320
+ s(:call, nil, :foo, s(:arglist)),
321
+ s(:resbody,
322
+ s(:array,
323
+ s(:const, :Bar),
324
+ s(:lasgn, :e, s(:gvar, :$!))),
325
+ s(:call, nil, :baz, s(:arglist))))
326
+ end
327
+
328
+ it "works rescuing multiple exception types" do
329
+ result = parser.parse "begin; foo; rescue Bar, Baz; qux; end"
330
+ result.must_equal s(:rescue,
331
+ s(:call, nil, :foo, s(:arglist)),
332
+ s(:resbody,
333
+ s(:array, s(:const, :Bar), s(:const, :Baz)),
334
+ s(:call, nil, :qux, s(:arglist))))
335
+ end
336
+
337
+ it "works in the postfix case" do
338
+ result = parser.parse "foo rescue bar"
339
+ result.must_equal s(:rescue,
340
+ s(:call, nil, :foo, s(:arglist)),
341
+ s(:resbody,
342
+ s(:array),
343
+ s(:call, nil, :bar, s(:arglist))))
344
+ end
345
+ end
346
+
347
+ describe "for the ensure statement" do
348
+ it "works with single statement main and ensure bodies" do
349
+ result = parser.parse "begin; foo; ensure; bar; end"
350
+ result.must_equal s(:ensure,
351
+ s(:call, nil, :foo, s(:arglist)),
352
+ s(:call, nil, :bar, s(:arglist)))
353
+ end
354
+
355
+ it "works with multi-statement main and ensure bodies" do
356
+ result = parser.parse "begin; foo; bar; ensure; baz; qux; end"
357
+ result.must_equal s(:ensure,
358
+ s(:block,
359
+ s(:call, nil, :foo, s(:arglist)),
360
+ s(:call, nil, :bar, s(:arglist))),
361
+ s(:block,
362
+ s(:call, nil, :baz, s(:arglist)),
363
+ s(:call, nil, :qux, s(:arglist))))
364
+ end
365
+
366
+ it "works together with rescue" do
367
+ result = parser.parse "begin; foo; rescue; bar; ensure; baz; end"
368
+ result.must_equal s(:ensure,
369
+ s(:rescue,
370
+ s(:call, nil, :foo, s(:arglist)),
371
+ s(:resbody,
372
+ s(:array),
373
+ s(:call, nil, :bar, s(:arglist)))),
374
+ s(:call, nil, :baz, s(:arglist)))
162
375
  end
163
376
  end
164
377
 
@@ -181,6 +394,14 @@ describe RipperRubyParser::Parser do
181
394
  s(:call, nil, :bar, s(:arglist)),
182
395
  s(:splat, s(:call, nil, :baz, s(:arglist)))))
183
396
  end
397
+
398
+ it "works for a simple case passing a block" do
399
+ result = parser.parse "foo &bar"
400
+ result.must_equal s(:call, nil, :foo,
401
+ s(:arglist,
402
+ s(:block_pass,
403
+ s(:call, nil, :bar, s(:arglist)))))
404
+ end
184
405
  end
185
406
 
186
407
  describe "for array literals" do
@@ -226,6 +447,13 @@ describe RipperRubyParser::Parser do
226
447
  end
227
448
  end
228
449
 
450
+ describe "for number literals" do
451
+ it "works for floats" do
452
+ result = parser.parse "3.14"
453
+ result.must_equal s(:lit, 3.14)
454
+ end
455
+ end
456
+
229
457
  describe "for collection indexing" do
230
458
  it "works in the simple case" do
231
459
  result = parser.parse "foo[bar]"
@@ -273,6 +501,81 @@ describe RipperRubyParser::Parser do
273
501
  s(:args, :bar),
274
502
  s(:scope, s(:block, s(:nil))))
275
503
  end
504
+
505
+ it "works with a simple splat" do
506
+ result = parser.parse "def foo *bar; end"
507
+ result.must_equal s(:defn,
508
+ :foo,
509
+ s(:args, :"*bar"),
510
+ s(:scope, s(:block, s(:nil))))
511
+ end
512
+
513
+ it "works with a regular argument plus splat" do
514
+ result = parser.parse "def foo bar, *baz; end"
515
+ result.must_equal s(:defn,
516
+ :foo,
517
+ s(:args, :bar, :"*baz"),
518
+ s(:scope, s(:block, s(:nil))))
519
+ end
520
+
521
+ it "works with a nameless splat" do
522
+ result = parser.parse "def foo *; end"
523
+ result.must_equal s(:defn,
524
+ :foo,
525
+ s(:args, :"*"),
526
+ s(:scope, s(:block, s(:nil))))
527
+ end
528
+
529
+ it "works for a simple case with explicit block parameter" do
530
+ result = parser.parse "def foo &bar; end"
531
+ result.must_equal s(:defn,
532
+ :foo,
533
+ s(:args, :"&bar"),
534
+ s(:scope, s(:block, s(:nil))))
535
+ end
536
+
537
+ it "works with a regular argument plus explicit block parameter" do
538
+ result = parser.parse "def foo bar, &baz; end"
539
+ result.must_equal s(:defn,
540
+ :foo,
541
+ s(:args, :bar, :"&baz"),
542
+ s(:scope, s(:block, s(:nil))))
543
+ end
544
+
545
+ it "works with a argument with default value plus explicit block parameter" do
546
+ result = parser.parse "def foo bar=1, &baz; end"
547
+ result.must_equal s(:defn,
548
+ :foo,
549
+ s(:args,
550
+ :bar, :"&baz",
551
+ s(:block,
552
+ s(:lasgn, :bar, s(:lit, 1)))),
553
+ s(:scope, s(:block, s(:nil))))
554
+ end
555
+
556
+ it "works with a splat plus explicit block parameter" do
557
+ result = parser.parse "def foo *bar, &baz; end"
558
+ result.must_equal s(:defn,
559
+ :foo,
560
+ s(:args, :"*bar", :"&baz"),
561
+ s(:scope, s(:block, s(:nil))))
562
+ end
563
+
564
+ it "works with an argument with default value plus splat" do
565
+ result = parser.parse "def foo bar=1, *baz; end"
566
+ result.must_equal s(:defn,
567
+ :foo,
568
+ s(:args, :bar, :"*baz",
569
+ s(:block,
570
+ s(:lasgn, :bar, s(:lit, 1)))),
571
+ s(:scope, s(:block, s(:nil))))
572
+ end
573
+
574
+ it "works when the method name is an operator" do
575
+ result = parser.parse "def +; end"
576
+ result.must_equal s(:defn, :+, s(:args),
577
+ s(:scope, s(:block, s(:nil))))
578
+ end
276
579
  end
277
580
 
278
581
  describe "for method calls" do
@@ -289,10 +592,20 @@ describe RipperRubyParser::Parser do
289
592
  s(:arglist, s(:call, nil, :bar, s(:arglist))))
290
593
  end
291
594
 
595
+ it "works with an empty parameter list and no brackets" do
596
+ result = parser.parse "foo"
597
+ result.must_equal s(:call, nil, :foo, s(:arglist))
598
+ end
599
+
292
600
  it "works with brackets around an empty parameter list" do
293
601
  result = parser.parse "foo()"
294
602
  result.must_equal s(:call, nil, :foo, s(:arglist))
295
603
  end
604
+
605
+ it "works for methods ending in a question mark" do
606
+ result = parser.parse "foo?"
607
+ result.must_equal s(:call, nil, :foo?, s(:arglist))
608
+ end
296
609
  end
297
610
 
298
611
  describe "with a reciever" do
@@ -351,6 +664,49 @@ describe RipperRubyParser::Parser do
351
664
  end
352
665
  end
353
666
 
667
+ describe "for yield" do
668
+ it "works with no arguments and no brackets" do
669
+ result = parser.parse "yield"
670
+ result.must_equal s(:yield)
671
+ end
672
+
673
+ it "works with brackets but no arguments" do
674
+ result = parser.parse "yield()"
675
+ result.must_equal s(:yield)
676
+ end
677
+
678
+ it "works with one argument and no brackets" do
679
+ result = parser.parse "yield foo"
680
+ result.must_equal s(:yield, s(:call, nil, :foo, s(:arglist)))
681
+ end
682
+
683
+ it "works with one argument and brackets" do
684
+ result = parser.parse "yield(foo)"
685
+ result.must_equal s(:yield, s(:call, nil, :foo, s(:arglist)))
686
+ end
687
+
688
+ it "works with multiple arguments and no brackets" do
689
+ result = parser.parse "yield foo, bar"
690
+ result.must_equal s(:yield,
691
+ s(:call, nil, :foo, s(:arglist)),
692
+ s(:call, nil, :bar, s(:arglist)))
693
+ end
694
+
695
+ it "works with multiple arguments and brackets" do
696
+ result = parser.parse "yield(foo, bar)"
697
+ result.must_equal s(:yield,
698
+ s(:call, nil, :foo, s(:arglist)),
699
+ s(:call, nil, :bar, s(:arglist)))
700
+ end
701
+
702
+ it "works with splat" do
703
+ result = parser.parse "yield foo, *bar"
704
+ result.must_equal s(:yield,
705
+ s(:call, nil, :foo, s(:arglist)),
706
+ s(:splat, s(:call, nil, :bar, s(:arglist))))
707
+ end
708
+ end
709
+
354
710
  describe "for literals" do
355
711
  it "works for symbols" do
356
712
  result = parser.parse ":foo"
@@ -440,10 +796,17 @@ describe RipperRubyParser::Parser do
440
796
  result.must_equal s(:lit, /\)\n\\/)
441
797
  end
442
798
 
443
- it "works for symbols created by prefixing a simple string with :" do
799
+ it "works for simple dsyms" do
444
800
  result = parser.parse ':"foo"'
445
801
  result.must_equal s(:lit, :foo)
446
802
  end
803
+
804
+ it "works for dsyms with interpolations" do
805
+ result = parser.parse ':"foo#{bar}"'
806
+ result.must_equal s(:dsym,
807
+ "foo",
808
+ s(:evstr, s(:call, nil, :bar, s(:arglist))))
809
+ end
447
810
  end
448
811
 
449
812
  describe "for the __FILE__ keyword" do
@@ -458,9 +821,26 @@ describe RipperRubyParser::Parser do
458
821
  result = parser.parse "::Foo"
459
822
  result.must_equal s(:colon3, :Foo)
460
823
  end
824
+
825
+ it "works with a three-level constant lookup" do
826
+ result = parser.parse "Foo::Bar::Baz"
827
+ result.must_equal s(:colon2,
828
+ s(:colon2, s(:const, :Foo), :Bar),
829
+ :Baz)
830
+ end
461
831
  end
462
832
 
463
833
  describe "for variable references" do
834
+ it "works for self" do
835
+ result = parser.parse "self"
836
+ result.must_equal s(:self)
837
+ end
838
+
839
+ it "works for instance variables" do
840
+ result = parser.parse "@foo"
841
+ result.must_equal s(:ivar, :@foo)
842
+ end
843
+
464
844
  it "works for global variables" do
465
845
  result = parser.parse "$foo"
466
846
  result.must_equal s(:gvar, :$foo)
@@ -470,6 +850,11 @@ describe RipperRubyParser::Parser do
470
850
  result = parser.parse "$1"
471
851
  result.must_equal s(:nth_ref, 1)
472
852
  end
853
+
854
+ it "works for class variables" do
855
+ result = parser.parse "@@foo"
856
+ result.must_equal s(:cvar, :@@foo)
857
+ end
473
858
  end
474
859
 
475
860
  describe "for single assignment" do
@@ -496,11 +881,33 @@ describe RipperRubyParser::Parser do
496
881
  s(:call, nil, :bar, s(:arglist)),
497
882
  s(:call, nil, :baz, s(:arglist))))
498
883
  end
884
+
885
+ it "works when assigning to an attribute" do
886
+ result = parser.parse "foo.bar = baz"
887
+ result.must_equal s(:attrasgn,
888
+ s(:call, nil, :foo, s(:arglist)),
889
+ :bar=,
890
+ s(:arglist, s(:call, nil, :baz, s(:arglist))))
891
+ end
892
+
893
+ it "works when assigning to a class variable" do
894
+ result = parser.parse "@@foo = bar"
895
+ result.must_equal s(:cvdecl,
896
+ :@@foo,
897
+ s(:call, nil, :bar, s(:arglist)))
898
+ end
899
+
900
+ it "works when assigning to a global variable" do
901
+ result = parser.parse "$foo = bar"
902
+ result.must_equal s(:gasgn,
903
+ :$foo,
904
+ s(:call, nil, :bar, s(:arglist)))
905
+ end
499
906
  end
500
907
 
501
908
  describe "for operator assignment" do
502
909
  it "works with +=" do
503
- result = parser.parse "foo += bar"
910
+ result = suppress_warnings { parser.parse "foo += bar" }
504
911
  result.must_equal s(:lasgn,
505
912
  :foo,
506
913
  s(:call,
@@ -510,7 +917,7 @@ describe RipperRubyParser::Parser do
510
917
  end
511
918
 
512
919
  it "works with -=" do
513
- result = parser.parse "foo -= bar"
920
+ result = suppress_warnings { parser.parse "foo -= bar" }
514
921
  result.must_equal s(:lasgn,
515
922
  :foo,
516
923
  s(:call,
@@ -519,6 +926,14 @@ describe RipperRubyParser::Parser do
519
926
  s(:arglist, s(:call, nil, :bar, s(:arglist)))))
520
927
  end
521
928
 
929
+ it "works with ||=" do
930
+ result = suppress_warnings { parser.parse "foo ||= bar" }
931
+ result.must_equal s(:op_asgn_or,
932
+ s(:lvar, :foo),
933
+ s(:lasgn, :foo,
934
+ s(:call, nil, :bar, s(:arglist))))
935
+ end
936
+
522
937
  it "works when assigning to an instance variable" do
523
938
  result = parser.parse "@foo += bar"
524
939
  result.must_equal s(:iasgn,
@@ -537,11 +952,38 @@ describe RipperRubyParser::Parser do
537
952
  :+,
538
953
  s(:call, nil, :baz, s(:arglist)))
539
954
  end
955
+
956
+ it "works with ||= when assigning to a collection element" do
957
+ result = parser.parse "foo[bar] ||= baz"
958
+ result.must_equal s(:op_asgn1,
959
+ s(:call, nil, :foo, s(:arglist)),
960
+ s(:arglist, s(:call, nil, :bar, s(:arglist))),
961
+ :"||",
962
+ s(:call, nil, :baz, s(:arglist)))
963
+ end
964
+
965
+ it "works when assigning to an attribute" do
966
+ result = parser.parse "foo.bar += baz"
967
+ result.must_equal s(:op_asgn2,
968
+ s(:call, nil, :foo, s(:arglist)),
969
+ :bar=,
970
+ :+,
971
+ s(:call, nil, :baz, s(:arglist)))
972
+ end
973
+
974
+ it "works with ||= when assigning to an attribute" do
975
+ result = parser.parse "foo.bar ||= baz"
976
+ result.must_equal s(:op_asgn2,
977
+ s(:call, nil, :foo, s(:arglist)),
978
+ :bar=,
979
+ :"||",
980
+ s(:call, nil, :baz, s(:arglist)))
981
+ end
540
982
  end
541
983
 
542
984
  describe "for multiple assignment" do
543
985
  it "works the same number of items on each side" do
544
- result = parser.parse "foo, bar = baz, qux"
986
+ result = suppress_warnings { parser.parse "foo, bar = baz, qux" }
545
987
  result.must_equal s(:masgn,
546
988
  s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
547
989
  s(:array,
@@ -550,7 +992,7 @@ describe RipperRubyParser::Parser do
550
992
  end
551
993
 
552
994
  it "works with a single item on the right-hand side" do
553
- result = parser.parse "foo, bar = baz"
995
+ result = suppress_warnings { parser.parse "foo, bar = baz" }
554
996
  result.must_equal s(:masgn,
555
997
  s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
556
998
  s(:to_ary,
@@ -558,16 +1000,117 @@ describe RipperRubyParser::Parser do
558
1000
  end
559
1001
 
560
1002
  it "works with left-hand splat" do
561
- result = parser.parse "foo, *bar = baz, qux"
1003
+ result = suppress_warnings { parser.parse "foo, *bar = baz, qux" }
562
1004
  result.must_equal s(:masgn,
563
1005
  s(:array, s(:lasgn, :foo), s(:splat, s(:lasgn, :bar))),
564
1006
  s(:array,
565
1007
  s(:call, nil, :baz, s(:arglist)),
566
1008
  s(:call, nil, :qux, s(:arglist))))
567
1009
  end
1010
+
1011
+ it "works with brackets around the left-hand side" do
1012
+ result = suppress_warnings { parser.parse "(foo, bar) = baz" }
1013
+ result.must_equal s(:masgn,
1014
+ s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
1015
+ s(:to_ary,
1016
+ s(:call, nil, :baz, s(:arglist))))
1017
+ end
1018
+
1019
+ it "works with complex destructuring" do
1020
+ result = suppress_warnings { parser.parse "foo, (bar, baz) = qux" }
1021
+ result.must_equal s(:masgn,
1022
+ s(:array,
1023
+ s(:lasgn, :foo),
1024
+ s(:masgn,
1025
+ s(:array,
1026
+ s(:lasgn, :bar),
1027
+ s(:lasgn, :baz)))),
1028
+ s(:to_ary,
1029
+ s(:call, nil, :qux, s(:arglist))))
1030
+ end
1031
+
1032
+ it "works with instance variables" do
1033
+ result = parser.parse "@foo, @bar = baz"
1034
+ result.must_equal s(:masgn,
1035
+ s(:array, s(:iasgn, :@foo), s(:iasgn, :@bar)),
1036
+ s(:to_ary,
1037
+ s(:call, nil, :baz, s(:arglist))))
1038
+ end
1039
+
1040
+ it "works with class variables" do
1041
+ result = parser.parse "@@foo, @@bar = baz"
1042
+ result.must_equal s(:masgn,
1043
+ s(:array, s(:cvdecl, :@@foo), s(:cvdecl, :@@bar)),
1044
+ s(:to_ary,
1045
+ s(:call, nil, :baz, s(:arglist))))
1046
+ end
1047
+
1048
+ it "works with attributes" do
1049
+ result = parser.parse "foo.bar, foo.baz = qux"
1050
+ result.must_equal s(:masgn,
1051
+ s(:array,
1052
+ s(:attrasgn,
1053
+ s(:call, nil, :foo, s(:arglist)),
1054
+ :bar=,
1055
+ s(:arglist)),
1056
+ s(:attrasgn,
1057
+ s(:call, nil, :foo, s(:arglist)),
1058
+ :baz=,
1059
+ s(:arglist))),
1060
+ s(:to_ary,
1061
+ s(:call, nil, :qux, s(:arglist))))
1062
+ end
1063
+
1064
+ it "works with collection elements" do
1065
+ result = parser.parse "foo[1], bar[2] = baz"
1066
+ result.must_equal s(:masgn,
1067
+ s(:array,
1068
+ s(:attrasgn,
1069
+ s(:call, nil, :foo, s(:arglist)),
1070
+ :[]=,
1071
+ s(:arglist, s(:lit, 1))),
1072
+ s(:attrasgn,
1073
+ s(:call, nil, :bar, s(:arglist)),
1074
+ :[]=,
1075
+ s(:arglist, s(:lit, 2)))),
1076
+ s(:to_ary, s(:call, nil, :baz, s(:arglist))))
1077
+ end
1078
+
1079
+ it "works with constants" do
1080
+ result = parser.parse "Foo, Bar = baz"
1081
+ result.must_equal s(:masgn,
1082
+ s(:array, s(:cdecl, :Foo), s(:cdecl, :Bar)),
1083
+ s(:to_ary,
1084
+ s(:call, nil, :baz, s(:arglist))))
1085
+ end
1086
+
1087
+ it "works with instance variables and splat" do
1088
+ result = parser.parse "@foo, *@bar = baz"
1089
+ result.must_equal s(:masgn,
1090
+ s(:array,
1091
+ s(:iasgn, :@foo),
1092
+ s(:splat, s(:iasgn, :@bar))),
1093
+ s(:to_ary,
1094
+ s(:call, nil, :baz, s(:arglist))))
1095
+ end
1096
+
568
1097
  end
569
1098
 
570
1099
  describe "for operators" do
1100
+ it "handles :and" do
1101
+ result = parser.parse "foo and bar"
1102
+ result.must_equal s(:and,
1103
+ s(:call, nil, :foo, s(:arglist)),
1104
+ s(:call, nil, :bar, s(:arglist)))
1105
+ end
1106
+
1107
+ it "handles :or" do
1108
+ result = parser.parse "foo or bar"
1109
+ result.must_equal s(:or,
1110
+ s(:call, nil, :foo, s(:arglist)),
1111
+ s(:call, nil, :bar, s(:arglist)))
1112
+ end
1113
+
571
1114
  it "converts :&& to :and" do
572
1115
  result = parser.parse "foo && bar"
573
1116
  result.must_equal s(:and,
@@ -582,6 +1125,38 @@ describe RipperRubyParser::Parser do
582
1125
  s(:call, nil, :bar, s(:arglist)))
583
1126
  end
584
1127
 
1128
+ it "handles :!=" do
1129
+ result = parser.parse "foo != bar"
1130
+ result.must_equal s(:not,
1131
+ s(:call,
1132
+ s(:call, nil, :foo, s(:arglist)),
1133
+ :==,
1134
+ s(:arglist,
1135
+ s(:call, nil, :bar, s(:arglist)))))
1136
+ end
1137
+
1138
+ it "handles :=~ with two non-literals" do
1139
+ result = parser.parse "foo =~ bar"
1140
+ result.must_equal s(:call,
1141
+ s(:call, nil, :foo, s(:arglist)),
1142
+ :=~,
1143
+ s(:arglist, s(:call, nil, :bar, s(:arglist))))
1144
+ end
1145
+
1146
+ it "handles :=~ with literal regexp on the left hand side" do
1147
+ result = parser.parse "/foo/ =~ bar"
1148
+ result.must_equal s(:match2,
1149
+ s(:lit, /foo/),
1150
+ s(:call, nil, :bar, s(:arglist)))
1151
+ end
1152
+
1153
+ it "handles :=~ with literal regexp on the right hand side" do
1154
+ result = parser.parse "foo =~ /bar/"
1155
+ result.must_equal s(:match3,
1156
+ s(:lit, /bar/),
1157
+ s(:call, nil, :foo, s(:arglist)))
1158
+ end
1159
+
585
1160
  it "handles unary minus with a number literal" do
586
1161
  result = parser.parse "-1"
587
1162
  result.must_equal s(:lit, -1)
@@ -595,6 +1170,29 @@ describe RipperRubyParser::Parser do
595
1170
  s(:arglist))
596
1171
  end
597
1172
 
1173
+ it "handles unary plus with a number literal" do
1174
+ result = parser.parse "+ 1"
1175
+ result.must_equal s(:lit, 1)
1176
+ end
1177
+
1178
+ it "handles unary plus with a non-literal" do
1179
+ result = parser.parse "+ foo"
1180
+ result.must_equal s(:call,
1181
+ s(:call, nil, :foo, s(:arglist)),
1182
+ :+@,
1183
+ s(:arglist))
1184
+ end
1185
+
1186
+ it "handles unary not" do
1187
+ result = parser.parse "not foo"
1188
+ result.must_equal s(:not, s(:call, nil, :foo, s(:arglist)))
1189
+ end
1190
+
1191
+ it "converts :! to :not" do
1192
+ result = parser.parse "!foo"
1193
+ result.must_equal s(:not, s(:call, nil, :foo, s(:arglist)))
1194
+ end
1195
+
598
1196
  it "handles the range operator with positive number literals" do
599
1197
  result = parser.parse "1..2"
600
1198
  result.must_equal s(:lit, 1..2)
@@ -618,6 +1216,203 @@ describe RipperRubyParser::Parser do
618
1216
  s(:call, nil, :foo, s(:arglist)),
619
1217
  s(:call, nil, :bar, s(:arglist)))
620
1218
  end
1219
+
1220
+ it "handles the ternary operator" do
1221
+ result = parser.parse "foo ? bar : baz"
1222
+ result.must_equal s(:if,
1223
+ s(:call, nil, :foo, s(:arglist)),
1224
+ s(:call, nil, :bar, s(:arglist)),
1225
+ s(:call, nil, :baz, s(:arglist)))
1226
+ end
1227
+ end
1228
+
1229
+ describe "for expressions" do
1230
+ it "handles assignment inside binary operator expressions" do
1231
+ result = suppress_warnings { parser.parse "foo + (bar = baz)" }
1232
+ result.must_equal s(:call,
1233
+ s(:call, nil, :foo, s(:arglist)),
1234
+ :+,
1235
+ s(:arglist,
1236
+ s(:lasgn,
1237
+ :bar,
1238
+ s(:call, nil, :baz, s(:arglist)))))
1239
+ end
1240
+
1241
+ it "handles assignment inside unary operator expressions" do
1242
+ result = suppress_warnings { parser.parse "+(foo = bar)" }
1243
+ result.must_equal s(:call,
1244
+ s(:lasgn, :foo, s(:call, nil, :bar, s(:arglist))),
1245
+ :+@,
1246
+ s(:arglist))
1247
+ end
1248
+ end
1249
+
1250
+ # Note: differences in the handling of comments are not caught by Sexp's
1251
+ # implementation of equality.
1252
+ describe "for comments" do
1253
+ it "handles method comments" do
1254
+ result = parser.parse "# Foo\ndef foo; end"
1255
+ result.must_equal s(:defn,
1256
+ :foo,
1257
+ s(:args), s(:scope, s(:block, s(:nil))))
1258
+ result.comments.must_equal "# Foo\n"
1259
+ end
1260
+
1261
+ it "matches comments to the correct entity" do
1262
+ result = parser.parse "# Foo\nclass Foo\n# Bar\ndef bar\nend\nend"
1263
+ result.must_equal s(:class, :Foo, nil,
1264
+ s(:scope,
1265
+ s(:defn, :bar,
1266
+ s(:args), s(:scope, s(:block, s(:nil))))))
1267
+ result.comments.must_equal "# Foo\n"
1268
+ defn = result[3][1]
1269
+ defn.sexp_type.must_equal :defn
1270
+ defn.comments.must_equal "# Bar\n"
1271
+ end
1272
+
1273
+ it "combines multi-line comments" do
1274
+ result = parser.parse "# Foo\n# Bar\ndef foo; end"
1275
+ result.must_equal s(:defn,
1276
+ :foo,
1277
+ s(:args), s(:scope, s(:block, s(:nil))))
1278
+ result.comments.must_equal "# Foo\n# Bar\n"
1279
+ end
1280
+ end
1281
+
1282
+ # Note: differences in the handling of line numbers are not caught by
1283
+ # Sexp's implementation of equality.
1284
+ describe "assigning line numbers" do
1285
+ it "works for a plain method call" do
1286
+ result = parser.parse "foo"
1287
+ result.line.must_equal 1
1288
+ end
1289
+
1290
+ it "works for a method call with brackets" do
1291
+ result = parser.parse "foo()"
1292
+ result.line.must_equal 1
1293
+ end
1294
+
1295
+ it "works for a method call with reciever" do
1296
+ result = parser.parse "foo.bar"
1297
+ result.line.must_equal 1
1298
+ end
1299
+
1300
+ it "works for a method call with reciever and arguments" do
1301
+ result = parser.parse "foo.bar baz"
1302
+ result.line.must_equal 1
1303
+ end
1304
+
1305
+ it "works for a method call with arguments" do
1306
+ result = parser.parse "foo bar"
1307
+ result.line.must_equal 1
1308
+ end
1309
+
1310
+ it "works for a block with two lines" do
1311
+ result = parser.parse "foo\nbar\n"
1312
+ result.sexp_type.must_equal :block
1313
+ result[1].line.must_equal 1
1314
+ result[2].line.must_equal 2
1315
+ result.line.must_equal 1
1316
+ end
1317
+
1318
+ it "works for a constant reference" do
1319
+ result = parser.parse "Foo"
1320
+ result.line.must_equal 1
1321
+ end
1322
+
1323
+ it "works for an instance variable" do
1324
+ result = parser.parse "@foo"
1325
+ result.line.must_equal 1
1326
+ end
1327
+
1328
+ it "works for a global variable" do
1329
+ result = parser.parse "$foo"
1330
+ result.line.must_equal 1
1331
+ end
1332
+
1333
+ it "works for a class variable" do
1334
+ result = parser.parse "@@foo"
1335
+ result.line.must_equal 1
1336
+ end
1337
+
1338
+ it "works for a local variable" do
1339
+ result = parser.parse "foo = bar\nfoo\n"
1340
+ result.sexp_type.must_equal :block
1341
+ result[1].line.must_equal 1
1342
+ result[2].line.must_equal 2
1343
+ result.line.must_equal 1
1344
+ end
1345
+
1346
+ it "works for an integer literal" do
1347
+ result = parser.parse "42"
1348
+ result.line.must_equal 1
1349
+ end
1350
+
1351
+ it "works for a float literal" do
1352
+ result = parser.parse "3.14"
1353
+ result.line.must_equal 1
1354
+ end
1355
+
1356
+ it "works for a regular expression back reference" do
1357
+ result = parser.parse "$1"
1358
+ result.line.must_equal 1
1359
+ end
1360
+
1361
+ it "works for self" do
1362
+ result = parser.parse "self"
1363
+ result.line.must_equal 1
1364
+ end
1365
+
1366
+ it "works for __FILE__" do
1367
+ result = parser.parse "__FILE__"
1368
+ result.line.must_equal 1
1369
+ end
1370
+
1371
+ it "works for nil" do
1372
+ result = parser.parse "nil"
1373
+ result.line.must_equal 1
1374
+ end
1375
+
1376
+ it "works for a symbol literal" do
1377
+ result = parser.parse ":foo"
1378
+ result.line.must_equal 1
1379
+ end
1380
+
1381
+ it "works for a class definition" do
1382
+ result = parser.parse "class Foo; end"
1383
+ result.line.must_equal 1
1384
+ end
1385
+
1386
+ it "works for a module definition" do
1387
+ result = parser.parse "module Foo; end"
1388
+ result.line.must_equal 1
1389
+ end
1390
+
1391
+ it "works for a method definition" do
1392
+ result = parser.parse "def foo; end"
1393
+ result.line.must_equal 1
1394
+ end
1395
+
1396
+ it "works for assignment of the empty hash" do
1397
+ result = suppress_warnings { parser.parse "foo = {}" }
1398
+ result.line.must_equal 1
1399
+ end
1400
+
1401
+ it "works for multiple assignment of empty hashes" do
1402
+ result = suppress_warnings { parser.parse "foo, bar = {}, {}" }
1403
+ result.line.must_equal 1
1404
+ end
1405
+
1406
+ it "assigns line numbers to all nested sexps" do
1407
+ result = parser.parse "foo() do\nend\n"
1408
+ result.must_equal s(:iter,
1409
+ s(:call,
1410
+ nil, :foo, s(:arglist)), nil, s(:block))
1411
+ arglist = result[1][3]
1412
+ block = result[3]
1413
+ nums = [ arglist.line, block.line ]
1414
+ nums.must_equal [1, 1]
1415
+ end
621
1416
  end
622
1417
  end
623
1418
  end