ripper_ruby_parser 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +2 -2
  4. data/Rakefile +1 -1
  5. data/lib/ripper_ruby_parser.rb +0 -7
  6. data/lib/ripper_ruby_parser/commenting_ripper_parser.rb +112 -34
  7. data/lib/ripper_ruby_parser/parser.rb +26 -12
  8. data/lib/ripper_ruby_parser/sexp_handlers.rb +4 -1
  9. data/lib/ripper_ruby_parser/sexp_handlers/arguments.rb +7 -6
  10. data/lib/ripper_ruby_parser/sexp_handlers/arrays.rb +4 -2
  11. data/lib/ripper_ruby_parser/sexp_handlers/assignment.rb +39 -43
  12. data/lib/ripper_ruby_parser/sexp_handlers/blocks.rb +93 -69
  13. data/lib/ripper_ruby_parser/sexp_handlers/conditionals.rb +30 -24
  14. data/lib/ripper_ruby_parser/sexp_handlers/hashes.rb +7 -9
  15. data/lib/ripper_ruby_parser/sexp_handlers/helper_methods.rb +51 -71
  16. data/lib/ripper_ruby_parser/sexp_handlers/literals.rb +72 -56
  17. data/lib/ripper_ruby_parser/sexp_handlers/loops.rb +14 -13
  18. data/lib/ripper_ruby_parser/sexp_handlers/method_calls.rb +19 -13
  19. data/lib/ripper_ruby_parser/sexp_handlers/methods.rb +19 -22
  20. data/lib/ripper_ruby_parser/sexp_handlers/operators.rb +47 -35
  21. data/lib/ripper_ruby_parser/sexp_processor.rb +72 -85
  22. data/lib/ripper_ruby_parser/version.rb +1 -1
  23. data/test/end_to_end/line_numbering_test.rb +1 -1
  24. data/test/end_to_end/samples_comparison_test.rb +0 -1
  25. data/test/pt_testcase/pt_test.rb +4 -6
  26. data/test/{unit → ripper_ruby_parser}/commenting_ripper_parser_test.rb +82 -25
  27. data/test/{unit → ripper_ruby_parser}/parser_test.rb +37 -170
  28. data/test/{unit/parser_assignment_test.rb → ripper_ruby_parser/sexp_handlers/assignment_test.rb} +1 -1
  29. data/test/{unit/parser_blocks_test.rb → ripper_ruby_parser/sexp_handlers/blocks_test.rb} +267 -2
  30. data/test/{unit/parser_conditionals_test.rb → ripper_ruby_parser/sexp_handlers/conditionals_test.rb} +125 -17
  31. data/test/{unit/parser_literals_test.rb → ripper_ruby_parser/sexp_handlers/literals_test.rb} +10 -12
  32. data/test/{unit/parser_loops_test.rb → ripper_ruby_parser/sexp_handlers/loops_test.rb} +1 -1
  33. data/test/{unit/parser_method_calls_test.rb → ripper_ruby_parser/sexp_handlers/method_calls_test.rb} +10 -10
  34. data/test/{unit/parser_operators_test.rb → ripper_ruby_parser/sexp_handlers/operators_test.rb} +22 -2
  35. data/test/{unit → ripper_ruby_parser}/sexp_processor_test.rb +49 -48
  36. data/test/{unit → ripper_ruby_parser}/version_test.rb +0 -0
  37. data/test/samples/misc.rb +4 -0
  38. data/test/test_helper.rb +4 -4
  39. metadata +28 -42
  40. data/test/end_to_end/error_conditions_test.rb +0 -51
@@ -2,7 +2,7 @@ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
2
  require 'ruby_parser'
3
3
 
4
4
  describe 'Using RipperRubyParser and RubyParser' do
5
- def to_line_numbers exp
5
+ def to_line_numbers(exp)
6
6
  exp.map! do |sub_exp|
7
7
  if sub_exp.is_a? Sexp
8
8
  to_line_numbers sub_exp
