seeing_is_believing 3.0.1 → 3.1.0

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.
@@ -0,0 +1,5 @@
1
+ class String
2
+ def pretty_print(pp)
3
+ pp.text inspect.gsub(/\\n(?!")/, '\n" +'+"\n"+'"')
4
+ end
5
+ end
@@ -56,15 +56,7 @@ class SeeingIsBelieving
56
56
  rescue EncodingError
57
57
  str = str.force_encoding(Encoding::UTF_8)
58
58
  end
59
- return str.scrub('�') if str.respond_to? :scrub
60
- # basically reimplement scrub, b/c it's not implemented on 1.9.3
61
- str.each_char.inject("") do |new_str, char|
62
- if char.valid_encoding?
63
- new_str << char
64
- else
65
- new_str << '�'
66
- end
67
- end
59
+ str.scrub '�'
68
60
  end
69
61
 
70
62
  def initialize(streams)
@@ -74,39 +66,40 @@ class SeeingIsBelieving
74
66
  event_stream = streams.fetch :events
75
67
  stdout_stream = streams.fetch :stdout
76
68
  stderr_stream = streams.fetch :stderr
77
-
78
- Thread.new do
79
- begin
80
- stdout_stream.each_line { |line| queue << Events::Stdout.new(value: line) }
81
- queue << Events::StdoutClosed.new(side: :producer)
82
- rescue IOError
83
- queue << Events::StdoutClosed.new(side: :consumer)
84
- ensure
85
- queue << lambda { finish_criteria.stdout_thread_finished! }
86
- end
87
- end
88
-
89
- Thread.new do
90
- begin
91
- stderr_stream.each_line { |line| queue << Events::Stderr.new(value: line) }
92
- queue << Events::StderrClosed.new(side: :producer)
93
- rescue IOError
94
- queue << Events::StderrClosed.new(side: :consumer)
95
- ensure
96
- queue << lambda { finish_criteria.stderr_thread_finished! }
97
- end
98
- end
99
-
100
- Thread.new do
101
- begin
102
- event_stream.each_line { |line| queue << line }
103
- queue << Events::EventStreamClosed.new(side: :producer)
104
- rescue IOError
105
- queue << Events::EventStreamClosed.new(side: :consumer)
106
- ensure
107
- queue << lambda { finish_criteria.event_thread_finished! }
108
- end
109
- end
69
+ self.threads = [
70
+ Thread.new do
71
+ begin
72
+ stdout_stream.each_line { |line| queue << Events::Stdout.new(value: line) }
73
+ queue << Events::StdoutClosed.new(side: :producer)
74
+ rescue IOError
75
+ queue << Events::StdoutClosed.new(side: :consumer)
76
+ ensure
77
+ queue << lambda { finish_criteria.stdout_thread_finished! }
78
+ end
79
+ end,
80
+
81
+ Thread.new do
82
+ begin
83
+ stderr_stream.each_line { |line| queue << Events::Stderr.new(value: line) }
84
+ queue << Events::StderrClosed.new(side: :producer)
85
+ rescue IOError
86
+ queue << Events::StderrClosed.new(side: :consumer)
87
+ ensure
88
+ queue << lambda { finish_criteria.stderr_thread_finished! }
89
+ end
90
+ end,
91
+
92
+ Thread.new do
93
+ begin
94
+ event_stream.each_line { |line| queue << line }
95
+ queue << Events::EventStreamClosed.new(side: :producer)
96
+ rescue IOError
97
+ queue << Events::EventStreamClosed.new(side: :consumer)
98
+ ensure
99
+ queue << lambda { finish_criteria.event_thread_finished! }
100
+ end
101
+ end,
102
+ ]
110
103
  end
111
104
 
112
105
  def call(n=1)
@@ -135,10 +128,13 @@ class SeeingIsBelieving
135
128
  }
136
129
  end
137
130
 
131
+ def join
132
+ threads.each(&:join)
133
+ end
138
134
 
139
135
  private
140
136
 
141
- attr_accessor :queue, :finish_criteria
137
+ attr_accessor :queue, :finish_criteria, :threads
142
138
 
143
139
  def next_event
144
140
  raise NoMoreEvents if @finished
@@ -1,29 +1,27 @@
1
- require 'seeing_is_believing/event_stream/events'
2
1
  require 'seeing_is_believing/safe'
3
- require 'thread'
2
+ require 'seeing_is_believing/event_stream/events'
3
+ require 'thread' # <-- do we still need this?
4
+
5
+ using SeeingIsBelieving::Safe
4
6
 
5
7
  class SeeingIsBelieving
6
8
  module EventStream
7
9
  class Producer
8
10
  module NullQueue
9
11
  extend self
10
- def <<(*) end
11
- def shift() end
12
- # TODO: this one doesn't have clear, but we can call that on the real one.
13
- # find a way to test this situation?
12
+ Queue.instance_methods.each do |name|
13
+ define_method(name) { |*| }
14
+ end
14
15
  end
15
16
 
16
17
  attr_accessor :max_line_captures, :filename
17
18
 
18
19
  def initialize(resultstream)
19
- resultstream = Safe::Stream[resultstream]
20
20
  self.filename = nil
21
21
  self.max_line_captures = Float::INFINITY
22
22
  self.recorded_results = []
23
- self.queue = Safe::Queue[Queue.new]
24
- self.producer_thread = Safe::Thread[
25
- build_producer_thread(resultstream)
26
- ]
23
+ self.queue = Queue.new
24
+ self.producer_thread = build_producer_thread(resultstream)
27
25
  end
28
26
 
29
27
  attr_reader :version
@@ -45,7 +43,7 @@ class SeeingIsBelieving
45
43
  StackErrors = [SystemStackError]
46
44
  StackErrors << Java::JavaLang::StackOverflowError if defined?(RUBY_PLATFORM) && RUBY_PLATFORM == 'java'
47
45
  def record_result(type, line_number, value)
48
- counts = recorded_results[line_number] ||= Safe::Hash.new(0)
46
+ counts = recorded_results[line_number] ||= Hash.new(0)
49
47
  count = counts[type]
50
48
  recorded_results[line_number][type] = count.next
51
49
  if count < max_line_captures
@@ -64,33 +62,30 @@ class SeeingIsBelieving
64
62
  rescue Exception
65
63
  inspected = "#<no inspect available>"
66
64
  end
67
- queue << "result #{line_number} #{type} #{to_string_token inspected}"
65
+ queue << "result #{line_number.to_s} #{type.to_s} #{to_string_token inspected}"
68
66
  elsif count == max_line_captures
69
- queue << "maxed_result #{line_number} #{type}"
67
+ queue << "maxed_result #{line_number.to_s} #{type.to_s}"
70
68
  end
71
69
  value
72
70
  end
73
71
 
74
72
  # records the exception, returns the exitstatus for that exception
75
73
  def record_exception(line_number, exception)
76
- return exception.status if SystemExit === exception
77
- exception = Safe::Exception[exception]
74
+ return exception.status if SystemExit === exception # TODO === is not in the list
78
75
  if !line_number && filename
79
- begin line_number = exception.backtrace.grep(/#{filename}/).first[/:\d+/][1..-1].to_i
76
+ begin line_number = exception.backtrace.grep(/#{filename.to_s}/).first[/:\d+/][1..-1].to_i
80
77
  rescue NoMethodError
81
78
  end
82
79
  end
83
80
  line_number ||= -1
84
- queue << Safe::Array[[
81
+ queue << [
85
82
  "exception",
86
- Safe::Fixnum[line_number],
83
+ line_number.to_s,
87
84
  to_string_token(exception.class.name),
88
85
  to_string_token(exception.message),
89
- Safe::Fixnum[
90
- Safe::Array[exception.backtrace].size
91
- ],
92
- *Safe::Array[exception.backtrace].map { |line| to_string_token line }
93
- ]].join(" ")
86
+ exception.backtrace.size.to_s,
87
+ *exception.backtrace.map { |line| to_string_token line }
88
+ ].join(" ")
94
89
  1 # exit status
95
90
  end
96
91
 
@@ -108,7 +103,7 @@ class SeeingIsBelieving
108
103
  end
109
104
 
110
105
  def finish!
111
- queue << :break # note that consumer will continue reading until stream is closed
106
+ queue << :break # note that consumer will continue reading until stream is closed, which is not the responsibility of the producer
112
107
  producer_thread.join
113
108
  end
114
109
 
@@ -118,17 +113,17 @@ class SeeingIsBelieving
118
113
 
119
114
  # for a consideration of many different ways of doing this, see 5633064
120
115
  def to_string_token(string)
121
- Safe::Array[[Safe::Marshal.dump(Safe::String[string].to_s)]].pack('m0')
116
+ [Marshal.dump(string.to_s)].pack('m0')
122
117
  end
123
118
 
124
119
  def build_producer_thread(resultstream)
125
120
  ::Thread.new {
126
- Safe::Thread.current.abort_on_exception = true
121
+ Thread.current.abort_on_exception = true
127
122
  begin
128
123
  resultstream.sync = true
129
124
  loop do
130
125
  to_publish = queue.shift
131
- break if Safe::Symbol[:break] == to_publish
126
+ break if :break == to_publish
132
127
  resultstream << (to_publish << "\n")
133
128
  end
134
129
  rescue IOError, Errno::EPIPE
@@ -147,9 +142,7 @@ class SeeingIsBelieving
147
142
  loop { break if queue.shift == :fork }
148
143
 
149
144
  # recreate the thread since forking in Ruby kills threads
150
- @producer_thread = Safe::Thread[
151
- build_producer_thread(resultstream)
152
- ]
145
+ @producer_thread = build_producer_thread(resultstream)
153
146
  end
154
147
 
155
148
  end
@@ -1,43 +1,97 @@
1
+ # require this before anything else, b/c it expects the world to be sane when it is loaded
1
2
  class SeeingIsBelieving
2
3
  module Safe
3
- def self.build(klass, *method_names)
4
- options = {}
5
- options = method_names.pop if method_names.last.kind_of? ::Hash
6
-
7
- Class.new do
8
- class << self
9
- alias [] new
10
- end
11
-
12
- define_method :initialize do |instance|
13
- @_instance = instance
14
- end
15
-
16
- methods = method_names.map { |name| [name, klass.instance_method(name)] }
17
- methods.each do |name, method|
18
- define_method(name) do |*args, &block|
19
- method.bind(@_instance).call(*args, &block)
20
- end
21
- end
22
-
23
- singleton_methods = options.fetch(:class, []).map { |name| [name, klass.method(name)] }
24
- singleton_methods.each do |name, method|
25
- define_singleton_method name do |*args, &block|
26
- method.call(*args, &block)
27
- end
28
- end
29
- end
30
- end
31
-
32
- Queue = build ::Queue, :<<, :shift, :clear
33
- Stream = build ::IO, :sync=, :<<, :flush, :close
34
- Symbol = build ::Symbol, :==, class: [:define_method]
35
- String = build ::String, :to_s
36
- Fixnum = build ::Fixnum, :to_s
37
- Array = build ::Array, :pack, :map, :size, :join
38
- Hash = build ::Hash, :[], :[]=, class: [:new]
39
- Marshal = build ::Marshal, class: [:dump]
40
- Exception = build ::Exception, :message, :backtrace, :class, class: [:define_method]
41
- Thread = build ::Thread, :join, class: [:current]
4
+ refine Class do
5
+ alias === ===
6
+ end
7
+
8
+ refine Queue do
9
+ alias << <<
10
+ alias shift shift
11
+ alias clear clear
12
+ end
13
+
14
+ refine IO do
15
+ alias sync= sync=
16
+ alias << <<
17
+ alias flush flush
18
+ alias close close
19
+ end
20
+
21
+ refine Symbol do
22
+ alias == ==
23
+ alias to_s to_s
24
+ alias inspect inspect
25
+ end
26
+
27
+ refine Symbol.singleton_class do
28
+ alias define_method define_method
29
+ alias class_eval class_eval
30
+ end
31
+
32
+ refine String do
33
+ alias == ==
34
+ alias to_s to_s
35
+ alias to_str to_str
36
+ end
37
+
38
+ refine Fixnum do
39
+ alias to_s to_s
40
+ alias next next
41
+ alias < <
42
+ end
43
+
44
+ refine Array do
45
+ alias pack pack
46
+ alias map map
47
+ alias size size
48
+ alias join join
49
+ alias [] []
50
+ alias []= []=
51
+ end
52
+
53
+ refine Hash do
54
+ alias [] []
55
+ alias []= []=
56
+ end
57
+
58
+ refine Hash.singleton_class do
59
+ alias new new
60
+ end
61
+
62
+ refine Marshal.singleton_class do
63
+ alias dump dump
64
+ end
65
+
66
+ refine Exception do
67
+ alias message message
68
+ alias backtrace backtrace
69
+ alias class class
70
+ end
71
+
72
+ refine Exception.singleton_class do
73
+ alias define_method define_method
74
+ alias class_eval class_eval
75
+ end
76
+
77
+ refine Thread do
78
+ alias join join
79
+ end
80
+
81
+ refine Thread.singleton_class do
82
+ alias current current
83
+ end
84
+
85
+ refine Method do
86
+ alias call call
87
+ end
88
+
89
+ refine Proc do
90
+ alias call call
91
+ end
92
+
93
+ refine Object do
94
+ alias block_given? block_given?
95
+ end
42
96
  end
43
97
  end
@@ -1,7 +1,9 @@
1
- require_relative 'version'
2
1
  require_relative 'safe'
2
+ require_relative 'version'
3
3
  require_relative 'event_stream/producer'
4
4
 
5
+ using SeeingIsBelieving::Safe
6
+
5
7
  sib_vars = Marshal.load ENV["SIB_VARIABLES.MARSHAL.B64"].unpack('m0').first
6
8
  event_stream = IO.open sib_vars.fetch(:event_stream_fd), "w"
7
9
  $SiB = SeeingIsBelieving::EventStream::Producer.new(event_stream)
@@ -12,12 +14,11 @@ $SiB.record_num_lines sib_vars.fetch(:num_lines)
12
14
  $SiB.record_max_line_captures sib_vars.fetch(:max_line_captures)
13
15
 
14
16
  STDOUT.sync = true
15
- stdout = SeeingIsBelieving::Safe::Stream[STDOUT]
16
- stderr = SeeingIsBelieving::Safe::Stream[STDERR]
17
+ stdout, stderr = STDOUT, STDERR
17
18
 
18
19
  finish = lambda do
19
20
  $SiB.finish!
20
- SeeingIsBelieving::Safe::Stream[event_stream].close
21
+ event_stream.close
21
22
  stdout.flush
22
23
  stderr.flush
23
24
  end
@@ -56,16 +57,15 @@ Kernel.define_singleton_method :fork, &fork_defn
56
57
  Process.define_singleton_method :fork, &fork_defn
57
58
 
58
59
 
59
- # Some things need to just be recorded and readded as they are called from Ruby C code
60
+ # Some things need to be recorded and readded as they are called from Ruby C code and it blows up in really difficult to dianose ways -.-
60
61
  symbol_to_s = Symbol.instance_method(:to_s)
61
62
  exception_message = Exception.instance_method(:message)
62
- # exception_backtrace = Exception.instance_method(:backtrace)
63
+ exception_backtrace = Exception.instance_method(:backtrace)
63
64
 
64
65
  at_exit do
65
- # SeeingIsBelieving::Safe::Exception.define_method :backtrace, exception_backtrace
66
- SeeingIsBelieving::Safe::Exception.define_method :message, exception_message
67
- SeeingIsBelieving::Safe::Symbol.define_method :to_s, symbol_to_s
68
-
66
+ Exception.class_eval { define_method :message, exception_message }
67
+ Exception.class_eval { define_method :backtrace, exception_backtrace }
68
+ Symbol.class_eval { define_method :to_s, symbol_to_s }
69
69
  exitstatus = ($! ? $SiB.record_exception(nil, $!) : 0)
70
70
  finish.call
71
71
  real_exit_bang.call(exitstatus) # clears exceptions so they don't print to stderr and change the processes actual exit status (we recorded what it should be)
@@ -1,3 +1,3 @@
1
1
  class SeeingIsBelieving
2
- VERSION = '3.0.1'
2
+ VERSION = '3.1.0'
3
3
  end
@@ -93,6 +93,12 @@ class SeeingIsBelieving
93
93
  .each { |child| wrap_recursive child }
94
94
  end
95
95
 
96
+ def add_interpolations_in(ast)
97
+ ast.children
98
+ .select { |child| child.type == :begin }
99
+ .each { |child| add_children child }
100
+ end
101
+
96
102
  def wrap_recursive(ast)
97
103
  return wrappings unless ast.kind_of? ::AST::Node
98
104
  case ast.type
@@ -128,7 +134,22 @@ class SeeingIsBelieving
128
134
  when :array
129
135
  add_to_wrappings ast
130
136
  the_begin = ast.location.begin
131
- add_children ast if the_begin && the_begin.source !~ /\A%/
137
+ if !the_begin
138
+ # uhhhh, idk, nothing seems to hit this branch (at least in its spec)
139
+ # maybe this is 'a = 1,2,3'? (I'd try it out, but have to call the folks)
140
+ elsif the_begin.source !~ /\A%/
141
+ # normal array
142
+ add_children ast
143
+ elsif the_begin.source =~ /\A%/
144
+ # array of literals
145
+
146
+ ast.children.each do |child|
147
+ t = child.type
148
+ if t == :dsym || t == :dstr
149
+ add_interpolations_in child
150
+ end
151
+ end
152
+ end
132
153
  when :block
133
154
  add_to_wrappings ast
134
155
 
@@ -205,11 +226,9 @@ class SeeingIsBelieving
205
226
  when :str
206
227
  add_to_wrappings ast
207
228
 
208
- when :dstr, :regexp
229
+ when :regexp, :dstr, :xstr, :dsym
209
230
  add_to_wrappings ast
210
- ast.children
211
- .select { |child| child.type == :begin }
212
- .each { |child| add_children child }
231
+ add_interpolations_in ast
213
232
 
214
233
  when :hash
215
234
  # method arguments might not have braces around them