ripper_ruby_parser 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc516bb8bd2fd0f9fd310f848dbf272481d6c15a8ee3aeecba41ac8e24a7b8c3
4
- data.tar.gz: 2d79ba2d094e3694993f48e92565c7424121331aad653bd6cb5fad51a7f9ea75
3
+ metadata.gz: 20d34b3ba8f1c186e8df1118334a231d2520c9ef51a36b4c7d5b12c33fe9947b
4
+ data.tar.gz: 881e3286d632c0189a33a2add98dd43bddda798cf6c7c8f3fa75e1b9dfdda7e3
5
5
  SHA512:
6
- metadata.gz: 2d521a088a674f96b3639d624de7ababb6dbea93965fee1185b6a14f8a289ef88566a87cc5918004d3765f19de7ea0a15d99cfb30792ff519e1d8426555bb162
7
- data.tar.gz: 0a79e0832ce26282bacb13d534dde0460f33b677e7a07c23bde4d530848228bda65460ce2c229a97ddc25c5f12cc0aa75ea176f09e3959fcbf78e34536fa6bcd
6
+ metadata.gz: f3a58dd16a10a8c0f64996c753e2da3c02d7b0ec074099795bf240925e388a5edb215edf680df0c70baab82c42ea77d22762d2a2b27a7a9a246aa01bb47753a1
7
+ data.tar.gz: 7b360aaea5ba1fe76855a4e534d56aec13b1a470f7cc9e539d4e2c996ef0684848142ea6c4d2e522c439e84d62628ebaf571da5c993e9a44a0f9641d8e3283df
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.1 / 2019-04-22
4
+
5
+ * Improve line numbering for some block structures ([#82])
6
+ - Fix line numbering for empty method bodies
7
+ - Assign correct line numbers to END blocks
8
+ - Assign correct line numbers to begin blocks
9
+ - Assign correct line numbers to BEGIN blocks
10
+ * Fix line numbering for several literals ([#80])
11
+ - Fix line numbering for plain regexp literals
12
+ - Fix line numbering for backtick literals
13
+ - Fix line numbering for simple string literals
14
+ - Fix line numbering for keyword-like symbols
15
+
3
16
  ## 1.6.0 / 2019-04-12
4
17
 
5
18
  * Fix line numbering for range literals ([#79])
@@ -158,6 +171,8 @@
158
171
  * Initial release
159
172
 
160
173
  <!-- Pull request links -->
174
+ [#82]: https://github.com/mvz/ripper_ruby_parser/pull/82
175
+ [#80]: https://github.com/mvz/ripper_ruby_parser/pull/80
161
176
  [#79]: https://github.com/mvz/ripper_ruby_parser/pull/79
162
177
  [#78]: https://github.com/mvz/ripper_ruby_parser/pull/78
163
178
  [#77]: https://github.com/mvz/ripper_ruby_parser/pull/77
data/README.md CHANGED
@@ -22,14 +22,14 @@ The following incompatibilities cannot be changed:
22
22
 
23
23
  * RipperRubyParser won't handle non-UTF-8 files without an encoding comment,
24
24
  just like regular Ruby
25
- * RipperRubyParser does not attempt to match RubyParser's line numbering bugs
25
+ * RipperRubyParser does not match RubyParser's line numbering
26
26
  * RipperRubyParser correctly dedents heredocs with interpolations
27
27
 
28
28
  The following incompatibilities can be made compatible by turning on
29
29
  extra-compatible mode:
30
30
 
31
31
  * Operator assignment of a method call without parentheses to a collection
32
- element uses and `:array` S-expression instead of `:arglist`
32
+ element uses an `:array` S-expression instead of `:arglist`
33
33
  * RipperRubyParser keeps carriage return characters in heredocs that include
34
34
  them
35
35
 
@@ -32,6 +32,15 @@ module RipperRubyParser
32
32
  super
33
33
  end
34
34
 
35
+ def on_begin(*args)
36
+ commentize(:begin, super)
37
+ end
38
+
39
+ def on_void_stmt
40
+ result = super
41
+ result << [lineno, column]
42
+ end
43
+
35
44
  def on_comment(tok)
36
45
  @comment += tok
37
46
  end
@@ -49,14 +58,15 @@ module RipperRubyParser
49
58
  end
50
59
 
51
60
  def on_kw(tok)
61
+ result = super
52
62
  case tok
53
- when 'class', 'def', 'module'
63
+ when 'class', 'def', 'module', 'BEGIN', 'begin', 'END'
54
64
  unless @in_symbol
55
- @comment_stack.push [tok.to_sym, @comment]
65
+ @comment_stack.push [result, @comment]
56
66
  @comment = ''
57
67
  end
58
68
  end
59
- super
69
+ result
60
70
  end
61
71
 
62
72
  def on_module(*args)
@@ -275,6 +285,14 @@ module RipperRubyParser
275
285
  super
276
286
  end
277
287
 
288
+ def on_BEGIN(*args)
289
+ commentize(:BEGIN, super)
290
+ end
291
+
292
+ def on_END(*args)
293
+ commentize(:END, super)
294
+ end
295
+
278
296
  def on_parse_error(*args)
279
297
  raise SyntaxError, *args
280
298
  end
@@ -298,8 +316,9 @@ module RipperRubyParser
298
316
  private
299
317
 
300
318
  def commentize(_name, exp)
301
- _tok, comment = @comment_stack.pop
319
+ (_, _kw, loc), comment = @comment_stack.pop
302
320
  @comment = ''
321
+ exp.push loc
303
322
  [:comment, comment, exp]
304
323
  end
305
324
  end
@@ -47,10 +47,10 @@ module RipperRubyParser
47
47
  end
48
48
 
49
49
  def process_begin(exp)
50
- _, body = exp.shift 2
50
+ _, body, pos = exp.shift 3
51
51
 
52
52
  body = convert_empty_to_nil_symbol process(body)
53
- s(:begin, body)
53
+ with_position pos, s(:begin, body)
54
54
  end
55
55
 
56
56
  def process_rescue(exp)
@@ -86,7 +86,9 @@ module RipperRubyParser
86
86
 
87
87
  body = s()
88
88
 
89
- main = wrap_in_block map_process_list_compact main.sexp_body
89
+ main_list = map_unwrap_begin_list map_process_list main.sexp_body
90
+ line = main_list.first.line
91
+ main = wrap_in_block reject_void_stmt main_list
90
92
  body << main if main
91
93
 
92
94
  if rescue_block
@@ -102,7 +104,7 @@ module RipperRubyParser
102
104
  body = s(s(:ensure, *body))
103
105
  end
104
106
 
105
- wrap_in_block(body) || s()
107
+ wrap_in_block(body) || s().line(line)
106
108
  end
107
109
 
108
110
  def process_rescue_mod(exp)
@@ -11,10 +11,10 @@ module RipperRubyParser
11
11
 
12
12
  def process_string_content(exp)
13
13
  _, *rest = shift_all exp
14
- string, rest = extract_string_parts(rest)
14
+ line, string, rest = extract_string_parts(rest)
15
15
 
16
16
  if rest.empty?
17
- s(:str, string)
17
+ with_line_number(line, s(:str, string))
18
18
  else
19
19
  s(:dstr, string, *rest)
20
20
  end
@@ -63,9 +63,9 @@ module RipperRubyParser
63
63
 
64
64
  def process_xstring(exp)
65
65
  _, *rest = shift_all exp
66
- string, rest = extract_string_parts(rest)
66
+ line, string, rest = extract_string_parts(rest)
67
67
  if rest.empty?
68
- s(:xstr, string)
68
+ s(:xstr, string).line(line)
69
69
  else
70
70
  s(:dxstr, string, *rest)
71
71
  end
@@ -77,7 +77,9 @@ module RipperRubyParser
77
77
  content = process(content)
78
78
  numflags = character_flags_to_numerical flags
79
79
 
80
- return s(:lit, Regexp.new(content.last, numflags)) if content.length == 2
80
+ if content.length == 2
81
+ return with_line_number(content.line, s(:lit, Regexp.new(content.last, numflags)))
82
+ end
81
83
 
82
84
  content.sexp_type = :dregx_once if flags =~ /o/
83
85
  content << numflags unless numflags == 0
@@ -86,8 +88,8 @@ module RipperRubyParser
86
88
 
87
89
  def process_regexp(exp)
88
90
  _, *rest = shift_all exp
89
- string, rest = extract_string_parts(rest)
90
- s(:dregx, string, *rest)
91
+ line, string, rest = extract_string_parts(rest)
92
+ with_line_number(line, s(:dregx, string, *rest))
91
93
  end
92
94
 
93
95
  def process_symbol_literal(exp)
@@ -126,10 +128,10 @@ module RipperRubyParser
126
128
  REGEXP_LITERALS = ['/', /^%r.$/].freeze
127
129
 
128
130
  def process_at_tstring_content(exp)
129
- _, content, _, delim = exp.shift 4
131
+ _, content, pos, delim = exp.shift 4
130
132
  string = handle_string_unescaping(content, delim)
131
133
  string = handle_string_encoding(string, delim)
132
- s(:str, string)
134
+ with_position(pos, s(:str, string))
133
135
  end
134
136
 
135
137
  def process_array(exp)
@@ -164,7 +166,7 @@ module RipperRubyParser
164
166
  private
165
167
 
166
168
  def extract_string_parts(list)
167
- return '', [] if list.empty?
169
+ return nil, '', [] if list.empty?
168
170
 
169
171
  list = merge_raw_string_literals list
170
172
  list = map_process_list list
@@ -185,10 +187,11 @@ module RipperRubyParser
185
187
  string = ''
186
188
  while parts.first&.sexp_type == :str
187
189
  str = parts.shift
190
+ line ||= str.line
188
191
  string += str.last
189
192
  end
190
193
 
191
- return string, parts
194
+ return line, string, parts
192
195
  end
193
196
 
194
197
  def merge_raw_string_literals(list)
@@ -230,12 +233,13 @@ module RipperRubyParser
230
233
  def handle_symbol_content(node)
231
234
  if node.sexp_type == :'@kw'
232
235
  symbol, position = extract_node_symbol_with_position(node)
236
+ with_position(position, s(:lit, symbol))
233
237
  else
234
238
  processed = process(node)
235
239
  symbol = processed.last.to_sym
236
- position = processed.line
240
+ line = processed.line
241
+ with_line_number(line, s(:lit, symbol))
237
242
  end
238
- with_line_number(position, s(:lit, symbol))
239
243
  end
240
244
 
241
245
  def merge_left_into_right(left, right)
@@ -52,10 +52,12 @@ module RipperRubyParser
52
52
  def handle_conditional_loop_mod(type, negated_type, exp)
53
53
  _, cond, body = exp.shift 3
54
54
 
55
+ cond = process(cond)
56
+ body = process(body)
55
57
  check_at_start = check_at_start?(body)
56
58
  construct_conditional_loop(type, negated_type,
57
- unwrap_begin(process(cond)),
58
- unwrap_begin(process(body)),
59
+ unwrap_begin(cond),
60
+ unwrap_begin(body),
59
61
  check_at_start)
60
62
  end
61
63
 
@@ -5,9 +5,9 @@ module RipperRubyParser
5
5
  # Sexp handers for method definitions and related constructs
6
6
  module Methods
7
7
  def process_def(exp)
8
- _, ident, params, body = exp.shift 4
8
+ _, ident, params, body, pos = exp.shift 5
9
9
 
10
- ident, pos = extract_node_symbol_with_position ident
10
+ ident, = extract_node_symbol_with_position ident
11
11
 
12
12
  in_method do
13
13
  params = convert_arguments(process(params))
@@ -19,7 +19,7 @@ module RipperRubyParser
19
19
  end
20
20
 
21
21
  def process_defs(exp)
22
- _, receiver, _, ident, params, body = exp.shift 6
22
+ _, receiver, _, ident, params, body, = exp.shift 7
23
23
 
24
24
  ident, = extract_node_symbol_with_position ident
25
25
 
@@ -85,7 +85,7 @@ module RipperRubyParser
85
85
  block = process exp
86
86
  case block.length
87
87
  when 0
88
- [s(:nil)]
88
+ [s(:nil).line(block.line)]
89
89
  else
90
90
  unwrap_block block
91
91
  end
@@ -45,6 +45,8 @@ module RipperRubyParser
45
45
  @in_method_body = false
46
46
  @kwrest = []
47
47
  @block_kwrest = []
48
+
49
+ @kept_comment = nil
48
50
  end
49
51
 
50
52
  include SexpHandlers
@@ -56,23 +58,23 @@ module RipperRubyParser
56
58
  end
57
59
 
58
60
  def process_module(exp)
59
- _, const_ref, body = exp.shift 3
60
- const, line = const_ref_to_const_with_line_number const_ref
61
- with_line_number(line,
62
- s(:module, const, *class_or_module_body(body)))
61
+ _, const_ref, body, pos = exp.shift 4
62
+ const = const_ref_to_const const_ref
63
+ with_position(pos,
64
+ s(:module, const, *class_or_module_body(body)))
63
65
  end
64
66
 
65
67
  def process_class(exp)
66
- _, const_ref, parent, body = exp.shift 4
67
- const, line = const_ref_to_const_with_line_number const_ref
68
+ _, const_ref, parent, body, pos = exp.shift 5
69
+ const = const_ref_to_const const_ref
68
70
  parent = process(parent)
69
- with_line_number(line,
70
- s(:class, const, parent, *class_or_module_body(body)))
71
+ with_position(pos,
72
+ s(:class, const, parent, *class_or_module_body(body)))
71
73
  end
72
74
 
73
75
  def process_sclass(exp)
74
- _, klass, block = exp.shift 3
75
- s(:sclass, process(klass), *class_or_module_body(block))
76
+ _, klass, block, pos = exp.shift 4
77
+ with_position pos, s(:sclass, process(klass), *class_or_module_body(block))
76
78
  end
77
79
 
78
80
  def process_stmts(exp)
@@ -104,6 +106,11 @@ module RipperRubyParser
104
106
  s(:valias, left[1].to_sym, right[1].to_sym)
105
107
  end
106
108
 
109
+ def process_void_stmt(exp)
110
+ _, pos = exp.shift 2
111
+ with_position pos, s(:void_stmt)
112
+ end
113
+
107
114
  def process_const_path_ref(exp)
108
115
  _, left, right = exp.shift 3
109
116
  s(:colon2, process(left), extract_node_symbol(process(right)))
@@ -139,21 +146,28 @@ module RipperRubyParser
139
146
 
140
147
  def process_comment(exp)
141
148
  _, comment, inner = exp.shift 3
149
+ comment = @kept_comment + comment if @kept_comment
150
+ @kept_comment = nil
142
151
  sexp = process(inner)
143
- sexp.comments = comment
152
+ case sexp.sexp_type
153
+ when :defs, :defn, :module, :class, :sclass
154
+ sexp.comments = comment
155
+ else
156
+ @kept_comment = comment
157
+ end
144
158
  sexp
145
159
  end
146
160
 
147
161
  def process_BEGIN(exp)
148
- _, body = exp.shift 2
162
+ _, body, pos = exp.shift 3
149
163
  body = reject_void_stmt map_process_list body.sexp_body
150
- s(:iter, s(:preexe), 0, *body)
164
+ with_position pos, s(:iter, s(:preexe), 0, *body)
151
165
  end
152
166
 
153
167
  def process_END(exp)
154
- _, body = exp.shift 2
168
+ _, body, pos = exp.shift 3
155
169
  body = map_process_list_compact body.sexp_body
156
- s(:iter, s(:postexe), 0, *body)
170
+ with_position pos, s(:iter, s(:postexe), 0, *body)
157
171
  end
158
172
 
159
173
  # number literals
@@ -242,11 +256,10 @@ module RipperRubyParser
242
256
 
243
257
  private
244
258
 
245
- def const_ref_to_const_with_line_number(const_ref)
259
+ def const_ref_to_const(const_ref)
246
260
  const = process(const_ref)
247
- line = const.line
248
261
  const = const[1] if const.sexp_type == :const
249
- return const, line
262
+ const
250
263
  end
251
264
 
252
265
  def class_or_module_body(exp)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RipperRubyParser
4
- VERSION = '1.6.0'
4
+ VERSION = '1.6.1'
5
5
  end
@@ -9,8 +9,8 @@ describe 'Using RipperRubyParser and RubyParser' do
9
9
  "puts 'Hello World'"
10
10
  end
11
11
 
12
- it 'gives the same result' do
13
- program.must_be_parsed_as_before
12
+ it 'gives the same result with line numbers' do
13
+ program.must_be_parsed_as_before with_line_numbers: true
14
14
  end
15
15
  end
16
16
 
@@ -35,8 +35,8 @@ describe 'Using RipperRubyParser and RubyParser' do
35
35
  END
36
36
  end
37
37
 
38
- it 'gives the same result' do
39
- program.must_be_parsed_as_before
38
+ it 'gives the same result with line numbers' do
39
+ program.must_be_parsed_as_before with_line_numbers: true
40
40
  end
41
41
  end
42
42
 
@@ -45,8 +45,8 @@ describe 'Using RipperRubyParser and RubyParser' do
45
45
  'def fred() yield(3) if block_given?; end'
46
46
  end
47
47
 
48
- it 'gives the same result' do
49
- program.must_be_parsed_as_before
48
+ it 'gives the same result with line numbers' do
49
+ program.must_be_parsed_as_before with_line_numbers: true
50
50
  end
51
51
  end
52
52
 
@@ -97,8 +97,8 @@ describe 'Using RipperRubyParser and RubyParser' do
97
97
  "/(\#{@types})\\s*(\\w+)\\s*\\(([^)]*)\\)/"
98
98
  end
99
99
 
100
- it 'gives the same result' do
101
- program.must_be_parsed_as_before
100
+ it 'gives the same result with line numbers' do
101
+ program.must_be_parsed_as_before with_line_numbers: true
102
102
  end
103
103
  end
104
104
  end
@@ -4,30 +4,6 @@ require File.expand_path('../test_helper.rb', File.dirname(__FILE__))
4
4
  require 'ruby_parser'
5
5
 
6
6
  describe 'Using RipperRubyParser and RubyParser' do
7
- def to_line_numbers(exp)
8
- exp.map! do |sub_exp|
9
- if sub_exp.is_a? Sexp
10
- to_line_numbers sub_exp
11
- else
12
- sub_exp
13
- end
14
- end
15
-
16
- if exp.sexp_type == :scope
17
- exp
18
- else
19
- s(:line_number, exp.line, exp)
20
- end
21
- end
22
-
23
- let :newparser do
24
- RipperRubyParser::Parser.new
25
- end
26
-
27
- let :oldparser do
28
- RubyParser.for_current_ruby
29
- end
30
-
31
7
  describe 'for a multi-line program' do
32
8
  let :program do
33
9
  <<-END
@@ -44,21 +20,12 @@ describe 'Using RipperRubyParser and RubyParser' do
44
20
  END
45
21
  end
46
22
 
47
- let :original do
48
- oldparser.parse program
49
- end
50
-
51
- let :imitation do
52
- newparser.parse program
53
- end
54
-
55
23
  it 'gives the same result' do
56
- imitation.must_equal original
24
+ program.must_be_parsed_as_before
57
25
  end
58
26
 
59
27
  it 'gives the same result with line numbers' do
60
- formatted(to_line_numbers(imitation)).
61
- must_equal formatted(to_line_numbers(original))
28
+ program.must_be_parsed_as_before with_line_numbers: true
62
29
  end
63
30
  end
64
31
  end
@@ -22,7 +22,9 @@ describe RipperRubyParser::CommentingRipperParser do
22
22
  s(:def,
23
23
  s(:@ident, 'foo', s(2, 4)),
24
24
  empty_params_list,
25
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
25
+ s(:bodystmt,
26
+ s(:stmts, s(:void_stmt, s(2, 12))), nil, nil, nil),
27
+ s(2, 0)))))
26
28
  end
27
29
 
28
30
  it 'produces a blank comment node surrounding a def that has no comment' do
@@ -34,7 +36,9 @@ describe RipperRubyParser::CommentingRipperParser do
34
36
  s(:def,
35
37
  s(:@ident, 'foo', s(1, 4)),
36
38
  empty_params_list,
37
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
39
+ s(:bodystmt,
40
+ s(:stmts, s(:void_stmt, s(1, 12))), nil, nil, nil),
41
+ s(1, 0)))))
38
42
  end
39
43
 
40
44
  it 'produces a comment node surrounding a commented class' do
@@ -46,7 +50,9 @@ describe RipperRubyParser::CommentingRipperParser do
46
50
  s(:class,
47
51
  s(:const_ref, s(:@const, 'Foo', s(2, 6))),
48
52
  nil,
49
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
53
+ s(:bodystmt,
54
+ s(:stmts, s(:void_stmt, s(2, 10))), nil, nil, nil),
55
+ s(2, 0)))))
50
56
  end
51
57
 
52
58
  it 'produce a blank comment node surrounding a class that has no comment' do
@@ -58,7 +64,9 @@ describe RipperRubyParser::CommentingRipperParser do
58
64
  s(:class,
59
65
  s(:const_ref, s(:@const, 'Foo', s(1, 6))),
60
66
  nil,
61
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
67
+ s(:bodystmt,
68
+ s(:stmts, s(:void_stmt, s(1, 10))), nil, nil, nil),
69
+ s(1, 0)))))
62
70
  end
