andyw8-seeing_is_believing 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +60 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +2 -0
  6. data/README.md +70 -0
  7. data/Rakefile +88 -0
  8. data/appveyor.yml +32 -0
  9. data/bin/seeing_is_believing +7 -0
  10. data/docs/example.gif +0 -0
  11. data/docs/frog-brown.png +0 -0
  12. data/docs/sib-streaming.gif +0 -0
  13. data/features/deprecated-flags.feature +91 -0
  14. data/features/errors.feature +155 -0
  15. data/features/examples.feature +423 -0
  16. data/features/flags.feature +852 -0
  17. data/features/regression.feature +898 -0
  18. data/features/support/env.rb +102 -0
  19. data/features/xmpfilter-style.feature +471 -0
  20. data/lib/seeing_is_believing/binary/align_chunk.rb +47 -0
  21. data/lib/seeing_is_believing/binary/align_file.rb +24 -0
  22. data/lib/seeing_is_believing/binary/align_line.rb +25 -0
  23. data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +56 -0
  24. data/lib/seeing_is_believing/binary/annotate_every_line.rb +52 -0
  25. data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +179 -0
  26. data/lib/seeing_is_believing/binary/comment_lines.rb +36 -0
  27. data/lib/seeing_is_believing/binary/commentable_lines.rb +126 -0
  28. data/lib/seeing_is_believing/binary/config.rb +455 -0
  29. data/lib/seeing_is_believing/binary/data_structures.rb +58 -0
  30. data/lib/seeing_is_believing/binary/engine.rb +161 -0
  31. data/lib/seeing_is_believing/binary/format_comment.rb +79 -0
  32. data/lib/seeing_is_believing/binary/interline_align.rb +57 -0
  33. data/lib/seeing_is_believing/binary/remove_annotations.rb +113 -0
  34. data/lib/seeing_is_believing/binary/rewrite_comments.rb +62 -0
  35. data/lib/seeing_is_believing/binary.rb +73 -0
  36. data/lib/seeing_is_believing/code.rb +139 -0
  37. data/lib/seeing_is_believing/compatibility.rb +28 -0
  38. data/lib/seeing_is_believing/debugger.rb +32 -0
  39. data/lib/seeing_is_believing/error.rb +17 -0
  40. data/lib/seeing_is_believing/evaluate_by_moving_files.rb +195 -0
  41. data/lib/seeing_is_believing/event_stream/consumer.rb +221 -0
  42. data/lib/seeing_is_believing/event_stream/events.rb +193 -0
  43. data/lib/seeing_is_believing/event_stream/handlers/debug.rb +61 -0
  44. data/lib/seeing_is_believing/event_stream/handlers/record_exit_events.rb +26 -0
  45. data/lib/seeing_is_believing/event_stream/handlers/stream_json_events.rb +23 -0
  46. data/lib/seeing_is_believing/event_stream/handlers/update_result.rb +41 -0
  47. data/lib/seeing_is_believing/event_stream/producer.rb +178 -0
  48. data/lib/seeing_is_believing/hard_core_ensure.rb +58 -0
  49. data/lib/seeing_is_believing/hash_struct.rb +206 -0
  50. data/lib/seeing_is_believing/result.rb +89 -0
  51. data/lib/seeing_is_believing/safe.rb +112 -0
  52. data/lib/seeing_is_believing/swap_files.rb +90 -0
  53. data/lib/seeing_is_believing/the_matrix.rb +97 -0
  54. data/lib/seeing_is_believing/version.rb +3 -0
  55. data/lib/seeing_is_believing/wrap_expressions.rb +265 -0
  56. data/lib/seeing_is_believing/wrap_expressions_with_inspect.rb +19 -0
  57. data/lib/seeing_is_believing.rb +69 -0
  58. data/seeing_is_believing.gemspec +84 -0
  59. data/spec/binary/alignment_specs.rb +27 -0
  60. data/spec/binary/comment_lines_spec.rb +852 -0
  61. data/spec/binary/config_spec.rb +831 -0
  62. data/spec/binary/engine_spec.rb +114 -0
  63. data/spec/binary/format_comment_spec.rb +210 -0
  64. data/spec/binary/marker_spec.rb +71 -0
  65. data/spec/binary/remove_annotations_spec.rb +342 -0
  66. data/spec/binary/rewrite_comments_spec.rb +106 -0
  67. data/spec/code_spec.rb +233 -0
  68. data/spec/debugger_spec.rb +45 -0
  69. data/spec/evaluate_by_moving_files_spec.rb +204 -0
  70. data/spec/event_stream_spec.rb +762 -0
  71. data/spec/hard_core_ensure_spec.rb +120 -0
  72. data/spec/hash_struct_spec.rb +514 -0
  73. data/spec/seeing_is_believing_spec.rb +1094 -0
  74. data/spec/sib_spec_helpers/version.rb +17 -0
  75. data/spec/spec_helper.rb +26 -0
  76. data/spec/spec_helper_spec.rb +16 -0
  77. data/spec/wrap_expressions_spec.rb +1013 -0
  78. metadata +340 -0
