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,7 +1,6 @@
1
1
  class SeeingIsBelieving
2
2
  class Debugger
3
-
4
- CONTEXT_COLOUR = "\e[37;44m"
3
+ CONTEXT_COLOUR = "\e[37;44m" # background blue
5
4
  RESET_COLOUR = "\e[0m"
6
5
 
7
6
  def initialize(options={})
@@ -9,6 +8,8 @@ class SeeingIsBelieving
9
8
  @stream = options[:stream]
10
9
  end
11
10
 
11
+ Null = new stream: nil
12
+
12
13
  def coloured?
13
14
  @coloured
14
15
  end
@@ -18,14 +19,14 @@ class SeeingIsBelieving
18
19
 
19
20
  def context(name, &block)
20
21
  if enabled?
21
- stream << CONTEXT_COLOUR if coloured?
22
+ stream << CONTEXT_COLOUR if coloured?
22
23
  stream << "#{name}:"
23
- stream << RESET_COLOUR if coloured?
24
+ stream << RESET_COLOUR if coloured?
24
25
  stream << "\n"
25
26
  stream << block.call.to_s << "\n" if block
26
27
  end
27
28
  self
28
29
  end
29
-
30
30
  end
31
+
31
32
  end
@@ -1,28 +1,17 @@
1
1
  class SeeingIsBelieving
2
- # all our errors will inherit from this so that a user
3
- # can catch any error generated by this lib
2
+ # All our errors will inherit from this so that a user can catch any error generated by this lib
4
3
  SeeingIsBelievingError = Class.new StandardError
5
4
 
6
5
  class TempFileAlreadyExists < SeeingIsBelievingError
7
- def initialize(from_filename, temp_filename)
6
+ def initialize(from_filename, backup_filename)
8
7
  super "Trying to back up #{from_filename.inspect} (FILE) to"\
9
- " #{temp_filename.inspect} (TEMPFILE) but TEMPFILE already exists."\
8
+ " #{backup_filename.inspect} (TEMPFILE) but TEMPFILE already exists."\
10
9
  " You should check the contents of these files. If FILE is correct,"\
11
10
  " then delete TEMPFILE. Otherwise rename TEMPFILE to FILE."
12
11
  end
13
12
  end
14
13
 
15
- class BugInSib < SeeingIsBelievingError
16
- def initialize(error)
17
- require 'parser/version'
18
- require 'seeing_is_believing/version'
19
-
20
- super "It blew up >.< Please log an issue at: https://github.com/JoshCheek/seeing_is_believing/issues\n"\
21
- "SeeingIsBelieving::VERSION #{SeeingIsBelieving::VERSION.inspect}\n"\
22
- "Parser::VERSION #{Parser::VERSION.inspect}\n"\
23
- "RUBY_VERSION #{RUBY_VERSION.inspect}\n"\
24
- "ENV['RUBY_VERSION'] #{ENV['RUBY_VERSION'].inspect}\n"\
25
- "Also include the source code of program that caused this behaviour."
26
- end
27
- end
14
+ # EventStream
15
+ NoMoreEvents = Class.new SeeingIsBelievingError
16
+ UnknownEvent = Class.new SeeingIsBelievingError
28
17
  end
@@ -11,89 +11,42 @@
11
11
  # read the wrong file... of course, since we rewrite the file,
12
12
  # its body will be incorrect, anyway.
13
13
 
14
- require 'open3'
15
14
  require 'timeout'
16
- require 'stringio'
17
- require 'fileutils' # DELETE?
18
15
  require 'seeing_is_believing/error'
19
16
  require 'seeing_is_believing/result'
20
17
  require 'seeing_is_believing/debugger'
21
18
  require 'seeing_is_believing/hard_core_ensure'
22
19
  require 'seeing_is_believing/event_stream/consumer'
23
- require 'seeing_is_believing/event_stream/update_result'
24
20
 
25
21
  class SeeingIsBelieving
26
22
  class EvaluateByMovingFiles