63
71
 
64
72
  it 'produces a comment node surrounding a commented module' do
@@ -69,7 +77,9 @@ describe RipperRubyParser::CommentingRipperParser do
69
77
  "# Foo\n",
70
78
  s(:module,
71
79
  s(:const_ref, s(:@const, 'Foo', s(2, 7))),
72
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
80
+ s(:bodystmt,
81
+ s(:stmts, s(:void_stmt, s(2, 11))), nil, nil, nil),
82
+ s(2, 0)))))
73
83
  end
74
84
 
75
85
  it 'produces a blank comment node surrounding a module that has no comment' do
@@ -80,7 +90,9 @@ describe RipperRubyParser::CommentingRipperParser do
80
90
  '',
81
91
  s(:module,
82
92
  s(:const_ref, s(:@const, 'Foo', s(1, 7))),
83
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
93
+ s(:bodystmt,
94
+ s(:stmts, s(:void_stmt, s(1, 11))), nil, nil, nil),
95
+ s(1, 0)))))
84
96
  end
85
97
 
86
98
  it 'is not confused by a symbol containing a keyword' do
@@ -93,7 +105,9 @@ describe RipperRubyParser::CommentingRipperParser do
93
105
  s(:def,
94
106
  s(:@ident, 'foo', s(1, 12)),
95
107
  empty_params_list,
96
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
108
+ s(:bodystmt,
109
+ s(:stmts, s(:void_stmt, s(1, 20))), nil, nil, nil),
110
+ s(1, 8)))))
97
111
  end
