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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 44bd9ec7c716649fbcf3698e39d9d7951b70a3d0
4
- data.tar.gz: 1b54fd14347e28a5c253b8f00be1a641dc7cbda5
2
+ SHA256:
3
+ metadata.gz: 57d07c4327035328992f94f2e0f49b36362743c84062414a6f09b8738aef709b
4
+ data.tar.gz: 9e19226ece2a88714fc2e2483e4accb0ee7aca7f31398d25396f72581f3c864f
5
5
  SHA512:
6
- metadata.gz: 4fd9c3ffee9de0d9948a126ca5e44d3dc46b50b36b4fd7d9537263b84b123ebeac09118f3b0ae12f203f7c3ee1eb438bca92b2b630502b7bc83f6d3ea1a47668
7
- data.tar.gz: c24028ea9320a5fdba4eee182d257e9f3c5db7fc57f9b3e6ba15471e90eb96b48c291b7046e8ca52b83af4957a62e6b4321901179d53fe53ea549f431baf7f85
6
+ metadata.gz: 9f68e5ad8f58a6035ae16be08e5188a4f22f6809ce59705de877527ede90247125525a7be007b86b794ab046a8861ac4bd417ee3974e4d6fe60c877ff92c4230
7
+ data.tar.gz: 6f1b8cbd085e0249a56bf937d8806cba3dad3a07893f843361c8142321693e6c8e10225782f8fee672eb4ee3c148512778544648731b486f5977c142004f1271
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Change log
2
2
 
3
+ ## 1.2.0 / 2018-01-12
4
+
5
+ * Improve code quality
6
+ * Document public API
7
+ * Speed improvements
8
+ - Process line numbers only once per parse run
9
+ - Reduce arbitrary conditionals
10
+ - Use deconstruction to split up block
11
+ * Improve intermediate s-expressions, reducing the number of typeless
12
+ expressions.
13
+ * Use SexpBuilder base class, giving more low-level access to the structure
14
+ created by Ripper.
15
+ * Support Ruby 2.5
16
+ * Improve handling of boolean operators with parenthes
17
+ * Improve compatibility for begin..end blocks used as method and operator
18
+ arguments.
19
+ * Drop support for Ruby 2.0 and 2.1
20
+ * Handle `__ENCODING__` constant.
21
+
3
22
  ## 1.1.2 / 2017-10-07
4
23
 
5
24
  * Fix support for newer Ruby syntax
data/README.md CHANGED
@@ -12,7 +12,7 @@ Parse with Ripper, produce sexps that are compatible with RubyParser.
12
12
 
13
13
  * Drop-in replacement for RubyParser.
14
14
  * Should handle 1.9 and later syntax gracefully.
15
- * Needs MRI 2.0 or higher
15
+ * Requires MRI 2.2 or higher
16
16
 
17
17
  ## Install
18
18
 
@@ -29,7 +29,7 @@ Parse with Ripper, produce sexps that are compatible with RubyParser.
29
29
 
30
30
  ## Requirements
31
31
 
32
- * Ruby 2.0 or higher
32
+ * Ruby 2.2 or higher
33
33
  * sexp_processor
34
34
 
35
35
  ## Hacking and contributing
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/testtask'
5
5
  namespace :test do
6
6
  Rake::TestTask.new(:unit) do |t|
7
7
  t.libs = ['lib']
8
- t.test_files = FileList['test/unit/*_test.rb']
8
+ t.test_files = FileList['test/ripper_ruby_parser/**/*_test.rb']
9
9
  t.warning = true
10
10
  end
11
11
 
@@ -1,9 +1,2 @@
1
- if RUBY_VERSION < '1.9.3'
2
- raise LoadError, 'Only ruby version 1.9.3 and up are supported'
3
- end
4
-
5
1
  require 'ripper_ruby_parser/version'
6
2
  require 'ripper_ruby_parser/parser'
7
-
8
- module RipperRubyParser
9
- end
@@ -2,10 +2,12 @@ require 'ripper'
2
2
  require 'ripper_ruby_parser/syntax_error'
3
3
 
4
4
  module RipperRubyParser
5
- # Variant of Ripper's SexpBuilderPP parser class that inserts comments as
5
+ # Variant of Ripper's SexpBuilder parser class that inserts comments as
6
6
  # Sexps into the built parse tree.
