ripper_ruby_parser 1.3.0 → 1.4.0

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: bd7842da24ae8db93c8a0c397a7648469dd549734c4903a252c042a7a45ad967
4
- data.tar.gz: c6684342b972c5d5a021fc4e1848b460f57a5f471158da76f9255427b224c356
3
+ metadata.gz: 4a4cdc97eb0ffc630d78101fbd5ec056919c03bd91571a27d5972f6b67794dbf
4
+ data.tar.gz: 192aa89ab393bfaa24690b4db77368cd608dd44de41575e2223d8936628f95c2
5
5
  SHA512:
6
- metadata.gz: f067ec3069d0baa143ded82de049ae1baa5c8811cee88ff930494baf5bbcdfb83bee1656712120150ca0293c55da9237923a170fd463f261b1cd4f637abbcad7
7
- data.tar.gz: 76e945832ebcefab6df4ae6c3fc26c4b03e1a24dac1399ea5ac4b1f92c2c331d8d7f8dff365757f5450bed8d738d769bf398b02843bb9aebff8c1010be70439f
6
+ metadata.gz: 8c44761bbf0e73e5c37a14ed1744639938d1e0e50f100735937f6727677224ef3f065a81a711246375a31df55394e7f2e0dd7a996a474a8c24dc3e01319b05f1
7
+ data.tar.gz: 6fed83fa681eb454030522d362bc7d0b5904d061331b659f695f5b668cb5124f94ad5aafe1dfa7ee21387cf5d292e72403aab27aa9daa5d99b7003026e712896
@@ -1,4 +1,9 @@
1
- # Change log
1
+ # Changelog
2
+
3
+ ## 1.4.0 / 2018-03-30
4
+
5
+ * Handle begin..end blocks with postfix conditionals
6
+ * Correctly handle string variants that do not allow escape sequences
2
7
 
3
8
  ## 1.3.0 / 2018-02-17
4
9
 
@@ -1,5 +1,6 @@
1
1
  require 'ripper'
2
2
  require 'ripper_ruby_parser/syntax_error'
3
+ require 'ripper_ruby_parser/unescape'
3
4
 
4
5
  module RipperRubyParser
5
6
  # Variant of Ripper's SexpBuilder parser class that inserts comments as
@@ -11,6 +12,7 @@ module RipperRubyParser
11
12
  super
12
13
  @comment = nil
13
14
  @comment_stack = []
15
+ @delimiter_stack = []
14
16
  @in_symbol = false
15
17
  end
16
18
 
@@ -21,6 +23,11 @@ module RipperRubyParser
21
23
  Sexp.from_array(result)
22
24
  end
23
25
 
26
+ def on_backtick(delimiter)
27
+ @delimiter_stack.push delimiter
28
+ super
29
+ end
30
+
24
31
  def on_comment(tok)
25
32
  @comment ||= ''
26
33
  @comment += tok
@@ -66,6 +73,16 @@ module RipperRubyParser
66
73
  list << elem
67
74
  end
68
75
 
76
+ def on_heredoc_beg(delimiter)
77
+ @delimiter_stack.push delimiter
78
+ super
79
+ end
80
+
81
+ def on_heredoc_end(delimiter)
82
+ @delimiter_stack.pop
83
+ super
84
+ end
85
+
69
86
  def on_mlhs_new
70
87
  [:mlhs]
71
88
  end
@@ -86,6 +103,11 @@ module RipperRubyParser
86
103
  list << elem
87
104
  end
88
105
 
106
+ def on_qsymbols_beg(delimiter)
107
+ @delimiter_stack.push delimiter
108
+ super
109
+ end
110
+
89
111
  def on_qsymbols_new
90
112
  [:qsymbols]
91
113
  end
@@ -94,6 +116,11 @@ module RipperRubyParser
94
116
  list << elem
95
117
  end
96
118
 
119
+ def on_qwords_beg(delimiter)
120
+ @delimiter_stack.push delimiter
121
+ super
122
+ end
123
+
97
124
  def on_qwords_new
98
125
  [:qwords]
99
126
  end
@@ -102,6 +129,16 @@ module RipperRubyParser
102
129
  list << elem
103
130
  end
104
131
 
132
+ def on_regexp_beg(delimiter)
133
+ @delimiter_stack.push delimiter
134
+ super
135
+ end
136
+
137
+ def on_regexp_end(delimiter)
138
+ @delimiter_stack.pop
139
+ super
140
+ end
141
+
105
142
  def on_regexp_new