98
112
 
99
113
  it 'is not confused by a dynamic symbol' do
@@ -107,7 +121,9 @@ describe RipperRubyParser::CommentingRipperParser do
107
121
  s(:def,
108
122
  s(:@ident, 'bar', s(1, 12)),
109
123
  empty_params_list,
110
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
124
+ s(:bodystmt,
125
+ s(:stmts, s(:void_stmt, s(1, 20))), nil, nil, nil),
126
+ s(1, 8)))))
111
127
  end
112
128
 
113
129
  it 'is not confused by a dynamic symbol containing a class definition' do
@@ -125,10 +141,8 @@ describe RipperRubyParser::CommentingRipperParser do
125
141
  s(:const_ref, s(:@const, 'Bar', s(1, 13))),
126
142
  nil,
127
143
  s(:bodystmt,
128
- s(:stmts, s(:void_stmt)),
129
- nil,
130
- nil,
131
- nil)))))))))
144
+ s(:stmts, s(:void_stmt, s(1, 17))), nil, nil, nil),
145
+ s(1, 7)))))))))
132
146
  end
133
147
 
134
148
  it 'turns an embedded document into a comment node' do
@@ -140,7 +154,9 @@ describe RipperRubyParser::CommentingRipperParser do
140
154
  s(:class,
141
155
  s(:const_ref, s(:@const, 'Foo', s(4, 6))),
142
156
  nil,
143
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil)))))
157
+ s(:bodystmt,
158
+ s(:stmts, s(:void_stmt, s(4, 10))), nil, nil, nil),
159
+ s(4, 0)))))
144
160
  end