7
- class CommentingRipperParser < Ripper::SexpBuilderPP
8
- def initialize *args
7
+ #
8
+ # @api private
9
+ class CommentingRipperParser < Ripper::SexpBuilder
10
+ def initialize(*args)
9
11
  super
10
12
  @comment = nil
11
13
  @comment_stack = []
@@ -19,13 +21,13 @@ module RipperRubyParser
19
21
  Sexp.from_array(result)
20
22
  end
21
23
 
22
- def on_comment tok
24
+ def on_comment(tok)
23
25
  @comment ||= ''
24
26
  @comment += tok
25
27
  super
26
28
  end
27
29
 
28
- def on_kw tok
30
+ def on_kw(tok)
29
31
  case tok
30
32
  when 'class', 'def', 'module'
31
33
  unless @in_symbol
@@ -36,42 +38,122 @@ module RipperRubyParser
36
38
  super
37
39
  end
38
40
 
39
- def on_module *args
41
+ def on_module(*args)
40
42
  commentize(:module, super)
41
43
  end
42
44
 
43
- def on_class *args
45
+ def on_class(*args)
44
46
  commentize(:class, super)
45
47
  end
46
48
 
47
- def on_sclass *args
49
+ def on_sclass(*args)
48
50
  commentize(:class, super)
49
51
  end
50
52
 
51
- def on_def *args
53
+ def on_def(*args)
52
54
  commentize(:def, super)
53
55
  end
54
56
 
55
- def on_defs *args
57
+ def on_defs(*args)
56
58
  commentize(:def, super)
57
59
  end
58
60
 
59
- def on_qsymbols_add list, elem
60
- super list, [:dyna_symbol, [elem]]
61
+ def on_args_new
62
+ [:args]
61
63
  end
62
64
 
63
- def on_symbols_add list, elem
64
- super list, [:dyna_symbol, elem]
65
+ def on_args_add(list, elem)
66
+ list << elem
65
67
  end
66
68
 
67
- def on_words_add list, elem
68
- if elem.count == 1
69
- super
69
+ def on_mlhs_new
70
+ [:mlhs]
71
+ end
72
+
73
+ def on_mlhs_add(list, elem)
74
+ if list.first == :mlhs
75
+ list << elem
70
76
  else
71
- super list, [:string_content, *elem]
77
+ [:mlhs_add_post, list, elem]
72
78
  end
73
79
  end
74
80
 
81
+ def on_mrhs_new
82
+ [:mrhs]
83
+ end
84
+
85
+ def on_mrhs_add(list, elem)
86
+ list << elem
87
+ end
88
+
89
+ def on_qsymbols_new
90
+ [:qsymbols]
91
+ end
92
+
93
+ def on_qsymbols_add(list, elem)
94
+ list << elem
95
+ end
96
+
97
+ def on_qwords_new
98
+ [:qwords]
99
+ end
100
+
101
+ def on_qwords_add(list, elem)
102
+ list << elem
103
+ end
104
+
105
+ def on_regexp_new
106
+ [:regexp]
107
+ end
108
+
109
+ def on_regexp_add(list, elem)
110
+ list << elem
111
+ end
112
+
113
+ def on_stmts_new
114
+ [:stmts]
115
+ end
116
+
117
+ def on_stmts_add(list, elem)
118
+ list << elem
119
+ end
120
+
121
+ def on_string_add(list, elem)
122
+ list << elem
123
+ end
124
+
125
+ def on_symbols_new
126
+ [:symbols]
127
+ end
128
+
129
+ def on_symbols_add(list, elem)
130
+ list << elem
131
+ end
132
+
133
+ def on_word_new
134
+ [:word]
135
+ end
136
+
137
+ def on_word_add(list, elem)
138
+ list << elem
139
+ end
140
+
141
+ def on_words_new
142
+ [:words]
143
+ end
144
+
145
+ def on_words_add(list, elem)
146
+ list << elem
147
+ end
148
+
149
+ def on_xstring_new
150
+ [:xstring]
151
+ end
152
+
153
+ def on_xstring_add(list, elem)
154
+ list << elem
155
+ end
156
+
75
157
  def on_op(token)
76
158
  @seen_space = false
77
159
  super
@@ -92,7 +174,7 @@ module RipperRubyParser
92
174
  super
93
175
  end
94
176
 