106
143
  [:regexp]
107
144
  end
@@ -122,6 +159,11 @@ module RipperRubyParser
122
159
  list << elem
123
160
  end
124
161
 
162
+ def on_symbols_beg(delimiter)
163
+ @delimiter_stack.push delimiter
164
+ super
165
+ end
166
+
125
167
  def on_symbols_new
126
168
  [:symbols]
127
169
  end
@@ -130,6 +172,28 @@ module RipperRubyParser
130
172
  list << elem
131
173
  end
132
174
 
175
+ def on_tstring_beg(delimiter)
176
+ @delimiter_stack.push delimiter
177
+ super
178
+ end
179
+
180
+ def on_tstring_content(content)
181
+ content = case @delimiter_stack.last
182
+ when '"', '`', ':"', /^<</, /^%I/, /^%Q/, /^%W/
183
+ Unescape.unescape(content)
184
+ when "'", ":'"
185
+ Unescape.simple_unescape(content)
186
+ else
187
+ content
188
+ end
189
+ super(content)
190
+ end
191
+
192
+ def on_tstring_end(delimiter)
193
+ @delimiter_stack.pop
194
+ super
195
+ end
196
+
133
197
  def on_word_new
134
198
  [:word]
135
199
  end
@@ -138,6 +202,11 @@ module RipperRubyParser
138
202
  list << elem
139
203
  end
140
204
 
205
+ def on_words_beg(delimiter)
206
+ @delimiter_stack.push delimiter
207
+ super
208
+ end
209
+
141
210
  def on_words_new
142
211
  [:words]
143
212
  end
@@ -176,8 +245,8 @@ module RipperRubyParser
176
245
 
177
246
  NUMBER_LITERAL_TYPES = [:@int, :@float].freeze
178
247
 
179
- def on_unary(op, value)
180
- if !@space_before && op == :-@ && NUMBER_LITERAL_TYPES.include?(value.first)
248
+ def on_unary(operator, value)
249
+ if !@space_before && operator == :-@ && NUMBER_LITERAL_TYPES.include?(value.first)
181
250
  type, literal, lines = value
182
251
  if literal[0] == '-'
183
252
  super
@@ -189,7 +258,8 @@ module RipperRubyParser
189
258
  end
190
259
  end
191
260
 
192
- def on_symbeg(*args)
261
+ def on_symbeg(delimiter)
262
+ @delimiter_stack.push delimiter
193
263
  @in_symbol = true
194
264
  super
195
265
  end
@@ -199,7 +269,7 @@ module RipperRubyParser
199
269
  super
200
270
  end
201
271
 
202
- def on_embexpr_beg(*args)
272
+ def on_embexpr_beg(_delimiter)
203
273
  @in_symbol = false
204
274
  super
205
275
  end
@@ -23,7 +23,7 @@ module RipperRubyParser
23
23
  _, cond, truepart = exp.shift 3
24
24
 
25
25
  construct_conditional(handle_condition(cond),
26
- process(truepart),
26
+ handle_operator_argument(truepart),
27
27
  nil)
28
28
  end
29
29
 
@@ -40,7 +40,7 @@ module RipperRubyParser
40
40
 
41
41
  construct_conditional(handle_condition(cond),
42
42
  nil,
43
- process(truepart))
43
+ handle_operator_argument(truepart))
44
44
  end
45
45
 
46
46
  def process_case(exp)
@@ -8,7 +8,8 @@ module RipperRubyParser
8
8
  end
9
9
 
10
10
  def process_string_content(exp)
11
- string, rest = extract_unescaped_string_parts exp
11
+ _, *rest = shift_all exp
12
+ string, rest = extract_string_parts(rest)
12
13
 
13
14
  if rest.empty?
14
15
  s(:str, string)
@@ -55,7 +56,12 @@ module RipperRubyParser
55
56
 
56
57
  def process_xstring_literal(exp)
57
58
  _, content = exp.shift 2
58
- string, rest = extract_unescaped_string_parts content
59
+ process(content)
60
+ end
61
+
62
+ def process_xstring(exp)
63
+ _, *rest = shift_all exp
64
+ string, rest = extract_string_parts(rest)
59
65
  if rest.empty?
60
66
  s(:xstr, string)
