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.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/features/flags.feature +39 -0
- data/features/regression.feature +154 -0
- data/features/xmpfilter-style.feature +57 -0
- data/lib/seeing_is_believing/binary/annotate_every_line.rb +11 -4
- data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +11 -5
- data/lib/seeing_is_believing/binary/config.rb +9 -0
- data/lib/seeing_is_believing/binary/data_structures.rb +1 -0
- data/lib/seeing_is_believing/binary/interline_align.rb +57 -0
- data/lib/seeing_is_believing/customize_pp.rb +5 -0
- data/lib/seeing_is_believing/event_stream/consumer.rb +39 -43
- data/lib/seeing_is_believing/event_stream/producer.rb +24 -31
- data/lib/seeing_is_believing/safe.rb +93 -39
- data/lib/seeing_is_believing/the_matrix.rb +10 -10
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/wrap_expressions.rb +24 -5
- data/spec/binary/config_spec.rb +17 -2
- data/spec/event_stream_spec.rb +1 -0
- data/spec/seeing_is_believing_spec.rb +58 -53
- data/spec/spec_helper.rb +22 -0
- data/spec/spec_helper_spec.rb +16 -0
- data/spec/wrap_expressions_spec.rb +35 -0
- metadata +7 -3
@@ -56,15 +56,7 @@ class SeeingIsBelieving
|
|
56
56
|
rescue EncodingError
|
57
57
|
str = str.force_encoding(Encoding::UTF_8)
|
58
58
|
end
|
59
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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 '
|
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
|
-
|
11
|
-
|
12
|
-
|
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 =
|
24
|
-
self.producer_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] ||=
|
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 <<
|
81
|
+
queue << [
|
85
82
|
"exception",
|
86
|
-
|
83
|
+
line_number.to_s,
|
87
84
|
to_string_token(exception.class.name),
|
88
85
|
to_string_token(exception.message),
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
-
|
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
|
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 =
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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 =
|
16
|
-
stderr = SeeingIsBelieving::Safe::Stream[STDERR]
|
17
|
+
stdout, stderr = STDOUT, STDERR
|
17
18
|
|
18
19
|
finish = lambda do
|
19
20
|
$SiB.finish!
|
20
|
-
|
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
|
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
|
-
|
63
|
+
exception_backtrace = Exception.instance_method(:backtrace)
|
63
64
|
|
64
65
|
at_exit do
|
65
|
-
|
66
|
-
|
67
|
-
|
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)
|
@@ -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
|
-
|
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, :
|
229
|
+
when :regexp, :dstr, :xstr, :dsym
|
209
230
|
add_to_wrappings ast
|
210
|
-
ast
|
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
|