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,102 @@
1
+ require_relative '../../lib/seeing_is_believing/version'
2
+
3
+ require 'haiti'
4
+ # A lot of the stuff in this file should get moved into haiti
5
+
6
+ module Haiti
7
+ module CommandLineHelpers
8
+ # overwriting this method while trying to get windows support working,
9
+ # it looks like the underlying shell is treating the commands differently
10
+ # probably on Unix it invoked `sh` and did shady shit with splitting a string into an array on whitespace
11
+ # and on Windows (powershell?) it expected an actual array of strings
12
+ require 'shellwords'
13
+ def execute(command_string, stdin_data, env_vars)
14
+ stdin_data ||= ''
15
+ env_vars ||= {}
16
+ in_proving_grounds do
17
+ with_bin_in_path do
18
+ Invocation.new *Open3.capture3(env_vars, command_string, stdin_data: stdin_data)
19
+ end
20
+ end
21
+ end
22
+
23
+ def execute_pipeline(command_strings, stdin_data, env_vars)
24
+ stdin_data ||= ''
25
+ env_vars ||= {}
26
+ in_proving_grounds do
27
+ with_bin_in_path do
28
+ ioin, ioout, pids = Open3.pipeline_rw *command_strings.map { |cmd| [env_vars, cmd] }
29
+ ioin.print stdin_data
30
+ ioin.close
31
+ stderr = "" # uh... how do I record it for real?
32
+ Invocation.new ioout.read, stderr, pids.last.value
33
+ end
34
+ end
35
+ end
36
+
37
+ def with_bin_in_path
38
+ original_path = ENV['PATH']
39
+ dirs = ENV["PATH"].split(File::PATH_SEPARATOR)
40
+ ENV['PATH'] = [config.bin_dir, *dirs].join(File::PATH_SEPARATOR)
41
+ yield
42
+ ensure
43
+ ENV['PATH'] = original_path
44
+ end
45
+ end
46
+ end
47
+
48
+ module SiBHelpers
49
+ def method_result(name)
50
+ @result = def __some_method__; end
51
+ if :__some_method__ == @result
52
+ name.inspect
53
+ elsif nil == @result
54
+ nil.inspect
55
+ else
56
+ raise "huh? #{@result.inspect}"
57
+ end
58
+ end
59
+ end
60
+
61
+ World SiBHelpers
62
+
63
+ Haiti.configure do |config|
64
+ lib_root = File.join __dir__, '..', '..'
65
+ config.proving_grounds_dir = File.expand_path 'proving_grounds', lib_root
66
+ config.bin_dir = File.expand_path 'bin', lib_root
67
+ end
68
+
69
+
70
+ Then 'stdout is exactly:' do |code|
71
+ expect(@last_executed.stdout).to eq eval_curlies(code)
72
+ end
73
+
74
+ Then 'stdout is exactly "$code"' do |code|
75
+ expect(@last_executed.stdout).to eq eval_curlies(code)
76
+ end
77
+
78
+ Then 'stdout is the JSON:' do |json|
79
+ require 'json'
80
+ expected = JSON.parse(json)
81
+ actual = JSON.parse(@last_executed.stdout)
82
+ expect(actual).to eq expected
83
+ end
84
+
85
+ Given %q(the file '$filename' '$body') do |filename, body|
86
+ Haiti::CommandLineHelpers.write_file filename, eval_curlies(body)
87
+ end
88
+
89
+ Given /^I run the pipeline "([^"]*)"(?: *\| *"([^"]*)")*$/ do |*commands|
90
+ @last_executed = Haiti::CommandLineHelpers.execute_pipeline(
91
+ commands,
92
+ @stdin_data,
93
+ @env_vars_to_set
94
+ )
95
+ end
96
+
97
+ Given(/^the binary file "([^"]*)" "([^"]*)"$/) do |filename, body|
98
+ Haiti::CommandLineHelpers.in_proving_grounds do
99
+ FileUtils.mkdir_p File.dirname filename
100
+ File.open(filename, 'wb') { |file| file.write body }
101
+ end
102
+ end
@@ -0,0 +1,471 @@
1
+ @xmpfilter
2
+ Feature: Xmpfilter style
3
+ Support the same (or highly similar) interface as xmpfilter,
4
+ so that people who use that lib can easily transition to SiB.
5
+
6
+ Scenario: --xmpfilter-style Generic updating of marked lines
7
+ Given the file "magic_comments.rb":
8
+ """
9
+ 1+1# =>
10
+ 2+2 # => 10
11
+ "a
12
+ b" # =>
13
+ /a
14
+ b/ # =>
15
+ 1
16
+ "omg"
17
+ # =>
18
+ "omg2"
19
+ # => "not omg2"
20
+ 3+3#=>
21
+ """
22
+ When I run "seeing_is_believing --xmpfilter-style magic_comments.rb"
23
+ Then stderr is empty
24
+ And the exit status is 0
25
+ And stdout is:
26
+ """
27
+ 1+1# => 2
28
+ 2+2 # => 4
29
+ "a
30
+ b" # => "a\n b"
31
+ /a
32
+ b/ # => /a\n b/
33
+ 1
34
+ "omg"
35
+ # => "omg"
36
+ "omg2"
37
+ # => "omg2"
38
+ 3+3# => 6
39
+ """
40
+
41
+
42
+ Scenario: --xmpfilter-style uses pp to inspect annotations whose value comes from the previous line (#44)
43
+ Given the file "xmpfilter-prev-line1.rb":
44
+ """
45
+ { foo: 42,
46
+ bar: {
47
+ baz: 1,
48
+ buz: 2,
49
+ fuz: 3,
50
+ },
51
+ wibble: {
52
+ magic_word: "xyzzy",
53
+ }
54
+ } # =>
55
+ # =>
56
+ """
57
+ When I run "seeing_is_believing --xmpfilter-style xmpfilter-prev-line1.rb"
58
+ Then stdout is:
59
+ """
60
+ { foo: 42,
61
+ bar: {
62
+ baz: 1,
63
+ buz: 2,
64
+ fuz: 3,
65
+ },
66
+ wibble: {
67
+ magic_word: "xyzzy",
68
+ }
69
+ } # => {:foo=>42, :bar=>{:baz=>1, :buz=>2, :fuz=>3}, :wibble=>{:magic_word=>"xyzzy"}}
70
+ # => {:foo=>42,
71
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
72
+ # :wibble=>{:magic_word=>"xyzzy"}}
73
+ """
74
+
75
+ @not-2.3
76
+ Scenario: --xmpfilter-style, when displayed on the next line, prints the string across multiple lines
77
+ Given the file "xmpfilter-prev-line-is-multiline-string.rb":
78
+ """
79
+ "0123456789\nabcdefghij\n0123456789\n0123456789\n0123456789\n0123456789\n" # =>
80
+ # =>
81
+ """
82
+ When I run "seeing_is_believing --xmpfilter-style xmpfilter-prev-line-is-multiline-string.rb"
83
+ Then stdout is:
84
+ """
85
+ "0123456789\nabcdefghij\n0123456789\n0123456789\n0123456789\n0123456789\n" # => "0123456789\nabcdefghij\n0123456789\n0123456789\n0123456789\n0123456789\n"
86
+ # => "0123456789\n" +
87
+ # "abcdefghij\n" +
88
+ # "0123456789\n" +
89
+ # "0123456789\n" +
90
+ # "0123456789\n" +
91
+ # "0123456789\n"
92
+ """
93
+
94
+
95
+ Scenario: --xmpfilter-style overrides previous multiline results
96
+ Given the file "xmpfilter-prev-line2.rb":
97
+ """
98
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
99
+ # =>
100
+ """
101
+ When I run the pipeline "seeing_is_believing --xmpfilter-style xmpfilter-prev-line2.rb" | "seeing_is_believing --xmpfilter-style"
102
+ Then stdout is:
103
+ """
104
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
105
+ # => {:foo=>42,
106
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
107
+ # :wibble=>{:magic_word=>"xyzzy"}}
108
+ """
109
+
110
+
111
+ Scenario: --xmpfilter-style respects the line formatting (but not currently alignment strategies, it just preserves submitted alignment)
112
+ Given the file "xmpfilter_line_lengths.rb":
113
+ """
114
+ '1' * 30 # =>
115
+ # =>
116
+ """
117
+ When I run "seeing_is_believing --xmpfilter-style --line-length 19 xmpfilter_line_lengths.rb"
118
+ Then stdout is:
119
+ """
120
+ '1' * 30 # => "1...
121
+ # => "1111111111...
122
+ """
123
+
124
+
125
+ Scenario: Errors on annotated lines
126
+ Given the file "xmpfilter_error_on_annotated_line.rb":
127
+ """
128
+ raise "ZOMG\n!!!!" # =>
129
+ """
130
+ When I run "seeing_is_believing --xmpfilter-style xmpfilter_error_on_annotated_line.rb"
131
+ Then stderr is empty
132
+ And the exit status is 1
133
+ Then stdout is:
134
+ """
135
+ raise "ZOMG\n!!!!" # => RuntimeError: ZOMG\n!!!!
136
+
137
+ # ~> RuntimeError
138
+ # ~> ZOMG
139
+ # ~> !!!!
140
+ # ~>
141
+ # ~> xmpfilter_error_on_annotated_line.rb:1:in `<main>'
142
+ """
143
+
144
+
145
+ Scenario: Errors on unannotated lines
146
+ Given the file "xmpfilter_error_on_unannotated_line.rb":
147
+ """
148
+ raise "ZOMG\n!!!!"
149
+ """
150
+ When I run "seeing_is_believing --xmpfilter-style xmpfilter_error_on_unannotated_line.rb"
151
+ Then stderr is empty
152
+ And the exit status is 1
153
+ Then stdout is:
154
+ """
155
+ raise "ZOMG\n!!!!" # ~> RuntimeError: ZOMG\n!!!!
156
+
157
+ # ~> RuntimeError
158
+ # ~> ZOMG
159
+ # ~> !!!!
160
+ # ~>
161
+ # ~> xmpfilter_error_on_unannotated_line.rb:1:in `<main>'
162
+ """
163
+
164
+
165
+ Scenario: Cleaning previous output does not clean the xmpfilter annotations
166
+ Given the file "xmpfilter_cleaning.rb":
167
+ """
168
+ # commented out # => previous annotation
169
+ 1 # => "1...
170
+ # => "1111111111...
171
+ # "1111111111...
172
+ # normal comment
173
+
174
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
175
+ # => {:foo=>42,
176
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
177
+ # :wibble=>{:magic_word=>"xyzzy"}}
178
+ """
179
+ When I run "seeing_is_believing --xmpfilter-style --clean xmpfilter_cleaning.rb"
180
+ Then stdout is:
181
+ """
182
+ # commented out # => previous annotation
183
+ 1 # =>
184
+ # =>
185
+ # normal comment
186
+
187
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
188
+ # =>
189
+ """
190
+
191
+
192
+ # Not totally in love with this, but it'll do unless I can think of something better.
193
+ Scenario: Error raised on an annotated line preserves the annotation
194
+ Given the file "error_on_annotated_line.a.rb":
195
+ """
196
+ "a"+1 # =>
197
+ # =>
198
+ """
199
+ When I run "seeing_is_believing --xmpfilter-style error_on_annotated_line.a.rb"
200
+ Then stdout includes:
201
+ """
202
+ "a"+1 # => TypeError:
203
+ """
204
+ And stdout includes:
205
+ """
206
+ # =>
207
+
208
+ # ~> TypeError
209
+ """
210
+ Given the file "error_on_annotated_line.b.rb":
211
+ """
212
+ "a"+"1" # => TypeError: no implicit conversion of Fixnum into String
213
+ # =>
214
+
215
+ # ~> TypeError
216
+ # ~> no implicit conversion of Fixnum into String
217
+ """
218
+ When I run "seeing_is_believing --xmpfilter-style error_on_annotated_line.b.rb"
219
+ Then stdout is:
220
+ """
221
+ "a"+"1" # => "a1"
222
+ # => "a1"
223
+ """
224
+
225
+
226
+ # maybe can't fix this as it depends on the implementation of PP.pp
227
+ @not-implemented
228
+ Scenario: It can record values even when method is overridden
229
+ Given the file "pretty_inspect_with_method_overridden.rb":
230
+ """
231
+ def method()end; self # =>
232
+ # =>
233
+ """
234
+ When I run "seeing_is_believing --xmpfilter-style pretty_inspect_with_method_overridden.rb"
235
+ Then stdout is:
236
+ """
237
+ def method()end; self # => main
238
+ # => main
239
+ """
240
+
241
+
242
+ # Choosing this output style b/c it's what xmpfilter chooses,
243
+ # and it works conveniently with what's already in place.
244
+ #
245
+ # It looks better with the comma on the preceding line, but harder to identify the individual results.
246
+ #
247
+ # It looks better with an empty line between the results, but if the user strips trailing whitespace inbetween runs,
248
+ # it will confuse the annotations for normal comments.
249
+ #
250
+ # Might be cool to have it do a value comment before each result, instead of a comma.
251
+ # But at present, it doesn't wipe out "useless" value comments,
252
+ # e.g. cleaning this would leave three value markers after the hash.
253
+ Scenario: Multiline output that is repeatedly invoked
254
+ Given the file "mutltiline_output_repeatedly_invoked.rb":
255
+ """
256
+ 3.times do
257
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
258
+ # =>
259
+ end
260
+ """
261
+ When I run "seeing_is_believing -x mutltiline_output_repeatedly_invoked.rb"
262
+ Then stdout is:
263
+ """
264
+ 3.times do
265
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
266
+ # => {:foo=>42,
267
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
268
+ # :wibble=>{:magic_word=>"xyzzy"}}
269
+ # ,{:foo=>42,
270
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
271
+ # :wibble=>{:magic_word=>"xyzzy"}}
272
+ # ,{:foo=>42,
273
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
274
+ # :wibble=>{:magic_word=>"xyzzy"}}
275
+ end
276
+ """
277
+ When I run the pipeline "seeing_is_believing -x mutltiline_output_repeatedly_invoked.rb" | "seeing_is_believing -x"
278
+ Then stdout is:
279
+ """
280
+ 3.times do
281
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
282
+ # => {:foo=>42,
283
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
284
+ # :wibble=>{:magic_word=>"xyzzy"}}
285
+ # ,{:foo=>42,
286
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
287
+ # :wibble=>{:magic_word=>"xyzzy"}}
288
+ # ,{:foo=>42,
289
+ # :bar=>{:baz=>1, :buz=>2, :fuz=>3},
290
+ # :wibble=>{:magic_word=>"xyzzy"}}
291
+ end
292
+ """
293
+
294
+
295
+ Scenario: Multiline values where the first line is indented more than the successive lines use a nonbreaking space
296
+ Given the file "inspect_tree.rb":
297
+ """
298
+ bst = Object.new
299
+ def bst.inspect
300
+ " 4\n"\
301
+ " 2 6\n"\
302
+ "1 3 5 7\n"
303
+ end
304
+ bst
305
+ # =>
306
+ """
307
+ When I run "seeing_is_believing --xmpfilter-style inspect_tree.rb"
308
+ # NOTE: The first space after the => is a nonbreaking space
309
+ Then stdout is:
310
+ """
311
+ bst = Object.new
312
+ def bst.inspect
313
+ " 4\n"\
314
+ " 2 6\n"\
315
+ "1 3 5 7\n"
316
+ end
317
+ bst
318
+ # =>   4
319
+ # 2 6
320
+ # 1 3 5 7
321
+ """
322
+
323
+
324
+ Scenario: Leading whitespace on nextline, but not multiline uses normal spaces
325
+ Given the file "nextline_with_leading_whitespace_but_not_multiline.rb":
326
+ """
327
+ o = Object.new
328
+ def o.inspect; " o" end
329
+ o
330
+ # =>
331
+ """
332
+ When I run "seeing_is_believing --xmpfilter-style nextline_with_leading_whitespace_but_not_multiline.rb"
333
+ Then stdout is:
334
+ """
335
+ o = Object.new
336
+ def o.inspect; " o" end
337
+ o
338
+ # => o
339
+ """
340
+
341
+
342
+ Scenario: When there are no results for the previous line it looks further back (#77)
343
+ Given the file "heredocs_and_blank_lines.rb":
344
+ """
345
+ # =>
346
+
347
+ <<DOC
348
+ 1
349
+ DOC
350
+ # =>
351
+
352
+ 2
353
+
354
+ # =>
355
+
356
+ if true
357
+ 3
358
+ # =>
359
+ else
360
+ 4
361
+ # =>
362
+ end
363
+ """
364
+ When I run "seeing_is_believing --xmpfilter-style heredocs_and_blank_lines.rb"
365
+ Then stdout is:
366
+ """
367
+ # =>
368
+
369
+ <<DOC
370
+ 1
371
+ DOC
372
+ # => "1\n"
373
+
374
+ 2
375
+
376
+ # => 2
377
+
378
+ if true
379
+ 3
380
+ # => 3
381
+ else
382
+ 4
383
+ # =>
384
+ end
385
+ """
386
+
387
+
388
+
389
+ Scenario: Xmpfilter uses the same comment formatting as normal
390
+ Given the file "xmpfilter_result_lengths.rb":
391
+ """
392
+ $stdout.puts "a"*100
393
+ $stderr.puts "a"*100
394
+
395
+ "a" # =>
396
+ "aa" # =>
397
+ "aaa" # =>
398
+ "aaaa" # =>
399
+
400
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
401
+ # =>
402
+
403
+ raise "a"*100
404
+ """
405
+ When I run "seeing_is_believing -x --result-length 10 xmpfilter_result_lengths.rb"
406
+ Then stderr is empty
407
+ And stdout is:
408
+ """
409
+ $stdout.puts "a"*100
410
+ $stderr.puts "a"*100
411
+
412
+ "a" # => "a"
413
+ "aa" # => "aa"
414
+ "aaa" # => "aaa"
415
+ "aaaa" # => "a...
416
+
417
+ {foo: 42, bar: {baz: 1, buz: 2, fuz: 3}, wibble: {magic_word: "xyzzy"}}
418
+ # => {:...
419
+ # :...
420
+ # :...
421
+
422
+ raise "a"*100 # ~> Ru...
423
+
424
+ # >> aa...
425
+
426
+ # !> aa...
427
+
428
+ # ~> Ru...
429
+ # ~> aa...
430
+ # ~>
431
+ # ~> xm...
432
+ """
433
+
434
+ Scenario: --interline-align and --no-interline-align determine whether adjacent lines with the same number of results get lined up, it defaults to --align
435
+ Given the file "xmpfilter_interline_alignment.rb":
436
+ """
437
+ 3.times do |num|
438
+ num # =>
439
+ .to_s # =>
440
+ end
441
+ """
442
+ When I run "seeing_is_believing -x xmpfilter_interline_alignment.rb"
443
+ Then stderr is empty
444
+ And the exit status is 0
445
+ And stdout is:
446
+ """
447
+ 3.times do |num|
448
+ num # => 0, 1, 2
449
+ .to_s # => "0", "1", "2"
450
+ end
451
+ """
452
+ When I run "seeing_is_believing -x --interline-align xmpfilter_interline_alignment.rb"
453
+ Then stderr is empty
454
+ And the exit status is 0
455
+ And stdout is:
456
+ """
457
+ 3.times do |num|
458
+ num # => 0, 1, 2
459
+ .to_s # => "0", "1", "2"
460
+ end
461
+ """
462
+ When I run "seeing_is_believing -x --no-interline-align xmpfilter_interline_alignment.rb"
463
+ Then stderr is empty
464
+ And the exit status is 0
465
+ And stdout is:
466
+ """
467
+ 3.times do |num|
468
+ num # => 0, 1, 2
469
+ .to_s # => "0", "1", "2"
470
+ end
471
+ """
@@ -0,0 +1,47 @@
1
+ require 'seeing_is_believing/binary/commentable_lines'
2
+
3
+ class SeeingIsBelieving
4
+ module Binary
5
+ class AlignChunk
6
+ def initialize(body)
7
+ self.body = body
8
+ end
9
+
10
+ # max line length of the the chunk (newline separated sections of code exempting comments) + 2 spaces for padding
11
+ def line_length_for(line_number)
12
+ line_lengths.fetch line_number, 0
13
+ end
14
+
15
+ private
16
+
17
+ attr_accessor :body
18
+
19
+ def line_lengths
20
+ @line_lengths ||= begin
21
+ # sheesh, I need like Hash#map_values or something
22
+ line_nums_to_cols = Hash.[] \
23
+ CommentableLines.call(body)
24
+ .map { |line_num, (file_index, col_index)|
25
+ [line_num, col_index-amount_of_preceding_whitespace(file_index)]
26
+ }
27
+
28
+ Hash.[] \
29
+ line_nums_to_cols
30
+ .keys
31
+ .sort
32
+ .slice_before { |line_number| line_nums_to_cols[line_number].zero? }
33
+ .flat_map { |slice|
34
+ max_chunk_length = 2 + slice.map { |line_num| line_nums_to_cols[line_num] }.max
35
+ slice.map { |line_number| [line_number, max_chunk_length] }
36
+ }
37
+ end
38
+ end
39
+
40
+ def amount_of_preceding_whitespace(index_of_trailing_newline)
41
+ index = index_of_trailing_newline - 1
42
+ index -= 1 while 0 <= index && body[index] !~ /[\S\n]/
43
+ index_of_trailing_newline - index - 1
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ require 'seeing_is_believing/binary/commentable_lines'
2
+
3
+ class SeeingIsBelieving
4
+ module Binary
5
+ class AlignFile
6
+ attr_accessor :body
7
+
8
+ def initialize(body)
9
+ self.body = body
10
+ end
11
+
12
+ # max line length of the lines to output (exempting comments) + 2 spaces for padding
13
+ def line_length_for(line_number)
14
+ @max_source_line_length ||= 2 + begin
15
+ line_num_to_indexes = CommentableLines.new(body).call # {line_number => [index_in_file, index_in_col]}
16
+ max_value = line_num_to_indexes
17
+ .values
18
+ .map { |index, col| col }.max
19
+ max_value || 0
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ class SeeingIsBelieving
2
+ module Binary
3
+ class AlignLine
4
+ attr_accessor :body
5
+
6
+ def initialize(body)
7
+ self.body = body
8
+ end
9
+
10
+ # length of the line + 2 spaces for padding
11
+ def line_length_for(line_number)
12
+ line_lengths[line_number]
13
+ end
14
+
15
+ def line_lengths
16
+ @line_lengths ||= Hash[ body.each_line
17
+ .map(&:chomp)
18
+ .each
19
+ .with_index(1)
20
+ .map { |line, index| [index, line.length+2] }
21
+ ]
22
+ end
23
+ end
24
+ end
25
+ end