95
- NUMBER_LITERAL_TYPES = [:@int, :@float]
177
+ NUMBER_LITERAL_TYPES = [:@int, :@float].freeze
96
178
 
97
179
  def on_unary(op, value)
98
180
  if !@space_before && op == :-@ && NUMBER_LITERAL_TYPES.include?(value.first)
@@ -107,55 +189,51 @@ module RipperRubyParser
107
189
  end
108
190
  end
109
191
 
110
- def on_symbeg *args
192
+ def on_symbeg(*args)
111
193
  @in_symbol = true
112
194
  super
113
195
  end
114
196
 
115
- def on_symbol *args
197
+ def on_symbol(*args)
116
198
  @in_symbol = false
117
199
  super
118
200
  end
119
201
 
120
- def on_embexpr_beg *args
202
+ def on_embexpr_beg(*args)
121
203
  @in_symbol = false
122
204
  super
123
205
  end
124
206
 
125
- def on_dyna_symbol *args
207
+ def on_dyna_symbol(*args)
126
208
  @in_symbol = false
127
209
  super
128
210
  end
129
211
 
130
- def on_parse_error *args
212
+ def on_parse_error(*args)
131
213
  raise SyntaxError, *args
132
214
  end
133
215
 
134
- def on_class_name_error *args
216
+ def on_class_name_error(*args)
135
217
  raise SyntaxError, *args
136
218
  end
137
219
 
138
- def on_alias_error *args
220
+ def on_alias_error(*args)
139
221
  raise SyntaxError, *args
140
222
  end
141
223
 
142
- def on_assign_error *args
224
+ def on_assign_error(*args)
143
225
  raise SyntaxError, *args
144
226
  end
145
227
 
146
- def on_param_error *args
228
+ def on_param_error(*args)
147
229
  raise SyntaxError, *args
148
230
  end
149
231
 
150
232
  private
151
233
 
152
- def commentize name, exp
153
- raise "Comment stack empty in #{name} event" if @comment_stack.empty?
154
- tok, comment = @comment_stack.pop
234
+ def commentize(_name, exp)
235
+ _tok, comment = @comment_stack.pop
155
236
  @comment = nil
156
- unless tok == name
157
- raise "Expected on_#{tok} event, got on_#{name}"
158
- end
159
237
  [:comment, comment || '', exp]
160
238
  end
161
239
 
@@ -5,26 +5,40 @@ module RipperRubyParser
5
5
  # Main parser class. Brings together Ripper and our
6
6
  # RipperRubyParser::SexpProcessor.
7
7
  class Parser
8
- attr_accessor :extra_compatible
9
-
10
- def initialize processor = SexpProcessor.new
11
- @processor = processor
12
- @extra_compatible = false
13
- end
14
-
15
- def parse source, filename = '(string)', lineno = 1
8
+ def parse(source, filename = '(string)', lineno = 1)
16
9
  parser = CommentingRipperParser.new(source, filename, lineno)
17
10
  exp = parser.parse
18
11
 
19
- @processor.filename = filename
20
- @processor.extra_compatible = extra_compatible
21
- result = @processor.process exp
12
+ processor = SexpProcessor.new(filename: filename)
13
+ result = processor.process exp
22
14
 
23
- if result == s(:void_stmt)
15
+ if result.sexp_type == :void_stmt
24
16
  nil
25
17
  else
18
+ trickle_up_line_numbers result
19
+ trickle_down_line_numbers result
26
20
  result
27
21
  end
28
22
  end
23
+
24
+ private
25
+
26
+ def trickle_up_line_numbers(exp)
27
+ exp.each do |sub_exp|
28
+ if sub_exp.is_a? Sexp
29
+ trickle_up_line_numbers sub_exp
30
+ exp.line ||= sub_exp.line
31
+ end
32
+ end
33
+ end
34
+
35
+ def trickle_down_line_numbers(exp)
36
+ exp.each do |sub_exp|
37
+ if sub_exp.is_a? Sexp
38
+ sub_exp.line ||= exp.line
39
+ trickle_down_line_numbers sub_exp
40
+ end
41
+ end
42
+ end
29
43
  end
30
44
  end
@@ -13,8 +13,11 @@ require 'ripper_ruby_parser/sexp_handlers/methods'
13
13
  require 'ripper_ruby_parser/sexp_handlers/operators'
