seeing_is_believing 3.0.0.beta.4 → 3.0.0.beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +0 -8
- data/Rakefile +1 -1
- data/Readme.md +65 -25
- data/bin/seeing_is_believing +1 -0
- data/docs/sib-streaming.gif +0 -0
- data/features/deprecated-flags.feature +62 -2
- data/features/errors.feature +12 -7
- data/features/examples.feature +143 -4
- data/features/flags.feature +89 -29
- data/features/regression.feature +58 -14
- data/features/support/env.rb +4 -0
- data/features/xmpfilter-style.feature +181 -36
- data/lib/seeing_is_believing.rb +44 -33
- data/lib/seeing_is_believing/binary.rb +31 -88
- data/lib/seeing_is_believing/binary/align_chunk.rb +30 -11
- data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +10 -16
- data/lib/seeing_is_believing/binary/annotate_every_line.rb +5 -25
- data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +136 -0
- data/lib/seeing_is_believing/binary/comment_lines.rb +8 -10
- data/lib/seeing_is_believing/binary/commentable_lines.rb +20 -26
- data/lib/seeing_is_believing/binary/config.rb +392 -0
- data/lib/seeing_is_believing/binary/data_structures.rb +57 -0
- data/lib/seeing_is_believing/binary/engine.rb +104 -0
- data/lib/seeing_is_believing/binary/{comment_formatter.rb → format_comment.rb} +6 -6
- data/lib/seeing_is_believing/binary/remove_annotations.rb +29 -28
- data/lib/seeing_is_believing/binary/rewrite_comments.rb +42 -43
- data/lib/seeing_is_believing/code.rb +105 -49
- data/lib/seeing_is_believing/debugger.rb +6 -5
- data/lib/seeing_is_believing/error.rb +6 -17
- data/lib/seeing_is_believing/evaluate_by_moving_files.rb +78 -129
- data/lib/seeing_is_believing/event_stream/consumer.rb +114 -64
- data/lib/seeing_is_believing/event_stream/events.rb +169 -11
- data/lib/seeing_is_believing/event_stream/handlers/debug.rb +57 -0
- data/lib/seeing_is_believing/event_stream/handlers/record_exitstatus.rb +18 -0
- data/lib/seeing_is_believing/event_stream/handlers/stream_json_events.rb +45 -0
- data/lib/seeing_is_believing/event_stream/handlers/update_result.rb +39 -0
- data/lib/seeing_is_believing/event_stream/producer.rb +25 -24
- data/lib/seeing_is_believing/hash_struct.rb +206 -0
- data/lib/seeing_is_believing/result.rb +20 -3
- data/lib/seeing_is_believing/the_matrix.rb +20 -12
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/wrap_expressions.rb +55 -115
- data/lib/seeing_is_believing/wrap_expressions_with_inspect.rb +14 -0
- data/seeing_is_believing.gemspec +1 -1
- data/spec/binary/alignment_specs.rb +27 -0
- data/spec/binary/comment_lines_spec.rb +3 -2
- data/spec/binary/config_spec.rb +657 -0
- data/spec/binary/engine_spec.rb +97 -0
- data/spec/binary/{comment_formatter_spec.rb → format_comment_spec.rb} +2 -2
- data/spec/binary/marker_spec.rb +71 -0
- data/spec/binary/options_spec.rb +0 -0
- data/spec/binary/remove_annotations_spec.rb +31 -18
- data/spec/binary/rewrite_comments_spec.rb +26 -11
- data/spec/code_spec.rb +190 -6
- data/spec/debugger_spec.rb +4 -0
- data/spec/evaluate_by_moving_files_spec.rb +38 -20
- data/spec/event_stream_spec.rb +265 -116
- data/spec/hash_struct_spec.rb +514 -0
- data/spec/seeing_is_believing_spec.rb +108 -46
- data/spec/spec_helper.rb +9 -0
- data/spec/wrap_expressions_spec.rb +207 -172
- metadata +30 -18
- data/docs/for-presentations +0 -33
- data/lib/seeing_is_believing/binary/annotate_xmpfilter_style.rb +0 -128
- data/lib/seeing_is_believing/binary/interpret_flags.rb +0 -156
- data/lib/seeing_is_believing/binary/parse_args.rb +0 -263
- data/lib/seeing_is_believing/event_stream/update_result.rb +0 -24
- data/lib/seeing_is_believing/inspect_expressions.rb +0 -21
- data/lib/seeing_is_believing/parser_helpers.rb +0 -82
- data/spec/binary/interpret_flags_spec.rb +0 -332
- data/spec/binary/parse_args_spec.rb +0 -415
@@ -20,13 +20,18 @@ RSpec.describe SeeingIsBelieving do
|
|
20
20
|
options.delete :debug
|
21
21
|
options[:debugger] = SeeingIsBelieving::Debugger.new(stream: $stderr, colour: true)
|
22
22
|
end
|
23
|
-
described_class.new(input, options).call
|
23
|
+
described_class.new(input, options).call.result
|
24
24
|
end
|
25
25
|
|
26
26
|
def values_for(input, options={})
|
27
27
|
invoke(input, options).to_a
|
28
28
|
end
|
29
29
|
|
30
|
+
root_path = File.expand_path("../..", __FILE__)
|
31
|
+
proving_grounds = File.expand_path('proving_grounds', root_path)
|
32
|
+
before(:all) { Dir.mkdir proving_grounds unless Dir.exist? proving_grounds }
|
33
|
+
around { |spec| Dir.chdir proving_grounds, &spec }
|
34
|
+
|
30
35
|
let(:proving_grounds_dir) { File.expand_path '../../proving_grounds', __FILE__ }
|
31
36
|
|
32
37
|
it 'takes a string and returns a result of the line numbers (counting from 1) and each inspected result from that line' do
|
@@ -35,6 +40,10 @@ RSpec.describe SeeingIsBelieving do
|
|
35
40
|
expect(invoke(input)[2]).to eq ['"22"']
|
36
41
|
end
|
37
42
|
|
43
|
+
it 'blows up if given unknown options' do
|
44
|
+
expect { invoke '', not_an_option: 123 }.to raise_error KeyError, /not_an_option/
|
45
|
+
end
|
46
|
+
|
38
47
|
it 'only invokes inspect once' do
|
39
48
|
input = "class Fixnum; def inspect; 'NUM'\nend\nend\n1"
|
40
49
|
expect(invoke(input)[1]).to eq ['"NUM"']
|
@@ -45,10 +54,10 @@ RSpec.describe SeeingIsBelieving do
|
|
45
54
|
end
|
46
55
|
|
47
56
|
it 'records various useful information on the result' do
|
48
|
-
result = invoke '',
|
57
|
+
result = invoke '', max_line_captures: 10, filename: 'abc.rb'
|
49
58
|
expect(result.sib_version).to eq SeeingIsBelieving::VERSION
|
50
59
|
expect(result.ruby_version).to eq RUBY_VERSION
|
51
|
-
expect(result.
|
60
|
+
expect(result.max_line_captures).to eq 10
|
52
61
|
expect(result.num_lines).to eq 1
|
53
62
|
expect(result.filename).to eq 'abc.rb'
|
54
63
|
end
|
@@ -58,14 +67,12 @@ RSpec.describe SeeingIsBelieving do
|
|
58
67
|
end
|
59
68
|
|
60
69
|
it 'allows uers to pass in their own inspection recorder' do
|
61
|
-
wrapper = lambda { |program
|
62
|
-
SeeingIsBelieving::
|
63
|
-
|
64
|
-
|
65
|
-
num_captures,
|
66
|
-
after_each: -> line_number { ").tap { $SiB.record_result(:inspect, #{line_number}, 'zomg') }" }
|
70
|
+
wrapper = lambda { |program|
|
71
|
+
SeeingIsBelieving::WrapExpressions.call program,
|
72
|
+
before_each: -> * { '(' },
|
73
|
+
after_each: -> line_number { ").tap { $SiB.record_result(:inspect, #{line_number}, 'zomg') }" }
|
67
74
|
}
|
68
|
-
expect(invoke(':body',
|
75
|
+
expect(invoke(':body', rewrite_code: wrapper)[1]).to eq ['"zomg"']
|
69
76
|
end
|
70
77
|
|
71
78
|
it 'remembers context of previous lines' do
|
@@ -74,8 +81,8 @@ RSpec.describe SeeingIsBelieving do
|
|
74
81
|
|
75
82
|
it 'can be invoked multiple times, returning the same result' do
|
76
83
|
believer = described_class.new("$xyz||=1\n$xyz+=1")
|
77
|
-
expect(believer.call
|
78
|
-
expect(believer.call.to_a).to eq [['1'], ['2']]
|
84
|
+
expect(believer.call).to eq believer.call
|
85
|
+
expect(believer.call.result.to_a).to eq [['1'], ['2']]
|
79
86
|
end
|
80
87
|
|
81
88
|
it 'is evaluated at the toplevel' do
|
@@ -179,7 +186,24 @@ RSpec.describe SeeingIsBelieving do
|
|
179
186
|
end
|
180
187
|
end
|
181
188
|
|
189
|
+
it 'supports catch/throw' do
|
190
|
+
values = values_for("catch :zomg do\n"\
|
191
|
+
" 1\n"\
|
192
|
+
" throw :zomg\n"\
|
193
|
+
" 2\n"\
|
194
|
+
"end")
|
195
|
+
expect(values).to eq [[], ['1'], [], [], ['nil']]
|
182
196
|
|
197
|
+
result = invoke("throw :zomg")
|
198
|
+
expect(result.exception.message).to match /:zomg/
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'does not fuck up the __ENCODING__ macro' do
|
202
|
+
expect(values_for("# encoding: utf-8
|
203
|
+
__ENCODING__")).to eq [[], ["#<Encoding:UTF-8>"]]
|
204
|
+
expect(values_for("# encoding: ascii-8bit
|
205
|
+
__ENCODING__")).to eq [[], ["#<Encoding:ASCII-8BIT>"]]
|
206
|
+
end
|
183
207
|
|
184
208
|
it 'does not fuck up __LINE__ macro' do
|
185
209
|
expect(values_for( '__LINE__
|
@@ -314,7 +338,7 @@ RSpec.describe SeeingIsBelieving do
|
|
314
338
|
it 'can deal with methods that are invoked entirely on the next line' do
|
315
339
|
expect(values_for("a = 1\n.even?\na")).to eq [['1'], ['false'], ['false']]
|
316
340
|
expect(values_for("a = 1.\neven?\na")).to eq [['1'], ['false'], ['false']]
|
317
|
-
expect(values_for("1\n.even?\n__END__")).to eq [['1'], ['false'], []]
|
341
|
+
expect(values_for("1\n.even?\n__END__")).to eq [['1'], ['false'], []]
|
318
342
|
end
|
319
343
|
|
320
344
|
it 'does not record leading comments' do
|
@@ -325,15 +349,35 @@ RSpec.describe SeeingIsBelieving do
|
|
325
349
|
end
|
326
350
|
|
327
351
|
it 'times out if the timeout limit is exceeded' do
|
328
|
-
expect { invoke "sleep 0.2",
|
352
|
+
expect { invoke "sleep 0.2", timeout_seconds: 0.1 }.to raise_error Timeout::Error
|
329
353
|
end
|
330
354
|
|
331
355
|
it 'records the exit status' do
|
332
|
-
expect(invoke(
|
333
|
-
expect(invoke('
|
334
|
-
expect(invoke('
|
356
|
+
expect(invoke("" ).exitstatus).to eq 0 # happy path: no exceptions
|
357
|
+
expect(invoke('raise "omg"' ).exitstatus).to eq 1 # exceptions: status is 1
|
358
|
+
expect(invoke('exit' ).exitstatus).to eq 0 # call exit, but with no args
|
359
|
+
expect(invoke('exit 0' ).exitstatus).to eq 0 # set numeric status with exit
|
360
|
+
expect(invoke('exit 123' ).exitstatus).to eq 123
|
361
|
+
expect(invoke('exit true' ).exitstatus).to eq 0 # set boolean status with exit
|
362
|
+
expect(invoke('exit false' ).exitstatus).to eq 1
|
363
|
+
expect(invoke('at_exit { exit 121 }').exitstatus).to eq 121 # when status is set in an at_exit hook
|
364
|
+
|
365
|
+
# setting status with exit!
|
366
|
+
# since we might be overriding this (a questionable decision) we make sure it behaves as expected (no at_exit hooks are called)
|
367
|
+
result = invoke 'at_exit { puts "omg" }; exit!'
|
368
|
+
expect([result.exitstatus, result.stdout, result.stderr]).to eq [1, '', '']
|
369
|
+
|
370
|
+
result = invoke 'at_exit { puts "omg" }; exit! 100'
|
371
|
+
expect([result.exitstatus, result.stdout]).to eq [100, '']
|
372
|
+
|
373
|
+
result = invoke 'at_exit { puts "omg" }; Kernel.exit! 101'
|
374
|
+
expect([result.exitstatus, result.stdout]).to eq [101, '']
|
375
|
+
|
376
|
+
result = invoke 'at_exit { puts "omg" }; Kernel.exit! 102'
|
377
|
+
expect([result.exitstatus, result.stdout]).to eq [102, '']
|
335
378
|
end
|
336
379
|
|
380
|
+
|
337
381
|
it 'records lines that have comments on them' do
|
338
382
|
expect(values_for('1+1 # comment uno
|
339
383
|
#comment dos
|
@@ -373,23 +417,28 @@ RSpec.describe SeeingIsBelieving do
|
|
373
417
|
['[6, 12]']]
|
374
418
|
end
|
375
419
|
|
376
|
-
it 'can be limited to a specific number of captures' do
|
377
|
-
expect(values_for "2.times do\n1\nend",
|
420
|
+
it 'can be limited to a specific number of captures per line' do
|
421
|
+
expect(values_for "2.times do\n1\nend", max_line_captures: 1).to \
|
378
422
|
eq [['2'],
|
379
423
|
['1', '...'],
|
380
424
|
['2']]
|
381
425
|
end
|
382
426
|
|
383
427
|
describe 'BEGIN and END' do
|
428
|
+
it 'doesn\'t fuck up when the BEGIN block exits / raises' do
|
429
|
+
expect(invoke("BEGIN { exit 100 }").exitstatus).to eq 100
|
430
|
+
expect(invoke("BEGIN { exit! 100 }").exitstatus).to eq 100
|
431
|
+
expect(invoke("BEGIN { raise Exception, 'wat'}").exception.message).to eq 'wat'
|
432
|
+
end
|
433
|
+
|
384
434
|
it 'Executes in the appropriate order' do
|
385
|
-
|
386
|
-
expect(invoke <<-CODE).stdout.to eq "1\n2\n3\n4\n5\n6\n7\n8\n9\n"
|
435
|
+
expect(invoke(<<-CODE).stdout).to eq "1\n2\n3\n4\n5\n6\n7\n8\n9\n"
|
387
436
|
p 3
|
388
|
-
END { p
|
437
|
+
END { p 9 }
|
389
438
|
p 4
|
390
439
|
BEGIN { p 1 }
|
391
440
|
p 5
|
392
|
-
END { p
|
441
|
+
END { p 8 }
|
393
442
|
p 6
|
394
443
|
BEGIN { p 2 }
|
395
444
|
p 7
|
@@ -397,7 +446,6 @@ RSpec.describe SeeingIsBelieving do
|
|
397
446
|
end
|
398
447
|
|
399
448
|
it 'Maintains correct line numbers' do
|
400
|
-
pending 'not implemented'
|
401
449
|
expected_values = [
|
402
450
|
['1'],
|
403
451
|
[],
|
@@ -434,7 +482,7 @@ RSpec.describe SeeingIsBelieving do
|
|
434
482
|
result = invoke(%[def self.inspect
|
435
483
|
self
|
436
484
|
end
|
437
|
-
self], filename: 'blowsup.rb')
|
485
|
+
self], filename: 'blowsup.rb')
|
438
486
|
expect(result).to have_exception
|
439
487
|
expect(result.exception.class_name).to eq 'SystemStackError'
|
440
488
|
expect(result.exception.backtrace.grep(/blowsup.rb/)).to_not be_empty # backtrace includes a line that we can show
|
@@ -454,34 +502,48 @@ RSpec.describe SeeingIsBelieving do
|
|
454
502
|
let(:debugger) { SeeingIsBelieving::Debugger.new stream: stream }
|
455
503
|
|
456
504
|
def call
|
457
|
-
invoke "1", debugger: debugger
|
505
|
+
result = invoke "1", debugger: debugger
|
506
|
+
expect(result[1]).to eq ["1"]
|
507
|
+
result
|
458
508
|
end
|
459
509
|
|
460
510
|
it 'prints the pre-evaluated program' do
|
461
511
|
call
|
462
|
-
expect(stream.string).to include "
|
463
|
-
expect(stream.string).to include "$SiB.
|
512
|
+
expect(stream.string).to include "REWRITTEN PROGRAM:"
|
513
|
+
expect(stream.string).to include "$SiB.record_result" # there is more, but we're just interested in showing that it wound up in the stream
|
464
514
|
end
|
465
515
|
|
466
|
-
it '
|
516
|
+
it 'records eventstream information' do
|
467
517
|
call
|
468
|
-
expect(stream.string).to include "
|
469
|
-
|
470
|
-
|
518
|
+
expect(stream.string).to include "EVENTS"
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
describe 'exec' do
|
523
|
+
it 'passes stdin, stdout, stderr, and actually does exec the process' do
|
524
|
+
result = invoke \
|
525
|
+
"1+1\n"\
|
526
|
+
"$stdout.puts *1..1000\n"\
|
527
|
+
"$stderr.puts *1..1000\n"\
|
528
|
+
"exec %(ruby -e '$stdout.puts %{from stdin: } + gets.inspect
|
529
|
+
$stdout.puts %[out from exec]
|
530
|
+
$stderr.puts %[err from exec]')\n"\
|
531
|
+
"$stdout.puts 'this will never be executed'",
|
532
|
+
stdin: "the-stdin-dataz"
|
533
|
+
expect(result[1]).to eq ['2']
|
534
|
+
nums = (1..1000).map { |n| "#{n}\n" }.join('')
|
535
|
+
expect(result.stdout).to eq "#{nums}from stdin: \"the-stdin-dataz\"\nout from exec\n"
|
536
|
+
expect(result.stderr).to eq "#{nums}err from exec\n"
|
537
|
+
end
|
538
|
+
|
539
|
+
it 'works for Kernel#exec, Kernel.exec, Process.exec' do
|
540
|
+
expect(invoke('exec "ruby", "-e", "puts %(hello)"').stdout).to eq "hello\n"
|
541
|
+
expect(invoke('Kernel.exec "ruby", "-e", "puts %(hello)"').stdout).to eq "hello\n"
|
542
|
+
expect(invoke('Process.exec "ruby", "-e", "puts %(hello)"').stdout).to eq "hello\n"
|
543
|
+
end
|
544
|
+
|
545
|
+
it 'gets the exit status off of the child process' do
|
546
|
+
expect(invoke('exec "ruby", "-e", "exit 5"').exitstatus).to eq 5
|
471
547
|
end
|
472
|
-
# should ProgramRewriter have some debug options?
|
473
|
-
end
|
474
|
-
|
475
|
-
it 'can deal with exec' do
|
476
|
-
result = invoke \
|
477
|
-
"1+1\n"\
|
478
|
-
"$stdout.puts *1..1000\n"\
|
479
|
-
"$stderr.puts *1..1000\n"\
|
480
|
-
"exec %(ruby -e '$stdout.puts %[out from exec];
|
481
|
-
$stderr.puts %[err from exec]')"
|
482
|
-
expect(result[1]).to eq ['2']
|
483
|
-
nums = (1..1000).map { |n| "#{n}\n" }.join('')
|
484
|
-
expect(result.stdout).to eq "#{nums}out from exec\n"
|
485
|
-
expect(result.stderr).to eq "#{nums}err from exec\n"
|
486
548
|
end
|
487
549
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,12 +2,29 @@ require 'spec_helper'
|
|
2
2
|
require 'seeing_is_believing/wrap_expressions'
|
3
3
|
|
4
4
|
RSpec.describe SeeingIsBelieving::WrapExpressions do
|
5
|
-
def wrap(code)
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
9
13
|
end
|
10
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
|
+
|
11
28
|
it 'raises a SyntaxError if the program is invalid' do
|
12
29
|
expect { wrap '+' }.to raise_error SyntaxError
|
13
30
|
end
|
@@ -17,34 +34,31 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
17
34
|
end
|
18
35
|
|
19
36
|
describe 'wrapping the body' do
|
20
|
-
let(:options) { { before_all: -> { "[".freeze },
|
21
|
-
after_all: -> { "]".freeze },
|
22
|
-
before_each: -> * { '<'.freeze },
|
23
|
-
after_each: -> * { '>'.freeze } } }
|
24
|
-
|
25
37
|
it 'wraps the entire body, ignoring leading comments and the data segment' do
|
26
|
-
expect(
|
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"
|
27
40
|
end
|
28
41
|
|
29
|
-
it '
|
30
|
-
expect(
|
42
|
+
it 'wraps when code is an empty string' do
|
43
|
+
expect(wrap_with_body '').to eq '[]'
|
31
44
|
end
|
32
45
|
|
33
|
-
it '
|
34
|
-
expect(
|
46
|
+
it 'places body before first comment when there are only comments' do
|
47
|
+
expect(wrap_with_body "# abc").to eq "[]# abc"
|
35
48
|
end
|
36
49
|
|
37
|
-
it '
|
38
|
-
expect(
|
50
|
+
it 'places body before trailing comments, but still wraps code' do
|
51
|
+
expect(wrap_with_body "1# abc").to eq "[<1>]# abc"
|
39
52
|
end
|
40
53
|
|
41
54
|
# this changes the number of lines, annoyingly, though it shouldn't mess anything up,
|
42
55
|
# unless you were trying to reopen the file to read it, in which case, *surprise* the whole thing's been rewritten
|
43
56
|
it 'injects a newline if there is a data segment and the after block doesn\'t end in a newline' do
|
44
|
-
expect(
|
45
|
-
expect(
|
46
|
-
expect(
|
47
|
-
expect(
|
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)>]"
|
48
62
|
end
|
49
63
|
|
50
64
|
it 'wraps bodies that are wrapped in parentheses' do
|
@@ -54,35 +68,28 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
54
68
|
|
55
69
|
context 'fucking heredocs' do
|
56
70
|
example 'single heredoc' do
|
57
|
-
expect(
|
71
|
+
expect(heredoc_wrap "<<A\nA").to eq "[{<<A}]\nA"
|
58
72
|
end
|
59
73
|
|
60
74
|
example 'multiple heredocs' do
|
61
|
-
|
62
|
-
# causes the toplevel begin to wrap the whole file.
|
63
|
-
# It's fine b/c it is ultimately the same, but that's why it's
|
64
|
-
# "[<<<<A>\nA\n<<B>]\nB"
|
65
|
-
# instead of
|
66
|
-
# "[<<<A>\nA\n<<<B>]\nB"
|
67
|
-
expect(described_class.call("<<A\nA\n<<B\nB", options)).to eq "[<<<<A>\nA\n<<B>]\nB"
|
75
|
+
expect(heredoc_wrap "<<A\nA\n<<B\nB").to eq "[{<<A}\nA\n{<<B}]\nB"
|
68
76
|
end
|
69
77
|
|
70
78
|
example 'heredocs as targets and arguments to methods' do
|
71
|
-
expect(
|
72
|
-
expect(
|
73
|
-
expect(
|
74
|
-
expect(
|
75
|
-
expect(
|
76
|
-
expect(
|
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"
|
77
85
|
end
|
78
86
|
end
|
79
87
|
|
80
88
|
it 'identifies the last line of the body' do
|
81
|
-
expect(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
options)
|
89
|
+
expect(wrap_with_body "a\n"\
|
90
|
+
"def b\n"\
|
91
|
+
" c = 1\n"\
|
92
|
+
"end"
|
86
93
|
).to eq "[<a>\n"\
|
87
94
|
"<def b\n"\
|
88
95
|
" <c = 1>\n"\
|
@@ -92,7 +99,7 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
92
99
|
|
93
100
|
it 'passes the current line number to the before_each and after_each wrappers' do
|
94
101
|
pre_line_num = post_line_num = nil
|
95
|
-
described_class.call("\na",
|
102
|
+
described_class.call("\na\n",
|
96
103
|
before_each: -> _pre_line_num { pre_line_num = _pre_line_num; '<' },
|
97
104
|
after_each: -> _post_line_num { post_line_num = _post_line_num; '>' }
|
98
105
|
)
|
@@ -101,8 +108,7 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
101
108
|
end
|
102
109
|
|
103
110
|
it 'does nothing for an empty program' do
|
104
|
-
expect(wrap("")).to eq ""
|
105
|
-
expect(wrap("\n")).to eq "\n"
|
111
|
+
expect(wrap("")).to eq "" # note that code will fix the missing newline, and wrap will chomp it from the result for convenience
|
106
112
|
end
|
107
113
|
|
108
114
|
it 'ignores comments' do
|
@@ -112,79 +118,6 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
112
118
|
expect(wrap "=begin\n1\n=end\n2").to eq "=begin\n1\n=end\n<2>"
|
113
119
|
end
|
114
120
|
|
115
|
-
describe 'void value expressions' do
|
116
|
-
def void_value?(ast)
|
117
|
-
klass = described_class.new '', {}
|
118
|
-
klass.__send__(:void_value?, ast)
|
119
|
-
end
|
120
|
-
|
121
|
-
def ast_for(code)
|
122
|
-
Parser::CurrentRuby.parse code
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'knows a `return`, `next`, `redo`, `retry`, and `break` are void values' do
|
126
|
-
expect(void_value?(ast_for("def a; return; end").children.last)).to be true
|
127
|
-
expect(void_value?(ast_for("loop { next }" ).children.last)).to be true
|
128
|
-
expect(void_value?(ast_for("loop { redo }" ).children.last)).to be true
|
129
|
-
expect(void_value?(ast_for("loop { break }" ).children.last)).to be true
|
130
|
-
|
131
|
-
the_retry = ast_for("begin; rescue; retry; end").children.first.children[1].children.last
|
132
|
-
expect(the_retry.type).to eq :retry
|
133
|
-
expect(void_value? the_retry).to eq true
|
134
|
-
end
|
135
|
-
it 'knows an `if` is a void value if either side is a void value' do
|
136
|
-
the_if = ast_for("def a; if 1; return 2; else; 3; end; end").children.last
|
137
|
-
expect(the_if.type).to eq :if
|
138
|
-
expect(void_value?(the_if)).to be true
|
139
|
-
|
140
|
-
the_if = ast_for("def a; if 1; 2; else; return 3; end; end").children.last
|
141
|
-
expect(the_if.type).to eq :if
|
142
|
-
expect(void_value?(the_if)).to be true
|
143
|
-
|
144
|
-
the_if = ast_for("def a; if 1; 2; else; 3; end; end").children.last
|
145
|
-
expect(the_if.type).to eq :if
|
146
|
-
expect(void_value?(the_if)).to be false
|
147
|
-
end
|
148
|
-
it 'knows a begin is a void value if its last element is a void value' do
|
149
|
-
the_begin = ast_for("loop { begin; break; end }").children.last
|
150
|
-
expect([:begin, :kwbegin]).to include the_begin.type
|
151
|
-
expect(void_value?(the_begin)).to be true
|
152
|
-
|
153
|
-
the_begin = ast_for("loop { begin; 1; end }").children.last
|
154
|
-
expect([:begin, :kwbegin]).to include the_begin.type
|
155
|
-
expect(void_value?(the_begin)).to be false
|
156
|
-
end
|
157
|
-
it 'knows a rescue is a void value if its last child or its else is a void value' do
|
158
|
-
the_rescue = ast_for("begin; rescue; retry; end").children.first
|
159
|
-
expect(the_rescue.type).to eq :rescue
|
160
|
-
expect(void_value?(the_rescue)).to be true
|
161
|
-
|
162
|
-
the_rescue = ast_for("begin; rescue; 1; else; retry; end").children.first
|
163
|
-
expect(the_rescue.type).to eq :rescue
|
164
|
-
expect(void_value?(the_rescue)).to be true
|
165
|
-
|
166
|
-
the_rescue = ast_for("begin; rescue; 1; else; 2; end").children.first
|
167
|
-
expect(the_rescue.type).to eq :rescue
|
168
|
-
expect(void_value?(the_rescue)).to be false
|
169
|
-
end
|
170
|
-
it 'knows an ensure is a void value if its body or ensure portion are void values' do
|
171
|
-
the_ensure = ast_for("loop { begin; break; ensure; 1; end }").children.last.children.last
|
172
|
-
expect(the_ensure.type).to eq :ensure
|
173
|
-
expect(void_value?(the_ensure)).to be true
|
174
|
-
|
175
|
-
the_ensure = ast_for("loop { begin; 1; ensure; break; end }").children.last.children.last
|
176
|
-
expect(the_ensure.type).to eq :ensure
|
177
|
-
expect(void_value?(the_ensure)).to be true
|
178
|
-
|
179
|
-
the_ensure = ast_for("loop { begin; 1; ensure; 2; end }").children.last.children.last
|
180
|
-
expect(the_ensure.type).to eq :ensure
|
181
|
-
expect(void_value?(the_ensure)).to be false
|
182
|
-
end
|
183
|
-
it 'knows other things are not void values' do
|
184
|
-
expect(void_value?(ast_for "123")).to be false
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
121
|
describe 'basic expressions' do
|
189
122
|
it 'wraps an expression' do
|
190
123
|
expect(wrap("A")).to eq "<A>"
|
@@ -200,6 +133,10 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
200
133
|
it 'does not wrap multiple expressions when they constitute a void value' do
|
201
134
|
expect(wrap("def a\n1\nreturn 2\nend")).to eq "<def a\n<1>\nreturn <2>\nend>"
|
202
135
|
expect(wrap("def a\nreturn 1\n2\nend")).to eq "<def a\nreturn <1>\n<2>\nend>"
|
136
|
+
# BUG, but I'm skipping it, b/c it's borderline invalid.
|
137
|
+
# To the point that Parser doesn't even emit the else clause in the AST
|
138
|
+
# And Ruby will warn you that it's useless
|
139
|
+
# expect(wrap("begin\n1\nelse\nbreak\nend")).to eq "begin\n<1>\nelse\nbreak\nend"
|
203
140
|
end
|
204
141
|
|
205
142
|
it 'wraps nested expressions' do
|
@@ -212,9 +149,6 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
212
149
|
|
213
150
|
# many of these taken from http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Literals
|
214
151
|
it 'wraps simple literals' do
|
215
|
-
# should maybe also do %i[] and %I[] for symbols,
|
216
|
-
# but that's only Ruby 2.0, so I'm ignoring it for now
|
217
|
-
# (I expect it to handle them just fine)
|
218
152
|
%w|123
|
219
153
|
-123
|
220
154
|
1_123
|
@@ -236,6 +170,7 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
236
170
|
1...2
|
237
171
|
|
238
172
|
(true==true)..(1==2)
|
173
|
+
(true==true)...(1==2)
|
239
174
|
|
240
175
|
true
|
241
176
|
false
|
@@ -268,16 +203,16 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
268
203
|
end
|
269
204
|
|
270
205
|
it 'wraps macros' do
|
271
|
-
# should this actually replace __FILE__ and __LINE__ so as to avoid fucking up values with the rewrite?
|
272
|
-
# there is also __dir__, but it's only 2.0
|
273
206
|
expect(wrap("__FILE__")).to eq "<__FILE__>"
|
274
207
|
expect(wrap("__LINE__")).to eq "<__LINE__>"
|
208
|
+
expect(wrap("__ENCODING__")).to eq "<__ENCODING__>"
|
275
209
|
expect(wrap("defined? a")).to eq "<defined? a>"
|
276
210
|
end
|
277
211
|
|
278
212
|
it 'does not wrap alias, undef' do
|
279
213
|
expect(wrap("alias tos to_s")).to eq "alias tos to_s"
|
280
214
|
expect(wrap("undef tos")).to eq "undef tos"
|
215
|
+
expect(wrap("alias $a $b")).to eq "alias $a $b"
|
281
216
|
end
|
282
217
|
|
283
218
|
it 'wraps syscalls, but not code interpolated into them' do
|
@@ -290,6 +225,7 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
290
225
|
it 'wraps them' do
|
291
226
|
expect(wrap('a')).to eq "<a>"
|
292
227
|
expect(wrap("$a")).to eq "<$a>"
|
228
|
+
expect(wrap("$1")).to eq "<$1>"
|
293
229
|
expect(wrap("@a")).to eq "<@a>"
|
294
230
|
expect(wrap("@@a")).to eq "<@@a>"
|
295
231
|
end
|
@@ -311,6 +247,8 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
311
247
|
expect(wrap("a { }")).to eq "<a { }>"
|
312
248
|
expect(wrap("a {\n}")).to eq "<a {\n}>"
|
313
249
|
expect(wrap("a(b) {\n}")).to eq "<a(b) {\n}>"
|
250
|
+
expect(wrap("a(&b\n)")).to eq "<a(&<b>\n)>"
|
251
|
+
expect(wrap("a(&lambda { }\n)")).to eq "<a(&<lambda { }>\n)>"
|
314
252
|
end
|
315
253
|
|
316
254
|
it 'wraps method calls with an explicit receiver' do
|
@@ -345,9 +283,9 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
345
283
|
expect(wrap("a 1,\n2")).to eq "<a <1>,\n2>"
|
346
284
|
end
|
347
285
|
|
348
|
-
it 'does
|
349
|
-
expect(wrap("a(\n*a\n)")).to eq "<a(\n
|
350
|
-
expect(wrap("a(\n*1..2\n)")).to eq "<a(\n
|
286
|
+
it 'does wraps splat args' do
|
287
|
+
expect(wrap("a(\n*a\n)")).to eq "<a(\n*<a>\n)>"
|
288
|
+
expect(wrap("a(\n*1..2\n)")).to eq "<a(\n*<1..2>\n)>"
|
351
289
|
end
|
352
290
|
|
353
291
|
it 'does not wrap hash args' do
|
@@ -407,11 +345,13 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
407
345
|
expect(wrap("a -= 1")).to eq "<a -= 1>"
|
408
346
|
expect(wrap("a /= 1")).to eq "<a /= 1>"
|
409
347
|
expect(wrap("a **= 1")).to eq "<a **= 1>"
|
348
|
+
expect(wrap("a != 1")).to eq "<a != 1>"
|
410
349
|
expect(wrap("a |= 1")).to eq "<a |= 1>"
|
411
350
|
expect(wrap("a &= 1")).to eq "<a &= 1>"
|
412
351
|
expect(wrap("a ||= 1")).to eq "<a ||= 1>"
|
413
352
|
expect(wrap("a &&= 1")).to eq "<a &&= 1>"
|
414
353
|
expect(wrap("a[1] = 2")).to eq "<a[1] = 2>"
|
354
|
+
expect(wrap("a[1,2] = 3")).to eq "<a[1,2] = 3>"
|
415
355
|
expect(wrap("a[1] ||= 2")).to eq "<a[1] ||= 2>"
|
416
356
|
expect(wrap("@a ||= 123")).to eq "<@a ||= 123>"
|
417
357
|
expect(wrap("$a ||= 123")).to eq "<$a ||= 123>"
|
@@ -444,6 +384,7 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
444
384
|
expect(wrap("a,@b={\n},{\n}")).to eq "<a,@b=<{\n}>,{\n}>"
|
445
385
|
expect(wrap("a,@@b={\n},{\n}")).to eq "<a,@@b=<{\n}>,{\n}>"
|
446
386
|
expect(wrap("a,$b={\n},{\n}")).to eq "<a,$b=<{\n}>,{\n}>"
|
387
|
+
expect(wrap("a,$b={\n},{\n}")).to eq "<a,$b=<{\n}>,{\n}>"
|
447
388
|
|
448
389
|
# repeated assignments
|
449
390
|
expect(wrap("a=\nb={\n}")).to eq "<a=\nb={\n}>"
|
@@ -502,8 +443,9 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
502
443
|
expect(wrap("1 if 2")).to eq "<1 if 2>"
|
503
444
|
end
|
504
445
|
|
505
|
-
it '
|
506
|
-
expect(wrap("if /a/\n1\nend")).to eq "<if
|
446
|
+
it 'wraps implicit regexes, retaining their magic behaviour by prepending a ~' do
|
447
|
+
expect(wrap("if /a/\n1\nend")).to eq "<if <~/a/>\n<1>\nend>"
|
448
|
+
expect(wrap("/a/ &&\n1")).to eq "<</a/> &&\n1>"
|
507
449
|
end
|
508
450
|
|
509
451
|
it 'wraps ternaries' do
|
@@ -545,6 +487,8 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
545
487
|
# not sure if I actually want this, or if it's just easier b/c it falls out of the current implementation
|
546
488
|
it 'wraps the conditional from an inline if, when it cannot wrap the entire if' do
|
547
489
|
expect(wrap("def a\nreturn if 1\nend")).to eq "<def a\nreturn if <1>\nend>"
|
490
|
+
# could maybe do this:
|
491
|
+
# `return 1 if b` -> `return <1> if (b) || <nil>`
|
548
492
|
end
|
549
493
|
|
550
494
|
it 'does not wrap &&, and, ||, or, not' do
|
@@ -567,15 +511,15 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
567
511
|
expect(wrap("while 1\n2\nend")).to eq "<while <1>\n<2>\nend>"
|
568
512
|
expect(wrap("1 while 2")).to eq "<1 while 2>"
|
569
513
|
expect(wrap("begin\n1\nend while true")).to eq "<begin\n<1>\nend while true>"
|
514
|
+
expect(wrap("begin\n1\nend until true")).to eq "<begin\n<1>\nend until true>"
|
570
515
|
end
|
571
516
|
it 'wraps for/in loops collections and bodies' do
|
572
517
|
expect(wrap("for a in range;1;end")).to eq "<for a in range;1;end>"
|
573
518
|
expect(wrap("for a in range\n1\nend")).to eq "<for a in <range>\n<1>\nend>"
|
574
519
|
expect(wrap("for a in range do\n1\nend")).to eq "<for a in <range> do\n<1>\nend>"
|
575
520
|
expect(wrap("for a,b in whatev\n1\nend")).to eq "<for a,b in <whatev>\n<1>\nend>"
|
576
|
-
|
577
|
-
|
578
|
-
# "<for char in <<<HERE.each_char>\nabc\nHERE\n<puts char>\nend>"
|
521
|
+
expect(wrap("for char in <<HERE.each_char\nabc\nHERE\nputs char\nend"))
|
522
|
+
.to eq "<for char in <<<HERE.each_char>\nabc\nHERE\n<puts char>\nend>"
|
579
523
|
end
|
580
524
|
it 'does not wrap redo' do
|
581
525
|
expect(wrap("loop do\nredo\nend")).to eq "<loop do\nredo\nend>"
|
@@ -596,6 +540,7 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
596
540
|
it 'wraps namespaced constant access' do
|
597
541
|
expect(wrap("::A")).to eq "<::A>"
|
598
542
|
expect(wrap("A::B")).to eq "<A::B>"
|
543
|
+
expect(wrap("a::B")).to eq "<a::B>"
|
599
544
|
end
|
600
545
|
end
|
601
546
|
|
@@ -618,8 +563,8 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
618
563
|
expect(wrap("%w[\n1\n]")).to eq "<%w[\n1\n]>"
|
619
564
|
end
|
620
565
|
|
621
|
-
it 'does
|
622
|
-
expect(wrap("[1,\n*2..3,\n4\n]")).to eq "<[<1>,\n
|
566
|
+
it 'does wraps splat elements' do
|
567
|
+
expect(wrap("[1,\n*2..3,\n4\n]")).to eq "<[<1>,\n*<2..3>,\n<4>\n]>"
|
623
568
|
end
|
624
569
|
end
|
625
570
|
|
@@ -683,45 +628,46 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
683
628
|
end
|
684
629
|
|
685
630
|
it 'wraps heredocs with call defined on them (edge cases on edge cases *sigh*)' do
|
686
|
-
expect(
|
631
|
+
expect(heredoc_wrap "<<HERE.()\na\nHERE")
|
632
|
+
.to eq "[{<<HERE.()}]\na\nHERE"
|
687
633
|
end
|
688
634
|
end
|
689
635
|
|
690
636
|
describe 'heredocs' do
|
691
637
|
it 'wraps heredocs on their first line' do
|
692
|
-
expect(
|
693
|
-
expect(
|
694
|
-
expect(
|
695
|
-
expect(
|
696
|
-
expect(
|
697
|
-
expect(
|
698
|
-
expect(
|
699
|
-
expect(
|
638
|
+
expect(heredoc_wrap "<<A\nA").to eq "[{<<A}]\nA"
|
639
|
+
expect(heredoc_wrap "<<A\n123\nA").to eq "[{<<A}]\n123\nA"
|
640
|
+
expect(heredoc_wrap "<<-A\nA").to eq "[{<<-A}]\nA"
|
641
|
+
expect(heredoc_wrap "<<-A\n123\nA").to eq "[{<<-A}]\n123\nA"
|
642
|
+
expect(heredoc_wrap "1\n<<A\nA").to eq "[{1}\n{<<A}]\nA"
|
643
|
+
expect(heredoc_wrap "<<A + <<B\n1\nA\n2\nB").to eq "[{<<A + <<B}]\n1\nA\n2\nB"
|
644
|
+
expect(heredoc_wrap "<<A\n1\nA\n<<B\n2\nB").to eq "[{<<A}\n1\nA\n{<<B}]\n2\nB"
|
645
|
+
expect(heredoc_wrap "puts <<A\nA\nputs <<B\nB").to eq "[{puts <<A}\nA\n{puts <<B}]\nB"
|
700
646
|
end
|
701
647
|
|
702
648
|
it "wraps methods that wrap heredocs, even whent hey don't have parentheses" do
|
703
|
-
expect(
|
704
|
-
expect(
|
705
|
-
expect(
|
706
|
-
expect(
|
707
|
-
"
|
708
|
-
expect(
|
649
|
+
expect(heredoc_wrap "a(<<HERE)\nHERE").to eq "[{a(<<HERE)}]\nHERE"
|
650
|
+
expect(heredoc_wrap "a <<HERE\nHERE").to eq "[{a <<HERE}]\nHERE"
|
651
|
+
expect(heredoc_wrap "a 1, <<HERE\nHERE").to eq "[{a 1, <<HERE}]\nHERE"
|
652
|
+
expect(heredoc_wrap "a.b 1, 2, <<HERE1, <<-HERE2 \nHERE1\n HERE2").to eq\
|
653
|
+
"[{a.b 1, 2, <<HERE1, <<-HERE2}] \nHERE1\n HERE2"
|
654
|
+
expect(heredoc_wrap "a.b 1,\n2,\n<<HERE\nHERE").to eq "[{a.b {1},\n{2},\n<<HERE}]\nHERE"
|
709
655
|
end
|
710
656
|
|
711
657
|
it "wraps assignments whose value is a heredoc" do
|
712
|
-
expect(
|
713
|
-
expect(
|
714
|
-
expect(
|
715
|
-
expect(
|
658
|
+
expect(heredoc_wrap "a=<<A\nA").to eq "[{a=<<A}]\nA"
|
659
|
+
expect(heredoc_wrap "a,b=<<A,<<B\nA\nB").to eq "[{a,b=<<A,<<B}]\nA\nB"
|
660
|
+
expect(heredoc_wrap "a,b=1,<<B\nB").to eq "[{a,b=1,<<B}]\nB"
|
661
|
+
expect(heredoc_wrap "a,b=<<A,1\nA").to eq "[{a,b=<<A,1}]\nA"
|
716
662
|
end
|
717
663
|
|
718
664
|
it 'wraps methods tacked onto the end of heredocs' do
|
719
|
-
expect(
|
720
|
-
expect(
|
721
|
-
expect(
|
722
|
-
expect(
|
723
|
-
expect(
|
724
|
-
expect(
|
665
|
+
expect(heredoc_wrap "<<A.size\nA").to eq "[{<<A.size}]\nA"
|
666
|
+
expect(heredoc_wrap "<<A.size 1\nA").to eq "[{<<A.size 1}]\nA"
|
667
|
+
expect(heredoc_wrap "<<A.size(1)\nA").to eq "[{<<A.size(1)}]\nA"
|
668
|
+
expect(heredoc_wrap "<<A.whatever <<B\nA\nB").to eq "[{<<A.whatever <<B}]\nA\nB"
|
669
|
+
expect(heredoc_wrap "<<A.whatever(<<B)\nA\nB").to eq "[{<<A.whatever(<<B)}]\nA\nB"
|
670
|
+
expect(heredoc_wrap "<<A.size()\nA").to eq "[{<<A.size()}]\nA"
|
725
671
|
end
|
726
672
|
end
|
727
673
|
|
@@ -760,36 +706,30 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
760
706
|
end
|
761
707
|
end
|
762
708
|
|
763
|
-
# eventually, don't wrap these b/c they're spammy, but can be annoying since they can be accidentally wraped
|
764
|
-
# by e.g. a begin/end
|
765
|
-
# ignoring public/private/protected for now, b/c they're just methods, not keywords
|
766
709
|
describe 'class definitions' do
|
767
710
|
it 'does not wrap the class definition, does wrap the body' do
|
768
|
-
expect(wrap("class A\n1\nend")).to eq "class A\n<1>\nend"
|
711
|
+
expect(wrap("class A\n1\nend")).to eq "<class A\n<1>\nend>"
|
769
712
|
end
|
770
713
|
|
771
714
|
it 'does not wrap the superclass definition' do
|
772
|
-
expect(wrap("class A < B\nend")).to eq "class A < B
|
715
|
+
expect(wrap("class A < B\nend")).to eq "<class A < <B>\nend>"
|
773
716
|
end
|
774
717
|
|
775
718
|
it 'wraps the rescue body' do
|
776
|
-
expect(wrap("class A < B\n1\nrescue\n2\nend")).to eq "class A < B
|
719
|
+
expect(wrap("class A < B\n1\nrescue\n2\nend")).to eq "<class A < <B>\n<1>\nrescue\n<2>\nend>"
|
777
720
|
end
|
778
721
|
|
779
722
|
it 'does not wrap the singleton class' do
|
780
|
-
expect(wrap("class << self\n end")).to eq "class << self
|
723
|
+
expect(wrap("class << self\n end")).to eq "<class << <self>\n end>"
|
781
724
|
end
|
782
725
|
end
|
783
726
|
|
784
|
-
# eventually, don't wrap these b/c they're spammy, but can be annoying since they can be accidentally wraped
|
785
|
-
# by e.g. a begin/end
|
786
|
-
# ignoring public/private/protected for now, b/c they're just methods, not keywords
|
787
727
|
describe 'module definitions' do
|
788
728
|
it 'does not wrap the definition, does wrap the body' do
|
789
|
-
expect(wrap("module A\n1\nend")).to eq "module A\n<1>\nend"
|
729
|
+
expect(wrap("module A\n1\nend")).to eq "<module A\n<1>\nend>"
|
790
730
|
end
|
791
731
|
it 'wraps the rescue portion' do
|
792
|
-
expect(wrap("module A\n1\nrescue\n2\nend")).to eq "module A\n<1>\nrescue\n<2>\nend"
|
732
|
+
expect(wrap("module A\n1\nrescue\n2\nend")).to eq "<module A\n<1>\nrescue\n<2>\nend>"
|
793
733
|
end
|
794
734
|
end
|
795
735
|
|
@@ -812,11 +752,15 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
812
752
|
|
813
753
|
it 'wraps calls to yield' do
|
814
754
|
expect(wrap("def a\nyield\nend")).to eq "<def a\n<yield>\nend>"
|
755
|
+
expect(wrap("def a\nyield 1\nend")).to eq "<def a\n<yield 1>\nend>"
|
756
|
+
expect(wrap("def a\nyield(\n1\n)\nend")).to eq "<def a\n<yield(\n<1>\n)>\nend>"
|
815
757
|
end
|
816
758
|
|
817
759
|
it 'wraps calls to super' do
|
818
760
|
expect(wrap("def a\nsuper\nend")).to eq "<def a\n<super>\nend>"
|
819
761
|
expect(wrap("def a\nsuper 1\nend")).to eq "<def a\n<super 1>\nend>"
|
762
|
+
expect(wrap("def a\nsuper(1)\nend")).to eq "<def a\n<super(1)>\nend>"
|
763
|
+
expect(wrap("def a\nsuper(\n1\n)\nend")).to eq "<def a\n<super(\n<1>\n)>\nend>"
|
820
764
|
end
|
821
765
|
|
822
766
|
it 'wraps the bodies of returns' do
|
@@ -828,11 +772,17 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
828
772
|
expect(wrap("def a\n1\nrescue\n2\nensure\n3\nend")).to eq "<def a\n<1>\nrescue\n<2>\nensure\n<3>\nend>"
|
829
773
|
expect(wrap("def a\n1\nensure\n2\nend")).to eq "<def a\n<1>\nensure\n<2>\nend>"
|
830
774
|
end
|
775
|
+
|
776
|
+
it 'wrap a definition as a call to an invocation' do
|
777
|
+
expect(wrap("a def b\nc\nend,\nd")).to eq "<a <def b\n<c>\nend>,\nd>"
|
778
|
+
end
|
831
779
|
end
|
832
780
|
|
833
781
|
describe 'lambdas' do
|
834
782
|
it 'wraps the lambda' do
|
835
783
|
expect(wrap("lambda { }")).to eq "<lambda { }>"
|
784
|
+
expect(wrap("lambda { |;a| }")).to eq "<lambda { |;a| }>"
|
785
|
+
expect(wrap("lambda { |a,b=1,*c,&d| }")).to eq "<lambda { |a,b=1,*c,&d| }>"
|
836
786
|
expect(wrap("-> { }")).to eq "<-> { }>"
|
837
787
|
expect(wrap("-> a, b { }")).to eq "<-> a, b { }>"
|
838
788
|
expect(wrap("-> {\n1\n}")).to eq "<-> {\n<1>\n}>"
|
@@ -865,15 +815,100 @@ RSpec.describe SeeingIsBelieving::WrapExpressions do
|
|
865
815
|
# <2>
|
866
816
|
# <3>]
|
867
817
|
#
|
868
|
-
#
|
869
|
-
#
|
870
|
-
#
|
871
|
-
|
872
|
-
|
818
|
+
# Because not iw matters why you want to wrap it. Are you doing this because you want
|
819
|
+
# to catch an exception? then maybe your wrapping code needs to go around the inside of each begin block
|
820
|
+
# or maybe the begin blocks need to get consolidated into a single begin block.
|
821
|
+
# or maybe removed from the begin block and just stuck as normal fkn code at the top of the file?
|
822
|
+
# but we do need to rewrite __LINE__ expressions now, because they are changing.
|
823
|
+
# which... maybe that's fine.
|
824
|
+
#
|
825
|
+
# Or, you might just be interested in having your code execute first. In which case,
|
826
|
+
# it doesn't need to wrap the body, it just needs its own BEGIN block.
|
827
|
+
#
|
828
|
+
# note that there are also things line nested BEGINs and nested ENDs
|
829
|
+
# but you can't nest a BEGIN inside an END.
|
830
|
+
it 'does not record them' do
|
873
831
|
expect(wrap("BEGIN {}")).to eq "BEGIN {}"
|
874
832
|
expect(wrap("END {}")).to eq "END {}"
|
875
833
|
expect(wrap("BEGIN {\n123\n}")).to eq "BEGIN {\n<123>\n}"
|
876
834
|
expect(wrap("END {\n123\n}")).to eq "END {\n<123>\n}"
|
877
835
|
end
|
836
|
+
|
837
|
+
it 'moves them out of the body', not_implemented: true do
|
838
|
+
expect(wrap_with_body(<<-HERE)).to eq(<<-THERE)
|
839
|
+
# encoding: utf-8
|
840
|
+
p [1, __LINE__]
|
841
|
+
BEGIN {
|
842
|
+
p [2, __LINE__]
|
843
|
+
}
|
844
|
+
p [3, __LINE__]
|
845
|
+
END {
|
846
|
+
p [4, __LINE__]
|
847
|
+
}
|
848
|
+
p [5, __LINE__]
|
849
|
+
BEGIN { p [6, __LINE__] }
|
850
|
+
END { p [7, __LINE__] }
|
851
|
+
p [8, __LINE__]
|
852
|
+
HERE
|
853
|
+
# encoding: utf-8
|
854
|
+
BEGIN {
|
855
|
+
<p [2, 4]>
|
856
|
+
}
|
857
|
+
BEGIN { <p [6, 11]> }
|
858
|
+
[<p [1, 2]>
|
859
|
+
<p [3, 6]>
|
860
|
+
<p [5, 10]>
|
861
|
+
<p [8, 13]>]
|
862
|
+
END {
|
863
|
+
<p [4, 8]>
|
864
|
+
}
|
865
|
+
END { <p [7, 12]> }
|
866
|
+
THERE
|
867
|
+
end
|
868
|
+
end
|
869
|
+
|
870
|
+
# only checking on 2.2 b/c its hard to figure out when different pieces were introduced
|
871
|
+
# 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
|
872
|
+
major, minor, * = RUBY_VERSION.split(".").map(&:to_i)
|
873
|
+
if major > 2 || (major == 2 && minor >= 2)
|
874
|
+
describe 'Ruby 2 syntaxes', :'2.x' => true do
|
875
|
+
it 'respects __dir__ macro' do
|
876
|
+
expect(wrap('__dir__')).to eq '<__dir__>'
|
877
|
+
end
|
878
|
+
|
879
|
+
it 'does not wrap keyword/keywordrest arguments' do
|
880
|
+
expect(wrap("def a(b,c=1,*d,e:,f:1,**g, &h)\n1\nend"))
|
881
|
+
.to eq "<def a(b,c=1,*d,e:,f:1,**g, &h)\n<1>\nend>"
|
882
|
+
expect(wrap("def a b:\n1\nend")).to eq "<def a b:\n<1>\nend>"
|
883
|
+
expect(wrap("def a b:\nreturn 1\nend")).to eq "<def a b:\nreturn <1>\nend>"
|
884
|
+
expect(wrap("def a b:\nreturn\nend")).to eq "<def a b:\nreturn\nend>"
|
885
|
+
expect(wrap("a b:1, **c")).to eq "<a b:1, **c>"
|
886
|
+
expect(wrap("{\na:1,\n**b\n}")).to eq "<{\na:<1>,\n**<b>\n}>"
|
887
|
+
expect(wrap("a(b:1,\n **c\n)")).to eq "<a(b:<1>,\n **<c>\n)>"
|
888
|
+
pending 'Fixed this in Parser, but it\'s not released yet https://github.com/whitequark/parser/commit/aeb95c776d11e212ed95b92c69e96d1cccdb6424'
|
889
|
+
expect(wrap("def a(*, **)\n1\nend")).to eq "<def a(*, **)\n<1>\nend>"
|
890
|
+
end
|
891
|
+
|
892
|
+
it 'tags javascript style hashes' do
|
893
|
+
expect(wrap(%[{\na:1,\n'b':2,\n"c":3\n}])).to eq %[<{\na:<1>,\n'b':<2>,\n"c":<3>\n}>]
|
894
|
+
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>]
|
895
|
+
end
|
896
|
+
|
897
|
+
it 'wraps symbol literals' do
|
898
|
+
expect(wrap("%i[abc]")).to eq "<%i[abc]>"
|
899
|
+
expect(wrap("%I[abc]")).to eq "<%I[abc]>"
|
900
|
+
expect(wrap("%I[a\nb\nc]")).to eq "<%I[a\nb\nc]>"
|
901
|
+
end
|
902
|
+
|
903
|
+
it 'wraps complex and rational' do
|
904
|
+
expect(wrap("1i")).to eq "<1i>"
|
905
|
+
expect(wrap("5+1i")).to eq "<5+1i>"
|
906
|
+
expect(wrap("1r")).to eq "<1r>"
|
907
|
+
expect(wrap("1.5r")).to eq "<1.5r>"
|
908
|
+
expect(wrap("1/2r")).to eq "<1/2r>"
|
909
|
+
expect(wrap("2/1r")).to eq "<2/1r>"
|
910
|
+
expect(wrap("1ri")).to eq "<1ri>"
|
911
|
+
end
|
912
|
+
end
|
878
913
|
end
|
879
914
|
end
|