145
161
  end
146
162
 
@@ -143,6 +143,22 @@ describe RipperRubyParser::Parser do
143
143
  'END { }'.
144
144
  must_be_parsed_as s(:iter, s(:postexe), 0)
145
145
  end
146
+
147
+ it 'assigns correct line numbers' do
148
+ "END {\nfoo\n}".
149
+ must_be_parsed_as s(:iter,
150
+ s(:postexe).line(1), 0,
151
+ s(:call, nil, :foo).line(2)).line(1),
152
+ with_line_numbers: true
153
+ end
154
+
155
+ it 'assigns correct line numbers to a embedded begin block' do
156
+ "END {\nbegin\nfoo\nend\n}".
157
+ must_be_parsed_as s(:iter,
158
+ s(:postexe).line(1), 0,
159
+ s(:call, nil, :foo).line(3)).line(1),
160
+ with_line_numbers: true
161
+ end
146
162
  end
147
163
 
148
164
  describe 'for the BEGIN keyword' do
@@ -155,6 +171,23 @@ describe RipperRubyParser::Parser do
155
171
  'BEGIN { }'.
156
172
  must_be_parsed_as s(:iter, s(:preexe), 0)
157
173
  end
174
+
175
+ it 'assigns correct line numbers' do
176
+ "BEGIN {\nfoo\n}".
177
+ must_be_parsed_as s(:iter,
178
+ s(:preexe).line(1), 0,
179
+ s(:call, nil, :foo).line(2)).line(1),
180
+ with_line_numbers: true
181
+ end
182
+
183
+ it 'assigns correct line numbers to a embedded begin block' do
184
+ "BEGIN {\nbegin\nfoo\nend\n}".
185
+ must_be_parsed_as s(:iter,
186
+ s(:preexe).line(1), 0,
187
+ s(:begin,
188
+ s(:call, nil, :foo).line(3)).line(2)).line(1),
189
+ with_line_numbers: true
190
+ end
158
191
  end