61
67
  else
@@ -66,7 +72,7 @@ module RipperRubyParser
66
72
  def process_regexp_literal(exp)
67
73
  _, content, (_, flags,) = exp.shift 3
68
74
 
69
- string, rest = extract_string_parts content
75
+ string, rest = process(content).sexp_body
70
76
  numflags = character_flags_to_numerical flags
71
77
 
72
78
  if rest.empty?
@@ -82,6 +88,12 @@ module RipperRubyParser
82
88
  end
83
89
  end
84
90
 
91
+ def process_regexp(exp)
92
+ _, *rest = shift_all exp
93
+ string, rest = extract_string_parts(rest)
94
+ s(:regexp, string, rest)
95
+ end
96
+
85
97
  def process_symbol_literal(exp)
86
98
  _, symbol = exp.shift 2
87
99
  process(symbol)
@@ -116,8 +128,8 @@ module RipperRubyParser
116
128
 
117
129
  private
118
130
 
119
- def extract_string_parts(exp)
120
- parts = internal_process_string_parts(exp)
131
+ def extract_string_parts(list)
132
+ parts = map_process_list list
121
133
 
122
134
  string = ''
123
135
  while !parts.empty? && parts.first.sexp_type == :str
@@ -130,74 +142,6 @@ module RipperRubyParser
130
142
  return string, rest
131
143
  end
132
144
 
133
- def internal_process_string_parts(exp)
134
- _, *rest = shift_all exp
135
- map_process_list rest
136
- end
137
-
138
- def extract_unescaped_string_parts(exp)
139
- string, rest = extract_string_parts exp
140
-
141
- string = unescape(string)
142
-
143
- rest.each do |sub_exp|
144
- sub_exp[1] = unescape(sub_exp[1]) if sub_exp.sexp_type == :str
145
- end
146
-
147
- return string, rest
148
- end
149
-
150
- SINGLE_LETTER_ESCAPES = {
151
- 'a' => "\a",
152
- 'b' => "\b",
153
- 'e' => "\e",
154
- 'f' => "\f",
155
- 'n' => "\n",
156
- 'r' => "\r",
157
- 's' => "\s",
158
- 't' => "\t",
159
- 'v' => "\v"
160
- }.freeze
161
-
162
- SINGLE_LETTER_ESCAPES_REGEXP =
163
- Regexp.new("^[#{SINGLE_LETTER_ESCAPES.keys.join}]$")
164
-
165
- def unescape(string)
166
- string.gsub(/\\(
167
- [0-7]{1,3} | # octal character
168
- x[0-9a-fA-F]{1,2} | # hex byte
169
- u[0-9a-fA-F]{4} | # unicode character
170
- M-\\C-. | # meta-ctrl
171
- C-\\M-. | # ctrl-meta
172
- M-\\c. | # meta-ctrl (shorthand)
173
- c\\M-. | # ctrl-meta (shorthand)
174
- C-. | # control (regular)
175
- c. | # control (shorthand)
176
- M-. | # meta
177
- . # single-character
178
- )/x) do
179
- bare = Regexp.last_match[1]
180
- case bare
181
- when SINGLE_LETTER_ESCAPES_REGEXP
182
- SINGLE_LETTER_ESCAPES[bare]
183
- when /^x/
184
- bare[1..-1].to_i(16).chr
185
- when /^u/
186
- bare[1..-1].to_i(16).chr(Encoding::UTF_8)
187
- when /^(c|C-).$/
188
- (bare[-1].ord & 0b1001_1111).chr
189
- when /^M-.$/
190
- (bare[-1].ord | 0b1000_0000).chr
191
- when /^(M-\\C-|C-\\M-|M-\\c|c\\M-).$/
192
- (bare[-1].ord & 0b1001_1111 | 0b1000_0000).chr
193
- when /^[0-7]+/
194
- bare.to_i(8).chr
195
- else
196
- bare
197
- end
198
- end
199
- end
200
-
201
145
  def character_flags_to_numerical(flags)
202
146
  numflags = 0
203
147
 
@@ -211,12 +155,15 @@ module RipperRubyParser
211
155
  numflags
212
156
  end
213
157
 