@@ -21,7 +21,6 @@ describe 'Using RipperRubyParser and RubyParser' do
21
21
  end
22
22
 
23
23
  let :imitation do
24
- newparser.extra_compatible = true
25
24
  newparser.parse program
26
25
  end
27
26
 
@@ -2,7 +2,7 @@ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
2
  require 'pt_testcase'
3
3
 
4
4
  class TestParser < RipperRubyParser::Parser
5
- def process input
5
+ def process(input)
6
6
  parse input
7
7
  end
8
8
  end
@@ -10,11 +10,11 @@ end
10
10
  SKIPPED_TESTS = ['dstr_heredoc_windoze_sucks'].freeze
11
11
 
12
12
  class RubyParserTestCase < ParseTreeTestCase
13
- def self.previous _key
13
+ def self.previous(_key)
14
14
  'Ruby'
15
15
  end
16
16
 
17
- def self.generate_test klass, node, data, input_name, output_name
17
+ def self.generate_test(klass, node, data, input_name, _output_name)
18
18
  if data['Ruby'].is_a? Array
19
19
  klass.send :define_method, "test_#{node}" do
20
20
  skip 'Not a parser test'
@@ -29,9 +29,7 @@ class RubyParserTestCase < ParseTreeTestCase
29
29
  return
30
30
  end
31
31
 
32
- output_name = 'ParseTree'
33
-
34
- super
32
+ super klass, node, data, input_name, 'ParseTree'
35
33
  end
36
34
  end
37
35
 
@@ -1,119 +1,176 @@
1
1
  require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
2
2
 
3
3
  describe RipperRubyParser::CommentingRipperParser do
4
- def parse_with_builder str
4
+ def parse_with_builder(str)
5
5
  builder = RipperRubyParser::CommentingRipperParser.new str
6
6
  builder.parse
7
7
  end
8
8
 
9
9
  def empty_params_list
10
- @empty_params_list ||= begin
11
- num_params = RUBY_VERSION < '2.0.0' ? 5 : 7
12
- s(:params, *([nil] * num_params))
13
- end
10
+ @empty_params_list ||= s(:params, *([nil] * 7))
14
11
  end
15
12
 
16
13
  describe 'handling comments' do
17
14
  it 'produces a comment node surrounding a commented def' do
18
15
  result = parse_with_builder "# Foo\ndef foo; end"