159
192
 
160
193
  describe 'for constant lookups' do
@@ -300,6 +333,35 @@ describe RipperRubyParser::Parser do
300
333
  s(:call, nil, :baz)))
301
334
  result.comments.must_equal "# Foo\n"
302
335
  end
336
+
337
+ # TODO: Prefer assigning comment to the BEGIN instead
338
+ it 'assigns comments on BEGIN blocks to the following item' do
339
+ result = parser.parse "# Bar\nBEGIN { }\n# Foo\nclass Bar\n# foo\ndef foo; end\nend"
340
+ result.must_equal s(:block,
341
+ s(:iter, s(:preexe), 0),
342
+ s(:class, :Bar, nil,
343
+ s(:defn, :foo, s(:args), s(:nil))))
344
+ result[2].comments.must_equal "# Bar\n# Foo\n"
345
+ result[2][3].comments.must_equal "# foo\n"
346
+ end
347
+
348
+ it 'assigns comments on multiple BEGIN blocks to the following item' do
349
+ result = parser.parse "# Bar\nBEGIN { }\n# Baz\nBEGIN { }\n# Foo\ndef foo; end"
350
+ result.must_equal s(:block,
351
+ s(:iter, s(:preexe), 0),
352
+ s(:iter, s(:preexe), 0),
353
+ s(:defn, :foo, s(:args), s(:nil)))
354
+ result[3].comments.must_equal "# Bar\n# Baz\n# Foo\n"
355
+ end
356
+
357
+ it 'assigns comments on BEGIN blocks to the first following item' do
358
+ result = parser.parse "# Bar\nBEGIN { }\n# Baz\nBEGIN { }\n# Foo\ndef foo; end"
359
+ result.must_equal s(:block,
360
+ s(:iter, s(:preexe), 0),
361
+ s(:iter, s(:preexe), 0),
362
+ s(:defn, :foo, s(:args), s(:nil)))
363
+ result[3].comments.must_equal "# Bar\n# Baz\n# Foo\n"
364
+ end
303
365
  end