214
- def handle_dyna_symbol_content(list)
215
- string, rest = extract_unescaped_string_parts list
216
- if rest.empty?
217
- s(:lit, string.to_sym)
158
+ def handle_dyna_symbol_content(node)
159
+ type, *body = *process(node)
160
+ case type
161
+ when :str, :xstr
162
+ s(:lit, body.first.to_sym)
163
+ when :dstr, :dxstr
164
+ s(:dsym, *body)
218
165
  else
219
- s(:dsym, string, *rest)
166
+ raise type.to_s
220
167
  end
221
168
  end
222
169
 
@@ -74,18 +74,18 @@ module RipperRubyParser
74
74
 
75
75
  private
76
76
 
77
- def make_boolean_operator(op, left, right)
78
- _, left, _, right = rebalance_binary(s(:binary, left, op, right))
79
- s(op, process(left), handle_operator_argument(right))
77
+ def make_boolean_operator(operator, left, right)
78
+ _, left, _, right = rebalance_binary(s(:binary, left, operator, right))
79
+ s(operator, process(left), handle_operator_argument(right))
80
80
  end
81
81
 
82
- def make_regexp_match_operator(op, left, right)
82
+ def make_regexp_match_operator(operator, left, right)
83
83
  if left.sexp_type == :regexp_literal
84
84
  s(:match2, process(left), process(right))
85
85
  elsif right.sexp_type == :regexp_literal
86
86
  s(:match3, process(right), process(left))
87
87
  else
88
- s(:call, process(left), op, process(right))
88
+ s(:call, process(left), operator, process(right))
89
89
  end
90
90
  end
91
91
 
@@ -1,5 +1,6 @@
1
1
  require 'sexp_processor'
2
2
  require 'ripper_ruby_parser/sexp_handlers'
3
+ require 'ripper_ruby_parser/unescape'
3
4
 
4
5
  module RipperRubyParser
5
6
  # Processes the sexp created by Ripper to what RubyParser would produce.
@@ -160,7 +161,7 @@ module RipperRubyParser
160
161
  # character literals
161
162
  def process_at_CHAR(exp)
162
163
  _, val, pos = exp.shift 3
163
- with_position(pos, s(:str, unescape(val[1..-1])))
164
+ with_position(pos, s(:str, Unescape.unescape(val[1..-1])))
164
165
  end
165
166
 
166
167
  def process_at_label(exp)
@@ -0,0 +1,68 @@
1
+ module RipperRubyParser
2
+ # Implements string unescaping
3
+ #
4
+ # @api private
5
+ module Unescape
6
+ module_function
7
+
8
+ SINGLE_LETTER_ESCAPES = {
9
+ 'a' => "\a",
10
+ 'b' => "\b",
11
+ 'e' => "\e",
12
+ 'f' => "\f",
13
+ 'n' => "\n",
14
+ 'r' => "\r",
15
+ 's' => "\s",
16
+ 't' => "\t",
17
+ 'v' => "\v"
18
+ }.freeze
19
+
20
+ SINGLE_LETTER_ESCAPES_REGEXP =
21
+ Regexp.new("^[#{SINGLE_LETTER_ESCAPES.keys.join}]$")
22
+
23
+ def simple_unescape(string)
24
+ string.gsub(/\\(
25
+ ' | # single quote
26
+ \\ # backslash
27
+ )/x) do
28
+ Regexp.last_match[1]
29
+ end
30
+ end
31
+
32
+ def unescape(string)
33
+ string.gsub(/\\(
34
+ [0-7]{1,3} | # octal character
35
+ x[0-9a-fA-F]{1,2} | # hex byte
36
+ u[0-9a-fA-F]{4} | # unicode character
37
+ M-\\C-. | # meta-ctrl
38
+ C-\\M-. | # ctrl-meta
39
+ M-\\c. | # meta-ctrl (shorthand)
40
+ c\\M-. | # ctrl-meta (shorthand)
41
+ C-. | # control (regular)
42
+ c. | # control (shorthand)
43
+ M-. | # meta
44
+ . # single-character
45
+ )/x) do
46
+ bare = Regexp.last_match[1]
47
+ case bare
48
+ when SINGLE_LETTER_ESCAPES_REGEXP
49
+ SINGLE_LETTER_ESCAPES[bare]
50
+ when /^x/
51
+ bare[1..-1].to_i(16).chr
52
+ when /^u/
53
+ bare[1..-1].to_i(16).chr(Encoding::UTF_8)
54
+ when /^(c|C-).$/
55
+ (bare[-1].ord & 0b1001_1111).chr
56
+ when /^M-.$/
57
+ (bare[-1].ord | 0b1000_0000).chr
58
+ when /^(M-\\C-|C-\\M-|M-\\c|c\\M-).$/
59
+ (bare[-1].ord & 0b1001_1111 | 0b1000_0000).chr
60
+ when /^[0-7]+/
61
+ bare.to_i(8).chr
62
+ else
63
+ bare
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -1,3 +1,3 @@
1
1
  module RipperRubyParser