27
-
28
- # *sigh* have to do this b/c can't use Open3, b/c keywords don't work right when the keys are not symbols, and I'm passing a file descriptor
29
- # https://github.com/ruby/ruby/pull/808 my pr
30
- # https://bugs.ruby-lang.org/issues/10699 they opened an issue
31
- # https://bugs.ruby-lang.org/issues/10118 weird feature vs bug conversation
32
- module Spawn
33
- extend self
34
- def popen(*cmd)
35
- opts = {}
36
- opts = cmd.pop if cmd.last.kind_of? Hash
37
-
38
- in_r, in_w = IO.pipe
39
- opts[:in] = in_r
40
- in_w.sync = true
41
-
42
- out_r, out_w = IO.pipe
43
- opts[:out] = out_w
44
-
45
- err_r, err_w = IO.pipe
46
- opts[:err] = err_w
47
-
48
- pid = spawn(*cmd, opts)
49
- wait_thr = Process.detach(pid)
50
-
51
- in_r.close
52
- out_w.close
53
- err_w.close
54
-
55
- begin
56
- yield in_w, out_r, err_r, wait_thr
57
- in_w.close unless in_w.closed?
58
- wait_thr.value
59
- ensure
60
- [in_w, out_r, err_r].each { |io| io.close unless io.closed? }
61
- wait_thr.join
62
- end
63
- end
64
- end
65
-
66
-
67
23
  def self.call(*args)
68
24
  new(*args).call
69
25
  end
70
26
 
71
- attr_accessor :program, :filename, :input_stream, :require_flags, :load_path_flags, :encoding, :timeout, :debugger, :result
72
-
73
- def initialize(program, filename, options={})
74
- self.program = program
75
- self.filename = filename
76
- self.input_stream = options.fetch :input_stream, StringIO.new('')
77
- self.require_flags = options.fetch(:require, ['seeing_is_believing/the_matrix']).map { |filename| ['-r', filename] }.flatten
78
- self.load_path_flags = options.fetch(:load_path, []).map { |dir| ['-I', dir] }.flatten
79
- self.encoding = options.fetch :encoding, nil
80
- self.timeout = options[:timeout]
81
- self.debugger = options.fetch :debugger, Debugger.new(stream: nil)
27
+ attr_accessor :program, :filename, :provided_input, :require_flags, :load_path_flags, :encoding, :timeout_seconds, :debugger, :event_handler, :max_line_captures
28
+
29
+ def initialize(program, filename, options={})
30
+ options = options.dup
31
+ self.program = program
32
+ self.filename = filename
33
+ self.encoding = options.delete(:encoding)
34
+ self.timeout_seconds = options.delete(:timeout_seconds) || 0 # 0 is the new infinity
35
+ self.provided_input = options.delete(:provided_input) || String.new
36
+ self.event_handler = options.delete(:event_handler) || raise("must provide an event handler")
37
+ self.load_path_flags = (options.delete(:load_path_dirs) || []).map { |dir| ['-I', dir] }.flatten
38
+ self.require_flags = (options.delete(:require_files) || ['seeing_is_believing/the_matrix']).map { |filename| ['-r', filename] }.flatten
39
+ self.max_line_captures = (options.delete(:max_line_captures) || Float::INFINITY) # (optimization: child stops producing results at this number, even though it might make more sense for the consumer to stop emitting them)
40
+ options.any? && raise(ArgumentError, "Unknown options: #{options.inspect}")
82
41
  end
83
42
 
84
43
  def call
85
- @result ||= HardCoreEnsure.call \
44
+ HardCoreEnsure.call \
86
45
  code: -> {
87
- we_will_not_overwrite_existing_tempfile!
88
- move_file_to_tempfile
46
+ we_will_not_overwrite_existing_backup_file!
47
+ backup_existing_file
89
48
  write_program_to_file
90
- begin
91
- evaluate_file
92
- result
93
- rescue Exception => error
94
- error = wrap_error error unless error.kind_of? Timeout::Error
95
- raise error
96
- end
49
+ evaluate_file
97
50
  },
