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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -8
  3. data/Rakefile +1 -1
  4. data/Readme.md +65 -25
  5. data/bin/seeing_is_believing +1 -0
  6. data/docs/sib-streaming.gif +0 -0
  7. data/features/deprecated-flags.feature +62 -2
  8. data/features/errors.feature +12 -7
  9. data/features/examples.feature +143 -4
  10. data/features/flags.feature +89 -29
  11. data/features/regression.feature +58 -14
  12. data/features/support/env.rb +4 -0
  13. data/features/xmpfilter-style.feature +181 -36
  14. data/lib/seeing_is_believing.rb +44 -33
  15. data/lib/seeing_is_believing/binary.rb +31 -88
  16. data/lib/seeing_is_believing/binary/align_chunk.rb +30 -11
  17. data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +10 -16
  18. data/lib/seeing_is_believing/binary/annotate_every_line.rb +5 -25
  19. data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +136 -0
  20. data/lib/seeing_is_believing/binary/comment_lines.rb +8 -10
  21. data/lib/seeing_is_believing/binary/commentable_lines.rb +20 -26
  22. data/lib/seeing_is_believing/binary/config.rb +392 -0
  23. data/lib/seeing_is_believing/binary/data_structures.rb +57 -0
  24. data/lib/seeing_is_believing/binary/engine.rb +104 -0
  25. data/lib/seeing_is_believing/binary/{comment_formatter.rb → format_comment.rb} +6 -6
  26. data/lib/seeing_is_believing/binary/remove_annotations.rb +29 -28
  27. data/lib/seeing_is_believing/binary/rewrite_comments.rb +42 -43
  28. data/lib/seeing_is_believing/code.rb +105 -49
  29. data/lib/seeing_is_believing/debugger.rb +6 -5
  30. data/lib/seeing_is_believing/error.rb +6 -17
  31. data/lib/seeing_is_believing/evaluate_by_moving_files.rb +78 -129
  32. data/lib/seeing_is_believing/event_stream/consumer.rb +114 -64
  33. data/lib/seeing_is_believing/event_stream/events.rb +169 -11
  34. data/lib/seeing_is_believing/event_stream/handlers/debug.rb +57 -0
  35. data/lib/seeing_is_believing/event_stream/handlers/record_exitstatus.rb +18 -0
  36. data/lib/seeing_is_believing/event_stream/handlers/stream_json_events.rb +45 -0
  37. data/lib/seeing_is_believing/event_stream/handlers/update_result.rb +39 -0
  38. data/lib/seeing_is_believing/event_stream/producer.rb +25 -24
  39. data/lib/seeing_is_believing/hash_struct.rb +206 -0
  40. data/lib/seeing_is_believing/result.rb +20 -3
  41. data/lib/seeing_is_believing/the_matrix.rb +20 -12
  42. data/lib/seeing_is_believing/version.rb +1 -1
  43. data/lib/seeing_is_believing/wrap_expressions.rb +55 -115
  44. data/lib/seeing_is_believing/wrap_expressions_with_inspect.rb +14 -0
  45. data/seeing_is_believing.gemspec +1 -1
  46. data/spec/binary/alignment_specs.rb +27 -0
  47. data/spec/binary/comment_lines_spec.rb +3 -2
  48. data/spec/binary/config_spec.rb +657 -0
  49. data/spec/binary/engine_spec.rb +97 -0
  50. data/spec/binary/{comment_formatter_spec.rb → format_comment_spec.rb} +2 -2
  51. data/spec/binary/marker_spec.rb +71 -0
  52. data/spec/binary/options_spec.rb +0 -0
  53. data/spec/binary/remove_annotations_spec.rb +31 -18
  54. data/spec/binary/rewrite_comments_spec.rb +26 -11
  55. data/spec/code_spec.rb +190 -6
  56. data/spec/debugger_spec.rb +4 -0
  57. data/spec/evaluate_by_moving_files_spec.rb +38 -20
  58. data/spec/event_stream_spec.rb +265 -116
  59. data/spec/hash_struct_spec.rb +514 -0
  60. data/spec/seeing_is_believing_spec.rb +108 -46
  61. data/spec/spec_helper.rb +9 -0
  62. data/spec/wrap_expressions_spec.rb +207 -172
  63. metadata +30 -18
  64. data/docs/for-presentations +0 -33
  65. data/lib/seeing_is_believing/binary/annotate_xmpfilter_style.rb +0 -128
  66. data/lib/seeing_is_believing/binary/interpret_flags.rb +0 -156
  67. data/lib/seeing_is_believing/binary/parse_args.rb +0 -263
  68. data/lib/seeing_is_believing/event_stream/update_result.rb +0 -24
  69. data/lib/seeing_is_believing/inspect_expressions.rb +0 -21
  70. data/lib/seeing_is_believing/parser_helpers.rb +0 -82
  71. data/spec/binary/interpret_flags_spec.rb +0 -332
  72. data/spec/binary/parse_args_spec.rb +0 -415