2
- VERSION = '1.3.0'.freeze
2
+ VERSION = '1.4.0'.freeze
3
3
  end
@@ -2,24 +2,13 @@ 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
- let :newparser do
6
- RipperRubyParser::Parser.new
7
- end
8
-
9
- let :oldparser do
10
- RubyParser.new
11
- end
12
-
13
5
  describe 'for a simple well known program' do
14
6
  let :program do
15
7
  "puts 'Hello World'"
16
8
  end
17
9
 
18
10
  it 'gives the same result' do
19
- original = oldparser.parse program
20
- imitation = newparser.parse program
21
-
22
- imitation.must_equal original
11
+ program.must_be_parsed_as_before
23
12
  end
24
13
  end
25
14
 
@@ -45,10 +34,7 @@ describe 'Using RipperRubyParser and RubyParser' do
45
34
  end
46
35
 
47
36
  it 'gives the same result' do
48
- original = oldparser.parse program
49
- imitation = newparser.parse program
50
-
51
- imitation.must_equal original
37
+ program.must_be_parsed_as_before
52
38
  end
53
39
  end
54
40
 
@@ -58,10 +44,7 @@ describe 'Using RipperRubyParser and RubyParser' do
58
44
  end
59
45
 
60
46
  it 'gives the same result' do
61
- original = oldparser.parse program
62
- imitation = newparser.parse program
63
-
64
- imitation.must_equal original
47
+ program.must_be_parsed_as_before
65
48
  end
66
49
  end
67
50
 
@@ -79,10 +62,7 @@ describe 'Using RipperRubyParser and RubyParser' do
79
62
  end
80
63
 
81
64
  it 'gives the same result' do
82
- original = oldparser.parse program
83
- imitation = newparser.parse program
84
-
85
- formatted(imitation).must_equal formatted(original)
65
+ program.must_be_parsed_as_before
86
66
  end
87
67
  end
88
68
 
@@ -106,10 +86,7 @@ describe 'Using RipperRubyParser and RubyParser' do
106
86
  end
107
87
 
108
88
  it 'gives the same result' do
109
- original = oldparser.parse program
110
- imitation = newparser.parse program
111
-
112
- formatted(imitation).must_equal formatted(original)
89
+ program.must_be_parsed_as_before
113
90
  end
114
91
  end
115
92
 
@@ -119,10 +96,7 @@ describe 'Using RipperRubyParser and RubyParser' do
119
96
  end
120
97
 
121
98
  it 'gives the same result' do
122
- original = oldparser.parse program
123
- imitation = newparser.parse program
124
-
125
- formatted(imitation).must_equal formatted(original)
99
+ program.must_be_parsed_as_before
126
100
  end
127
101
  end
128
102
 
@@ -145,4 +119,58 @@ describe 'Using RipperRubyParser and RubyParser' do
145
119
  program.must_be_parsed_as_before
146
120
  end
147
121
  end
122
+
123
+ describe 'for an example with __ENCODING__' do
124
+ it 'gives the same result' do
125
+ program = 'foo = __ENCODING__'
126
+ program.must_be_parsed_as_before
127
+ end
128
+ end
129
+
130
+ describe 'for an example with self[]' do
131
+ # https://github.com/seattlerb/ruby_parser/issues/250
132
+ it 'gives the same result' do
133
+ program = 'self[:foo]'
134
+ program.must_be_parsed_as_before
135
+ end
136
+ end
137
+
138
+ describe 'for an example with required keyword arguments and no parentheses' do
139
+ # https://github.com/seattlerb/ruby_parser/pull/254
140
+ let(:program) do
141
+ <<-END
142
+ def foo a:, b:
143
+ # body
144
+ end
145
+ END
146
+ end
147
+
148
+ it 'gives the same result' do
149
+ program.must_be_parsed_as_before
150
+ end
151
+ end
152
+
153
+ describe 'for an example combining begin..end and diverse operators' do
154
+ let(:program) do
155
+ <<-END
156
+ begin end
157
+ begin; foo; end
158
+ begin; foo; bar; end
159
+ - begin; foo; end
160
+ begin; bar; end + foo
161
+ foo + begin; bar; end
162
+ begin; foo; end ? bar : baz
163
+ foo ? begin; bar; end : baz
164
+ foo ? bar : begin; baz; end
165
+ begin; bar; end and foo
166
+ foo and begin; bar; end
167
+ begin; foo; end if bar
168
+ begin; foo; end unless bar
169
+ END
170
+ end
171
+
172
+ it 'gives the same result' do
173
+ program.must_be_parsed_as_before
174
+ end
175
+ end
148
176
  end