19
16
  result.must_equal s(:program,
20
- s(s(:comment,
17
+ s(:stmts,
18
+ s(:comment,
21
19
  "# Foo\n",
22
20
  s(:def,
23
21
  s(:@ident, 'foo', s(2, 4)),
24
22
  empty_params_list,
25
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
23
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
26
24
  end
27
25
 
28
26
  it 'produces a blank comment node surrounding a def that has no comment' do
29
27
  result = parse_with_builder 'def foo; end'
30
28
  result.must_equal s(:program,
31
- s(s(:comment,
29
+ s(:stmts,
30
+ s(:comment,
32
31
  '',
33
32
  s(:def,
34
33
  s(:@ident, 'foo', s(1, 4)),
35
34
  empty_params_list,
36
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
35
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
37
36
  end
38
37
 
39
38
  it 'produces a comment node surrounding a commented class' do
40
39
  result = parse_with_builder "# Foo\nclass Foo; end"
41
40
  result.must_equal s(:program,
42
- s(s(:comment,
41
+ s(:stmts,
42
+ s(:comment,
43
43
  "# Foo\n",
44
44
  s(:class,
45
45
  s(:const_ref, s(:@const, 'Foo', s(2, 6))),
46
46
  nil,
47
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
47
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
48
48
  end
49
49
 
50
50
  it 'produce a blank comment node surrounding a class that has no comment' do
51
51
  result = parse_with_builder 'class Foo; end'
52
52
  result.must_equal s(:program,
53
- s(s(:comment,
53
+ s(:stmts,
54
+ s(:comment,
54
55
  '',
55
56
  s(:class,
56
57
  s(:const_ref, s(:@const, 'Foo', s(1, 6))),
57
58
  nil,
58
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
59
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
59
60
  end
60
61
 
61
62
  it 'produces a comment node surrounding a commented module' do
62
63
  result = parse_with_builder "# Foo\nmodule Foo; end"
63
64
  result.must_equal s(:program,
64
- s(s(:comment,
65
+ s(:stmts,
66
+ s(:comment,
65
67
  "# Foo\n",
66
68
  s(:module,
67
69
  s(:const_ref, s(:@const, 'Foo', s(2, 7))),
68
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
70
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
69
71
  end
70
72
 
71
73
  it 'produces a blank comment node surrounding a module that has no comment' do
72
74
  result = parse_with_builder 'module Foo; end'
73
75
  result.must_equal s(:program,
74
- s(s(:comment,
76
+ s(:stmts,
77
+ s(:comment,
75
78
  '',
76
79
  s(:module,
77
80
  s(:const_ref, s(:@const, 'Foo', s(1, 7))),
78
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
81
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
79
82
  end
80
83
 
81
84
  it 'is not confused by a symbol containing a keyword' do
82
85
  result = parse_with_builder ':class; def foo; end'
83
86
  result.must_equal s(:program,
84
- s(s(:symbol_literal, s(:symbol, s(:@kw, 'class', s(1, 1)))),
87
+ s(:stmts,
88
+ s(:symbol_literal, s(:symbol, s(:@kw, 'class', s(1, 1)))),
85
89
  s(:comment,
86
90
  '',
87
91
  s(:def,
88
92
  s(:@ident, 'foo', s(1, 12)),
89
93
  empty_params_list,
90
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
94
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
91
95
  end
92
96
 
93
97
  it 'is not confused by a dynamic symbol' do
94
98
  result = parse_with_builder ":'foo'; def bar; end"
95
99
  result.must_equal s(:program,
96
- s(s(:dyna_symbol, s(s(:@tstring_content, 'foo', s(1, 2)))),
100
+ s(:stmts,
101
+ s(:dyna_symbol,
102
+ s(:xstring, s(:@tstring_content, 'foo', s(1, 2)))),
97
103
  s(:comment,
98
104
  '',
99
105
  s(:def,
100
106
  s(:@ident, 'bar', s(1, 12)),
101
107
  empty_params_list,
102
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))
108
+ s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
103
109
  end
104
110
 
105
111
  it 'is not confused by a dynamic symbol containing a class definition' do
106
112
  result = parse_with_builder ":\"foo\#{class Bar;end}\""
107
113
  result.must_equal s(:program,
108
- s(s(:dyna_symbol,
109
- s(s(:@tstring_content, 'foo', s(1, 2)),
114
+ s(:stmts,
115
+ s(:dyna_symbol,
116
+ s(:xstring,
117
+ s(:@tstring_content, 'foo', s(1, 2)),
110
118
  s(:string_embexpr,
111
- s(s(:comment,
119
+ s(:stmts,
120
+ s(:comment,
112
121
  '',
113
122
  s(:class,
114
123
  s(:const_ref, s(:@const, 'Bar', s(1, 13))),
115
124
  nil,
116
- s(:bodystmt, s(s(:void_stmt)), nil, nil, nil)))))))))
125
+ s(:bodystmt,
126
+ s(:stmts, s(:void_stmt)),
127
+ nil,
128
+ nil,
129
+ nil)))))))))
130
+ end
131
+ end
132
+
133
+ describe 'handling syntax errors' do
134
+ it 'raises an error for an incomplete source' do
135
+ proc {
136
+ parse_with_builder 'def foo'
137
+ }.must_raise RipperRubyParser::SyntaxError
138
+ end
139
+
140
+ it 'raises an error for an invalid class name' do
141
+ proc {
142
+ parse_with_builder 'class foo; end'
143
+ }.must_raise RipperRubyParser::SyntaxError
144
+ end
145
+
146
+ it 'raises an error aliasing $1 as foo' do
147
+ proc {
148
+ parse_with_builder 'alias foo $1'
149
+ }.must_raise RipperRubyParser::SyntaxError
150
+ end
151
+
152
+ it 'raises an error aliasing foo as $1' do
153
+ proc {
154
+ parse_with_builder 'alias $1 foo'
155
+ }.must_raise RipperRubyParser::SyntaxError
156
+ end
157
+
158
+ it 'raises an error aliasing $2 as $1' do
159
+ proc {
160
+ parse_with_builder 'alias $1 $2'
161
+ }.must_raise RipperRubyParser::SyntaxError
162
+ end
163
+
164
+ it 'raises an error assigning to $1' do
165
+ proc {
166
+ parse_with_builder '$1 = foo'
167
+ }.must_raise RipperRubyParser::SyntaxError
168
+ end
169
+
170
+ it 'raises an error using an invalid parameter name' do
171
+ proc {
172
+ parse_with_builder 'def foo(BAR); end'
173
+ }.must_raise RipperRubyParser::SyntaxError
117
174
  end
118
175
  end
119
176
  end
@@ -8,19 +8,6 @@ describe RipperRubyParser::Parser do
8
8
  result.must_be_instance_of Sexp
9
9
  end
10
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
- sexp_p.expect :filename=, nil, ['(string)']
15
- sexp_p.expect :extra_compatible=, nil, [false]
16
-
17
- parser = RipperRubyParser::Parser.new sexp_p
18
- result = parser.parse 'any code'
19
-
20
- result.must_equal s(:result)
21
- sexp_p.verify
22
- end
23
-
24
11
  describe 'for an empty program' do
25
12
  it 'returns nil' do
26
13
  ''.must_be_parsed_as nil
@@ -48,7 +35,7 @@ describe RipperRubyParser::Parser do
48
35
  end
49
36
  end
50
37
 
51
- describe 'for empty brackets' do
38
+ describe 'for empty parentheses' do
52
39
  it 'works with lone ()' do
53
40
  '()'.must_be_parsed_as s(:nil)
54
41
  end
@@ -293,7 +280,7 @@ describe RipperRubyParser::Parser do
293
280
  s(:nil))
294
281
  end
295
282
 
296
- it 'works with brackets around the parameter list' do
283
+ it 'works with parentheses around the parameter list' do
297
284
  'def foo(bar); end'.
298
285
  must_be_parsed_as s(:defn, :foo, s(:args, :bar), s(:nil))
299
286
  end
@@ -390,7 +377,6 @@ describe RipperRubyParser::Parser do
390
377
  end
391
378
 
392
379
  it 'works with a named argument with no default value' do
393
- skip 'Default values are required in Ruby 2.0' if RUBY_VERSION < '2.1.0'
394
380
  'def foo bar:; end'.
395
381
  must_be_parsed_as s(:defn,
396
382
  :foo,
@@ -414,181 +400,35 @@ describe RipperRubyParser::Parser do
414
400
  end
415
401
  end
416
402
 
417
- describe 'for blocks' do
418
- it 'works with no statements in the block body' do
419
- 'foo do; end'.
420
- must_be_parsed_as s(:iter,
421
- s(:call, nil, :foo),
422
- 0)
423
- end
424
-
425
- it 'works with next with no arguments' do
426
- 'foo do; next; end'.
427
- must_be_parsed_as s(:iter,
428
- s(:call, nil, :foo),
429
- 0,
430
- s(:next))
431
- end
432
-
433
- it 'works with next with one argument' do
434
- 'foo do; next bar; end'.
435
- must_be_parsed_as s(:iter,
436
- s(:call, nil, :foo),
437
- 0,
438
- s(:next, s(:call, nil, :bar)))
439
- end
440
-
441
- it 'works with next with several arguments' do
442
- 'foo do; next bar, baz; end'.
443
- must_be_parsed_as s(:iter,
444
- s(:call, nil, :foo),
445
- 0,
446
- s(:next,
447
- s(:array,
448
- s(:call, nil, :bar),
449
- s(:call, nil, :baz))))
450
- end
451
-
452
- it 'works with next with a function call with parentheses' do
453
- 'foo do; next foo(bar); end'.
454
- must_be_parsed_as s(:iter,
455
- s(:call, nil, :foo),
456
- 0,
457
- s(:next,
458
- s(:call, nil, :foo,
459
- s(:call, nil, :bar))))
460
- end
461
-
462
- it 'works with next with a function call without parentheses' do
463
- 'foo do; next foo bar; end'.
464
- must_be_parsed_as s(:iter,
465
- s(:call, nil, :foo),
466
- 0,
467
- s(:next,
468
- s(:call, nil, :foo,
469
- s(:call, nil, :bar))))
470
- end
471
-
472
- it 'works with break with no arguments' do
473
- 'foo do; break; end'.
474
- must_be_parsed_as s(:iter,
475
- s(:call, nil, :foo),
476
- 0,
477
- s(:break))
478
- end
479
-
480
- it 'works with break with one argument' do
481
- 'foo do; break bar; end'.
482
- must_be_parsed_as s(:iter,
483
- s(:call, nil, :foo),
484
- 0,
485
- s(:break, s(:call, nil, :bar)))
486
- end
487
-
488
- it 'works with break with several arguments' do
489
- 'foo do; break bar, baz; end'.
490
- must_be_parsed_as s(:iter,
491
- s(:call, nil, :foo),
492
- 0,
493
- s(:break,
494
- s(:array,
495
- s(:call, nil, :bar),
496
- s(:call, nil, :baz))))
497
- end
498
-
499
- it 'works with break with a function call with parentheses' do
500
- 'foo do; break foo(bar); end'.
501
- must_be_parsed_as s(:iter,
502
- s(:call, nil, :foo),
503
- 0,
504
- s(:break,
505
- s(:call, nil, :foo,
506
- s(:call, nil, :bar))))
507
- end
508
-
509
- it 'works with break with a function call without parentheses' do
510
- 'foo do; break foo bar; end'.
511
- must_be_parsed_as s(:iter,
512
- s(:call, nil, :foo),
513
- 0,
514
- s(:break,
515
- s(:call, nil, :foo,
516
- s(:call, nil, :bar))))
517
- end
518
-
519
- it 'works with redo' do
520
- 'foo do; redo; end'.
521
- must_be_parsed_as s(:iter,
522
- s(:call, nil, :foo),
523
- 0,
524
- s(:redo))
525
- end
526
-
527
- it 'works with zero arguments' do
528
- 'foo do ||; end'.
529
- must_be_parsed_as s(:iter,
530
- s(:call, nil, :foo),
531
- s(:args))
532
- end
533
-
534
- it 'works with one argument' do
535
- 'foo do |bar|; end'.
536
- must_be_parsed_as s(:iter,
537
- s(:call, nil, :foo),
538
- s(:args, :bar))
539
- end
540
-
541
- it 'works with multiple arguments' do
542
- 'foo do |bar, baz|; end'.
543
- must_be_parsed_as s(:iter,
544
- s(:call, nil, :foo),
545
- s(:args, :bar, :baz))
546
- end
547
-
548
- it 'works with a single splat argument' do
549
- 'foo do |*bar|; end'.
550
- must_be_parsed_as s(:iter,
551
- s(:call, nil, :foo),
552
- s(:args, :"*bar"))
553
- end
554
-
555
- it 'works with a combination of regular arguments and a splat argument' do
556
- 'foo do |bar, *baz|; end'.
557
- must_be_parsed_as s(:iter,
558
- s(:call, nil, :foo),
559
- s(:args, :bar, :"*baz"))
560
- end
561
- end
562
-
563
403
  describe 'for yield' do
564
- it 'works with no arguments and no brackets' do
404
+ it 'works with no arguments and no parentheses' do
565
405
  'yield'.
566
406
  must_be_parsed_as s(:yield)
567
407
  end
568
408
 
569
- it 'works with brackets but no arguments' do
409
+ it 'works with parentheses but no arguments' do
570
410
  'yield()'.
571
411
  must_be_parsed_as s(:yield)
572
412
  end
573
413
 
574
- it 'works with one argument and no brackets' do
414
+ it 'works with one argument and no parentheses' do
575
415
  'yield foo'.
576
416
  must_be_parsed_as s(:yield, s(:call, nil, :foo))
577
417
  end
578
418
 
579
- it 'works with one argument and brackets' do
419
+ it 'works with one argument and parentheses' do
580
420
  'yield(foo)'.
581
421
  must_be_parsed_as s(:yield, s(:call, nil, :foo))
582
422
  end
583
423
 
584
- it 'works with multiple arguments and no brackets' do
424
+ it 'works with multiple arguments and no parentheses' do
585
425
  'yield foo, bar'.
586
426
  must_be_parsed_as s(:yield,
587
427
  s(:call, nil, :foo),
588
428
  s(:call, nil, :bar))
589
429
  end
590
430
 
591
- it 'works with multiple arguments and brackets' do
431
+ it 'works with multiple arguments and parentheses' do
592
432
  'yield(foo, bar)'.
593
433
  must_be_parsed_as s(:yield,
594
434
  s(:call, nil, :foo),
@@ -617,6 +457,13 @@ describe RipperRubyParser::Parser do
617
457
  end
618
458
  end
619
459
 
460
+ describe 'for the __ENCODING__ keyword' do
461
+ it 'evaluates to the equivalent of Encoding::UTF_8' do
462
+ '__ENCODING__'.
463
+ must_be_parsed_as s(:colon2, s(:const, :Encoding), :UTF_8)
464
+ end
465
+ end
466
+
620
467
  describe 'for the __FILE__ keyword' do
621
468
  describe 'when not passing a file name' do
622
469
  it "creates a string sexp with value '(string)'" do
@@ -871,7 +718,7 @@ describe RipperRubyParser::Parser do
871
718
  s(:call, nil, :qux)))
872
719
  end
873
720
 
874
- it 'works with brackets around the left-hand side' do
721
+ it 'works with parentheses around the left-hand side' do
875
722
  '(foo, bar) = baz'.
876
723
  must_be_parsed_as s(:masgn,
877
724
  s(:array, s(:lasgn, :foo), s(:lasgn, :bar)),
@@ -1167,7 +1014,7 @@ describe RipperRubyParser::Parser do
1167
1014
  result.line.must_equal 1
1168
1015
  end
1169
1016
 
1170
- it 'works for a method call with brackets' do
1017
+ it 'works for a method call with parentheses' do
1171
1018
  result = parser.parse 'foo()'
1172
1019
  result.line.must_equal 1
1173
1020
  end
@@ -1308,4 +1155,24 @@ describe RipperRubyParser::Parser do
1308
1155
  end
1309
1156
  end
1310
1157
  end
1158
+
1159
+ describe '#trickle_up_line_numbers' do
1160
+ it 'works through several nested levels' do
1161
+ inner = s(:foo)
1162
+ outer = s(:bar, s(:baz, s(:qux, inner)))
1163
+ outer.line = 42
1164
+ parser.send :trickle_down_line_numbers, outer
1165
+ inner.line.must_equal 42
1166
+ end
1167
+ end
1168
+
1169
+ describe '#trickle_down_line_numbers' do
1170
+ it 'works through several nested levels' do
1171
+ inner = s(:foo)
1172
+ inner.line = 42
1173
+ outer = s(:bar, s(:baz, s(:qux, inner)))
1174
+ parser.send :trickle_up_line_numbers, outer
1175
+ outer.line.must_equal 42
1176
+ end
1177
+ end
1311
1178
  end