304
366
 
305
367
  # Note: differences in the handling of line numbers are not caught by
@@ -359,11 +421,11 @@ describe RipperRubyParser::Parser do
359
421
  end
360
422
 
361
423
  it 'works for a local variable' do
362
- result = parser.parse "foo = bar\nfoo\n"
363
- result.sexp_type.must_equal :block
364
- result[1].line.must_equal 1
365
- result[2].line.must_equal 2
366
- result.line.must_equal 1
424
+ "foo = bar\nfoo\n".
425
+ must_be_parsed_as s(:block,
426
+ s(:lasgn, :foo, s(:call, nil, :bar).line(1)).line(1),
427
+ s(:lvar, :foo).line(2)).line(1),
428
+ with_line_numbers: true
367
429
  end
368
430
 
369
431
  it 'works for an integer literal' do
@@ -386,6 +448,31 @@ describe RipperRubyParser::Parser do
386
448
  result.line.must_equal 1
387
449
  end
388
450
 
451
+ it 'works for a symbol literal' do
452
+ result = parser.parse ':foo'
453
+ result.line.must_equal 1
454
+ end
455
+
456
+ it 'works for a keyword-like symbol literal' do
457
+ result = parser.parse ':and'
458
+ result.line.must_equal 1
459
+ end
460
+
461
+ it 'works for a string literal' do
462
+ result = parser.parse '"foo"'
463
+ result.line.must_equal 1
464
+ end
465
+
466
+ it 'works for a backtick string literal' do
467
+ result = parser.parse '`foo`'
468
+ result.line.must_equal 1
469
+ end
470
+
471
+ it 'works for a plain regexp literal' do
472
+ result = parser.parse '/foo/'
473
+ result.line.must_equal 1
474
+ end
475
+
389
476
  it 'works for a regular expression back reference' do