98
51
  ensure: -> {
99
52
  set_back_to_initial_conditions
@@ -104,75 +57,87 @@ class SeeingIsBelieving
104
57
  File.dirname filename
105
58
  end
106
59
 
107
- def temp_filename
60
+ def backup_filename
108
61
  File.join file_directory, "seeing_is_believing_backup.#{File.basename filename}"
109
62
  end
110
63
 
111
64
  private
112
65
 
113
- attr_accessor :stdout, :stderr, :exitstatus
114
-
115
- def we_will_not_overwrite_existing_tempfile!
116
- raise TempFileAlreadyExists.new(filename, temp_filename) if File.exist? temp_filename
66
+ def we_will_not_overwrite_existing_backup_file!
67
+ raise TempFileAlreadyExists.new(filename, backup_filename) if File.exist? backup_filename
117
68
  end
118
69
 
119
- def move_file_to_tempfile
70
+ def backup_existing_file
120
71
  return unless File.exist? filename
121
- FileUtils.mv filename, temp_filename
72
+ File.rename filename, backup_filename
122
73
  @was_backed_up = true
123
74
  end
124
75
 
125
76
  def set_back_to_initial_conditions
126
- if @was_backed_up
127
- FileUtils.mv temp_filename, filename
128
- else
129
- FileUtils.rm filename
130
- end
77
+ @was_backed_up ?
78
+ File.rename(backup_filename, filename) :
79
+ File.delete(filename)
131
80
  end
132
81
 
133
82
  def write_program_to_file
134
83
  File.open(filename, 'w') { |f| f.write program.to_s }
135
84
  end
136
85
 
86
+ # have to basically copy a bunch of Open3 code into here b/c keywords don't work right when the keys are not symbols
87
+ # https://github.com/ruby/ruby/pull/808 my PR
88
+ # https://bugs.ruby-lang.org/issues/10699 they opened an issue
89
+ # https://bugs.ruby-lang.org/issues/10118 weird feature vs bug conversation
137
90
  def evaluate_file
138
- # the event stream
139
- es_read, es_write = IO.pipe
140
- es_fd = es_write.to_i.to_s
141
-
142
- # invoke the process
143
- Spawn.popen ENV, *popen_args, es_fd, es_write => es_write do |process_stdin, process_stdout, process_stderr, thread|
144
- # child writes here, we close b/c won't get EOF until all fds are closed
145
- es_write.close
146
-
147
- # send stdin
148
- Thread.new {
149
- input_stream.each_char { |char| process_stdin.write char }
150
- process_stdin.close
151
- }
152
-
153
- # consume events
154
- self.result = Result.new # set on self b/c if an error is raised, we still want to keep what we recorded
155
- event_consumer = Thread.new do
156
- EventStream::Consumer
157
- .new(events: es_read, stdout: process_stdout, stderr: process_stderr)
158
- .each { |event| EventStream::UpdateResult.call result, event }
159
- end
160
-
161
- begin
162
- Timeout::timeout timeout do
163
- event_consumer.join
164
- # TODO: seems like these belong entirely on result, not as ivars of this class
165
- self.exitstatus = thread.value
166
- self.stderr = result.stderr
167
- end
168
- rescue Timeout::Error
169
- Process.kill "TERM", thread.pid
170
- raise $!
171
- end
91
+ # setup streams
92
+ eventstream, child_eventstream = IO.pipe
93
+ stdout, child_stdout = IO.pipe
94
+ stderr, child_stderr = IO.pipe
95
+ child_stdin, stdin = IO.pipe
96
+
97
+ # setup environment variables
98
+ env = ENV.to_hash.merge 'SIB_VARIABLES.MARSHAL.B64' =>
99
+ [Marshal.dump(
100
+ event_stream_fd: child_eventstream.to_i,
101
+ max_line_captures: max_line_captures,
102
+ num_lines: program.lines.count,
103
+ filename: filename
104
+ )].pack('m0')
105
+
106
+ # evaluate the code in a child process
107
+ opts = { in: child_stdin,
108
+ out: child_stdout,
109
+ err: child_stderr,
110
+ child_eventstream => child_eventstream }
111
+ child = Process.detach Kernel.spawn(env, *popen_args, opts)
112
+
113
+ # close b/c we won't get EOF until all fds are closed
114
+ child_eventstream.close
115
+ child_stdout.close
116
+ child_stderr.close
117
+ child_stdin.close
118
+ stdin.sync = true
119
+
120
+ # send stdin
121
+ Thread.new {
122
+ provided_input.each_char { |char| stdin.write char }
123
+ stdin.close
124
+ }
125
+
126
+ # consume events
127
+ consumer = EventStream::Consumer.new(events: eventstream, stdout: stdout, stderr: stderr)
128
+ consumer_thread = Thread.new { consumer.each { |e| event_handler.call e } }
129
+
130
+ # wait for completion
131
+ Timeout.timeout timeout_seconds do
132
+ exitstatus = child.value.exitstatus
133
+ consumer.process_exitstatus exitstatus
134
+ consumer_thread.join
172
135
  end
136
+ rescue Timeout::Error
137
+ Process.kill "TERM", child.pid
138
+ raise
173
139
  ensure
174
- es_read.close unless es_read.closed?
175
- es_write.close unless es_write.closed?
140
+ [stdin, stdout, stderr, eventstream].each { |io| io.close unless io.closed? }
176
141
  end
177
142
 
178
143
  def popen_args
@@ -184,21 +149,5 @@ class SeeingIsBelieving
184
149
  *require_flags, # users can inject files to be required
185
150
  filename]