@@ -1,24 +0,0 @@
1
- require 'seeing_is_believing/event_stream/events'
2
- class SeeingIsBelieving
3
- module EventStream
4
- # Adapter between EventStream and Result
5
- module UpdateResult
6
- def self.call(result, event)
7
- case event
8
- when EventStream::Events::LineResult then result.record_result(event.type, event.line_number, event.inspected)
9
- when EventStream::Events::UnrecordedResult then result.record_result(event.type, event.line_number, '...') # <-- is this really what I want?
10
- when EventStream::Events::Exception then result.record_exception event.line_number, event.class_name, event.message, event.backtrace
11
- when EventStream::Events::Stdout then result.stdout << event.value
12
- when EventStream::Events::Stderr then result.stderr << event.value
13
- when EventStream::Events::MaxLineCaptures then result.number_of_captures = event.value
14
- when EventStream::Events::Exitstatus then result.exitstatus = event.value
15
- when EventStream::Events::NumLines then result.num_lines = event.value
16
- when EventStream::Events::SiBVersion then result.sib_version = event.value
17
- when EventStream::Events::RubyVersion then result.ruby_version = event.value
18
- when EventStream::Events::Filename then result.filename = event.value
19
- else raise "Unknown event: #{event.inspect}"
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,21 +0,0 @@
1
- require 'seeing_is_believing/wrap_expressions'
2
- class SeeingIsBelieving
3
- module InspectExpressions
4
- def self.call(program, filename, number_of_captures, options={})
5
- # TODO: much of this is duplicated in annotate_xmpfilter_stle
6
- number_of_captures_as_str = number_of_captures.inspect
7
- number_of_captures_as_str = 'Float::INFINITY' if number_of_captures == Float::INFINITY
8
-
9
- wrap_expressions_callbacks = {}
10
- wrap_expressions_callbacks[:before_all] = options.fetch :before_all, -> { "$SiB.record_ruby_version RUBY_VERSION;"\
11
- "$SiB.record_sib_version #{VERSION.inspect};"\
12
- "$SiB.record_filename #{filename.inspect};"\
13
- "$SiB.record_max_line_captures #{number_of_captures_as_str};"\
14
- "$SiB.num_lines = #{program.lines.count}; " }
15
- wrap_expressions_callbacks[:after_all] = options.fetch :after_all, -> { "" }
16
- wrap_expressions_callbacks[:before_each] = options.fetch :before_each, -> line_number { "(" }
17
- wrap_expressions_callbacks[:after_each] = options.fetch :after_each, -> line_number { ").tap { |v| $SiB.record_result(:inspect, #{line_number}, v) }" }
18
- WrapExpressions.call program, wrap_expressions_callbacks
19
- end
20
- end
21
- end
@@ -1,82 +0,0 @@
1
- module Parser
2
- class << self
3
- # With new versioning, there's lots of small versions
4
- # we don't need it to complain that we're on 2.1.1 and its parsing 2.1.5
5
- # https://github.com/whitequark/parser/blob/e2249d7051b1adb6979139928e14a81bc62f566e/lib/parser/current.rb#L3
6
- def warn(*) end
7
- require 'parser/current'
8
- remove_method :warn
9
- end
10
- end
11
-
12
- class SeeingIsBelieving
13
- module ParserHelpers
14
-
15
- # override #process so it does not raise an error on
16
- # fatal parsings (we want to keep going if possible,
17
- # this allows us to find comments in syntactically invalid files)
18
- class NullDiagnostics < Parser::Diagnostic::Engine
19
- def process(*)
20
- # no op
21
- end
22
- end
23
-
24
- extend self
25
-
26
- def initialize_parser(code, name)
27
- buffer = Parser::Source::Buffer.new(name)
28
- buffer.source = code
29
-
30
- builder = Parser::Builders::Default.new
31
- builder.emit_file_line_as_literals = false
32
-
33
- parser = Parser::CurrentRuby.new builder
34
- rewriter = Parser::Source::Rewriter.new buffer
35
-
36
- [buffer, parser, rewriter]
37
- end
38
-
39
- # useful b/c it can find comments even in syntactically invalid code
40
- def comments_from(parser, buffer)
41
- parser.instance_variable_set(:@diagnostics, NullDiagnostics.new) # seems really fucking risky
42
- success, comments, tokens, * = parser.tokenize buffer # experimentally, seems to be what these things return
43
- comments
44
- end
45
-
46
- # this is the scardest fucking method I think I've ever written.
47
- # *anything* can go wrong!
48
- def heredoc?(ast)
49
- # some strings are fucking weird.
50
- # e.g. the "1" in `%w[1]` returns nil for ast.location.begin
51
- # and `__FILE__` is a string whose location is a Parser::Source::Map instead of a Parser::Source::Map::Collection,
52
- # so it has no #begin
53
- ast.kind_of?(Parser::AST::Node) &&
54
- (ast.type == :dstr || ast.type == :str) &&
55
- (location = ast.location) &&
56
- (ast.location.kind_of? Parser::Source::Map::Heredoc)
57
- end
58
-
59
- def void_value?(ast)
60
- case ast && ast.type
61
- when :begin, :kwbegin, :resbody
62
- void_value?(ast.children[-1])
63
- when :rescue, :ensure
64
- ast.children.any? { |child| void_value? child }
65
- when :if
66
- void_value?(ast.children[1]) || void_value?(ast.children[2])
67
- when :return, :next, :redo, :retry, :break
68
- true
69
- else
70
- false
71
- end
72
- end
73
-
74
- def heredoc_hack(ast)
75
- return ast
76
- return ast unless heredoc? ast
77
- Parser::AST::Node.new :str,
78
- [],
79
- location: Parser::Source::Map.new(ast.location.begin)
80
- end
81
- end
82
- end
@@ -1,332 +0,0 @@
1
- require 'seeing_is_believing/binary/parse_args'
2
- require 'seeing_is_believing/binary/interpret_flags'
3
-
4
- class SeeingIsBelieving
5
- module Binary
6
- RSpec.describe 'SeeingIsBelieving::Binary::InterpretFlags' do
7
- let(:stdin_data) { 'stdin data' }
8
- let(:stdin) { double 'stdin', read: stdin_data }
9
- let(:stdout) { double 'stdout' }
10
-
11
- let(:file_body) { 'good file body' }
12
- let(:nonexisting_filename) { 'badfilename' }
13
- let(:existing_filename) { 'goodfilename' }
14
-
15
- before do
16
- allow(File).to receive(:exist?).and_return(false)
17
- allow(File).to receive(:exist?).with(existing_filename).and_return(true)
18
- allow(File).to receive(:exist?).with(nonexisting_filename).and_return(false)
19
- allow(File).to receive(:read).with(existing_filename).and_return(file_body)
20
- end
21
-
22
- def call(overrides={})
23
- flags = ParseArgs.call []
24
- InterpretFlags.new(flags.merge(overrides), stdin, stdout)
25
- end
26
-
27
- describe '.to_regex' do
28
- def call(input, regex)
29
- expect(InterpretFlags.to_regex input).to eq regex
30
- end
31
-
32
- it 'converts strings into regexes' do
33
- call '', %r()
34
- call 'a', %r(a)
35
- end
36
-
37
- it 'ignores surrounding slashes' do
38
- call '//', %r()
39
- call '/a/', %r(a)
40
- end
41
-
42
- it 'respects flags after the trailing slash in surrounding slashes' do
43
- call '/a/', %r(a)
44
- call '/a//', %r(a/)
45
- call '//a/', %r(/a)
46
- call '/a/i', %r(a)i
47
- call '/a/im', %r(a)im
48
- call '/a/xim', %r(a)xim
49
- call '/a/mix', %r(a)mix
50
- call '/a/mixi', %r(a)mixi
51
- end
52
-
53
- it 'isn\'t fooled by strings that kinda look regexy' do
54
- call '/a', %r(/a)
55
- call 'a/', %r(a/)
56
- call '/', %r(/)
57
- call '/i', %r(/i)
58
- end
59
-
60
- it 'does not escape the content' do
61
- call 'a\\s+', %r(a\s+)
62
- call '/a\\s+/', %r(a\s+)
63
- end
64
- end
65
-
66
- describe 'annotator' do
67
- it 'annotates every line by default' do
68
- expect(call.annotator).to eq AnnotateEveryLine
69
- end
70
-
71
- it 'annotates xmpfilter-style if xmpfilter_style was set' do
72
- expect(call.annotator).to eq AnnotateEveryLine
73
- end
74
- end
75
-
76
- describe 'help' do
77
- let(:overrides) { {short_help_screen: 'short help screen',
78
- long_help_screen: 'long help screen'} }
79
-
80
- context 'when the value is not set' do
81
- before { overrides[:help] = nil }
82
-
83
- it 'does not set print_help?' do
84
- expect(call(overrides).print_help?).to eq false
85
- end
86
- end
87
-
88
- context 'when the value is "help"' do
89
- before { overrides[:help] = 'help' }
90
-
91
- it 'sets print_help?' do
92
- expect(call(overrides).print_help?).to eq true
93
- end
94
-
95
- it 'sets the help_screen to the short one' do
96
- expect(call(overrides).help_screen).to eq 'short help screen'
97
- end
98
- end
99
-
100
- context 'when the value is "help+"' do
101
- before { overrides[:help] = 'help+' }
102
-
103
- it 'sets print_help?' do
104
- expect(call(overrides).print_help?).to eq true
105
- end
106
-
107
- it 'sets the help screen to the long one' do
108
- expect(call(overrides).help_screen).to eq 'long help screen'
109
- end
110
- end
111
- end
112
-
113
- context 'debug' do
114
- it 'sts a null debugger when false' do
115
- expect(call(debug: false).debugger).to_not be_enabled
116
- end
117
-
118
- it 'sets a debugger to the output stream when true' do
119
- expect(call(debug: true).debugger).to be_enabled
120
- end
121
- end
122
-
123
- context 'markers' do
124
- # TODO: fix this later to use objs
125
- end
126
-
127
- context 'timeout' do
128
- it 'sets timeout to the value' do
129
- expect(call(timeout: 0).timeout).to eq 0 # TODO: Should the interpretation of 0 move up from flags to here?
130
- expect(call(timeout: 1).timeout).to eq 1
131
- end
132
- end
133
-
134
- context 'filename' do
135
- it 'sets this as the filename' do
136
- expect(call(filename: 'somefilename').filename).to eq 'somefilename'
137
- end
138
- end
139
-
140
- context 'filenames' do
141
- it 'sets an error if more than one filename was provided' do
142
- expect(call(filenames: []).errors.join).to_not match /filename/
143
- expect(call(filenames: ['a']).errors.join).to_not match /filename/
144
- expect(call(filenames: ['a', 'b']).errors.join).to match /filename/
145
- end
146
-
147
- it 'sets an error if there is a filename and the program was also passed on stdin' do
148
- matcher = /also specified the filename/
149
- expect(call(filename: 'f', program_from_args: 'prog').errors.join).to match matcher
150
- expect(call(filename: nil, program_from_args: 'prog').errors.join).to_not match matcher
151
- expect(call(filename: 'f', program_from_args: nil ).errors.join).to_not match matcher
152
- end
153
- end
154
-
155
- context 'predicates' do
156
- it 'sets print_version? when version is true' do
157
- expect(call(version: false).print_version?).to eq false
158
- expect(call(version: true).print_version?).to eq true
159
- end
160
-
161
- it 'sets inherit_exit_status when inherit_exit_status is true' do
162
- expect(call(inherit_exit_status: false).inherit_exit_status?).to eq false
163
- expect(call(inherit_exit_status: true).inherit_exit_status?).to eq true
164
- end
165
-
166
- it 'sets result_as_json when result_as_json is true' do
167
- expect(call(result_as_json: false).result_as_json?).to eq false
168
- expect(call(result_as_json: true).result_as_json?).to eq true
169
- end
170
-
171
- it 'sets print_help when help has a value' do
172
- expect(call(help: nil).print_help?).to eq false
173
- expect(call(help: 'help').print_help?).to eq true
174
- end
175
-
176
- it 'sets print_cleaned when clean is set' do
177
- expect(call(clean: false).print_cleaned?).to eq false
178
- expect(call(clean: true).print_cleaned?).to eq true
179
- end
180
-
181
- it 'sets provided_filename_dne when there is a filename and that file does not exist' do
182
- expect(call(filename: nonexisting_filename).provided_filename_dne?).to eq true
183
- expect(call(filename: existing_filename).provided_filename_dne?).to eq false
184
- expect(call(filename: nil).provided_filename_dne?).to eq false
185
- end
186
-
187
- it 'sets file_is_on_stdin when there is no filename and the program is not provided in the args' do
188
- expect(call(filename: nil, program_from_args: nil).file_is_on_stdin?).to eq true
189
- expect(call(filename: 'f', program_from_args: nil).file_is_on_stdin?).to eq false
190
- expect(call(filename: nil, program_from_args: 'p').file_is_on_stdin?).to eq false
191
- end
192
- end
193
-
194
- context 'body' do
195
- it 'is an empty string if we\'re going to print the version or help instead of the program' do
196
- expect(call(version: true).body).to eq ''
197
- expect(call(help: true).body).to eq ''
198
- end
199
-
200
- it 'is the program_from_args if this is provided' do
201
- expect(call(program_from_args: 'prog').body).to eq 'prog'
202
- end
203
-
204
- it 'is stdin if there is no file and no program_from_args' do
205
- expect(call(filename: nil, program_from_args: nil).body).to eq stdin_data
206
- end
207
-
208
- it 'is the file body if the filename is provded and exists' do
209
- expect(call(filename: existing_filename).body).to eq file_body
210
- end
211
-
212
- it 'is an empty string if the provided filename dne' do
213
- expect(call(filename: nonexisting_filename).body).to eq ""
214
- end
215
- end
216
-
217
- context 'prepared_body' do
218
- it 'is the body after being run throught he annotator\'s prepare method' do
219
- expect(call(program_from_args: '1+1 # => ').prepared_body).to eq '1+1'
220
- end
221
- end
222
-
223
- context 'lib_options' do
224
- def call(overrides={})
225
- super(overrides).lib_options
226
- end
227
-
228
- it 'returns a hash to be passed to the evaluator' do
229
- expect(call).to be_a_kind_of Hash
230
- end
231
-
232
- specify 'evaluate_with is EvaluateByMovingFiles by default' do
233
- expect(call[:evaluate_with]).to eq EvaluateByMovingFiles
234
- end
235
-
236
- specify 'filename is the as option or the provided filename' do
237
- expect(call(filename: 'from_fn')[:filename]).to eq 'from_fn'
238
- expect(call(as: 'from_as')[:filename]).to eq 'from_as'
239
- expect(call(as: 'from_as', filename: 'from_fn')[:filename]).to eq 'from_as'
240
- end
241
-
242
- specify 'stdin is empty when the program is on stdin, and is stdin otherwise' do
243
- # NOTE: the lib will normalize this into a stream
244
- expect(call(filename: nil, program_from_args: nil)[:stdin]).to eq ''
245
- expect(call(filename: nil, program_from_args: '1')[:stdin]).to eq stdin
246
- end
247
-
248
- # TODO: Add cuke where required file prints
249
- specify 'require includes the matrix first, plus any other required files' do
250
- expect(call(require: ['somefile'])[:require]).to eq ['seeing_is_believing/the_matrix', 'somefile']
251
- end
252
-
253
- # TODO: This is prob not ture for eval_in... maybe let the evaluators provide defaults?
254
- specify 'load_path is the load_path, with the full path to sib\'s lib added' do
255
- path_to_lib = File.expand_path('../../../lib', __FILE__)
256
- expect(call(load_path: ['somepath'])[:load_path]).to eq [path_to_lib, 'somepath']
257
- end
258
-
259
- # TODO: Default this to utf-8
260
- specify 'encoding is set to the encoding' do
261
- expect(call(encoding: 'someencoding')[:encoding]).to eq 'someencoding'
262
- end
263
-
264
- specify 'timeout is set to timeout' do
265
- expect(call(timeout: 1.2)[:timeout]).to eq 1.2
266
- end
267
-
268
- specify 'debugger is the same as the toplevel debugger' do
269
- options = InterpretFlags.new(ParseArgs.call([]), stdin, stdout)
270
- expect(options.lib_options[:debugger]).to equal options.debugger
271
- end
272
-
273
- specify 'number_of_captures is number_of_captures' do
274
- expect(call(number_of_captures: 12345)[:number_of_captures]).to eq 12345
275
- end
276
-
277
- specify 'record_expressions is the annotator\'s expression wrapper' do
278
- expect(call[:record_expressions]).to eq InspectExpressions
279
- expect(call(xmpfilter_style: true)[:record_expressions]).to be_a_kind_of Proc
280
- end
281
- end
282
-
283
- context 'annotator_options' do
284
- def call(overrides={})
285
- super(overrides).annotator_options
286
- end
287
-
288
- it 'sets alignment_strategy to the provided alignment strategy' do
289
- expect(call(alignment_strategy: 'chunk')[:alignment_strategy]).to eq AlignChunk
290
- expect(call(alignment_strategy: 'file' )[:alignment_strategy]).to eq AlignFile
291
- expect(call(alignment_strategy: 'line' )[:alignment_strategy]).to eq AlignLine
292
- end
293
-
294
- it 'sets an error if the requested alignment strategy is not known, or not provided' do
295
- flags = ParseArgs.call([])
296
- options = InterpretFlags.new(flags.merge(alignment_strategy: 'chunk'), stdin, stdout)
297
- expect(options.errors.join).to_not include 'alignment-strategy'
298
-
299
- options = InterpretFlags.new(flags.merge(alignment_strategy: 'nonsense'), stdin, stdout)
300
- expect(options.errors.join).to include 'alignment-strategy does not know'
301
-
302
- options = InterpretFlags.new(flags.merge(alignment_strategy: nil), stdin, stdout)
303
- expect(options.errors.join).to include 'alignment-strategy expected an alignment strategy'
304
- end
305
-
306
- it 'sets the debugger to the toplevel debugger' do
307
- options = InterpretFlags.new(ParseArgs.call([]), stdin, stdout)
308
- expect(options.annotator_options[:debugger]).to equal options.debugger
309
- end
310
-
311
- # TODO: markers
312
- it 'sets max_line_length to the max_line_length' do
313
- expect(call(max_line_length: 123321)[:max_line_length]).to eq 123321
314
- end
315
-
316
- it 'sets max_result_length to the max_result_length' do
317
- expect(call(max_result_length: 99889)[:max_result_length]).to eq 99889
318
- end
319
- end
320
-
321
- it 'has a fancy inspect that shows predicates and attributes on multiple lines' do
322
- inspected = call.inspect
323
- expect(inspected).to include "PREDICATES"
324
- expect(inspected).to include "ATTRIBUTES"
325
- expect(inspected.lines.to_a.length).to be > 1
326
- inspected.lines.each do |line|
327
- expect(line.length).to be < 80 # truncate output so it doesn't get spammy
328
- end
329
- end
330
- end
331
- end
332
- end