seeing_is_believing 3.6.1 → 4.0.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/.travis.yml +2 -5
- data/Rakefile +2 -0
- data/Readme.md +1 -1
- data/appveyor.yml +3 -5
- data/features/regression.feature +7 -0
- data/features/xmpfilter-style.feature +1 -0
- data/lib/seeing_is_believing.rb +2 -1
- data/lib/seeing_is_believing/binary.rb +1 -1
- data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +1 -0
- data/lib/seeing_is_believing/binary/comment_lines.rb +1 -1
- data/lib/seeing_is_believing/binary/commentable_lines.rb +7 -7
- data/lib/seeing_is_believing/binary/config.rb +1 -3
- data/lib/seeing_is_believing/binary/remove_annotations.rb +1 -1
- data/lib/seeing_is_believing/code.rb +3 -3
- data/lib/seeing_is_believing/evaluate_by_moving_files.rb +30 -32
- data/lib/seeing_is_believing/event_stream/consumer.rb +2 -0
- data/lib/seeing_is_believing/event_stream/events.rb +7 -0
- data/lib/seeing_is_believing/event_stream/handlers/record_exit_events.rb +3 -3
- data/lib/seeing_is_believing/event_stream/handlers/update_result.rb +2 -1
- data/lib/seeing_is_believing/event_stream/producer.rb +14 -0
- data/lib/seeing_is_believing/safe.rb +1 -7
- data/lib/seeing_is_believing/swap_files.rb +90 -0
- data/lib/seeing_is_believing/the_matrix.rb +17 -4
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/wrap_expressions.rb +22 -8
- data/lib/seeing_is_believing/wrap_expressions_with_inspect.rb +3 -0
- data/seeing_is_believing.gemspec +4 -5
- data/spec/binary/config_spec.rb +2 -2
- data/spec/evaluate_by_moving_files_spec.rb +18 -17
- data/spec/event_stream_spec.rb +1 -0
- data/spec/seeing_is_believing_spec.rb +99 -24
- data/spec/sib_spec_helpers/version.rb +17 -0
- data/spec/spec_helper.rb +2 -18
- data/spec/wrap_expressions_spec.rb +9 -3
- metadata +26 -12
- data/lib/seeing_is_believing/backup_file.rb +0 -50
- data/lib/seeing_is_believing/customize_pp.rb +0 -5
@@ -48,23 +48,32 @@ Kernel.module_eval do
|
|
48
48
|
private
|
49
49
|
|
50
50
|
define_method :warn do |*args, &block|
|
51
|
-
$stderr.puts
|
51
|
+
$stderr.puts(*args)
|
52
52
|
end
|
53
53
|
|
54
|
+
alias :exec :exec # disable warning
|
54
55
|
define_method :exec do |*args, &block|
|
55
56
|
$SiB.record_exec(args)
|
56
57
|
finish.call
|
57
58
|
real_exec.call(*args, &block)
|
58
59
|
end
|
59
60
|
|
61
|
+
alias :exit! :exit! # disable warning
|
60
62
|
define_method :exit! do |status=false|
|
61
63
|
finish.call
|
62
64
|
real_exit_bang.call(status)
|
63
65
|
end
|
64
66
|
|
67
|
+
alias :fork :fork
|
65
68
|
define_method :fork, &fork_defn
|
66
69
|
end
|
67
70
|
|
71
|
+
module Process
|
72
|
+
class << self
|
73
|
+
alias :fork :fork
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
68
77
|
Kernel.define_singleton_method :fork, &fork_defn
|
69
78
|
Process.define_singleton_method :fork, &fork_defn
|
70
79
|
|
@@ -74,10 +83,14 @@ symbol_to_s = Symbol.instance_method(:to_s)
|
|
74
83
|
exception_message = Exception.instance_method(:message)
|
75
84
|
exception_backtrace = Exception.instance_method(:backtrace)
|
76
85
|
|
86
|
+
# Guarding against hostile users (e.g. me) that do ridiculous things like blowing away these constants
|
87
|
+
exception_class = Exception
|
88
|
+
symbol_class = Symbol
|
89
|
+
|
77
90
|
at_exit do
|
78
|
-
|
79
|
-
|
80
|
-
|
91
|
+
exception_class.class_eval { define_method :message, exception_message }
|
92
|
+
exception_class.class_eval { define_method :backtrace, exception_backtrace }
|
93
|
+
symbol_class.class_eval { define_method :to_s, symbol_to_s }
|
81
94
|
exitstatus = ($! ? $SiB.record_exception(nil, $!) : 0)
|
82
95
|
finish.call
|
83
96
|
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)
|
@@ -25,7 +25,7 @@ class SeeingIsBelieving
|
|
25
25
|
|
26
26
|
wrappings = wrappings().sort_by(&:first)
|
27
27
|
|
28
|
-
wrappings.each do |line_num, (range,
|
28
|
+
wrappings.each do |line_num, (range, _last_col, meta)|
|
29
29
|
case meta
|
30
30
|
when :total_fucking_failure
|
31
31
|
rewriter.replace range, '.....TOTAL FUCKING FAILURE!.....'
|
@@ -34,11 +34,11 @@ class SeeingIsBelieving
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
wrappings.each do |line_num, (range,
|
37
|
+
wrappings.each do |line_num, (range, _last_col, _meta)|
|
38
38
|
rewriter.insert_before range, before_each.call(line_num)
|
39
39
|
end
|
40
40
|
|
41
|
-
wrappings.each do |line_num, (range,
|
41
|
+
wrappings.each do |line_num, (range, _last_col, _meta)|
|
42
42
|
rewriter.insert_after range, after_each.call(line_num)
|
43
43
|
end
|
44
44
|
|
@@ -53,8 +53,13 @@ class SeeingIsBelieving
|
|
53
53
|
attr_accessor :before_all, :after_all, :before_each, :after_each
|
54
54
|
attr_accessor :code, :wrappings
|
55
55
|
|
56
|
-
def buffer
|
57
|
-
|
56
|
+
def buffer
|
57
|
+
code.buffer
|
58
|
+
end
|
59
|
+
|
60
|
+
def rewriter
|
61
|
+
code.rewriter
|
62
|
+
end
|
58
63
|
|
59
64
|
def root_range
|
60
65
|
code.root.location.expression
|
@@ -107,7 +112,10 @@ class SeeingIsBelieving
|
|
107
112
|
when :defs, :module
|
108
113
|
add_to_wrappings ast
|
109
114
|
add_children ast, true
|
110
|
-
when :
|
115
|
+
when :ensure, :return, :break, :next, :splat, :kwsplat
|
116
|
+
add_children ast
|
117
|
+
when :rescue
|
118
|
+
add_to_wrappings ast if inline_rescue? ast
|
111
119
|
add_children ast
|
112
120
|
when :class
|
113
121
|
name, * = ast.children
|
@@ -135,8 +143,8 @@ class SeeingIsBelieving
|
|
135
143
|
add_to_wrappings ast
|
136
144
|
the_begin = ast.location.begin
|
137
145
|
if !the_begin
|
138
|
-
#
|
139
|
-
|
146
|
+
# a = 1,2,3
|
147
|
+
add_children ast
|
140
148
|
elsif the_begin.source !~ /\A%/
|
141
149
|
# normal array
|
142
150
|
add_children ast
|
@@ -247,5 +255,11 @@ class SeeingIsBelieving
|
|
247
255
|
add_children ast
|
248
256
|
end
|
249
257
|
end
|
258
|
+
|
259
|
+
def inline_rescue?(ast)
|
260
|
+
primary_code, rescue_body, _else_body = ast.children
|
261
|
+
return false unless primary_code
|
262
|
+
primary_code.loc.expression.last_line == rescue_body.loc.expression.first_line
|
263
|
+
end
|
250
264
|
end
|
251
265
|
end
|
@@ -5,6 +5,9 @@ class SeeingIsBelieving
|
|
5
5
|
# NOTE: if it received the AST, it could figure out if it needs
|
6
6
|
# to always wrap the expression in parentheses
|
7
7
|
WrapExpressions.call program,
|
8
|
+
before_all: -> {
|
9
|
+
"BEGIN { $SiB.file_loaded };"
|
10
|
+
},
|
8
11
|
before_each: -> line_number {
|
9
12
|
"$SiB.record_result(:inspect, #{line_number}, ("
|
10
13
|
},
|
data/seeing_is_believing.gemspec
CHANGED
@@ -12,19 +12,18 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = %q{Records the results of every line of code in your file (intended to be like xmpfilter), inspired by Bret Victor's JavaScript example in his talk "Inventing on Principle"}
|
13
13
|
s.license = "WTFPL"
|
14
14
|
|
15
|
-
s.rubyforge_project = "seeing_is_believing"
|
16
|
-
|
17
15
|
s.files = `git ls-files`.split("\n") - ['docs/seeing is believing.psd'] # remove psd b/c it boosts the gem size from 50kb to 20mb O.o
|
18
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
18
|
s.require_paths = ["lib"]
|
21
19
|
|
22
|
-
s.add_dependency "parser", "~> 2.
|
23
|
-
s.add_dependency "childprocess","~> 0.
|
20
|
+
s.add_dependency "parser", "~> 2.7.0"
|
21
|
+
s.add_dependency "childprocess","~> 3.0.0"
|
22
|
+
s.add_dependency "ffi", "~> 1.11.1"
|
24
23
|
|
25
24
|
s.add_development_dependency "pry"
|
26
25
|
s.add_development_dependency "haiti", ">= 0.1", "< 0.3"
|
27
|
-
s.add_development_dependency "rake", "~>
|
26
|
+
s.add_development_dependency "rake", "~> 13.0.0"
|
28
27
|
s.add_development_dependency "mrspec", "~> 0.3.1"
|
29
28
|
s.add_development_dependency "rspec", "~> 3.6.0"
|
30
29
|
s.add_development_dependency "cucumber", "~> 2.4"
|
data/spec/binary/config_spec.rb
CHANGED
@@ -257,8 +257,8 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
257
257
|
expect(parse([]).lib_options.require_files).to eq [matrix_file]
|
258
258
|
end
|
259
259
|
|
260
|
-
it 'appends pp
|
261
|
-
expect(parse(['-x']).lib_options.require_files).to eq [matrix_file, 'pp'
|
260
|
+
it 'appends pp for xmpfilter style' do
|
261
|
+
expect(parse(['-x']).lib_options.require_files).to eq [matrix_file, 'pp']
|
262
262
|
end
|
263
263
|
|
264
264
|
specify '-r and --require set an error if not provided with a filename' do
|
@@ -23,32 +23,32 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
23
23
|
def invoke(program, options={})
|
24
24
|
result = SeeingIsBelieving::Result.new
|
25
25
|
options[:event_handler] ||= SeeingIsBelieving::EventStream::Handlers::UpdateResult.new(result)
|
26
|
-
evaluator = described_class.new(program,
|
27
|
-
FileUtils.rm_f evaluator.
|
26
|
+
evaluator = described_class.new(filename, program, program, options)
|
27
|
+
FileUtils.rm_f evaluator.backup_path
|
28
28
|
evaluator.call
|
29
29
|
result
|
30
30
|
end
|
31
31
|
|
32
|
-
it 'evaluates the code
|
32
|
+
it 'evaluates the code as the given file' do
|
33
|
+
expect(invoke('print __FILE__').stdout).to eq filename
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'evaluates the code when the given file DNE' do
|
33
37
|
FileUtils.rm_f filename
|
34
38
|
expect(invoke('print 1').stdout).to eq '1'
|
35
39
|
end
|
36
40
|
|
37
|
-
it 'evaluates the code when the file Exists' do
|
41
|
+
it 'evaluates the code when the given file Exists' do
|
38
42
|
FileUtils.touch filename
|
39
43
|
expect(invoke('print 1').stdout).to eq '1'
|
40
44
|
end
|
41
45
|
|
42
46
|
it 'raises an error when the temp file already exists' do
|
43
|
-
evaluator = described_class.new('',
|
44
|
-
FileUtils.touch evaluator.
|
47
|
+
evaluator = described_class.new(filename, '', '', null_options)
|
48
|
+
FileUtils.touch evaluator.backup_path
|
45
49
|
expect { evaluator.call }.to raise_error SeeingIsBelieving::TempFileAlreadyExists
|
46
50
|
end
|
47
51
|
|
48
|
-
it 'evaluates the code as the given file' do
|
49
|
-
expect(invoke('print __FILE__').stdout).to eq filename
|
50
|
-
end
|
51
|
-
|
52
52
|
it 'does not change the original file' do
|
53
53
|
File.open(filename, 'w') { |f| f.write "ORIGINAL" }
|
54
54
|
invoke '1 + 1'
|
@@ -56,29 +56,29 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'uses HardCoreEnsure to move the file back' do
|
59
|
-
evaluator = described_class.new 'PROGRAM',
|
59
|
+
evaluator = described_class.new filename, 'PROGRAM', 'PROGRAM', null_options
|
60
60
|
File.open(filename, 'w') { |f| f.write 'ORIGINAL' }
|
61
|
-
FileUtils.rm_rf evaluator.
|
61
|
+
FileUtils.rm_rf evaluator.backup_path
|
62
62
|
expect(SeeingIsBelieving::HardCoreEnsure).to receive(:call) do |options|
|
63
63
|
# initial state
|
64
|
-
expect(File.exist? evaluator.
|
64
|
+
expect(File.exist? evaluator.backup_path).to eq false
|
65
65
|
expect(File.read filename).to eq 'ORIGINAL'
|
66
66
|
|
67
67
|
# after code
|
68
68
|
options[:code].call rescue nil
|
69
|
-
expect(File.read evaluator.
|
69
|
+
expect(File.read evaluator.backup_path).to eq 'ORIGINAL'
|
70
70
|
expect(File.read filename).to eq 'PROGRAM'
|
71
71
|
|
72
72
|
# after ensure
|
73
73
|
options[:ensure].call
|
74
74
|
expect(File.read filename).to eq 'ORIGINAL'
|
75
|
-
expect(File.exist? evaluator.
|
75
|
+
expect(File.exist? evaluator.backup_path).to eq false
|
76
76
|
end
|
77
77
|
evaluator.call
|
78
78
|
end
|
79
79
|
|
80
80
|
it 'uses HardCoreEnsure to delete the file if it wrote it where one did not previously exist' do
|
81
|
-
evaluator = described_class.new 'PROGRAM',
|
81
|
+
evaluator = described_class.new filename, 'PROGRAM', 'PROGRAM', null_options
|
82
82
|
FileUtils.rm_rf filename
|
83
83
|
expect(SeeingIsBelieving::HardCoreEnsure).to receive(:call) do |options|
|
84
84
|
# initial state
|
@@ -149,7 +149,7 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
149
149
|
|
150
150
|
it 'must provide an event handler, which receives the process\'s events' do
|
151
151
|
# raises error
|
152
|
-
expect { described_class.new("",
|
152
|
+
expect { described_class.new(filename, "", "", {}) }
|
153
153
|
.to raise_error ArgumentError, /event_handler/
|
154
154
|
|
155
155
|
# sees all the events
|
@@ -164,6 +164,7 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
164
164
|
result = invoke <<-RUBY, timeout_seconds: 0.5
|
165
165
|
child_pid = spawn 'ruby', '-e', 'sleep' # child makes a grandchild which sleeps
|
166
166
|
puts Process.pid, child_pid # print ids so we can check they got killed
|
167
|
+
$stdout.flush
|
167
168
|
sleep # child sleeps
|
168
169
|
RUBY
|
169
170
|
post = Time.now
|
data/spec/event_stream_spec.rb
CHANGED
@@ -664,6 +664,7 @@ module SeeingIsBelieving::EventStream
|
|
664
664
|
[Events::StderrClosed , :stderr_closed],
|
665
665
|
[Events::EventStreamClosed, :event_stream_closed],
|
666
666
|
[Events::Finished , :finished],
|
667
|
+
[Events::FileLoaded , :file_loaded],
|
667
668
|
]
|
668
669
|
pairs.each { |klass, name| expect(klass.event_name).to eq name }
|
669
670
|
|
@@ -251,8 +251,8 @@ RSpec.describe SeeingIsBelieving do
|
|
251
251
|
# Currently we dont' differentiate between inline and multiline if statements,
|
252
252
|
# also, we can't wrap the whole statement since it's void value, which means we'd have to introduce
|
253
253
|
# the idea of multiple wrappings for the same line, which I just don't care enough about to consider
|
254
|
-
expect(values_for("def meth \n return 1 if true \n end \n meth")).to eq [[], ['1'], [], ['1']] # records true instead of 1
|
255
|
-
expect(values_for("def meth \n return 1 if false \n end \n meth")).to eq [[], ['nil'], [], ['nil']] # records false instead of nil
|
254
|
+
expect(values_for("def meth \n return 1 if true \n end \n meth")).to eq [[], ['1'], [':meth'], ['1']] # records true instead of 1
|
255
|
+
expect(values_for("def meth \n return 1 if false \n end \n meth")).to eq [[], ['nil'], [':meth'], ['nil']] # records false instead of nil
|
256
256
|
end
|
257
257
|
|
258
258
|
it 'does not try to record the keyword next' do
|
@@ -557,7 +557,7 @@ RSpec.describe SeeingIsBelieving do
|
|
557
557
|
it 'sees refined inspect (#128)' do
|
558
558
|
result = invoke <<-RUBY
|
559
559
|
module BinMeUp
|
560
|
-
refine
|
560
|
+
refine Integer do
|
561
561
|
def inspect
|
562
562
|
"%08b" % self
|
563
563
|
end
|
@@ -569,10 +569,6 @@ RSpec.describe SeeingIsBelieving do
|
|
569
569
|
expect(result[9]).to eq ['00000101']
|
570
570
|
end
|
571
571
|
|
572
|
-
it 'works when the exception does not have a backtrace (#134)' do
|
573
|
-
|
574
|
-
end
|
575
|
-
|
576
572
|
it 'respects timeout, even when children do semi-ridiculous things, it cleans up children rather than orphaning them' do
|
577
573
|
pre = Time.now
|
578
574
|
result = invoke <<-CHILD, timeout_seconds: 0.5
|
@@ -654,6 +650,18 @@ RSpec.describe SeeingIsBelieving do
|
|
654
650
|
end
|
655
651
|
end
|
656
652
|
|
653
|
+
# Okay, doesn't totally belong here, b/c there could be another implementation which doesn't overwrite files,
|
654
|
+
# but it requires coordination between the rewritten code and the evaluator, so isn't really an evaluator unit test,
|
655
|
+
# so putting this here.
|
656
|
+
context 'cleaning up files' do
|
657
|
+
it 'replaces the rewritten source with the original source as soon as it sees a result' do
|
658
|
+
program = "sleep 0.01 while File.read(__FILE__).include?('RECORD_RESULT'.downcase); File.read __FILE__\n"
|
659
|
+
result = invoke program
|
660
|
+
expect(result[1]).to eq [program.inspect]
|
661
|
+
expect(File.exist? result.filename).to eq false
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
657
665
|
|
658
666
|
context 'when given a debugger' do
|
659
667
|
let(:stream) { StringIO.new }
|
@@ -823,23 +831,19 @@ RSpec.describe SeeingIsBelieving do
|
|
823
831
|
').stderr).to eq ''
|
824
832
|
end
|
825
833
|
|
826
|
-
specify 'when
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
expect(result.stderr).to eq ''
|
840
|
-
expect(result.exitstatus).to eq 0
|
841
|
-
expect(result.to_a.last).to eq ['"a"']
|
842
|
-
end
|
834
|
+
specify 'when Integer does not have <, <<, next, ==, inspect, to_s' do
|
835
|
+
result = invoke('class Integer
|
836
|
+
undef <
|
837
|
+
undef <<
|
838
|
+
undef ==
|
839
|
+
undef next
|
840
|
+
undef to_s
|
841
|
+
undef inspect
|
842
|
+
end
|
843
|
+
"a"')
|
844
|
+
expect(result.stderr).to eq ''
|
845
|
+
expect(result.exitstatus).to eq 0
|
846
|
+
expect(result.to_a.last).to eq ['"a"']
|
843
847
|
end
|
844
848
|
|
845
849
|
specify 'when Integer does not have <, <<, next, ==, inspect, to_s' do
|
@@ -1015,5 +1019,76 @@ RSpec.describe SeeingIsBelieving do
|
|
1015
1019
|
end
|
1016
1020
|
').stderr).to eq ''
|
1017
1021
|
end
|
1022
|
+
|
1023
|
+
def executes_without_error!(code)
|
1024
|
+
result = invoke(code)
|
1025
|
+
expect(result.stderr).to eq ''
|
1026
|
+
begin
|
1027
|
+
expect(result).to_not have_exception, result.exception.pretty_inspect
|
1028
|
+
rescue NoMethodError
|
1029
|
+
require 'pp'
|
1030
|
+
retry
|
1031
|
+
end
|
1032
|
+
result
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
specify 'when constants are reassigned' do
|
1036
|
+
result = executes_without_error!('
|
1037
|
+
# producer
|
1038
|
+
Hash = "fake Hash"
|
1039
|
+
String = "fake String"
|
1040
|
+
class << String
|
1041
|
+
undef ===
|
1042
|
+
end
|
1043
|
+
Exception = "fake Exception"
|
1044
|
+
|
1045
|
+
kernel = Kernel
|
1046
|
+
Kernel = "fake Kernel"
|
1047
|
+
SystemExit = "fake SystemExit"
|
1048
|
+
NoMethodError = "fake NoMethodError"
|
1049
|
+
Marshal = "fake Marshal"
|
1050
|
+
TypeError = "fake TypeError"
|
1051
|
+
|
1052
|
+
# only matter when forking
|
1053
|
+
Thread = "fake Thread"
|
1054
|
+
IOError = "fake IOError"
|
1055
|
+
Errno::EPIPE = "fake Errno::EPIPE" # we don\'t actually put it in a situation to hit this
|
1056
|
+
Errno = "fake Errno"
|
1057
|
+
|
1058
|
+
# the matrix
|
1059
|
+
Exception = "Exception"
|
1060
|
+
Symbol = "Symbol"
|
1061
|
+
|
1062
|
+
# normal inspect
|
1063
|
+
1 + 1
|
1064
|
+
|
1065
|
+
# force it down the sad path
|
1066
|
+
obj = Object.new
|
1067
|
+
def obj.inspect
|
1068
|
+
"pass"
|
1069
|
+
end
|
1070
|
+
obj
|
1071
|
+
puts __LINE__-1 # so we know where to assert
|
1072
|
+
|
1073
|
+
NotAString = Module.new
|
1074
|
+
def obj.inspect
|
1075
|
+
NotAString
|
1076
|
+
end
|
1077
|
+
obj
|
1078
|
+
|
1079
|
+
def obj.inspect
|
1080
|
+
raise "whoops"
|
1081
|
+
end
|
1082
|
+
obj
|
1083
|
+
puts __LINE__-1 # should be replaced with Kernel#inspect
|
1084
|
+
|
1085
|
+
kernel.exit 0
|
1086
|
+
')
|
1087
|
+
|
1088
|
+
pass_str, kernel_inspect = result.stdout.lines.map(&:to_i)
|
1089
|
+
expect(result[pass_str]).to eq ['pass']
|
1090
|
+
expect(result[kernel_inspect].size).to eq 1
|
1091
|
+
expect(result[kernel_inspect][0]).to match /^#<Object/
|
1092
|
+
end
|
1018
1093
|
end
|
1019
1094
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SibSpecHelpers
|
2
|
+
class Version
|
3
|
+
attr_reader :segments
|
4
|
+
include Comparable
|
5
|
+
def initialize(version_string)
|
6
|
+
@segments = version_string.scan(/\d+/).map(&:to_i)
|
7
|
+
end
|
8
|
+
def <=>(other)
|
9
|
+
other = Version.new other unless other.kind_of? Version
|
10
|
+
segments.zip(other.segments).each do |ours, theirs|
|
11
|
+
return 1 if theirs.nil? || theirs < ours
|
12
|
+
return -1 if ours < theirs
|
13
|
+
end
|
14
|
+
segments.length <=> other.segments.length
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|