390
477
  result = parser.parse '$1'
391
478
  result.line.must_equal 1
@@ -422,15 +509,12 @@ describe RipperRubyParser::Parser do
422
509
  end
423
510
 
424
511
  it 'assigns line numbers to nested sexps without their own line numbers' do
425
- result = parser.parse "foo(bar) do\nnext baz\nend\n"
426
- result.must_equal s(:iter,
427
- s(:call, nil, :foo, s(:call, nil, :bar)),
428
- 0,
429
- s(:next, s(:call, nil, :baz)))
430
- arglist = result[1][3]
431
- block = result[3]
432
- nums = [arglist.line, block.line]
433
- nums.must_equal [1, 2]
512
+ "foo(bar) do\nnext baz\nend\n".
513
+ must_be_parsed_as s(:iter,
514
+ s(:call, nil, :foo, s(:call, nil, :bar).line(1)).line(1),
515
+ 0,
516
+ s(:next, s(:call, nil, :baz).line(2)).line(2)).line(1),
517
+ with_line_numbers: true
434
518
  end
435
519
 
436
520
  describe 'when a line number is passed' do
@@ -204,6 +204,15 @@ describe RipperRubyParser::Parser do
204
204
  must_be_parsed_as s(:defn, :for, s(:args),
205
205
  s(:nil))
206
206
  end
207
+
208
+ it 'assigns correct line numbers when the body is empty' do
209
+ "def bar\nend".
210
+ must_be_parsed_as s(:defn,
211
+ :bar,
212
+ s(:args).line(1),
213
+ s(:nil).line(2)).line(1),
214
+ with_line_numbers: true
215
+ end
207
216
  end
208
217
 
209
218
  describe 'for singleton method definitions' do
@@ -74,10 +74,10 @@ describe RipperRubyParser::SexpProcessor do
74
74
  end
75
75
 
76
76
  describe 'for a :module sexp' do
77
- it 'does not create body eleents for an empty definition' do
77
+ it 'does not create body elements for an empty definition' do
78
78
  sexp = s(:module,
79
79
  s(:const_ref, s(:@const, 'Foo', s(1, 13))),
80
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil))
80
+ s(:bodystmt, s(:stmts, s(:void_stmt, s(2, 3))), nil, nil, nil))
81
81
  result = processor.process sexp
82
82
  result.must_equal s(:module, :Foo)
83
83
  end
@@ -103,7 +103,7 @@ describe RipperRubyParser::SexpProcessor do
103
103
  it 'does not create body eleents for an empty definition' do
104
104
  sexp = s(:class,
105
105
  s(:const_ref, s(:@const, 'Foo', s(1, 13))), nil,
106
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil))
106
+ s(:bodystmt, s(:stmts, s(:void_stmt, s(2, 8))), nil, nil, nil))
107
107
  result = processor.process sexp
108
108
  result.must_equal s(:class, :Foo, nil)
109
109
  end
@@ -128,7 +128,7 @@ describe RipperRubyParser::SexpProcessor do
128
128
  sexp = s(:class,
129
129
  s(:const_ref, s(:@const, 'Foo', s(1, 13))),
130
130
  s(:var_ref, s(:@const, 'Bar', s(1, 12))),
131
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil))
131
+ s(:bodystmt, s(:stmts, s(:void_stmt, s(2, 7))), nil, nil, nil))
132
132
  result = processor.process sexp