@@ -0,0 +1,1013 @@
1
+ require 'spec_helper'
2
+ require 'seeing_is_believing/wrap_expressions'
3
+
4
+ RSpec.describe SeeingIsBelieving::WrapExpressions do
5
+ def wrap(code, overrides={})
6
+ code = code + "\n" unless code.end_with? "\n"
7
+ described_class.call(code,
8
+ before_all: -> { overrides.fetch :before_all, '' },
9
+ after_all: -> { overrides.fetch :after_all, '' },
10
+ before_each: -> * { overrides.fetch :before_each, '<' },
11
+ after_each: -> * { overrides.fetch :after_each, '>' }
12
+ ).chomp
13
+ end
14
+
15
+ def wrap_with_body(code, overrides={})
16
+ wrap code, { before_all: '[',
17
+ after_all: ']',
18
+ }.merge(overrides)
19
+ end
20
+
21
+ def heredoc_wrap(code, overrides={})
22
+ wrap_with_body code, { before_each: '{'.freeze,
23
+ after_each: '}'.freeze,
24
+ }.merge(overrides)
25
+ end
26
+
27
+
28
+ it 'raises a SyntaxError if the program is invalid' do
29
+ expect { wrap '+' }.to raise_error SyntaxError
30
+ end
31
+
32
+ it 'can inject syntax errors with __TOTAL_FUCKING_FAILURE__' do
33
+ expect(wrap('__TOTAL_FUCKING_FAILURE__')).to eq '<.....TOTAL FUCKING FAILURE!.....>'
34
+ end
35
+
36
+ describe 'wrapping the body' do
37
+ it 'wraps the entire body, ignoring leading comments and the data segment' do
38
+ expect(wrap_with_body "#comment\nA\n__END__\n1").to eq "#comment\n[<A>]\n__END__\n1"
39
+ expect(wrap_with_body "#comment\n__END__\n1").to eq "[]#comment\n__END__\n1"
40
+ end
41
+
42
+ it 'wraps when code is an empty string' do
43
+ expect(wrap_with_body '').to eq '[]'
44
+ end
45
+
46
+ it 'places body before first comment when there are only comments' do
47
+ expect(wrap_with_body "# abc").to eq "[]# abc"
48
+ end
49
+
50
+ it 'places body before trailing comments, but still wraps code' do
51
+ expect(wrap_with_body "1# abc").to eq "[<1>]# abc"
52
+ end
53
+
54
+ # this changes the number of lines, annoyingly, though it shouldn't mess anything up,
55
+ # unless you were trying to reopen the file to read it, in which case, *surprise* the whole thing's been rewritten
56
+ it 'injects a newline if there is a data segment and the after block doesn\'t end in a newline' do
57
+ expect(wrap_with_body "__END__").to eq "[]\n__END__"
58
+ expect(wrap_with_body "\n__END__").to eq "[]\n__END__"
59
+ expect(wrap_with_body "\n\n__END__").to eq "[]\n\n__END__"
60
+ expect(wrap_with_body "__END__!").to eq "[<__END__!>]"
61
+ expect(wrap_with_body "%(\n__END__\n)").to eq "[<%(\n__END__\n)>]"
62
+ end
63
+
64
+ it 'wraps bodies that are wrapped in parentheses' do
65
+ expect(wrap('(1)')).to eq '<(1)>'
66
+ expect(wrap("(\n<<doc\ndoc\n)")).to eq "<(\n<<<doc>\ndoc\n)>"
67
+ end
68
+
69
+ context 'fucking heredocs' do
70
+ example 'single heredoc' do
71
+ expect(heredoc_wrap "<<A\nA").to eq "[{<<A}]\nA"
72
+ end
73
+
74
+ example 'multiple heredocs' do
75
+ expect(heredoc_wrap "<<A\nA\n<<B\nB").to eq "[{<<A}\nA\n{<<B}]\nB"
76
+ end
77
+
78
+ example 'heredocs as targets and arguments to methods' do
79
+ expect(heredoc_wrap "<<A.size 1\nA").to eq "[{<<A.size 1}]\nA"
80
+ expect(heredoc_wrap "<<A.size\nA").to eq "[{<<A.size}]\nA"
81
+ expect(heredoc_wrap "<<A.size()\nA").to eq "[{<<A.size()}]\nA"
82
+ expect(heredoc_wrap "a.size <<A\nA").to eq "[{a.size <<A}]\nA"
83
+ expect(heredoc_wrap "<<A.size <<B\nA\nB").to eq "[{<<A.size <<B}]\nA\nB"
84
+ expect(heredoc_wrap "<<A.size(<<B)\nA\nB").to eq "[{<<A.size(<<B)}]\nA\nB"
85
+ end
86
+
87
+ example 'heredocs withs spaces in the delimiter' do
88
+ expect(heredoc_wrap "<<'a b'\n1\na b").to eq "[{<<'a b'}]\n1\na b"
89
+ expect(heredoc_wrap "<<'a b'\n1\na b\n1").to eq "[{<<'a b'}\n1\na b\n{1}]"
90
+ expect(heredoc_wrap '<<"a b"'+"\n1\na b").to eq '[{<<"a b"}]'+"\n1\na b"
91
+ end
92
+ end
93
+
94
+ it 'identifies the last line of the body' do
95
+ expect(wrap_with_body "a\n"\
96
+ "def b\n"\
97
+ " c = 1\n"\
98
+ "end"
99
+ ).to eq "[<a>\n"\
100
+ "<def b\n"\
101
+ " <c = 1>\n"\
102
+ "end>]"
103
+ end
104
+ end
105
+
106
+ it 'passes the current line number to the before_each and after_each wrappers' do
107
+ result = described_class.call("a.each { |b|\n}\n",
108
+ before_each: -> n { "(#{n})" },
109
+ after_each: -> n { "<#{n}>" }
110
+ )
111
+ expect(result).to eq "(2)(1)a<1>.each { |b|\n}<2>\n"
112
+ end
113
+
114
+ it 'does nothing for an empty program' do
115
+ expect(wrap("")).to eq "" # note that code will fix the missing newline, and wrap will chomp it from the result for convenience
116
+ end
117
+
118
+ it 'ignores comments' do
119
+ expect(wrap "# comment" ).to eq "# comment"
120
+ expect(wrap "1 #abc\n#def" ).to eq "<1> #abc\n#def"
121
+ expect(wrap "1\n=begin\n2\n=end").to eq "<1>\n=begin\n2\n=end"
122
+ expect(wrap "=begin\n1\n=end\n2").to eq "=begin\n1\n=end\n<2>"
123
+ end
124
+
125
+ describe 'basic expressions' do
126
+ it 'wraps an expression' do
127
+ expect(wrap("A")).to eq "<A>"
128
+ end
129
+
130
+ it 'wraps multiple expressions' do
131
+ expect(wrap("A\nB")).to eq "<A>\n<B>"
132
+ expect(wrap("(1\n2)")).to eq "<(<1>\n2)>"
133
+ expect(wrap("(1\n2\n)")).to eq "<(<1>\n<2>\n)>"
134
+ expect(wrap("begin\n1\n2\nend")).to eq "<begin\n<1>\n<2>\nend>"
135
+ end
136
+
137
+ it 'does not wrap multiple expressions when they constitute a void value' do
138
+ expect(wrap("def a\n1\nreturn 2\nend")).to eq "<def a\n<1>\nreturn <2>\nend>"
139
+ expect(wrap("def a\nreturn 1\n2\nend")).to eq "<def a\nreturn <1>\n<2>\nend>"
140
+ # BUG, but I'm skipping it, b/c it's borderline invalid.
141
+ # To the point that Parser doesn't even emit the else clause in the AST
142
+ # And Ruby will warn you that it's useless
143
+ # expect(wrap("begin\n1\nelse\nbreak\nend")).to eq "begin\n<1>\nelse\nbreak\nend"
144
+ end
145
+
146
+ it 'wraps nested expressions' do
147
+ expect(wrap("A do\nB\nend")).to eq "<A do\n<B>\nend>"
148
+ end
149
+
150
+ it 'wraps multiple expressions on the same line' do
151
+ expect(wrap("a;b")).to eq "a;<b>"
152
+ end
153
+
154
+ # many of these taken from http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Literals
155
+ it 'wraps simple literals' do
156
+ %w|123
157
+ -123
158
+ 1_123
159
+ -543
160
+ 123_456_789_123_456_789
161
+ 123.45
162
+ 1.2e-3
163
+ 0xaabb
164
+ 0377
165
+ -0b1010
166
+ 0b001_001
167
+
168
+ ?a
169
+ ?\\C-a
170
+
171
+ 1..2
172
+ 1...2
173
+
174
+ (true==true)..(1==2)
175
+ (true==true)...(1==2)
176
+
177
+ true
178
+ false
179
+ nil
180
+ self
181
+
182
+ [1,2,3]
183
+ [1,*a,*[2,3,4]]
184
+ %w(1)
185
+ %W(2)
186
+
187
+ %x[ls]
188
+
189
+ /abc/
190
+ %r(abc)
191
+ %r.abc.
192
+
193
+ :abc
194
+ :'abc'
195
+ :"abc"
196
+ :"a\#{1}"
197
+
198
+ {1=>2}
199
+ {a:1}
200
+ |.each do |literal|
201
+ actual = wrap(literal)
202
+ expected = "<#{literal}>"
203
+ expect(actual).to eq(expected), "expected #{literal.inspect} to equal #{expected.inspect}, got #{actual.inspect}"
204
+ end
205
+ end
206
+
207
+ it 'wraps macros' do
208
+ expect(wrap("__dir__")).to eq "<__dir__>"
209
+ expect(wrap("__FILE__")).to eq "<__FILE__>"
210
+ expect(wrap("__LINE__")).to eq "<__LINE__>"
211
+ expect(wrap("__ENCODING__")).to eq "<__ENCODING__>"
212
+ expect(wrap("defined? a")).to eq "<defined? a>"
213
+ end
214
+
215
+ it 'does not wrap alias, undef' do
216
+ expect(wrap("alias tos to_s")).to eq "alias tos to_s"
217
+ expect(wrap("undef tos")).to eq "undef tos"
218
+ expect(wrap("alias $a $b")).to eq "alias $a $b"
219
+ end
220
+
221
+ it 'wraps syscalls, and the code interpolated into them' do
222
+ expect(wrap("`a\nb`")).to eq "<`a\nb`>"
223
+ expect(wrap("`a\n\#{1\n2\n3}b`")).to eq "<`a\n\#{<1>\n<2>\n3}b`>"
224
+ end
225
+ end
226
+
227
+ describe 'variable lookups' do
228
+ it 'wraps them' do
229
+ expect(wrap('a')).to eq "<a>"
230
+ expect(wrap("$a")).to eq "<$a>"
231
+ expect(wrap("$1")).to eq "<$1>"
232
+ expect(wrap("@a")).to eq "<@a>"
233
+ expect(wrap("@@a")).to eq "<@@a>"
234
+ end
235
+ end
236
+
237
+ describe 'method invocations' do
238
+ it 'wraps the whole invocation with or without parens' do
239
+ expect(wrap("a")).to eq "<a>"
240
+ expect(wrap("a()")).to eq "<a()>"
241
+ expect(wrap("a()")).to eq "<a()>"
242
+ end
243
+
244
+ it 'does not wrap arguments' do
245
+ expect(wrap("a b")).to eq "<a b>"
246
+ expect(wrap("a(b,c=1,*d,&e)")).to eq "<a(b,c=1,*d,&e)>"
247
+ end
248
+
249
+ it 'wraps blocks' do
250
+ expect(wrap("a { }")).to eq "<a { }>"
251
+ expect(wrap("a {\n}")).to eq "<a {\n}>"
252
+ expect(wrap("a(b) {\n}")).to eq "<a(b) {\n}>"
253
+ expect(wrap("a(&b\n)")).to eq "<a(&<b>\n)>"
254
+ expect(wrap("a(&lambda { }\n)")).to eq "<a(&<lambda { }>\n)>"
255
+ end
256
+
257
+ it 'wraps method calls with an explicit receiver' do
258
+ expect(wrap("1.mod(2)")).to eq "<1.mod(2)>"
259
+ expect(wrap("1.mod 2")).to eq "<1.mod 2>"
260
+ end
261
+
262
+ it 'wraps operators calls' do
263
+ expect(wrap("1+1")).to eq "<1+1>"
264
+ expect(wrap("a.b+1")).to eq "<a.b+1>"
265
+ expect(wrap("a.b - 1")).to eq "<a.b - 1>"
266
+ expect(wrap("a.b -1")).to eq "<a.b -1>"
267
+ expect(wrap("!1")).to eq "<!1>"
268
+ expect(wrap("~1")).to eq "<~1>"
269
+ end
270
+
271
+ it 'wraps methods that end in bangs and questions' do
272
+ expect(wrap("a.b!")).to eq "<a.b!>"
273
+ expect(wrap("a.b?")).to eq "<a.b?>"
274
+ end
275
+
276
+ it 'wraps method invocations that span multiple lines' do
277
+ expect(wrap("a\n.b\n.c")).to eq "<<<a>\n.b>\n.c>"
278
+ expect(wrap("a\n.b{\n}")).to eq "<<a>\n.b{\n}>"
279
+ expect(wrap("a\n.b{}")).to eq "<<a>\n.b{}>"
280
+ expect(wrap("[*1..5]\n.map { |n| n * 2 }\n.take(2).\nsize")).to eq\
281
+ "<<<<[*1..5]>\n.map { |n| n * 2 }>\n.take(2)>.\nsize>"
282
+ expect(wrap("a = b\n.c\na")).to eq "<a = <b>\n.c>\n<a>"
283
+ end
284
+
285
+ it 'wraps args in method arguments when the method spans multiple lines' do
286
+ expect(wrap("a 1,\n2")).to eq "<a <1>,\n2>"
287
+ end
288
+
289
+ it 'does wraps splat args' do
290
+ expect(wrap("a(\n*a\n)")).to eq "<a(\n*<a>\n)>"
291
+ expect(wrap("a(\n*1..2\n)")).to eq "<a(\n*<1..2>\n)>"
292
+ end
293
+
294
+ it 'does not wrap hash args' do
295
+ expect(wrap("a(b: 1,\nc: 2\n)")).to eq "<a(b: <1>,\nc: <2>\n)>"
296
+ end
297
+ end
298
+
299
+ describe 'assignment' do
300
+ it 'wraps entire simple assignment' do
301
+ expect(wrap("a=1")).to eq "<a=1>"
302
+ expect(wrap("a.b=1")).to eq "<a.b=1>"
303
+ expect(wrap("A=1")).to eq "<A=1>"
304
+ expect(wrap("::A=1")).to eq "<::A=1>"
305
+ expect(wrap("A::B=1")).to eq "<A::B=1>"
306
+ expect(wrap("@a=1")).to eq "<@a=1>"
307
+ expect(wrap("@@a=1")).to eq "<@@a=1>"
308
+ expect(wrap("$a=1")).to eq "<$a=1>"
309
+ end
310
+
311
+ it 'wraps multiple assignments' do
312
+ expect(wrap("a,b=c")).to eq "<a,b=c>"
313
+ expect(wrap("a,b=1,2")).to eq "<a,b=1,2>"
314
+ expect(wrap("a,b.c=1,2")).to eq "<a,b.c=1,2>"
315
+ expect(wrap("a,B=1,2")).to eq "<a,B=1,2>"
316
+ expect(wrap("a,B::C=1,2")).to eq "<a,B::C=1,2>"
317
+ expect(wrap("a,@b=1,2")).to eq "<a,@b=1,2>"
318
+ expect(wrap("a,@@b=1,2")).to eq "<a,@@b=1,2>"
319
+ expect(wrap("a,$b=1,2")).to eq "<a,$b=1,2>"
320
+ expect(wrap("a, b = x.()")).to eq "<a, b = x.()>"
321
+ expect(wrap("a, b = c\n.d,\ne\n.f")).to eq "<a, b = <<c>\n.d>,\n<e>\n.f>"
322
+ end
323
+
324
+ it 'wraps multiple assignment on each line' do
325
+ expect(wrap("a,b=1,\n2")).to eq "<a,b=<1>,\n2>"
326
+ expect(wrap("a,b=[1,2]\n.map(&:to_s)")).to eq "<a,b=<[1,2]>\n.map(&:to_s)>"
327
+ expect(wrap("a,b=[1,\n2\n.even?\n]")).to eq "<a,b=[<1>,\n<<2>\n.even?>\n]>"
328
+ end
329
+
330
+ it 'wraps multiple assignment with splats' do
331
+ expect(wrap("a,* =1,2,3")).to eq "<a,* =1,2,3>"
332
+ end
333
+
334
+ it 'wraps the array equivalent' do
335
+ expect(wrap("a,* =[1,2,3]")).to eq "<a,* =[1,2,3]>"
336
+ expect(wrap("a,* = [ 1,2,3 ] ")).to eq "<a,* = [ 1,2,3 ]> "
337
+ expect(wrap("a,* = 1,2,3")).to eq "<a,* = 1,2,3>"
338
+ end
339
+
340
+ it 'wraps the array elements' do
341
+ expect(wrap("a,* = [ 1,2,\n3 ] ")).to eq "<a,* = [ 1,<2>,\n3 ]> "
342
+ expect(wrap("a,* = 1,2,\n3")).to eq "<a,* = 1,<2>,\n3>"
343
+ expect(wrap("a = [ 1,2,\n3 ] ")).to eq "<a = [ 1,<2>,\n3 ]> "
344
+ expect(wrap("a = 1,2,\n3")).to eq "<a = 1,<2>,\n3>"
345
+ end
346
+
347
+ it 'wraps repeated assignments' do
348
+ expect(wrap("a=b=1")).to eq "<a=b=1>"
349
+ expect(wrap("a=b=\n1")).to eq "<a=b=\n1>"
350
+ expect(wrap("a=\nb=\n1")).to eq "<a=\nb=\n1>"
351
+ end
352
+
353
+ it 'wraps operator assignment' do
354
+ expect(wrap("a += 1")).to eq "<a += 1>"
355
+ expect(wrap("a *= 1")).to eq "<a *= 1>"
356
+ expect(wrap("a -= 1")).to eq "<a -= 1>"
357
+ expect(wrap("a /= 1")).to eq "<a /= 1>"
358
+ expect(wrap("a **= 1")).to eq "<a **= 1>"
359
+ expect(wrap("a != 1")).to eq "<a != 1>"
360
+ expect(wrap("a |= 1")).to eq "<a |= 1>"
361
+ expect(wrap("a &= 1")).to eq "<a &= 1>"
362
+ expect(wrap("a ||= 1")).to eq "<a ||= 1>"
363
+ expect(wrap("a &&= 1")).to eq "<a &&= 1>"
364
+ expect(wrap("a[1] = 2")).to eq "<a[1] = 2>"
365
+ expect(wrap("a[1,2] = 3")).to eq "<a[1,2] = 3>"
366
+ expect(wrap("a[1] ||= 2")).to eq "<a[1] ||= 2>"
367
+ expect(wrap("@a ||= 123")).to eq "<@a ||= 123>"
368
+ expect(wrap("$a ||= 123")).to eq "<$a ||= 123>"
369
+ expect(wrap("@@a ||= 123")).to eq "<@@a ||= 123>"
370
+ expect(wrap("B ||= 123")).to eq "<B ||= 123>"
371
+ expect(wrap("@a ||= begin\n123\nend")).to eq "<@a ||= begin\n<123>\nend>"
372
+ expect(wrap("$a ||= begin\n123\nend")).to eq "<$a ||= begin\n<123>\nend>"
373
+ expect(wrap("@@a ||= begin\n123\nend")).to eq "<@@a ||= begin\n<123>\nend>"
374
+ expect(wrap("B ||= begin\n123\nend")).to eq "<B ||= begin\n<123>\nend>"
375
+ end
376
+
377
+ it 'wraps assignments that span multiple lines' do
378
+ # simple assignment
379
+ expect(wrap("a={\n}")).to eq "<a={\n}>"
380
+ expect(wrap("a, b = c,{\n}")).to eq "<a, b = <c>,{\n}>"
381
+ expect(wrap("a.b={\n}")).to eq "<<a>.b={\n}>"
382
+ expect(wrap("A={\n}")).to eq "<A={\n}>"
383
+ expect(wrap("::A={\n}")).to eq "<::A={\n}>"
384
+ expect(wrap("A::B={\n}")).to eq "<A::B={\n}>"
385
+ expect(wrap("@a={\n}")).to eq "<@a={\n}>"
386
+ expect(wrap("@@a={\n}")).to eq "<@@a={\n}>"
387
+ expect(wrap("$a={\n}")).to eq "<$a={\n}>"
388
+
389
+ # multiple assignment
390
+ expect(wrap("a,b={\n}")).to eq "<a,b={\n}>"
391
+ expect(wrap("a,b={\n},{\n}")).to eq "<a,b=<{\n}>,{\n}>"
392
+ expect(wrap("a,b.c={\n},{\n}")).to eq "<a,b.c=<{\n}>,{\n}>"
393
+ expect(wrap("a,B={\n},{\n}")).to eq "<a,B=<{\n}>,{\n}>"
394
+ expect(wrap("a,B::C={\n},{\n}")).to eq "<a,B::C=<{\n}>,{\n}>"
395
+ expect(wrap("a,@b={\n},{\n}")).to eq "<a,@b=<{\n}>,{\n}>"
396
+ expect(wrap("a,@@b={\n},{\n}")).to eq "<a,@@b=<{\n}>,{\n}>"
397
+ expect(wrap("a,$b={\n},{\n}")).to eq "<a,$b=<{\n}>,{\n}>"
398
+ expect(wrap("a,$b={\n},{\n}")).to eq "<a,$b=<{\n}>,{\n}>"
399
+
400
+ # repeated assignments
401
+ expect(wrap("a=\nb={\n}")).to eq "<a=\nb={\n}>"
402
+
403
+ # operator assignment
404
+ expect(wrap("a +={\n}")).to eq "<a +={\n}>"
405
+ expect(wrap("a *= {\n}")).to eq "<a *= {\n}>"
406
+ expect(wrap("a -= {\n}")).to eq "<a -= {\n}>"
407
+ expect(wrap("a /= {\n}")).to eq "<a /= {\n}>"
408
+ expect(wrap("a **= {\n}")).to eq "<a **= {\n}>"
409
+ expect(wrap("a |= {\n}")).to eq "<a |= {\n}>"
410
+ expect(wrap("a &= {\n}")).to eq "<a &= {\n}>"
411
+ expect(wrap("a ||= {\n}")).to eq "<a ||= {\n}>"
412
+ expect(wrap("a &&= {\n}")).to eq "<a &&= {\n}>"
413
+ expect(wrap("a[1] = {\n}")).to eq "<a[<1>] = {\n}>"
414
+ expect(wrap("a[1] ||= {\n}")).to eq "<a[1] ||= {\n}>"
415
+ expect(wrap("@a ||= {\n}")).to eq "<@a ||= {\n}>"
416
+ expect(wrap("$a ||= {\n}")).to eq "<$a ||= {\n}>"
417
+ expect(wrap("@@a ||= {\n}")).to eq "<@@a ||= {\n}>"
418
+ expect(wrap("B ||= {\n}")).to eq "<B ||= {\n}>"
419
+ expect(wrap("{}[:a] ||= {\n}")).to eq "<{}[:a] ||= {\n}>"
420
+
421
+ # LHS with values in it on all the operator assignments
422
+ expect(wrap("a.b += {\n}")).to eq "<a.b += {\n}>"
423
+ expect(wrap("a.b *= {\n}")).to eq "<a.b *= {\n}>"
424
+ expect(wrap("a.b -= {\n}")).to eq "<a.b -= {\n}>"
425
+ expect(wrap("a.b /= {\n}")).to eq "<a.b /= {\n}>"
426
+ expect(wrap("a.b **= {\n}")).to eq "<a.b **= {\n}>"
427
+ expect(wrap("a.b |= {\n}")).to eq "<a.b |= {\n}>"
428
+ expect(wrap("a.b &= {\n}")).to eq "<a.b &= {\n}>"
429
+ expect(wrap("a.b &&= {\n}")).to eq "<a.b &&= {\n}>"
430
+ end
431
+
432
+ it 'wraps arguments in the assignment' do
433
+ expect(wrap("a[1\n]=2")).to eq "<a[<1>\n]=2>"
434
+ expect(wrap("a[1,\n2\n]=3")).to eq "<a[<1>,\n<2>\n]=3>"
435
+ end
436
+
437
+ it 'wraps 2.4 style multiple assignment' do
438
+ next if ruby_version < '2.4'
439
+ expect(wrap("if (a,b=1,2)\nend")).to eq "<if <(a,b=1,2)>\nend>"
440
+ expect(wrap("if (a,b=1)\nend")).to eq "<if <(a,b=1)>\nend>"
441
+ end
442
+ end
443
+
444
+ describe 'conditionals' do
445
+ it 'wraps if/elsif/else/end, the whole thing, their conditionals, and their bodies' do
446
+ expect(wrap("if 1\n2\nelsif 2\n3\nelsif 4\n5\nend")).to eq "<if <1>\n<2>\nelsif <2>\n<3>\nelsif <4>\n<5>\nend>" # multiple elsif
447
+ expect(wrap("if 1\n2\nelsif 2\n3\nelse\n4\nend")).to eq "<if <1>\n<2>\nelsif <2>\n<3>\nelse\n<4>\nend>" # elisf and else
448
+ expect(wrap("if 1\n2\nelsif 3\n4\nend")).to eq "<if <1>\n<2>\nelsif <3>\n<4>\nend>" # elsif only
449
+ expect(wrap("if 1\n2\nelse\n2\nend")).to eq "<if <1>\n<2>\nelse\n<2>\nend>" # else only
450
+ expect(wrap("if 1\n2\nend")).to eq "<if <1>\n<2>\nend>" # if only
451
+
452
+ # same as above, but with then
453
+ expect(wrap("if 1 then\n2\nelsif 2 then\n3\nelsif 4 then\n5\nend")).to eq "<if <1> then\n<2>\nelsif <2> then\n<3>\nelsif <4> then\n<5>\nend>"
454
+ expect(wrap("if 1 then\n2\nelsif 2 then\n3\nelse\n4\nend")).to eq "<if <1> then\n<2>\nelsif <2> then\n<3>\nelse\n<4>\nend>"
455
+ expect(wrap("if 1 then\n2\nelsif 3 then\n4\nend")).to eq "<if <1> then\n<2>\nelsif <3> then\n<4>\nend>"
456
+ expect(wrap("if 1 then\n2\nelse\n2\nend")).to eq "<if <1> then\n<2>\nelse\n<2>\nend>"
457
+ expect(wrap("if 1 then\n2\nend")).to eq "<if <1> then\n<2>\nend>"
458
+
459
+ # inline
460
+ expect(wrap("1 if 2")).to eq "<1 if 2>"
461
+ end
462
+
463
+ it 'wraps implicit regexes, retaining their magic behaviour by prepending a ~' do
464
+ expect(wrap("if /a/\n1\nend")).to eq "<if <~/a/>\n<1>\nend>"
465
+ expect(wrap("/a/ &&\n1")).to eq "<</a/> &&\n1>"
466
+ end
467
+
468
+ it 'wraps ternaries' do
469
+ expect(wrap("1 ? 2 : 3")).to eq "<1 ? 2 : 3>"
470
+ expect(wrap("1\\\n?\\\n2\\\n:\\\n3")).to eq "<<1>\\\n?\\\n<2>\\\n:\\\n3>"
471
+ end
472
+
473
+ it 'wraps "unless" statements' do
474
+ expect(wrap("unless 1\n2\nelse\n3\nend")).to eq "<unless <1>\n<2>\nelse\n<3>\nend>"
475
+ expect(wrap("unless 1\n2\nend")).to eq "<unless <1>\n<2>\nend>"
476
+ expect(wrap("unless 1 then\n2\nelse\n3\nend")).to eq "<unless <1> then\n<2>\nelse\n<3>\nend>"
477
+ expect(wrap("unless 1 then\n2\nend")).to eq "<unless <1> then\n<2>\nend>"
478
+ expect(wrap("1 unless 2")).to eq "<1 unless 2>"
479
+ end
480
+
481
+ it 'wraps case statements, and the value they are initialized with, but not the conditionals' do
482
+ expect(wrap("case 1\nwhen 2\n3\nwhen 4, 5\nelse\n6\nend")).to eq "<case <1>\nwhen 2\n<3>\nwhen 4, 5\nelse\n<6>\nend>"
483
+ expect(wrap("case 1\nwhen 2\nend")).to eq "<case <1>\nwhen 2\nend>"
484
+ expect(wrap("case\nwhen 2\nend")).to eq "<case\nwhen 2\nend>"
485
+ expect(wrap("case\nwhen 2, 3\n4\n5\nend")).to eq "<case\nwhen 2, 3\n<4>\n<5>\nend>"
486
+
487
+ expect(wrap("case 1\nwhen 2 then\n3\nwhen 4, 5 then\nelse\n6\nend")).to eq "<case <1>\nwhen 2 then\n<3>\nwhen 4, 5 then\nelse\n<6>\nend>"
488
+ expect(wrap("case 1\nwhen 2 then\nend")).to eq "<case <1>\nwhen 2 then\nend>"
489
+ expect(wrap("case\nwhen 2 then\nend")).to eq "<case\nwhen 2 then\nend>"
490
+ expect(wrap("case\nwhen 2, 3 then\n4\n5\nend")).to eq "<case\nwhen 2, 3 then\n<4>\n<5>\nend>"
491
+ end
492
+
493
+ it 'does not wrap flip flops in if-statement conditionals' do
494
+ # these match
495
+ expect(wrap("if (a==1)..(zomg.wtf?)\n 1\nend")).to eq "<if (a==1)..(zomg.wtf?)\n <1>\nend>"
496
+ expect(wrap("if (a==1)...(zomg.wtf?)\n 1\nend")).to eq "<if (a==1)...(zomg.wtf?)\n <1>\nend>"
497
+
498
+ # these match $_
499
+ expect(wrap("if /a/../b/\n 1\nend")).to eq "<if /a/../b/\n <1>\nend>"
500
+ expect(wrap("if /a/.../b/\n 1\nend")).to eq "<if /a/.../b/\n <1>\nend>"
501
+
502
+ # these are match $.
503
+ expect(wrap("if 1..2\n 1\nend")).to eq "<if 1..2\n <1>\nend>"
504
+ expect(wrap("if 1...2\n 1\nend")).to eq "<if 1...2\n <1>\nend>"
505
+ end
506
+
507
+ it 'does not wrap if the last value in any portion is a void value expression' do
508
+ expect(wrap("def a\nif true\nreturn 1\nend\nend")).to eq "<def a\nif <true>\nreturn <1>\nend\nend>"
509
+ expect(wrap("def a\nif true\n1\nelse\nreturn 2\nend\nend")).to eq "<def a\nif <true>\n<1>\nelse\nreturn <2>\nend\nend>"
510
+ expect(wrap("def a\nif true\n1\nelsif true\n2\nelse\nreturn 3\nend\nend")).to eq "<def a\nif <true>\n<1>\nelsif <true>\n<2>\nelse\nreturn <3>\nend\nend>"
511
+ expect(wrap("def a\nif true\nif true\nreturn 1\nend\nend\nend")).to eq "<def a\nif <true>\nif <true>\nreturn <1>\nend\nend\nend>"
512
+ expect(wrap("def a\nunless true\nreturn 1\nend\nend")).to eq "<def a\nunless <true>\nreturn <1>\nend\nend>"
513
+ expect(wrap("def a\nunless true\n1\nelse\nreturn 2\nend\nend")).to eq "<def a\nunless <true>\n<1>\nelse\nreturn <2>\nend\nend>"
514
+ expect(wrap("def a\ntrue ?\n(return 1) :\n2\nend")).to eq "<def a\n<true> ?\n(return <1>) :\n<2>\nend>"
515
+ expect(wrap("def a\ntrue ?\n1 :\n(return 2)\nend")).to eq "<def a\n<true> ?\n<1> :\n(return <2>)\nend>"
516
+ end
517
+
518
+ # not sure if I actually want this, or if it's just easier b/c it falls out of the current implementation
519
+ it 'wraps the conditional from an inline if, when it cannot wrap the entire if' do
520
+ expect(wrap("def a\nreturn if 1\nend")).to eq "<def a\nreturn if <1>\nend>"
521
+ # could maybe do this:
522
+ # `return 1 if b` -> `return <1> if (b) || <nil>`
523
+ end
524
+
525
+ it 'does not wrap &&, and, ||, or, not' do
526
+ expect(wrap("1\\\n&& 2")).to eq "<<1>\\\n&& 2>"
527
+ expect(wrap("1\\\nand 2")).to eq "<<1>\\\nand 2>"
528
+ expect(wrap("1\\\n|| 2")).to eq "<<1>\\\n|| 2>"
529
+ expect(wrap("1\\\nor 2")).to eq "<<1>\\\nor 2>"
530
+ expect(wrap("not\\\n1")).to eq "<not\\\n1>"
531
+ expect(wrap("!\\\n1")).to eq "<!\\\n1>"
532
+ end
533
+ end
534
+
535
+ describe 'loops' do
536
+ it 'wraps the until condition and body' do
537
+ expect(wrap("until 1\n2\nend")).to eq "<until <1>\n<2>\nend>"
538
+ expect(wrap("1 until 2")).to eq "<1 until 2>"
539
+ expect(wrap("begin\n1\nend until true")).to eq "<begin\n<1>\nend until true>"
540
+ end
541
+ it 'wraps the while condition and body' do
542
+ expect(wrap("while 1\n2\nend")).to eq "<while <1>\n<2>\nend>"
543
+ expect(wrap("1 while 2")).to eq "<1 while 2>"
544
+ expect(wrap("begin\n1\nend while true")).to eq "<begin\n<1>\nend while true>"
545
+ expect(wrap("begin\n1\nend until true")).to eq "<begin\n<1>\nend until true>"
546
+ end
547
+ it 'wraps for/in loops collections and bodies' do
548
+ expect(wrap("for a in range;1;end")).to eq "<for a in range;1;end>"
549
+ expect(wrap("for a in range\n1\nend")).to eq "<for a in <range>\n<1>\nend>"
550
+ expect(wrap("for a in range do\n1\nend")).to eq "<for a in <range> do\n<1>\nend>"
551
+ expect(wrap("for a,b in whatev\n1\nend")).to eq "<for a,b in <whatev>\n<1>\nend>"
552
+ expect(wrap("for char in <<HERE.each_char\nabc\nHERE\nputs char\nend"))
553
+ .to eq "<for char in <<<HERE.each_char>\nabc\nHERE\n<puts char>\nend>"
554
+ end
555
+ it 'does not wrap redo' do
556
+ expect(wrap("loop do\nredo\nend")).to eq "<loop do\nredo\nend>"
557
+ end
558
+ it 'wraps the value of break' do
559
+ expect(wrap("loop do\nbreak 1\nend")).to eq "<loop do\nbreak <1>\nend>"
560
+ end
561
+ it 'wraps the value of next' do
562
+ expect(wrap("loop do\nnext 10\nend")).to eq "<loop do\nnext <10>\nend>"
563
+ end
564
+ end
565
+
566
+ describe 'constant access' do
567
+ it 'wraps simple constant access' do
568
+ expect(wrap("A")).to eq "<A>"
569
+ end
570
+
571
+ it 'wraps namespaced constant access' do
572
+ expect(wrap("::A")).to eq "<::A>"
573
+ expect(wrap("A::B")).to eq "<A::B>"
574
+ expect(wrap("a::B")).to eq "<a::B>"
575
+ end
576
+ end
577
+
578
+ describe 'hash literals' do
579
+ it 'wraps the whole hash and values that are on their own lines' do
580
+ expect(wrap("{}")).to eq "<{}>"
581
+ expect(wrap("{\n1 => 2}")).to eq "<{\n1 => 2}>"
582
+ expect(wrap("{\n1 => 2,\n:abc => 3,\ndef: 4\n}")).to eq "<{\n1 => <2>,\n:abc => <3>,\ndef: <4>\n}>"
583
+ end
584
+ end
585
+
586
+ describe 'array literals' do
587
+ it 'wraps the array and each element that is on its own line' do
588
+ expect(wrap("[1]")).to eq "<[1]>"
589
+ expect(wrap("[1,\n2,\n]")).to eq "<[<1>,\n<2>,\n]>"
590
+ expect(wrap("[1, 2,\n]")).to eq "<[1, <2>,\n]>"
591
+ end
592
+
593
+ it 'does not wrap magic arrays' do
594
+ expect(wrap("%w[\n1\n]")).to eq "<%w[\n1\n]>"
595
+ end
596
+
597
+ it 'wraps splat elements' do
598
+ expect(wrap("[1,\n*2..3,\n4\n]")).to eq "<[<1>,\n*<2..3>,\n<4>\n]>"
599
+ end
600
+ end
601
+
602
+ describe 'regex literals' do
603
+ it 'wraps regexes' do
604
+ expect(wrap("/a/")).to eq "</a/>"
605
+ expect(wrap("/(?<a>x)/")).to eq "</(?<a>x)/>"
606
+ end
607
+
608
+ it 'wraps regexes with %r' do
609
+ expect(wrap("%r(a)")).to eq "<%r(a)>"
610
+ expect(wrap("%r'a'")).to eq "<%r'a'>"
611
+ end
612
+
613
+ it 'wraps regexes that span mulitple lines' do
614
+ expect(wrap("/a\nb/")).to eq "</a\nb/>"
615
+ expect(wrap("/a\nb/i")).to eq "</a\nb/i>"
616
+ end
617
+
618
+ it 'wraps regexes with interpolation, including the interpolated portion' do
619
+ expect(wrap("/a\#{1}/")).to eq "</a\#{1}/>"
620
+ expect(wrap("/a\n\#{1}\nb/")).to eq "</a\n\#{<1>}\nb/>"
621
+ expect(wrap("/a\n\#{1\n}b/")).to eq "</a\n\#{<1>\n}b/>"
622
+ end
623
+ end
624
+
625
+ describe 'string literals (except heredocs)' do
626
+ it 'wraps single and double quoted strings' do
627
+ expect(wrap("'a'")).to eq "<'a'>"
628
+ expect(wrap('"a"')).to eq '<"a">'
629
+ end
630
+
631
+ it 'wraps strings with %, %Q, and %q' do
632
+ expect(wrap("%'a'")).to eq "<%'a'>"
633
+ expect(wrap("%q'a'")).to eq "<%q'a'>"
634
+ expect(wrap("%Q'a'")).to eq "<%Q'a'>"
635
+ end
636
+
637
+ it 'wraps strings that span mulitple lines' do
638
+ expect(wrap("'a\nb'")).to eq "<'a\nb'>"
639
+ expect(wrap(%'"a\nb"')).to eq %'<"a\nb">'
640
+ end
641
+
642
+ it 'wraps strings with interpolation, including the interpolated portion' do
643
+ expect(wrap('"a#{1}"')).to eq '<"a#{1}">'
644
+ expect(wrap(%'"a\n\#{1}\nb"')).to eq %'<"a\n\#{<1>}\nb">'
645
+ expect(wrap(%'"a\n\#{1\n}b"')).to eq %'<"a\n\#{<1>\n}b">'
646
+ end
647
+
648
+ it 'wraps %, %q, %Q' do
649
+ expect(wrap('%(A)')).to eq '<%(A)>'
650
+ expect(wrap('%.A.')).to eq '<%.A.>'
651
+ expect(wrap('%q(A)')).to eq '<%q(A)>'
652
+ expect(wrap('%q.A.')).to eq '<%q.A.>'
653
+ expect(wrap('%Q(A)')).to eq '<%Q(A)>'
654
+ expect(wrap('%Q.A.')).to eq '<%Q.A.>'
655
+ end
656
+
657
+ it 'wraps heredocs with call defined on them (edge cases on edge cases *sigh*)' do
658
+ expect(heredoc_wrap "<<HERE.()\na\nHERE")
659
+ .to eq "[{<<HERE.()}]\na\nHERE"
660
+ end
661
+ end
662
+
663
+ describe 'heredocs' do
664
+ it 'wraps heredocs on their first line' do
665
+ expect(heredoc_wrap "<<A\nA").to eq "[{<<A}]\nA"
666
+ expect(heredoc_wrap "<<A\n123\nA").to eq "[{<<A}]\n123\nA"
667
+ expect(heredoc_wrap "<<-A\nA").to eq "[{<<-A}]\nA"
668
+ expect(heredoc_wrap "<<-A\n123\nA").to eq "[{<<-A}]\n123\nA"
669
+ if ruby_version >= '2.3'
670
+ expect(heredoc_wrap "<<~A\nA").to eq "[{<<~A}]\nA"
671
+ expect(heredoc_wrap "<<~A\n123\nA").to eq "[{<<~A}]\n123\nA"
672
+ end
673
+ expect(heredoc_wrap "1\n<<A\nA").to eq "[{1}\n{<<A}]\nA"
674
+ expect(heredoc_wrap "<<A + <<B\n1\nA\n2\nB").to eq "[{<<A + <<B}]\n1\nA\n2\nB"
675
+ expect(heredoc_wrap "<<A\n1\nA\n<<B\n2\nB").to eq "[{<<A}\n1\nA\n{<<B}]\n2\nB"
676
+ expect(heredoc_wrap "puts <<A\nA\nputs <<B\nB").to eq "[{puts <<A}\nA\n{puts <<B}]\nB"
677
+ end
678
+
679
+ it "wraps methods that wrap heredocs, even whent hey don't have parentheses" do
680
+ expect(heredoc_wrap "a(<<HERE)\nHERE").to eq "[{a(<<HERE)}]\nHERE"
681
+ expect(heredoc_wrap "a <<HERE\nHERE").to eq "[{a <<HERE}]\nHERE"
682
+ expect(heredoc_wrap "a 1, <<HERE\nHERE").to eq "[{a 1, <<HERE}]\nHERE"
683
+ expect(heredoc_wrap "a.b 1, 2, <<HERE1, <<-HERE2 \nHERE1\n HERE2").to eq\
684
+ "[{a.b 1, 2, <<HERE1, <<-HERE2}] \nHERE1\n HERE2"
685
+ expect(heredoc_wrap "a.b 1,\n2,\n<<HERE\nHERE").to eq "[{a.b {1},\n{2},\n<<HERE}]\nHERE"
686
+ end
687
+
688
+ it "wraps assignments whose value is a heredoc" do
689
+ expect(heredoc_wrap "a=<<A\nA").to eq "[{a=<<A}]\nA"
690
+ expect(heredoc_wrap "a,b=<<A,<<B\nA\nB").to eq "[{a,b=<<A,<<B}]\nA\nB"
691
+ expect(heredoc_wrap "a,b=1,<<B\nB").to eq "[{a,b=1,<<B}]\nB"
692
+ expect(heredoc_wrap "a,b=<<A,1\nA").to eq "[{a,b=<<A,1}]\nA"
693
+ end
694
+
695
+ it 'wraps methods tacked onto the end of heredocs' do
696
+ expect(heredoc_wrap "<<A.size\nA").to eq "[{<<A.size}]\nA"
697
+ expect(heredoc_wrap "<<A.size 1\nA").to eq "[{<<A.size 1}]\nA"
698
+ expect(heredoc_wrap "<<A.size(1)\nA").to eq "[{<<A.size(1)}]\nA"
699
+ expect(heredoc_wrap "<<A.whatever <<B\nA\nB").to eq "[{<<A.whatever <<B}]\nA\nB"
700
+ expect(heredoc_wrap "<<A.whatever(<<B)\nA\nB").to eq "[{<<A.whatever(<<B)}]\nA\nB"
701
+ expect(heredoc_wrap "<<A.size()\nA").to eq "[{<<A.size()}]\nA"
702
+ end
703
+
704
+ it 'is not confused by external heredocs (backticks)' do
705
+ expect(heredoc_wrap "<<`A`\nA").to eq "[{<<`A`}]\nA"
706
+ expect(heredoc_wrap "<<-`A`\nA").to eq "[{<<-`A`}]\nA"
707
+ expect(heredoc_wrap "<<~`A`\nA").to eq "[{<<~`A`}]\nA" if ruby_version >= '2.3'
708
+ end
709
+ end
710
+
711
+ # raises can be safely ignored, they're just method invocations
712
+ describe 'begin/rescue/else/ensure/end blocks' do
713
+ it 'wraps begin/rescue/else/ensure/end blocks' do
714
+ expect(wrap("begin\nrescue\nelse\nensure\nend")).to eq "<begin\nrescue\nelse\nensure\nend>"
715
+ expect(wrap("begin\nrescue e\ne\nend")).to eq "<begin\nrescue e\n<e>\nend>"
716
+ expect(wrap("begin\nrescue Exception\n$!\nend")).to eq "<begin\nrescue Exception\n<$!>\nend>"
717
+ end
718
+ it 'wraps inline rescues' do
719
+ expect(wrap("1 rescue nil")).to eq "<1 rescue nil>"
720
+ end
721
+ it 'wraps the bodies' do
722
+ expect(wrap("begin\n1\nrescue\n2\nelse\n3\nensure\n4\nend")).to eq\
723
+ "<begin\n<1>\nrescue\n<2>\nelse\n<3>\nensure\n<4>\nend>"
724
+ end
725
+ it 'wraps bodies with various pieces missing' do
726
+ expect(wrap("begin\n1\nrescue\n2\nelse\n3\nensure\n4\nend")).to eq "<begin\n<1>\nrescue\n<2>\nelse\n<3>\nensure\n<4>\nend>"
727
+ expect(wrap("begin\n1\nrescue\n2\nelse\n3\nend")).to eq "<begin\n<1>\nrescue\n<2>\nelse\n<3>\nend>"
728
+ expect(wrap("begin\n1\nrescue\n2\nend")).to eq "<begin\n<1>\nrescue\n<2>\nend>"
729
+ expect(wrap("begin\n1\nend")).to eq "<begin\n<1>\nend>"
730
+ expect(wrap("begin\nend")).to eq "<begin\nend>"
731
+ expect(wrap("begin\n1\nensure\n2\nend")).to eq "<begin\n<1>\nensure\n<2>\nend>"
732
+ end
733
+ it 'does not wrap arguments to rescue' do
734
+ expect(wrap("begin\nrescue\nrescue => a\nrescue SyntaxError\nrescue Exception => a\nelse\nensure\nend")).to eq\
735
+ "<begin\nrescue\nrescue => a\nrescue SyntaxError\nrescue Exception => a\nelse\nensure\nend>"
736
+ end
737
+ it 'does not wrap retry' do
738
+ # in this case, it could wrap the retry
739
+ # but I don't know how to tell the difference between this and
740
+ # "loop { begin; retry; end }" so w/e
741
+ expect(wrap("begin\nrescue\nretry\nend")).to eq "<begin\nrescue\nretry\nend>"
742
+ end
743
+ end
744
+
745
+ describe 'class definitions' do
746
+ it 'does wraps the class definition, and body' do
747
+ expect(wrap("class A\n1\nend")).to eq "<class A\n<1>\nend>"
748
+ end
749
+
750
+ it 'does wraps the superclass definition' do
751
+ expect(wrap("class A < B\nend")).to eq "<class A < <B>\nend>"
752
+ end
753
+
754
+ it 'wraps the rescue, else, ensure body' do
755
+ expect(wrap("class A < B\n1\nrescue\n2\nelse\n3\nensure\n4\nend")).to eq "<class A < <B>\n<1>\nrescue\n<2>\nelse\n<3>\nensure\n<4>\nend>"
756
+ end
757
+
758
+ it 'wraps the else body' do
759
+ expect(wrap("class A < B\n1\nrescue\n2\nend")).to eq "<class A < <B>\n<1>\nrescue\n<2>\nend>"
760
+ end
761
+
762
+ it 'wraps the singleton class' do
763
+ expect(wrap("class << self\n end")).to eq "<class << <self>\n end>"
764
+ end
765
+
766
+ it 'wraps the namespace' do
767
+ expect(wrap("class A::B\nend")).to eq "<class <A>::B\nend>"
768
+ expect(wrap("class (\n1\nObject\n)::String\nend")).to eq "<class <(\n<1>\n<Object>\n)>::String\nend>"
769
+ end
770
+ end
771
+
772
+ describe 'module definitions' do
773
+ it 'does not wrap the definition, does wrap the body' do
774
+ expect(wrap("module A\n1\nend")).to eq "<module A\n<1>\nend>"
775
+ end
776
+ it 'wraps the rescue portion' do
777
+ expect(wrap("module A\n1\nrescue\n2\nend")).to eq "<module A\n<1>\nrescue\n<2>\nend>"
778
+ end
779
+ end
780
+
781
+ describe 'method definitions' do
782
+ it 'does wraps the definition, but not the arguments' do
783
+ expect(wrap("def a(b,c=1,*d,&e)\nend")).to eq "<def a(b,c=1,*d,&e)\nend>"
784
+ end
785
+
786
+ it 'wraps the the body' do
787
+ expect(wrap("def a\n1\nend")).to eq "<def a\n<1>\nend>"
788
+ expect(wrap("def a()\n1\nend")).to eq "<def a()\n<1>\nend>"
789
+ expect(wrap("def a\n1\n2\nend")).to eq "<def a\n<1>\n<2>\nend>"
790
+ end
791
+
792
+ it 'wraps singleton method definitions' do
793
+ expect(wrap("def a.b\n1\nend")).to eq "<def a.b\n<1>\nend>"
794
+ expect(wrap("def a.b()\n1\nend")).to eq "<def a.b()\n<1>\nend>"
795
+ expect(wrap("def a.b\n1\n2\nend")).to eq "<def a.b\n<1>\n<2>\nend>" # <-- seems redundant, but this was a regression
796
+ end
797
+
798
+ it 'wraps calls to yield' do
799
+ expect(wrap("def a\nyield\nend")).to eq "<def a\n<yield>\nend>"
800
+ expect(wrap("def a\nyield 1\nend")).to eq "<def a\n<yield 1>\nend>"
801
+ expect(wrap("def a\nyield(\n1\n)\nend")).to eq "<def a\n<yield(\n<1>\n)>\nend>"
802
+ end
803
+
804
+ it 'wraps calls to super' do
805
+ expect(wrap("def a\nsuper\nend")).to eq "<def a\n<super>\nend>"
806
+ expect(wrap("def a\nsuper 1\nend")).to eq "<def a\n<super 1>\nend>"
807
+ expect(wrap("def a\nsuper(1)\nend")).to eq "<def a\n<super(1)>\nend>"
808
+ expect(wrap("def a\nsuper(\n1\n)\nend")).to eq "<def a\n<super(\n<1>\n)>\nend>"
809
+ end
810
+
811
+ it 'wraps the bodies of returns' do
812
+ expect(wrap("def a\nreturn 1\nend")).to eq "<def a\nreturn <1>\nend>"
813
+ end
814
+
815
+ it 'wraps the rescue and ensure portion' do
816
+ expect(wrap("def a\n1\nrescue\n2\nend")).to eq "<def a\n<1>\nrescue\n<2>\nend>"
817
+ expect(wrap("def a\n1\nrescue\n2\nensure\n3\nend")).to eq "<def a\n<1>\nrescue\n<2>\nensure\n<3>\nend>"
818
+ expect(wrap("def a\n1\nensure\n2\nend")).to eq "<def a\n<1>\nensure\n<2>\nend>"
819
+ end
820
+
821
+ it 'wrap a definition as a call to an invocation' do
822
+ expect(wrap("a def b\nc\nend,\nd")).to eq "<a <def b\n<c>\nend>,\nd>"
823
+ end
824
+ end
825
+
826
+ describe 'lambdas' do
827
+ it 'wraps the lambda' do
828
+ expect(wrap("lambda { }")).to eq "<lambda { }>"
829
+ expect(wrap("lambda { |;a| }")).to eq "<lambda { |;a| }>"
830
+ expect(wrap("lambda { |a,b=1,*c,&d| }")).to eq "<lambda { |a,b=1,*c,&d| }>"
831
+ expect(wrap("-> { }")).to eq "<-> { }>"
832
+ expect(wrap("-> a, b { }")).to eq "<-> a, b { }>"
833
+ expect(wrap("-> {\n1\n}")).to eq "<-> {\n<1>\n}>"
834
+ expect(wrap("-> * { }")).to eq "<-> * { }>"
835
+ end
836
+
837
+ it 'wraps the full invocation' do
838
+ expect(wrap("lambda { }.()")).to eq "<lambda { }.()>"
839
+ expect(wrap("-> { }.()")).to eq "<-> { }.()>"
840
+ expect(wrap("-> a, b {\n1\n}.(1,\n2)")).to eq "<-> a, b {\n<1>\n}.(<1>,\n2)>"
841
+ expect(wrap("-> a, b { }.call(1, 2)")).to eq "<-> a, b { }.call(1, 2)>"
842
+ expect(wrap("-> * { }.()")).to eq "<-> * { }.()>"
843
+ end
844
+ end
845
+
846
+ describe 'interpolation wraps the whole value and interpolated values' do
847
+ def self.assert_interpolates(name, code, expected)
848
+ example(name) { expect(wrap code).to eq expected }
849
+ end
850
+
851
+ assert_interpolates 'backtick syscall', "`a\#{\n1\n}\nb\n`", "<`a\#{\n<1>\n}\nb\n`>"
852
+ assert_interpolates 'slash regex', "/a\#{\n1\n}\nb\n/", "</a\#{\n<1>\n}\nb\n/>"
853
+ assert_interpolates 'double quoted string', "\"a\#{\n1\n}\nb\n\"", "<\"a\#{\n<1>\n}\nb\n\">"
854
+ assert_interpolates 'double quoted symbol', ":\"a\#{\n1\n}\nb\n\"", "<:\"a\#{\n<1>\n}\nb\n\">"
855
+
856
+ assert_interpolates 'symbol array with interpolation', "%I.a\#{\n1\n}\nb\n.", "<%I.a\#{\n<1>\n}\nb\n.>"
857
+ assert_interpolates '%x syscall', "%x.a\#{\n1\n}\nb\n.", "<%x.a\#{\n<1>\n}\nb\n.>"
858
+ assert_interpolates '% string', "%.a\#{\n1\n}\nb\n.", "<%.a\#{\n<1>\n}\nb\n.>"
859
+ assert_interpolates 'string array with interpolation', "%W.a\#{\n1\n}\nb\n.", "<%W.a\#{\n<1>\n}\nb\n.>"
860
+ assert_interpolates '%r regex', "%r.a\#{\n1\n}\nb\n.", "<%r.a\#{\n<1>\n}\nb\n.>"
861
+ assert_interpolates '%Q string', "%Q.a\#{\n1\n}\nb\n.", "<%Q.a\#{\n<1>\n}\nb\n.>"
862
+
863
+ assert_interpolates '%s symbol', "%s.a\#{\n1\n}\nb\n.", "<%s.a\#{\n1\n}\nb\n.>"
864
+ assert_interpolates 'single quoted string', "'a\#{\n1\n}\nb\n'", "<'a\#{\n1\n}\nb\n'>"
865
+ assert_interpolates 'single quoted symbol', ":'a\#{\n1\n}\nb\n'", "<:'a\#{\n1\n}\nb\n'>"
866
+ assert_interpolates 'symbol array without interpolation', "%i.a\#{\n1\n}\nb\n.", "<%i.a\#{\n1\n}\nb\n.>"
867
+ assert_interpolates '%q string without interpolation', "%q.a\#{\n1\n}\nb\n.", "<%q.a\#{\n1\n}\nb\n.>"
868
+ assert_interpolates 'string array without interpolation', "%w.a\#{\n1\n}\nb\n.", "<%w.a\#{\n1\n}\nb\n.>"
869
+ end
870
+
871
+ describe 'BEGIN/END' do
872
+ # not implemented b/c we cannot wrap around these either.
873
+ # So what does it mean to wrap around?
874
+ # maybe this?
875
+ # 1
876
+ # BEGIN {}
877
+ # 2
878
+ # END {}
879
+ # 3
880
+ #
881
+ # becomes
882
+ # BEGIN {}
883
+ # END {}
884
+ # [<1>
885
+ # <2>
886
+ # <3>]
887
+ #
888
+ # Because not iw matters why you want to wrap it. Are you doing this because you want
889
+ # to catch an exception? then maybe your wrapping code needs to go around the inside of each begin block
890
+ # or maybe the begin blocks need to get consolidated into a single begin block.
891
+ # or maybe removed from the begin block and just stuck as normal fkn code at the top of the file?
892
+ # but we do need to rewrite __LINE__ expressions now, because they are changing.
893
+ # which... maybe that's fine.
894
+ #
895
+ # Or, you might just be interested in having your code execute first. In which case,
896
+ # it doesn't need to wrap the body, it just needs its own BEGIN block.
897
+ #
898
+ # note that there are also things line nested BEGINs and nested ENDs
899
+ # but you can't nest a BEGIN inside an END.
900
+ it 'does not record them' do
901
+ expect(wrap("BEGIN {}")).to eq "BEGIN {}"
902
+ expect(wrap("END {}")).to eq "END {}"
903
+ expect(wrap("BEGIN {\n123\n}")).to eq "BEGIN {\n<123>\n}"
904
+ expect(wrap("END {\n123\n}")).to eq "END {\n<123>\n}"
905
+ end
906
+
907
+ it 'moves them out of the body', not_implemented: true do
908
+ expect(wrap_with_body(<<-HERE)).to eq(<<-THERE)
909
+ # encoding: utf-8
910
+ p [1, __LINE__]
911
+ BEGIN {
912
+ p [2, __LINE__]
913
+ }
914
+ p [3, __LINE__]
915
+ END {
916
+ p [4, __LINE__]
917
+ }
918
+ p [5, __LINE__]
919
+ BEGIN { p [6, __LINE__] }
920
+ END { p [7, __LINE__] }
921
+ p [8, __LINE__]
922
+ HERE
923
+ # encoding: utf-8
924
+ BEGIN {
925
+ <p [2, 4]>
926
+ }
927
+ BEGIN { <p [6, 11]> }
928
+ [<p [1, 2]>
929
+ <p [3, 6]>
930
+ <p [5, 10]>
931
+ <p [8, 13]>]
932
+ END {
933
+ <p [4, 8]>
934
+ }
935
+ END { <p [7, 12]> }
936
+ THERE
937
+ end
938
+ end
939
+
940
+ describe 'Perl style globals' do
941
+ # from English.rb
942
+ specify('$ERROR_INFO $!') { expect(wrap('$!')).to eq '<$!>' }
943
+ specify('$ERROR_POSITION $@') { expect(wrap('$@')).to eq '<$@>' }
944
+ specify('$FS $;') { expect(wrap('$;')).to eq '<$;>' }
945
+ specify('$FIELD_SEPARATOR $;') { expect(wrap('$;')).to eq '<$;>' }
946
+ specify('$OFS $,') { expect(wrap('$,')).to eq '<$,>' }
947
+ specify('$OUTPUT_FIELD_SEPARATOR $,') { expect(wrap('$,')).to eq '<$,>' }
948
+ specify('$RS $/') { expect(wrap('$/')).to eq '<$/>' }
949
+ specify('$INPUT_RECORD_SEPARATOR $/') { expect(wrap('$/')).to eq '<$/>' }
950
+ specify('$ORS $\\') { expect(wrap('$\\')).to eq '<$\\>' }
951
+ specify('$OUTPUT_RECORD_SEPARATOR $\\') { expect(wrap('$\\')).to eq '<$\\>' }
952
+ specify('$INPUT_LINE_NUMBER $.') { expect(wrap('$.')).to eq '<$.>' }
953
+ specify('$NR $.') { expect(wrap('$.')).to eq '<$.>' }
954
+ specify('$LAST_READ_LINE $_') { expect(wrap('$_')).to eq '<$_>' }
955
+ specify('$DEFAULT_OUTPUT $>') { expect(wrap('$>')).to eq '<$>>' }
956
+ specify('$DEFAULT_INPUT $<') { expect(wrap('$<')).to eq '<$<>' }
957
+ specify('$PID $$') { expect(wrap('$$')).to eq '<$$>' }
958
+ specify('$PROCESS_ID $$') { expect(wrap('$$')).to eq '<$$>' }
959
+ specify('$CHILD_STATUS $?') { expect(wrap('$?')).to eq '<$?>' }
960
+ specify('$LAST_MATCH_INFO $~') { expect(wrap('$~')).to eq '<$~>' }
961
+ specify('$IGNORECASE $=') { expect(wrap('$=')).to eq '<$=>' }
962
+ specify('$ARGV $*') { expect(wrap('$*')).to eq '<$*>' }
963
+ specify('$MATCH $&') { expect(wrap('$&')).to eq '<$&>' }
964
+ specify('$PREMATCH $`') { expect(wrap('$`')).to eq '<$`>' }
965
+ specify('$POSTMATCH $\'') { expect(wrap("$'")).to eq "<$'>" }
966
+ specify('$LAST_PAREN_MATCH $+') { expect(wrap('$+')).to eq '<$+>' }
967
+ end
968
+
969
+
970
+ # only checking on 2.2 b/c its hard to figure out when different pieces were introduced
971
+ # we'll assume that if it passes on 2.2, it will pass on 2.0 or 2.1, if the feature is available on that Ruby
972
+ major, minor, * = RUBY_VERSION.split(".").map(&:to_i)
973
+ if major > 2 || (major == 2 && minor >= 2)
974
+ describe 'Ruby 2 syntaxes', :'2.x' => true do
975
+ it 'respects __dir__ macro' do
976
+ expect(wrap('__dir__')).to eq '<__dir__>'
977
+ end
978
+
979
+ it 'does not wrap keyword/keywordrest arguments' do
980
+ expect(wrap("def a(b,c=1,*d,e:,f:1,**g, &h)\n1\nend"))
981
+ .to eq "<def a(b,c=1,*d,e:,f:1,**g, &h)\n<1>\nend>"
982
+ expect(wrap("def a b:\n1\nend")).to eq "<def a b:\n<1>\nend>"
983
+ expect(wrap("def a b:\nreturn 1\nend")).to eq "<def a b:\nreturn <1>\nend>"
984
+ expect(wrap("def a b:\nreturn\nend")).to eq "<def a b:\nreturn\nend>"
985
+ expect(wrap("a b:1, **c")).to eq "<a b:1, **c>"
986
+ expect(wrap("{\na:1,\n**b\n}")).to eq "<{\na:<1>,\n**<b>\n}>"
987
+ expect(wrap("a(b:1,\n **c\n)")).to eq "<a(b:<1>,\n **<c>\n)>"
988
+ expect(wrap("def a(*, **)\n1\nend")).to eq "<def a(*, **)\n<1>\nend>"
989
+ end
990
+
991
+ it 'tags javascript style hashes' do
992
+ expect(wrap(%[{\na:1,\n'b':2,\n"c":3\n}])).to eq %[<{\na:<1>,\n'b':<2>,\n"c":<3>\n}>]
993
+ expect(wrap(%[a b: 1,\n'c': 2,\n"d": 3,\n:e => 4])).to eq %[<a b: <1>,\n'c': <2>,\n"d": <3>,\n:e => 4>]
994
+ end
995
+
996
+ it 'wraps symbol literals' do
997
+ expect(wrap("%i[abc]")).to eq "<%i[abc]>"
998
+ expect(wrap("%I[abc]")).to eq "<%I[abc]>"
999
+ expect(wrap("%I[a\nb\nc]")).to eq "<%I[a\nb\nc]>"
1000
+ end
1001
+
1002
+ it 'wraps complex and rational' do
1003
+ expect(wrap("1i")).to eq "<1i>"
1004
+ expect(wrap("5+1i")).to eq "<5+1i>"
1005
+ expect(wrap("1r")).to eq "<1r>"
1006
+ expect(wrap("1.5r")).to eq "<1.5r>"
1007
+ expect(wrap("1/2r")).to eq "<1/2r>"
1008
+ expect(wrap("2/1r")).to eq "<2/1r>"
1009
+ expect(wrap("1ri")).to eq "<1ri>"
1010
+ end
1011
+ end
1012
+ end
1013
+ end