186
151
  end
187
-
188
- def fail
189
- raise "Exitstatus: #{exitstatus.inspect},\nError: #{stderr.inspect}"
190
- end
191
-
192
- def wrap_error(error)
193
- debugger.context "Program could not be evaluated" do
194
- "Program: #{program.inspect.chomp}\n\n"\
195
- "Stderr: #{stderr.inspect.chomp}\n\n"\
196
- "Status: #{exitstatus.inspect.chomp}\n\n"\
197
- "Result: #{result.inspect.chomp}\n\n"\
198
- "Actual Error: #{error.inspect.chomp}\n"+
199
- error.backtrace.map { |sf| " #{sf}\n" }.join("")
200
- end
201
- BugInSib.new error
202
- end
203
152
  end
204
153
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'seeing_is_believing/event_stream/events'
2
4
  require 'seeing_is_believing/error'
3
5
  require 'thread'
@@ -5,36 +7,79 @@ require 'thread'
5
7
  class SeeingIsBelieving
6
8
  module EventStream
7
9
  class Consumer
8
- NoMoreInput = Class.new SeeingIsBelievingError
9
- WtfWhoClosedMyShit = Class.new SeeingIsBelievingError
10
- UnknownEvent = Class.new SeeingIsBelievingError
10
+ class FinishCriteria
11
+ CRITERIA = [
12
+ :event_thread_finished!,
13
+ :stdout_thread_finished!,
14
+ :stderr_thread_finished!,
15
+ :process_exited!,
16
+ ].freeze.each do |name|
17
+ define_method name do
18
+ @unmet_criteria.delete name
19
+ @satisfied = @unmet_criteria.empty?
20
+ end
21
+ end
22
+ def initialize
23
+ @satisfied = false
24
+ @unmet_criteria = CRITERIA.dup
25
+ end
26
+ def satisfied?
27
+ @satisfied
28
+ end
29
+ end
30
+
31
+ # https://github.com/JoshCheek/seeing_is_believing/issues/46
32
+ def self.fix_encoding(str)
33
+ str.encode! Encoding::UTF_8
34
+ rescue EncodingError
35
+ str = str.force_encoding(Encoding::UTF_8)
36
+ return str.scrub('�') if str.respond_to? :scrub # b/c it's not implemented on 1.9.3
37
+ str.each_char.inject("") do |new_str, char|
38
+ if char.valid_encoding?
39
+ new_str << char
40
+ else
41
+ new_str << '�'
42
+ end
43
+ end
44
+ end
11
45
 