14
14
 
15
15
  module RipperRubyParser
16
+ # Umbrella module for handlers of particular sexp types
17
+ #
18
+ # @api private
16
19
  module SexpHandlers
17
- def self.included base
20
+ def self.included(base)
18
21
  base.class_eval do
19
22
  include HelperMethods
20
23
 
@@ -1,25 +1,26 @@
1
1
  module RipperRubyParser
2
2
  module SexpHandlers
3
+ # Sexp handlers for argument lists
3
4
  module Arguments
4
- def process_args_add_block exp
5
+ def process_args_add_block(exp)
5
6
  _, regular, block = exp.shift 3
6
- args = handle_potentially_typeless_sexp(regular)
7
+ args = process(regular)
7
8
  args << s(:block_pass, process(block)) if block
8
- s(:arglist, *args)
9
+ s(:arglist, *args.sexp_body)
9
10
  end
10
11
 
11
- def process_args_add_star exp
12
+ def process_args_add_star(exp)
12
13
  generic_add_star exp
13
14
  end
14
15
 
15
- def process_arg_paren exp
16
+ def process_arg_paren(exp)
16
17
  _, args = exp.shift 2
17
18
  args = s() if args.nil?
18
19
  args.unshift :arglist unless args.first.is_a? Symbol
19
20
  process(args)
20
21
  end
21
22
 
22
- def process_rest_param exp
23
+ def process_rest_param(exp)
23
24
  _, ident = exp.shift 2
24
25
  s(:splat, process(ident))
25
26
  end
@@ -1,12 +1,14 @@
1
1
  module RipperRubyParser
2
2
  module SexpHandlers
3
+ # Sexp handlers for array literals
3
4
  module Arrays
4
- def process_array exp
5
+ def process_array(exp)
5
6
  _, elems = exp.shift 2
7
+ return s(:array) if elems.nil?
6
8
  s(:array, *handle_array_elements(elems))
7
9
  end
8
10
 
9
- def process_aref exp
11
+ def process_aref(exp)
10
12
  _, coll, idx = exp.shift 3
11
13
 
12
14
  coll = process(coll)
@@ -1,14 +1,15 @@
1
1
  module RipperRubyParser
2
2
  module SexpHandlers
3
+ # Sexp handlers for assignments
3
4
  module Assignment
4
- def process_assign exp
5
+ def process_assign(exp)
5
6
  _, lvalue, value = exp.shift 3
6
7
  lvalue = process(lvalue)
7
8
  value = process(value)
8
9
 
9
10
  case value.sexp_type
10
- when :splat
11
- value = s(:svalue, value)
11
+ when :mrhs
12
+ value.sexp_type = :svalue
12
13
  when :fake_array
13
14
  value = s(:svalue, s(:array, *value.sexp_body))
14
15
  end
@@ -17,25 +18,21 @@ module RipperRubyParser
17
18
  create_regular_assignment_sub_type(lvalue, value))
18
19
  end
19
20
 
20
- def process_massign exp
21
+ def process_massign(exp)
21
22
  _, left, right = exp.shift 3
22
23
 
23
- left = handle_potentially_typeless_sexp left
24
+ left = process left
24
25
 
25
- if left.first == :masgn
26
- left = left[1]
27
- left.shift
28
- end
29
-
30
- left = create_multiple_assignment_sub_types left
26
+ left = left[1] if left.sexp_type == :masgn
27
+ left = create_multiple_assignment_sub_types left.sexp_body
31
28
 
32
29
  right = process(right)
33
30
 
34
31
  case right.sexp_type
35
32
  when :fake_array
36
33
  right[0] = :array
37
- when :splat
38
- nil # Do nothing
34
+ when :mrhs
35
+ right = right[1]
39
36
  else
40
37
  right = s(:to_ary, right)
41
38
  end
@@ -43,42 +40,41 @@ module RipperRubyParser
43
40
  s(:masgn, s(:array, *left), right)
44
41
  end
45
42
 
46
- def process_mrhs_new_from_args exp
43
+ def process_mrhs_new_from_args(exp)
47
44
  _, inner, last = exp.shift 3
48
- inner.map! { |item| process(item) }
49
- inner.push process(last) unless last.nil?
45
+ inner = map_process_sexp_body_compact(inner)
46
+ inner.push process(last) if last
50
47
  s(:fake_array, *inner)
