ripper_ruby_parser 1.6.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
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