ripper_ruby_parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,623 @@
1
+ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
+
3
+ describe RipperRubyParser::Parser do
4
+ let(:parser) { RipperRubyParser::Parser.new }
5
+ describe "#parse" do
6
+ it "returns an s-expression" do
7
+ result = parser.parse "foo"
8
+ result.must_be_instance_of Sexp
9
+ end
10
+
11
+ it "post-processes its result with the passed sexp processor" do
12
+ sexp_p = MiniTest::Mock.new
13
+ sexp_p.expect :process, s(:result), [Sexp]
14
+
15
+ parser = RipperRubyParser::Parser.new sexp_p
16
+ result = parser.parse "any code"
17
+
18
+ result.must_equal s(:result)
19
+ sexp_p.verify
20
+ end
21
+
22
+ describe "for if" do
23
+ it "works in the postfix case" do
24
+ result = parser.parse "foo if bar"
25
+ result.must_equal s(:if,
26
+ s(:call, nil, :bar, s(:arglist)),
27
+ s(:call, nil, :foo, s(:arglist)),
28
+ nil)
29
+ end
30
+
31
+ it "works with an else clause" do
32
+ result = parser.parse "if foo; bar; else; baz; end"
33
+ result.must_equal s(:if,
34
+ s(:call, nil, :foo, s(:arglist)),
35
+ s(:call, nil, :bar, s(:arglist)),
36
+ s(:call, nil, :baz, s(:arglist)))
37
+ end
38
+
39
+ it "works with an elsif clause" do
40
+ result = parser.parse "if foo; bar; elsif baz; qux; end"
41
+ result.must_equal s(:if,
42
+ s(:call, nil, :foo, s(:arglist)),
43
+ s(:call, nil, :bar, s(:arglist)),
44
+ s(:if,
45
+ s(:call, nil, :baz, s(:arglist)),
46
+ s(:call, nil, :qux, s(:arglist)),
47
+ nil))
48
+ end
49
+ end
50
+
51
+ describe "for unless" do
52
+ it "works in the postfix case" do
53
+ result = parser.parse "foo unless bar"
54
+ result.must_equal s(:if,
55
+ s(:call, nil, :bar, s(:arglist)),
56
+ nil,
57
+ s(:call, nil, :foo, s(:arglist)))
58
+ end
59
+
60
+ it "works in the block case" do
61
+ result = parser.parse "unless bar; foo; end"
62
+ result.must_equal s(:if,
63
+ s(:call, nil, :bar, s(:arglist)),
64
+ nil,
65
+ s(:call, nil, :foo, s(:arglist)))
66
+ end
67
+
68
+ it "works with an else clause" do
69
+ result = parser.parse "unless foo; bar; else; baz; end"
70
+ result.must_equal s(:if,
71
+ s(:call, nil, :foo, s(:arglist)),
72
+ s(:call, nil, :baz, s(:arglist)),
73
+ s(:call, nil, :bar, s(:arglist)))
74
+ end
75
+ end
76
+
77
+ describe "for a case block" do
78
+ it "works with a single when clause" do
79
+ result = parser.parse "case foo; when bar; baz; end"
80
+ result.must_equal s(:case,
81
+ s(:call, nil, :foo, s(:arglist)),
82
+ s(:when,
83
+ s(:array, s(:call, nil, :bar, s(:arglist))),
84
+ s(:call, nil, :baz, s(:arglist))),
85
+ nil)
86
+ end
87
+
88
+ it "works with multiple when clauses" do
89
+ result = parser.parse "case foo; when bar; baz; when qux; quux; end"
90
+ result.must_equal s(:case,
91
+ s(:call, nil, :foo, s(:arglist)),
92
+ s(:when,
93
+ s(:array, s(:call, nil, :bar, s(:arglist))),
94
+ s(:call, nil, :baz, s(:arglist))),
95
+ s(:when,
96
+ s(:array, s(:call, nil, :qux, s(:arglist))),
97
+ s(:call, nil, :quux, s(:arglist))),
98
+ nil)
99
+ end
100
+
101
+ it "works with multiple statements in the when block" do
102
+ result = parser.parse "case foo; when bar; baz; qux; end"
103
+ result.must_equal s(:case,
104
+ s(:call, nil, :foo, s(:arglist)),
105
+ s(:when,
106
+ s(:array, s(:call, nil, :bar, s(:arglist))),
107
+ s(:block,
108
+ s(:call, nil, :baz, s(:arglist)),
109
+ s(:call, nil, :qux, s(:arglist)))),
110
+ nil)
111
+ end
112
+
113
+ it "works with an else clause" do
114
+ result = parser.parse "case foo; when bar; baz; else; qux; end"
115
+ result.must_equal s(:case,
116
+ s(:call, nil, :foo, s(:arglist)),
117
+ s(:when,
118
+ s(:array, s(:call, nil, :bar, s(:arglist))),
119
+ s(:call, nil, :baz, s(:arglist))),
120
+ s(:call, nil, :qux, s(:arglist)))
121
+ end
122
+ end
123
+
124
+ describe "for the return statement" do
125
+ it "works with no arguments" do
126
+ result = parser.parse "return"
127
+ result.must_equal s(:return)
128
+ end
129
+
130
+ it "works with one argument" do
131
+ result = parser.parse "return foo"
132
+ result.must_equal s(:return,
133
+ s(:call, nil, :foo, s(:arglist)))
134
+ end
135
+ end
136
+
137
+ describe "for the until statement" do
138
+ it "works with do" do
139
+ result = parser.parse "until foo do; bar; end"
140
+ result.must_equal s(:until,
141
+ s(:call, nil, :foo, s(:arglist)),
142
+ s(:call, nil, :bar, s(:arglist)), true)
143
+ end
144
+
145
+ it "works without do" do
146
+ result = parser.parse "until foo; bar; end"
147
+ result.must_equal s(:until,
148
+ s(:call, nil, :foo, s(:arglist)),
149
+ s(:call, nil, :bar, s(:arglist)), true)
150
+ end
151
+ end
152
+
153
+ describe "for identifiers" do
154
+ it "works for an ivar" do
155
+ result = parser.parse "@foo"
156
+ result.must_equal s(:ivar, :@foo)
157
+ end
158
+
159
+ it "works for self" do
160
+ result = parser.parse "self"
161
+ result.must_equal s(:self)
162
+ end
163
+ end
164
+
165
+ describe "for arguments" do
166
+ it "works for a simple case with splat" do
167
+ result = parser.parse "foo *bar"
168
+ result.must_equal s(:call,
169
+ nil,
170
+ :foo,
171
+ s(:arglist,
172
+ s(:splat, s(:call, nil, :bar, s(:arglist)))))
173
+ end
174
+
175
+ it "works for a multi-argument case with splat" do
176
+ result = parser.parse "foo bar, *baz"
177
+ result.must_equal s(:call,
178
+ nil,
179
+ :foo,
180
+ s(:arglist,
181
+ s(:call, nil, :bar, s(:arglist)),
182
+ s(:splat, s(:call, nil, :baz, s(:arglist)))))
183
+ end
184
+ end
185
+
186
+ describe "for array literals" do
187
+ it "works for an empty array" do
188
+ result = parser.parse "[]"
189
+ result.must_equal s(:array)
190
+ end
191
+
192
+ it "works for a simple case with splat" do
193
+ result = parser.parse "[*foo]"
194
+ result.must_equal s(:array,
195
+ s(:splat, s(:call, nil, :foo, s(:arglist))))
196
+ end
197
+
198
+ it "works for a multi-element case with splat" do
199
+ result = parser.parse "[foo, *bar]"
200
+ result.must_equal s(:array,
201
+ s(:call, nil, :foo, s(:arglist)),
202
+ s(:splat, s(:call, nil, :bar, s(:arglist))))
203
+ end
204
+ end
205
+
206
+ describe "for hash literals" do
207
+ it "works for an empty hash" do
208
+ result = parser.parse "{}"
209
+ result.must_equal s(:hash)
210
+ end
211
+
212
+ it "works for a hash with one pair" do
213
+ result = parser.parse "{foo => bar}"
214
+ result.must_equal s(:hash,
215
+ s(:call, nil, :foo, s(:arglist)),
216
+ s(:call, nil, :bar, s(:arglist)))
217
+ end
218
+
219
+ it "works for a hash with multiple pairs" do
220
+ result = parser.parse "{foo => bar, baz => qux}"
221
+ result.must_equal s(:hash,
222
+ s(:call, nil, :foo, s(:arglist)),
223
+ s(:call, nil, :bar, s(:arglist)),
224
+ s(:call, nil, :baz, s(:arglist)),
225
+ s(:call, nil, :qux, s(:arglist)))
226
+ end
227
+ end
228
+
229
+ describe "for collection indexing" do
230
+ it "works in the simple case" do
231
+ result = parser.parse "foo[bar]"
232
+ result.must_equal s(:call,
233
+ s(:call, nil, :foo, s(:arglist)),
234
+ :[],
235
+ s(:arglist, s(:call, nil, :bar, s(:arglist))))
236
+ end
237
+ end
238
+
239
+ describe "for method definitions" do
240
+ it "works with def with reciever" do
241
+ result = parser.parse "def foo.bar; end"
242
+ result.must_equal s(:defs,
243
+ s(:call, nil, :foo, s(:arglist)),
244
+ :bar,
245
+ s(:args),
246
+ s(:scope, s(:block)))
247
+ end
248
+
249
+ it "works with a method argument with a default value" do
250
+ result = parser.parse "def foo bar=nil; end"
251
+ result.must_equal s(:defn,
252
+ :foo,
253
+ s(:args, :bar, s(:block, s(:lasgn, :bar, s(:nil)))),
254
+ s(:scope, s(:block, s(:nil))))
255
+ end
256
+
257
+ it "works with several method arguments with default values" do
258
+ result = parser.parse "def foo bar=1, baz=2; end"
259
+ result.must_equal s(:defn,
260
+ :foo,
261
+ s(:args,
262
+ :bar, :baz,
263
+ s(:block,
264
+ s(:lasgn, :bar, s(:lit, 1)),
265
+ s(:lasgn, :baz, s(:lit, 2)))),
266
+ s(:scope, s(:block, s(:nil))))
267
+ end
268
+
269
+ it "works with brackets around the parameter list" do
270
+ result = parser.parse "def foo(bar); end"
271
+ result.must_equal s(:defn,
272
+ :foo,
273
+ s(:args, :bar),
274
+ s(:scope, s(:block, s(:nil))))
275
+ end
276
+ end
277
+
278
+ describe "for method calls" do
279
+ describe "without a reciever" do
280
+ it "works without brackets" do
281
+ result = parser.parse "foo bar"
282
+ result.must_equal s(:call, nil, :foo,
283
+ s(:arglist, s(:call, nil, :bar, s(:arglist))))
284
+ end
285
+
286
+ it "works with brackets" do
287
+ result = parser.parse "foo(bar)"
288
+ result.must_equal s(:call, nil, :foo,
289
+ s(:arglist, s(:call, nil, :bar, s(:arglist))))
290
+ end
291
+
292
+ it "works with brackets around an empty parameter list" do
293
+ result = parser.parse "foo()"
294
+ result.must_equal s(:call, nil, :foo, s(:arglist))
295
+ end
296
+ end
297
+
298
+ describe "with a reciever" do
299
+ it "works without brackets" do
300
+ result = parser.parse "foo.bar baz"
301
+ result.must_equal s(:call,
302
+ s(:call, nil, :foo, s(:arglist)),
303
+ :bar,
304
+ s(:arglist, s(:call, nil, :baz, s(:arglist))))
305
+ end
306
+
307
+ it "works with brackets" do
308
+ result = parser.parse "foo.bar(baz)"
309
+ result.must_equal s(:call,
310
+ s(:call, nil, :foo, s(:arglist)),
311
+ :bar,
312
+ s(:arglist, s(:call, nil, :baz, s(:arglist))))
313
+ end
314
+
315
+ it "works with brackets around a call with no brackets" do
316
+ result = parser.parse "foo.bar(baz qux)"
317
+ result.must_equal s(:call,
318
+ s(:call, nil, :foo, s(:arglist)),
319
+ :bar,
320
+ s(:arglist,
321
+ s(:call, nil, :baz,
322
+ s(:arglist,
323
+ s(:call, nil, :qux, s(:arglist))))))
324
+ end
325
+ end
326
+
327
+ describe "with blocks" do
328
+ it "works for a do block" do
329
+ result = parser.parse "foo.bar do baz; end"
330
+ result.must_equal s(:iter,
331
+ s(:call,
332
+ s(:call, nil, :foo, s(:arglist)),
333
+ :bar,
334
+ s(:arglist)),
335
+ nil,
336
+ s(:call, nil, :baz, s(:arglist)))
337
+ end
338
+
339
+ it "works for a do block with several statements" do
340
+ result = parser.parse "foo.bar do baz; qux; end"
341
+ result.must_equal s(:iter,
342
+ s(:call,
343
+ s(:call, nil, :foo, s(:arglist)),
344
+ :bar,
345
+ s(:arglist)),
346
+ nil,
347
+ s(:block,
348
+ s(:call, nil, :baz, s(:arglist)),
349
+ s(:call, nil, :qux, s(:arglist))))
350
+ end
351
+ end
352
+ end
353
+
354
+ describe "for literals" do
355
+ it "works for symbols" do
356
+ result = parser.parse ":foo"
357
+ result.must_equal s(:lit, :foo)
358
+ end
359
+
360
+ it "works for symbols that look like instance variable names" do
361
+ result = parser.parse ":@foo"
362
+ result.must_equal s(:lit, :@foo)
363
+ end
364
+
365
+ it "works for empty strings" do
366
+ result = parser.parse "''"
367
+ result.must_equal s(:str, "")
368
+ end
369
+
370
+ it "works for strings with escape sequences" do
371
+ result = parser.parse "\"\\n\""
372
+ result.must_equal s(:str, "\n")
373
+ end
374
+
375
+ it "works for strings with escaped backslashes" do
376
+ result = parser.parse "\"\\\\n\""
377
+ result.must_equal s(:str, "\\n")
378
+ end
379
+
380
+ it "works for a double-quoted string representing a regex literal with escaped right bracket" do
381
+ result = parser.parse "\"/\\)/\""
382
+ result.must_equal s(:str, "/\\)/")
383
+ end
384
+
385
+ it "works for a single-quoted string representing a regex literal with escaped right bracket" do
386
+ result = parser.parse "'/\\)/'"
387
+ result.must_equal s(:str, "/\\)/")
388
+ end
389
+
390
+ it "works for a string containing escaped quotes" do
391
+ result = parser.parse "\"\\\"\""
392
+ result.must_equal s(:str, "\"")
393
+ end
394
+
395
+ it "works for trivial interpolated strings" do
396
+ result = parser.parse '"#{foo}"'
397
+ result.must_equal s(:dstr,
398
+ "",
399
+ s(:evstr,
400
+ s(:call, nil, :foo, s(:arglist))))
401
+ end
402
+
403
+ it "works for basic interpolated strings" do
404
+ result = parser.parse '"foo#{bar}"'
405
+ result.must_equal s(:dstr,
406
+ "foo",
407
+ s(:evstr,
408
+ s(:call, nil, :bar, s(:arglist))))
409
+ end
410
+
411
+ it "works for strings with several interpolations" do
412
+ result = parser.parse '"foo#{bar}baz#{qux}"'
413
+ result.must_equal s(:dstr,
414
+ "foo",
415
+ s(:evstr, s(:call, nil, :bar, s(:arglist))),
416
+ s(:str, "baz"),
417
+ s(:evstr, s(:call, nil, :qux, s(:arglist))))
418
+ end
419
+
420
+ it "works for strings with interpolations followed by escape sequences" do
421
+ result = parser.parse '"#{foo}\\n"'
422
+ result.must_equal s(:dstr,
423
+ "",
424
+ s(:evstr, s(:call, nil, :foo, s(:arglist))),
425
+ s(:str, "\n"))
426
+ end
427
+
428
+ it "works for a simple regex literal" do
429
+ result = parser.parse "/foo/"
430
+ result.must_equal s(:lit, /foo/)
431
+ end
432
+
433
+ it "works for regex literals with escaped right bracket" do
434
+ result = parser.parse '/\\)/'
435
+ result.must_equal s(:lit, /\)/)
436
+ end
437
+
438
+ it "works for regex literals with escape sequences" do
439
+ result = parser.parse '/\\)\\n\\\\/'
440
+ result.must_equal s(:lit, /\)\n\\/)
441
+ end
442
+
443
+ it "works for symbols created by prefixing a simple string with :" do
444
+ result = parser.parse ':"foo"'
445
+ result.must_equal s(:lit, :foo)
446
+ end
447
+ end
448
+
449
+ describe "for the __FILE__ keyword" do
450
+ it "creates a string sexp with value '(string)'" do
451
+ result = parser.parse "__FILE__"
452
+ result.must_equal s(:str, "(string)")
453
+ end
454
+ end
455
+
456
+ describe "for constant references" do
457
+ it "works when explicitely starting from the root namespace" do
458
+ result = parser.parse "::Foo"
459
+ result.must_equal s(:colon3, :Foo)
460
+ end
461
+ end
462
+
463
+ describe "for variable references" do
464
+ it "works for global variables" do
465
+ result = parser.parse "$foo"
466
+ result.must_equal s(:gvar, :$foo)
467
+ end
468
+
469
+ it "works for regexp match references" do
470
+ result = parser.parse "$1"
471
+ result.must_equal s(:nth_ref, 1)
472
+ end
473
+ end
474
+
475
+ describe "for single assignment" do
476
+ it "works when assigning to an instance variable" do
477
+ result = parser.parse "@foo = bar"
478
+ result.must_equal s(:iasgn,
479
+ :@foo,
480
+ s(:call, nil, :bar, s(:arglist)))
481
+ end
482
+
483
+ it "works when assigning to a constant" do
484
+ result = parser.parse "FOO = bar"
485
+ result.must_equal s(:cdecl,
486
+ :FOO,
487
+ s(:call, nil, :bar, s(:arglist)))
488
+ end
489
+
490
+ it "works when assigning to a collection element" do
491
+ result = parser.parse "foo[bar] = baz"
492
+ result.must_equal s(:attrasgn,
493
+ s(:call, nil, :foo, s(:arglist)),
494
+ :[]=,
495
+ s(:arglist,
496
+ s(:call, nil, :bar, s(:arglist)),
497
+ s(:call, nil, :baz, s(:arglist))))
498
+ end
499
+ end
500
+
501
+ describe "for operator assignment" do
502
+ it "works with +=" do
503
+ result = parser.parse "foo += bar"
504
+ result.must_equal s(:lasgn,
505
+ :foo,
506
+ s(:call,
507
+ s(:lvar, :foo),
508
+ :+,
509
+ s(:arglist, s(:call, nil, :bar, s(:arglist)))))
510
+ end
511
+
512
+ it "works with -=" do
513
+ result = parser.parse "foo -= bar"
514
+ result.must_equal s(:lasgn,
515
+ :foo,
516
+ s(:call,
517
+ s(:lvar, :foo),
518
+ :-,
519
+ s(:arglist, s(:call, nil, :bar, s(:arglist)))))
520
+ end
521
+
522
+ it "works when assigning to an instance variable" do
523
+ result = parser.parse "@foo += bar"
524
+ result.must_equal s(:iasgn,
525
+ :@foo,
526
+ s(:call,
527
+ s(:ivar, :@foo),
528
+ :+,
529
+ s(:arglist, s(:call, nil, :bar, s(:arglist)))))
530
+ end
531
+
532
+ it "works when assigning to a collection element" do
533
+ result = parser.parse "foo[bar] += baz"
534
+ result.must_equal s(:op_asgn1,
535
+ s(:call, nil, :foo, s(:arglist)),
536
+ s(:arglist, s(:call, nil, :bar, s(:arglist))),
537
+ :+,
538
+ s(:call, nil, :baz, s(:arglist)))
539
+ end
540
+ end
541
+
542
+ describe "for multiple assignment" do
543
+ it "works the same number of items on each side" do
544
+ result = parser.parse "foo, bar = baz, qux"
545
+ result.must_equal s(:masgn,
546
+ s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
547
+ s(:array,
548
+ s(:call, nil, :baz, s(:arglist)),
549
+ s(:call, nil, :qux, s(:arglist))))
550
+ end
551
+
552
+ it "works with a single item on the right-hand side" do
553
+ result = parser.parse "foo, bar = baz"
554
+ result.must_equal s(:masgn,
555
+ s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
556
+ s(:to_ary,
557
+ s(:call, nil, :baz, s(:arglist))))
558
+ end
559
+
560
+ it "works with left-hand splat" do
561
+ result = parser.parse "foo, *bar = baz, qux"
562
+ result.must_equal s(:masgn,
563
+ s(:array, s(:lasgn, :foo), s(:splat, s(:lasgn, :bar))),
564
+ s(:array,
565
+ s(:call, nil, :baz, s(:arglist)),
566
+ s(:call, nil, :qux, s(:arglist))))
567
+ end
568
+ end
569
+
570
+ describe "for operators" do
571
+ it "converts :&& to :and" do
572
+ result = parser.parse "foo && bar"
573
+ result.must_equal s(:and,
574
+ s(:call, nil, :foo, s(:arglist)),
575
+ s(:call, nil, :bar, s(:arglist)))
576
+ end
577
+
578
+ it "converts :|| to :or" do
579
+ result = parser.parse "foo || bar"
580
+ result.must_equal s(:or,
581
+ s(:call, nil, :foo, s(:arglist)),
582
+ s(:call, nil, :bar, s(:arglist)))
583
+ end
584
+
585
+ it "handles unary minus with a number literal" do
586
+ result = parser.parse "-1"
587
+ result.must_equal s(:lit, -1)
588
+ end
589
+
590
+ it "handles unary minus with a non-literal" do
591
+ result = parser.parse "-foo"
592
+ result.must_equal s(:call,
593
+ s(:call, nil, :foo, s(:arglist)),
594
+ :-@,
595
+ s(:arglist))
596
+ end
597
+
598
+ it "handles the range operator with positive number literals" do
599
+ result = parser.parse "1..2"
600
+ result.must_equal s(:lit, 1..2)
601
+ end
602
+
603
+ it "handles the range operator with negative number literals" do
604
+ result = parser.parse "-1..-2"
605
+ result.must_equal s(:lit, -1..-2)
606
+ end
607
+
608
+ it "handles the range operator with string literals" do
609
+ result = parser.parse "'a'..'z'"
610
+ result.must_equal s(:dot2,
611
+ s(:str, "a"),
612
+ s(:str, "z"))
613
+ end
614
+
615
+ it "handles the range operator with non-literals" do
616
+ result = parser.parse "foo..bar"
617
+ result.must_equal s(:dot2,
618
+ s(:call, nil, :foo, s(:arglist)),
619
+ s(:call, nil, :bar, s(:arglist)))
620
+ end
621
+ end
622
+ end
623
+ end