133
133
  result.must_equal s(:class, :Foo, s(:const, :Bar))
134
134
  end
@@ -153,7 +153,7 @@ describe RipperRubyParser::SexpProcessor do
153
153
  sexp = s(:def,
154
154
  s(:@ident, 'foo', s(1, 4)),
155
155
  s(:params, nil, nil, nil, nil, nil),
156
- s(:bodystmt, s(:stmts, s(:void_stmt)), nil, nil, nil))
156
+ s(:bodystmt, s(:stmts, s(:void_stmt, s(2, 3))), nil, nil, nil))
157
157
  result = processor.process sexp
158
158
  result.must_equal s(:defn, :foo, s(:args), s(:nil))
159
159
  end
@@ -13,14 +13,36 @@ require 'ripper_ruby_parser'
13
13
 
14
14
  module MiniTest
15
15
  class Spec
16
- def formatted(exp)
17
- exp.to_s.gsub(/\), /, "),\n")
16
+ def inspect_with_line_numbers(exp)
17
+ parts = exp.map do |sub_exp|
18
+ if sub_exp.is_a? Sexp
19
+ inspect_with_line_numbers(sub_exp)
20
+ else
21
+ sub_exp.inspect
22
+ end
23
+ end
24
+
25
+ plain = "s(#{parts.join(', ')})"
26
+ if exp.line
27
+ "#{plain}.line(#{exp.line})"
28
+ else
29
+ plain
30
+ end
31
+ end
32
+
33
+ def formatted(exp, with_line_numbers: false)
34
+ inspection = if with_line_numbers
35
+ inspect_with_line_numbers(exp)
36
+ else
37
+ exp.inspect
38
+ end
39
+ inspection.gsub(/\), /, "),\n")
18
40
  end
19
41
 
20
42
  def fix_lines(exp)
21
- return s(:lit, :__LINE__) if exp.sexp_type == :lit && exp.line == exp[1]
43
+ return s(:lit, :__LINE__).line(exp.line) if exp.sexp_type == :lit && exp.line == exp[1]
22
44
 
23
- inner = exp.map do |sub_exp|
45
+ exp.sexp_body = exp.sexp_body.map do |sub_exp|
24
46
  if sub_exp.is_a? Sexp
25
47
  fix_lines sub_exp
26
48
  else
@@ -28,11 +50,13 @@ module MiniTest
28
50
  end
29
51
  end
30
52
 
31
- s(*inner)
53
+ exp
32
54
  end
33
55
 
34
56
  def to_comments(exp)
35
- inner = exp.map do |sub_exp|
57
+ comments = exp.comments.to_s.gsub(/\n\s*\n/, "\n")
58
+
59
+ exp.sexp_body = exp.sexp_body.map do |sub_exp|
36
60
  if sub_exp.is_a? Sexp
37
61
  to_comments sub_exp
38
62
  else
@@ -40,15 +64,14 @@ module MiniTest
40
64
  end
41
65
  end
42
66
 
43
- comments = exp.comments.to_s.gsub(/\n\s*\n/, "\n")
44
67
  if comments.empty?
45
- s(*inner)
68
+ exp
46
69
  else
47
- s(:comment, comments, s(*inner))
70
+ s(:comment, comments, exp)
48
71
  end
49
72
  end
50
73
 
51
- def assert_parsed_as(sexp, code, extra_compatible: false)
74
+ def assert_parsed_as(sexp, code, extra_compatible: false, with_line_numbers: false)
52
75
  parser = RipperRubyParser::Parser.new
53
76
  parser.extra_compatible = extra_compatible
54
77
  result = parser.parse code
@@ -56,11 +79,12 @@ module MiniTest
56
79
  assert_nil result
57
80
  else
58
81
  assert_equal sexp, result
59
- assert_equal sexp.to_s, result.to_s
82
+ assert_equal(formatted(sexp, with_line_numbers: with_line_numbers),
83
+ formatted(result, with_line_numbers: with_line_numbers))
60
84
  end
61
85
  end
62
86
 
63
- def assert_parsed_as_before(code)
87
+ def assert_parsed_as_before(code, with_line_numbers: false)
64
88
  oldparser = RubyParser.for_current_ruby
65
89
  newparser = RipperRubyParser::Parser.new
66
90
  newparser.extra_compatible = true
@@ -68,7 +92,9 @@ module MiniTest
68
92
  result = newparser.parse code
69
93
  expected = to_comments fix_lines expected
70
94
  result = to_comments fix_lines result
71
- assert_equal formatted(expected), formatted(result)
95
+ assert_equal expected, result
96
+ assert_equal(formatted(expected, with_line_numbers: with_line_numbers),
97
+ formatted(result, with_line_numbers: with_line_numbers))
72
98
  end
73
99
  end
74
100
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ripper_ruby_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matijs van Zuijlen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-12 00:00:00.000000000 Z
11
+ date: 2019-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sexp_processor