51
48
  end
52
49
 
53
- def process_mrhs_add_star exp
54
- exp = generic_add_star exp
55
-
56
- if exp.first.is_a? Symbol
57
- exp
58
- else
59
- exp.first
60
- end
50
+ def process_mrhs_add_star(exp)
51
+ generic_add_star exp
61
52
  end
62
53
 
63
- def process_mlhs_add_star exp
64
- _, args, splatarg, rest = exp.shift 4
65
- items = handle_potentially_typeless_sexp args
54
+ def process_mlhs_add_star(exp)
55
+ _, args, splatarg = exp.shift 3
56
+ items = process args
66
57
  items << s(:splat, process(splatarg))
67
- rest.each { |arg| items << process(arg) } if rest
68
- items
69
58
  end
70
59
 
71
- def process_mlhs_paren exp
72
- _, contents = exp.shift 2
60
+ def process_mlhs_add_post(exp)
61
+ _, base, rest = exp.shift 3
62
+ process(base).push(*process(rest).sexp_body)
63
+ end
73
64
 
74
- items = handle_potentially_typeless_sexp(contents)
65
+ def process_mlhs_paren(exp)
66
+ _, contents = exp.shift 2
75
67
 
76
- return items if items.first.is_a? Symbol
68
+ items = process(contents)
77
69
 
78
- s(:masgn, s(:array, *create_multiple_assignment_sub_types(items)))
70
+ if items.sexp_type == :mlhs
71
+ s(:masgn, s(:array, *create_multiple_assignment_sub_types(items.sexp_body)))
72
+ else
73
+ items
74
+ end
79
75
  end
80
76
 
81
- def process_opassign exp
77
+ def process_opassign(exp)
82
78
  _, lvalue, operator, value = exp.shift 4
83
79
 
84
80
  lvalue = process(lvalue)
@@ -90,7 +86,7 @@ module RipperRubyParser
90
86
 
91
87
  private
92
88
 
93
- def create_multiple_assignment_sub_types sexp_list
89
+ def create_multiple_assignment_sub_types(sexp_list)
94
90
  sexp_list.map! do |item|
95
91
  if item.sexp_type == :splat
96
92
  if item[1].nil?
@@ -104,7 +100,7 @@ module RipperRubyParser
104
100
  end
105
101
  end
106
102
 
107
- def create_valueless_assignment_sub_type item
103
+ def create_valueless_assignment_sub_type(item)
108
104
  item = with_line_number(item.line,
109
105
  create_regular_assignment_sub_type(item, nil))
110
106
  item.pop
@@ -112,11 +108,11 @@ module RipperRubyParser
112
108
  end
113
109
 
114
110
  OPERATOR_ASSIGNMENT_MAP = {
115
- :"||" => :op_asgn_or,
116
- :"&&" => :op_asgn_and
111
+ '||': :op_asgn_or,
112
+ '&&': :op_asgn_and
117
113
  }.freeze
118
114
 
119
- def create_operator_assignment_sub_type lvalue, value, operator
115
+ def create_operator_assignment_sub_type(lvalue, value, operator)
120
116
  case lvalue.sexp_type
121
117
  when :aref_field
122
118
  _, arr, arglist = lvalue
@@ -134,7 +130,7 @@ module RipperRubyParser
134
130
  end
135
131
  end
136
132
 
137
- def create_regular_assignment_sub_type lvalue, value
133
+ def create_regular_assignment_sub_type(lvalue, value)
138
134
  case lvalue.sexp_type
139
135
  when :aref_field
140
136
  _, arr, arglist = lvalue
@@ -161,11 +157,11 @@ module RipperRubyParser
161
157
  cvar: :cvasgn
162
158
  }.freeze
163
159
 
164
- def create_assignment_sub_type lvalue, value
160
+ def create_assignment_sub_type(lvalue, value)
165
161
  s(map_assignment_lvalue_type(lvalue.sexp_type), lvalue[1], value)
166
162
  end
167
163
 
168
- def map_assignment_lvalue_type type
164
+ def map_assignment_lvalue_type(type)
169
165
  @in_method_body && ASSIGNMENT_IN_METHOD_SUB_TYPE_MAP[type] ||
170
166
  ASSIGNMENT_SUB_TYPE_MAP[type] ||
171
167
  type