12
46
  def initialize(streams)
13
- self.finished_threads = []
14
- self.queue = Queue.new
15
- self.event_stream = streams.fetch :events
16
- stdout_stream = streams.fetch :stdout
17
- stderr_stream = streams.fetch :stderr
18
-
19
- self.stdout_thread = Thread.new do
20
- stdout_stream.each_line { |line| queue << Events::Stdout.new(line) }
21
- queue << :stdout_thread_finished
47
+ self.finish_criteria = FinishCriteria.new
48
+ self.queue = Queue.new
49
+ event_stream = streams.fetch :events
50
+ stdout_stream = streams.fetch :stdout
51
+ stderr_stream = streams.fetch :stderr
52
+
53
+ Thread.new do
54
+ begin
55
+ stdout_stream.each_line { |line| queue << Events::Stdout.new(value: line) }
56
+ queue << Events::StdoutClosed.new(side: :producer)
57
+ rescue IOError
58
+ queue << Events::StdoutClosed.new(side: :consumer)
59
+ ensure
60
+ queue << lambda { finish_criteria.stdout_thread_finished! }
61
+ end
22
62
  end
23
63
 
24
- self.stderr_thread = Thread.new do
25
- stderr_stream.each_line { |line| queue << Events::Stderr.new(line) }
26
- queue << :stderr_thread_finished
64
+ Thread.new do
65
+ begin
66
+ stderr_stream.each_line { |line| queue << Events::Stderr.new(value: line) }
67
+ queue << Events::StderrClosed.new(side: :producer)
68
+ rescue IOError
69
+ queue << Events::StderrClosed.new(side: :consumer)
70
+ ensure
71
+ queue << lambda { finish_criteria.stderr_thread_finished! }
72
+ end
27
73
  end
28
74
 
29
- self.event_thread = Thread.new do
30
- begin loop do
31
- break unless line = event_stream.gets
32
- event = event_for line
33
- queue << event
34
- end
35
- rescue IOError; queue << WtfWhoClosedMyShit.new("Our end of the pipe was closed!")
36
- rescue SeeingIsBelievingError; queue << $!
37
- ensure queue << :event_thread_finished
75
+ Thread.new do
76
+ begin
77
+ event_stream.each_line { |line| queue << line }
78
+ queue << Events::EventStreamClosed.new(side: :producer)
79
+ rescue IOError
80
+ queue << Events::EventStreamClosed.new(side: :consumer)
81
+ ensure
82
+ queue << lambda { finish_criteria.event_thread_finished! }
38
83
  end
39
84
  end
40
85
  end
@@ -46,42 +91,54 @@ class SeeingIsBelieving
46
91
 
47
92
  def each
48
93
  return to_enum :each unless block_given?
49
- loop { yield call(1) }
50
- rescue NoMoreInput
94
+ yield call 1 until @finished
95
+ end
96
+
97
+ # NOTE: Note it's probably a bad plan to call this method
98
+ # from within the same thread as the consumer, because if it
99
+ # blocks, who will remove items from the queue?
100
+ def process_exitstatus(status)
101
+ queue << Events::Exitstatus.new(value: status)
102
+ queue << lambda {
103
+ finish_criteria.process_exited!
104
+ }
51
105
  end
52
106
 
53
107
  private
54
108
 
55
- attr_accessor :queue, :event_stream, :finished_threads
56
- attr_accessor :event_thread, :stdout_thread, :stderr_thread
109
+ attr_accessor :queue, :finish_criteria
57
110
 
58
111
  def next_event