@@ -201,6 +201,22 @@ describe RipperRubyParser::Parser do
201
201
  s(:call, nil, :bar),
202
202
  s(:begin, s(:call, nil, :baz)))
203
203
  end
204
+
205
+ it 'keeps :begin for the truepart of a postfix if' do
206
+ 'begin; foo; end if bar'.
207
+ must_be_parsed_as s(:if,
208
+ s(:call, nil, :bar),
209
+ s(:begin, s(:call, nil, :foo)),
210
+ nil)
211
+ end
212
+
213
+ it 'keeps :begin for the falsepart of a postfix unless' do
214
+ 'begin; foo; end unless bar'.
215
+ must_be_parsed_as s(:if,
216
+ s(:call, nil, :bar),
217
+ nil,
218
+ s(:begin, s(:call, nil, :foo)))
219
+ end
204
220
  end
205
221
 
206
222
  describe 'for rescue/else' do
@@ -302,6 +302,40 @@ describe RipperRubyParser::Parser do
302
302
  end
303
303
  end
304
304
 
305
+ describe 'with single quoted strings' do
306
+ it 'works with escaped single quotes' do
307
+ "'foo\\'bar'".
308
+ must_be_parsed_as s(:str, "foo'bar")
309
+ end
310
+
311
+ it 'works with embedded backslashes' do
312
+ "'foo\\abar'".
313
+ must_be_parsed_as s(:str, 'foo\abar')
314
+ end
315
+
316
+ it 'works with escaped embedded backslashes' do
317
+ "'foo\\\\abar'".
318
+ must_be_parsed_as s(:str, 'foo\abar')
319
+ end
320
+
321
+ it 'works with sequences of backslashes' do
322
+ "'foo\\\\\\abar'".
323
+ must_be_parsed_as s(:str, 'foo\\\\abar')
324
+ end
325
+ end
326
+
327
+ describe 'with %Q-delimited strings' do
328
+ it 'works for the simple case' do
329
+ '%Q[bar]'.
330
+ must_be_parsed_as s(:str, 'bar')
331
+ end
332
+
333
+ it 'works for escape sequences' do
334
+ '%Q[foo\\nbar]'.
335
+ must_be_parsed_as s(:str, "foo\nbar")
336
+ end
337
+ end
338
+
305
339
  describe 'with string concatenation' do
306
340
  it 'performs the concatenation in the case of two simple literal strings' do
307
341
  '"foo" "bar"'.must_be_parsed_as s(:str, 'foobar')
@@ -351,6 +385,18 @@ describe RipperRubyParser::Parser do
351
385
  end
352
386
  end
353
387
  end
388
+
389
+ describe 'for heredocs' do
390
+ it 'works for the simple case' do
391
+ "<<FOO\nbar\nFOO".
392
+ must_be_parsed_as s(:str, "bar\n")
393
+ end
394
+
395
+ it 'works for escape sequences' do
396
+ "<<FOO\nbar\\tbaz\nFOO".
397
+ must_be_parsed_as s(:str, "bar\tbaz\n")
398
+ end
399
+ end
354
400
  end
355
401
 
356
402
  describe 'for word list literals' do
@@ -389,19 +435,35 @@ describe RipperRubyParser::Parser do
389
435
  s(:evstr, s(:call, nil, :bar)),
390
436
  s(:str, 'baz')))
391
437
  end
438
+
439
+ it 'correctly handles escape sequences' do
440
+ '%W(foo\nbar baz)'.
441
+ must_be_parsed_as s(:array,
442
+ s(:str, "foo\nbar"),
443
+ s(:str, 'baz'))
444
+ end
392
445
  end
