seeing_is_believing 3.0.0.beta.4 → 3.0.0.beta.5

Sign up to get free protection for your applications and to get access to all the features.
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