59
- raise NoMoreInput if @no_more_input
60
-
61
- case event = queue.shift
62
- when Symbol
63
- @no_more_input = true if finished_threads.push(event).size == 3
112
+ raise NoMoreEvents if @finished
113
+ case element = queue.shift
114
+ when String
115
+ event_for element
116
+ when Proc
117
+ element.call
118
+ if finish_criteria.satisfied?
119
+ queue << Events::Finished.new
120
+ end
64
121
  next_event
65
- when SeeingIsBelievingError
66
- raise event
122
+ when Events::Finished
123
+ @finished = true
124
+ element
125
+ when Event
126
+ element
67
127
  else
68
- event
128
+ p "WAT: #{element.inspect}"
69
129
  end
70
130
  end
71
131
 
72
132
  def extract_token(line)
73
133
  event_name = line[/[^ ]+/]
74
- line.sub! /^\s*[^ ]+\s*/, ''
134
+ line.sub!(/^\s*[^ ]+\s*/, '')
75
135
  event_name
76
136
  end
77
137
 
78
- # for a consideration of many different ways of doing this, see 5633064
138
+ # For a consideration of many different ways of passing the message, see 5633064
79
139
  def extract_string(line)
80
- Marshal.load extract_token(line).unpack('m0').first
81
- end
82
-
83
- def tokenize(line)
84
- line.split(' ')
140
+ str = Marshal.load extract_token(line).unpack('m0').first
141
+ Consumer.fix_encoding(str)
85
142
  end
86
143
 
87
144
  def event_for(original_line)
@@ -92,38 +149,31 @@ class SeeingIsBelieving
92
149
  line_number = extract_token(line).to_i
93
150
  type = extract_token(line).intern
94
151
  inspected = extract_string(line)
95
- Events::LineResult.new(type, line_number, inspected)
152
+ Events::LineResult.new(type: type, line_number: line_number, inspected: inspected)
96
153
  when :maxed_result
97
154
  line_number = extract_token(line).to_i
98
155
  type = extract_token(line).intern
99
- Events::UnrecordedResult.new(type, line_number)
156
+ Events::ResultsTruncated.new(type: type, line_number: line_number)
100
157
  when :exception
101
- Events::Exception.new(-1, '', '', []).tap do |exception|
102
- loop do
103
- line = event_stream.gets.chomp
104
- case extract_token(line).intern
105
- when :line_number then exception.line_number = extract_token(line).to_i
106
- when :class_name then exception.class_name = extract_string(line)
107
- when :message then exception.message = extract_string(line)
108
- when :backtrace then exception.backtrace << extract_string(line)
109
- when :end then break
110
- end
111
- end
112
- end
158
+ Events::Exception.new \
159
+ line_number: extract_token(line).to_i,
160
+ class_name: extract_string(line),
161
+ message: extract_string(line),
162
+ backtrace: extract_token(line).to_i.times.map { extract_string line }
113
163
  when :max_line_captures
114
164
  token = extract_token(line)
115
165
  value = token =~ /infinity/i ? Float::INFINITY : token.to_i
116
- Events::MaxLineCaptures.new(value)
117
- when :exitstatus
118
- Events::Exitstatus.new(extract_token(line).to_i)
166
+ Events::MaxLineCaptures.new(value: value)
119
167
  when :num_lines
120
- Events::NumLines.new(extract_token(line).to_i)
168
+ Events::NumLines.new(value: extract_token(line).to_i)
121
169
  when :sib_version
122
- Events::SiBVersion.new(extract_string line)
170
+ Events::SiBVersion.new(value: extract_string(line))
123
171
  when :ruby_version
124
- Events::RubyVersion.new(extract_string line)
172
+ Events::RubyVersion.new(value: extract_string(line))
125
173
  when :filename
126
- Events::Filename.new(extract_string line)
174
+ Events::Filename.new(value: extract_string(line))
175
+ when :exec
176
+ Events::Exec.new(args: extract_string(line))
127
177
  else
128
178
  raise UnknownEvent, original_line.inspect
129
179
  end