393
446
 
394
- describe 'for symbol list literals' do
395
- it 'works for an array created with %i' do
447
+ describe 'for symbol list literals with %i delimiter' do
448
+ it 'works for the simple case' do
396
449
  '%i(foo bar)'.
397
450
  must_be_parsed_as s(:array, s(:lit, :foo), s(:lit, :bar))
398
451
  end
452
+ end
399
453
 
400
- it 'works for an array created with %I' do
454
+ describe 'for symbol list literals with %I delimiter' do
455
+ it 'works for the simple case' do
401
456
  '%I(foo bar)'.
402
457
  must_be_parsed_as s(:array, s(:lit, :foo), s(:lit, :bar))
403
458
  end
404
459
 
460
+ it 'correctly handles escape sequences' do
461
+ '%I(foo\nbar baz)'.
462
+ must_be_parsed_as s(:array,
463
+ s(:lit, :"foo\nbar"),
464
+ s(:lit, :baz))
465
+ end
466
+
405
467
  it 'correctly handles interpolation' do
406
468
  "%I(foo \#{bar} baz)".
407
469
  must_be_parsed_as s(:array,
@@ -485,6 +547,26 @@ describe RipperRubyParser::Parser do
485
547
  'foo',
486
548
  s(:evstr, s(:call, nil, :bar)))
487
549
  end
550
+
551
+ it 'works for dsyms with escape sequences' do
552
+ ':"foo\nbar"'.
553
+ must_be_parsed_as s(:lit, :"foo\nbar")
554
+ end
555
+
556
+ it 'works with single quoted dsyms' do
557
+ ":'foo'".
558
+ must_be_parsed_as s(:lit, :foo)
559
+ end
560
+
561
+ it 'works with single quoted dsyms with escaped single quotes' do
562
+ ":'foo\\'bar'".
563
+ must_be_parsed_as s(:lit, :'foo\'bar')
564
+ end
565
+
566
+ it 'works with single quoted dsyms with embedded backslashes' do
567
+ ":'foo\\abar'".
568
+ must_be_parsed_as s(:lit, :"foo\\abar")
569
+ end
488
570
  end
489
571
 
490
572
  describe 'for backtick string literals' do
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.3.0
4
+ version: 1.4.0
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: 2018-02-17 00:00:00.000000000 Z
11
+ date: 2018-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sexp_processor
@@ -111,6 +111,7 @@ files:
111
111
  - lib/ripper_ruby_parser/sexp_handlers/operators.rb
112
112
  - lib/ripper_ruby_parser/sexp_processor.rb
113
113
  - lib/ripper_ruby_parser/syntax_error.rb
114
+ - lib/ripper_ruby_parser/unescape.rb
114
115
  - lib/ripper_ruby_parser/version.rb
115
116
  - test/end_to_end/comments_test.rb
116
117
  - test/end_to_end/comparison_test.rb
@@ -131,7 +132,6 @@ files:
131
132
  - test/ripper_ruby_parser/sexp_processor_test.rb
132
133
  - test/ripper_ruby_parser/version_test.rb
133
134
  - test/samples/inline.rb
134
- - test/samples/misc.rb
135
135
  - test/test_helper.rb
136
136
  homepage: http://www.github.com/mvz/ripper_ruby_parser
137
137
  licenses:
@@ -155,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
155
  version: '0'
156
156
  requirements: []
157
157
  rubyforge_project:
158
- rubygems_version: 2.7.3
158
+ rubygems_version: 2.7.6
159
159
  signing_key:
160
160
  specification_version: 4
161
161
  summary: Parse with Ripper, produce sexps that are compatible with RubyParser.
@@ -179,5 +179,4 @@ test_files:
179
179
  - test/ripper_ruby_parser/sexp_processor_test.rb
180
180
  - test/ripper_ruby_parser/version_test.rb
181
181
  - test/samples/inline.rb
182
- - test/samples/misc.rb
183
182
  - test/test_helper.rb
@@ -1,12 +0,0 @@
1
- # Collect diverse tricky pieces of code here
2
- #
3
-
4
- enc = __ENCODING__
5
-
6
- # https://github.com/seattlerb/ruby_parser/issues/250
7
- self[:x]
8
-
9
- # https://github.com/seattlerb/ruby_parser/pull/254
10
- def foo a:, b:
11
- # body
12
- end