ztk 0.2.5 → 0.2.6
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.
- data/lib/ztk.rb +2 -0
- data/lib/ztk/background.rb +145 -0
- data/lib/ztk/benchmark.rb +2 -2
- data/lib/ztk/command.rb +6 -5
- data/lib/ztk/logger.rb +4 -0
- data/lib/ztk/parallel.rb +1 -1
- data/lib/ztk/rescue_retry.rb +5 -3
- data/lib/ztk/spinner.rb +1 -1
- data/lib/ztk/ssh.rb +48 -12
- data/lib/ztk/tcp_socket_check.rb +1 -1
- data/lib/ztk/version.rb +1 -1
- data/spec/ztk/background_spec.rb +108 -0
- data/spec/ztk/parallel_spec.rb +4 -2
- metadata +6 -3
data/lib/ztk.rb
CHANGED
@@ -0,0 +1,145 @@
|
|
1
|
+
################################################################################
|
2
|
+
#
|
3
|
+
# Author: Zachary Patten <zachary@jovelabs.net>
|
4
|
+
# Copyright: Copyright (c) Jove Labs
|
5
|
+
# License: Apache License, VersIOn 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, VersIOn 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissIOns and
|
17
|
+
# limitatIOns under the License.
|
18
|
+
#
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
require "base64"
|
22
|
+
|
23
|
+
module ZTK
|
24
|
+
|
25
|
+
# ZTK::Background Error Class
|
26
|
+
#
|
27
|
+
# @author Zachary Patten <zachary@jovelabs.net>
|
28
|
+
class BackgroundError < Error; end
|
29
|
+
|
30
|
+
# Background Processing Class
|
31
|
+
#
|
32
|
+
# This class can be used to easily run a linear process in a background manner.
|
33
|
+
#
|
34
|
+
# a_callback = Proc.new do |pid|
|
35
|
+
# puts "Hello from After Callback - PID #{pid}"
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# b_callback = Proc.new do |pid|
|
39
|
+
# puts "Hello from Before Callback - PID #{pid}"
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# background = ZTK::Background.new
|
43
|
+
# background.config do |config|
|
44
|
+
# config.before_fork = b_callback
|
45
|
+
# config.after_fork = a_callback
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# background.process do
|
49
|
+
# x
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# background.wait
|
53
|
+
# background.result
|
54
|
+
#
|
55
|
+
# The before fork callback is called once in the parent process.
|
56
|
+
#
|
57
|
+
# The after fork callback is called twice, once in the parent process and once
|
58
|
+
# in the child process.
|
59
|
+
#
|
60
|
+
# @author Zachary Patten <zachary@jovelabs.net>
|
61
|
+
class Background < ZTK::Base
|
62
|
+
|
63
|
+
# Result Set
|
64
|
+
attr_accessor :pid, :result
|
65
|
+
|
66
|
+
# @param [Hash] config Configuration options hash.
|
67
|
+
# @option config [Integer] :max_forks Maximum number of forks to use.
|
68
|
+
# @option config [Proc] :before_fork (nil) Proc to call before forking.
|
69
|
+
# @option config [Proc] :after_fork (nil) Proc to call after forking.
|
70
|
+
def initialize(configuration={})
|
71
|
+
super({
|
72
|
+
}.merge(configuration))
|
73
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
74
|
+
|
75
|
+
@result = nil
|
76
|
+
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true
|
77
|
+
end
|
78
|
+
|
79
|
+
# Process in background.
|
80
|
+
#
|
81
|
+
# @yield Block should execute tasks to be performed in background.
|
82
|
+
# @yieldreturn [Object] Block can return any object to be marshalled back to
|
83
|
+
# the parent processes result set.
|
84
|
+
# @return [Integer] Returns the pid of the child process forked.
|
85
|
+
def process(&block)
|
86
|
+
!block_given? and log_and_raise(BackgroundError, "You must supply a block to the process method!")
|
87
|
+
|
88
|
+
@child_reader, @parent_writer = IO.pipe
|
89
|
+
@parent_reader, @child_writer = IO.pipe
|
90
|
+
|
91
|
+
config.before_fork and config.before_fork.call(Process.pid)
|
92
|
+
@pid = Process.fork do
|
93
|
+
config.after_fork and config.after_fork.call(Process.pid)
|
94
|
+
|
95
|
+
@parent_writer.close
|
96
|
+
@parent_reader.close
|
97
|
+
|
98
|
+
STDOUT.reopen("/dev/null", "a")
|
99
|
+
STDERR.reopen("/dev/null", "a")
|
100
|
+
STDIN.reopen("/dev/null")
|
101
|
+
|
102
|
+
if !(data = block.call).nil?
|
103
|
+
config.logger.debug { "write(#{data.inspect})" }
|
104
|
+
@child_writer.write(Base64.encode64(Marshal.dump(data)))
|
105
|
+
end
|
106
|
+
|
107
|
+
@child_reader.close
|
108
|
+
@child_writer.close
|
109
|
+
Process.exit!(0)
|
110
|
+
end
|
111
|
+
config.after_fork and config.after_fork.call(Process.pid)
|
112
|
+
|
113
|
+
@child_reader.close
|
114
|
+
@child_writer.close
|
115
|
+
|
116
|
+
@pid
|
117
|
+
end
|
118
|
+
|
119
|
+
# Wait for the background process to finish.
|
120
|
+
#
|
121
|
+
# If a process successfully finished, it's return value from the *process*
|
122
|
+
# block is stored into the result set.
|
123
|
+
#
|
124
|
+
# @return [Array<pid, status, data>] An array containing the pid,
|
125
|
+
# status and data returned from the process block. If wait2() fails nil
|
126
|
+
# is returned.
|
127
|
+
def wait
|
128
|
+
config.logger.debug { "wait" }
|
129
|
+
pid, status = (Process.wait2(@pid) rescue nil)
|
130
|
+
if !pid.nil? && !status.nil?
|
131
|
+
data = (Marshal.load(Base64.decode64(@parent_reader.read.to_s)) rescue nil)
|
132
|
+
config.logger.debug { "read(#{data.inspect})" }
|
133
|
+
!data.nil? and @result = data
|
134
|
+
|
135
|
+
@parent_reader.close
|
136
|
+
@parent_writer.close
|
137
|
+
|
138
|
+
return [pid, status, data]
|
139
|
+
end
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
data/lib/ztk/benchmark.rb
CHANGED
@@ -35,7 +35,7 @@ module ZTK
|
|
35
35
|
|
36
36
|
def bench(options={}, &block)
|
37
37
|
options = Base.build_config(options)
|
38
|
-
options.logger.debug { "options
|
38
|
+
options.logger.debug { "options=#{options.send(:table).inspect}" }
|
39
39
|
|
40
40
|
!block_given? and Base.log_and_raise(options.logger, BenchmarkError, "You must supply a block!")
|
41
41
|
|
@@ -54,7 +54,7 @@ module ZTK
|
|
54
54
|
end
|
55
55
|
|
56
56
|
(options.message && options.mark) and options.stdout.print("#{options.mark}\n" % benchmark)
|
57
|
-
options.logger.info { "#{options.message} #{options.mark}" }
|
57
|
+
options.logger.info { "#{options.message} #{options.mark}" % benchmark }
|
58
58
|
|
59
59
|
benchmark
|
60
60
|
end
|
data/lib/ztk/command.rb
CHANGED
@@ -44,9 +44,10 @@ module ZTK
|
|
44
44
|
|
45
45
|
def initialize(configuration={})
|
46
46
|
super({
|
47
|
-
:timeout => 600
|
47
|
+
:timeout => 600,
|
48
|
+
:ignore_exit_status => false
|
48
49
|
}.merge(configuration))
|
49
|
-
config.logger.debug { "config
|
50
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
50
51
|
end
|
51
52
|
|
52
53
|
def inspect
|
@@ -78,8 +79,8 @@ module ZTK
|
|
78
79
|
|
79
80
|
options = OpenStruct.new({ :exit_code => 0, :silence => false }.merge(options))
|
80
81
|
|
81
|
-
config.logger.debug { "config
|
82
|
-
config.logger.debug { "options
|
82
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
83
|
+
config.logger.debug { "options=#{options.send(:table).inspect}" }
|
83
84
|
config.logger.info { "command(#{command.inspect})" }
|
84
85
|
|
85
86
|
output = ""
|
@@ -167,7 +168,7 @@ module ZTK
|
|
167
168
|
|
168
169
|
config.logger.debug { "exit_code(#{exit_code})" }
|
169
170
|
|
170
|
-
if (exit_code != options.exit_code)
|
171
|
+
if !config.ignore_exit_status && (exit_code != options.exit_code)
|
171
172
|
log_and_raise(CommandError, "exec(#{command.inspect}, #{options.inspect}) failed! [#{exit_code}]")
|
172
173
|
end
|
173
174
|
OpenStruct.new(:output => output, :exit_code => exit_code)
|
data/lib/ztk/logger.rb
CHANGED
data/lib/ztk/parallel.rb
CHANGED
@@ -80,7 +80,7 @@ module ZTK
|
|
80
80
|
super({
|
81
81
|
:max_forks => MAX_FORKS
|
82
82
|
}.merge(configuration))
|
83
|
-
config.logger.debug { "config
|
83
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
84
84
|
|
85
85
|
(config.max_forks < 1) and log_and_raise(ParallelError, "max_forks must be equal to or greater than one!")
|
86
86
|
|
data/lib/ztk/rescue_retry.rb
CHANGED
@@ -34,9 +34,10 @@ module ZTK
|
|
34
34
|
def try(options={}, &block)
|
35
35
|
options = Base.build_config({
|
36
36
|
:tries => 1,
|
37
|
-
:on => Exception
|
37
|
+
:on => Exception,
|
38
|
+
:delay => 1
|
38
39
|
}.merge(options))
|
39
|
-
options.logger.debug { "options
|
40
|
+
options.logger.debug { "options=#{options.send(:table).inspect}" }
|
40
41
|
|
41
42
|
!block_given? and Base.log_and_raise(options.logger, RescueRetryError, "You must supply a block!")
|
42
43
|
|
@@ -45,9 +46,10 @@ module ZTK
|
|
45
46
|
rescue options.on => e
|
46
47
|
if ((options.tries -= 1) > 0)
|
47
48
|
options.logger.warn { "Caught #{e.inspect}, we will give it #{options.tries} more tr#{options.tries > 1 ? 'ies' : 'y'}." }
|
49
|
+
sleep(options.delay)
|
48
50
|
retry
|
49
51
|
else
|
50
|
-
options.logger.fatal { "Caught #{e.inspect}, sorry, we have to give up now." }
|
52
|
+
options.logger.fatal { "Caught #{e.inspect} and we have no more tries left, sorry, we have to give up now." }
|
51
53
|
raise e
|
52
54
|
end
|
53
55
|
end
|
data/lib/ztk/spinner.rb
CHANGED
@@ -40,7 +40,7 @@ module ZTK
|
|
40
40
|
options = Base.build_config({
|
41
41
|
:sleep => 0.1
|
42
42
|
}.merge(options))
|
43
|
-
options.logger.debug { "options(#{options.inspect})" }
|
43
|
+
options.logger.debug { "options(#{options.send(:table).inspect})" }
|
44
44
|
|
45
45
|
!block_given? and Base.log_and_raise(options.logger, SpinnerError, "You must supply a block!")
|
46
46
|
|
data/lib/ztk/ssh.rb
CHANGED
@@ -85,6 +85,36 @@ module ZTK
|
|
85
85
|
# @author Zachary Patten <zachary@jovelabs.net>
|
86
86
|
class SSH < ZTK::Base
|
87
87
|
|
88
|
+
EXIT_SIGNALS = {
|
89
|
+
1 => "SIGHUP",
|
90
|
+
2 => "SIGINT",
|
91
|
+
3 => "SIGQUIT",
|
92
|
+
4 => "SIGILL",
|
93
|
+
5 => "SIGTRAP",
|
94
|
+
6 => "SIGABRT",
|
95
|
+
7 => "SIGBUS",
|
96
|
+
8 => "SIGFPE",
|
97
|
+
9 => "SIGKILL",
|
98
|
+
10 => "SIGUSR1",
|
99
|
+
11 => "SIGSEGV",
|
100
|
+
12 => "SIGUSR2",
|
101
|
+
13 => "SIGPIPE",
|
102
|
+
14 => "SIGALRM",
|
103
|
+
15 => "SIGTERM",
|
104
|
+
# 16 unused?
|
105
|
+
17 => "SIGCHLD",
|
106
|
+
18 => "SIGCONT",
|
107
|
+
19 => "SIGSTOP",
|
108
|
+
20 => "SIGTSTP",
|
109
|
+
21 => "SIGTTIN",
|
110
|
+
22 => "SIGTTOU",
|
111
|
+
23 => "SIGURG",
|
112
|
+
24 => "SIGXCPU",
|
113
|
+
25 => "SIGXFSZ",
|
114
|
+
26 => "SIGVTALRM",
|
115
|
+
27 => "SIGPROF"
|
116
|
+
}
|
117
|
+
|
88
118
|
# @param [Hash] config Configuration options hash.
|
89
119
|
# @option config [String] :host_name Server hostname to connect to.
|
90
120
|
# @option config [String] :user Username to use for authentication.
|
@@ -106,9 +136,10 @@ module ZTK
|
|
106
136
|
:forward_agent => true,
|
107
137
|
:compression => false,
|
108
138
|
:user_known_hosts_file => '/dev/null',
|
109
|
-
:timeout => 60
|
139
|
+
:timeout => 60,
|
140
|
+
:ignore_exit_status => false
|
110
141
|
}.merge(configuration))
|
111
|
-
config.logger.debug { "config
|
142
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
112
143
|
end
|
113
144
|
|
114
145
|
def inspect
|
@@ -160,7 +191,7 @@ module ZTK
|
|
160
191
|
# end
|
161
192
|
# ssh.console
|
162
193
|
def console
|
163
|
-
config.logger.debug { "config
|
194
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
164
195
|
config.logger.info { "console(#{console_command.inspect})" }
|
165
196
|
|
166
197
|
Kernel.exec(console_command)
|
@@ -198,12 +229,12 @@ module ZTK
|
|
198
229
|
|
199
230
|
options = OpenStruct.new({ :exit_code => 0, :silence => false }.merge(options))
|
200
231
|
|
201
|
-
config.logger.debug { "config
|
202
|
-
config.logger.debug { "options
|
203
|
-
config.logger.info { "exec(#{command.inspect}
|
232
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
233
|
+
config.logger.debug { "options=#{options.send(:table).inspect}" }
|
234
|
+
config.logger.info { "exec(#{command.inspect})" }
|
204
235
|
|
205
236
|
output = ""
|
206
|
-
exit_code =
|
237
|
+
exit_code = -1
|
207
238
|
exit_signal = nil
|
208
239
|
stdout_header = false
|
209
240
|
stderr_header = false
|
@@ -273,10 +304,15 @@ module ZTK
|
|
273
304
|
log_and_raise(SSHError, "Session timed out after #{config.timeout} seconds!")
|
274
305
|
end
|
275
306
|
|
276
|
-
|
307
|
+
message = [
|
308
|
+
"exit_code=#{exit_code}",
|
309
|
+
(exit_signal.nil? ? nil : "exit_signal=#{exit_signal} (#{EXIT_SIGNALS[exit_signal]})")
|
310
|
+
].compact.join(", ")
|
311
|
+
|
312
|
+
config.logger.debug { message }
|
277
313
|
|
278
|
-
if (exit_code != options.exit_code)
|
279
|
-
log_and_raise(SSHError,
|
314
|
+
if !config.ignore_exit_status && (exit_code != options.exit_code)
|
315
|
+
log_and_raise(SSHError, message)
|
280
316
|
end
|
281
317
|
OpenStruct.new(:output => output, :exit_code => exit_code, :exit_signal => exit_signal)
|
282
318
|
end
|
@@ -297,7 +333,7 @@ module ZTK
|
|
297
333
|
# remote = File.expand_path(File.join("/tmp", "id_rsa.pub"))
|
298
334
|
# ssh.upload(local, remote)
|
299
335
|
def upload(local, remote)
|
300
|
-
config.logger.debug { "config
|
336
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
301
337
|
config.logger.info { "upload(#{local.inspect}, #{remote.inspect})" }
|
302
338
|
|
303
339
|
ZTK::RescueRetry.try(:tries => 3, :on => EOFError) do
|
@@ -337,7 +373,7 @@ module ZTK
|
|
337
373
|
# remote = File.expand_path(File.join(ENV["HOME"], ".ssh", "id_rsa.pub"))
|
338
374
|
# ssh.download(remote, local)
|
339
375
|
def download(remote, local)
|
340
|
-
config.logger.debug { "config
|
376
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
341
377
|
config.logger.info { "download(#{remote.inspect}, #{local.inspect})" }
|
342
378
|
|
343
379
|
ZTK::RescueRetry.try(:tries => 3, :on => EOFError) do
|
data/lib/ztk/tcp_socket_check.rb
CHANGED
@@ -95,7 +95,7 @@ module ZTK
|
|
95
95
|
:timeout => 5,
|
96
96
|
:wait => 60
|
97
97
|
}.merge(configuration))
|
98
|
-
config.logger.debug { "config
|
98
|
+
config.logger.debug { "config=#{config.send(:table).inspect}" }
|
99
99
|
end
|
100
100
|
|
101
101
|
# Check to see if socket on the host and port specified is ready. This
|
data/lib/ztk/version.rb
CHANGED
@@ -0,0 +1,108 @@
|
|
1
|
+
################################################################################
|
2
|
+
#
|
3
|
+
# Author: Zachary Patten <zachary@jovelabs.net>
|
4
|
+
# Copyright: Copyright (c) Jove Labs
|
5
|
+
# License: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
require "spec_helper"
|
22
|
+
|
23
|
+
describe ZTK::Background do
|
24
|
+
|
25
|
+
subject { ZTK::Background.new }
|
26
|
+
|
27
|
+
before(:all) do
|
28
|
+
$stdout = File.open("/dev/null", "w")
|
29
|
+
$stderr = File.open("/dev/null", "w")
|
30
|
+
$stdin = File.open("/dev/null", "r")
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "class" do
|
34
|
+
|
35
|
+
it "should be an instance of ZTK::Background" do
|
36
|
+
subject.should be_an_instance_of ZTK::Background
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "default config" do
|
40
|
+
|
41
|
+
it "should use $stdout as the default" do
|
42
|
+
subject.config.stdout.should be_a_kind_of $stdout.class
|
43
|
+
subject.config.stdout.should == $stdout
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should use $stderr as the default" do
|
47
|
+
subject.config.stderr.should be_a_kind_of $stderr.class
|
48
|
+
subject.config.stderr.should == $stderr
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should use $stdin as the default" do
|
52
|
+
subject.config.stdin.should be_a_kind_of $stdin.class
|
53
|
+
subject.config.stdin.should == $stdin
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should use $logger as the default" do
|
57
|
+
subject.config.logger.should be_a_kind_of ZTK::Logger
|
58
|
+
subject.config.logger.should == $logger
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "behaviour" do
|
66
|
+
|
67
|
+
it "should throw an exception if the process method is called without a block" do
|
68
|
+
lambda{ subject.process }.should raise_error ZTK::BackgroundError, "You must supply a block to the process method!"
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "process" do
|
72
|
+
|
73
|
+
it "should spawn a process to handle the task" do
|
74
|
+
subject.process do
|
75
|
+
Process.pid
|
76
|
+
end
|
77
|
+
subject.wait
|
78
|
+
|
79
|
+
subject.result.should be_kind_of Integer
|
80
|
+
subject.result.should > 0
|
81
|
+
subject.result.should_not == Process.pid
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "result" do
|
87
|
+
|
88
|
+
it "should marshal objects" do
|
89
|
+
class BackgroundMarshalTest
|
90
|
+
def hello_world
|
91
|
+
"Hello World"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
subject.process do
|
96
|
+
BackgroundMarshalTest.new
|
97
|
+
end
|
98
|
+
subject.wait
|
99
|
+
|
100
|
+
subject.result.should be_kind_of BackgroundMarshalTest
|
101
|
+
subject.result.hello_world.should == "Hello World"
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
data/spec/ztk/parallel_spec.rb
CHANGED
@@ -74,8 +74,9 @@ describe ZTK::Parallel do
|
|
74
74
|
Process.pid
|
75
75
|
end
|
76
76
|
end
|
77
|
+
|
77
78
|
subject.waitall
|
78
|
-
|
79
|
+
|
79
80
|
subject.results.all?{ |r| r.should be_kind_of Integer }
|
80
81
|
subject.results.all?{ |r| r.should > 0 }
|
81
82
|
subject.results.uniq.count.should == 3
|
@@ -88,10 +89,11 @@ describe ZTK::Parallel do
|
|
88
89
|
Process.pid
|
89
90
|
end
|
90
91
|
end
|
92
|
+
|
91
93
|
3.times do
|
92
94
|
subject.wait
|
93
95
|
end
|
94
|
-
|
96
|
+
|
95
97
|
subject.results.all?{ |r| r.should be_kind_of Integer }
|
96
98
|
subject.results.all?{ |r| r.should > 0 }
|
97
99
|
subject.results.uniq.count.should == 3
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ztk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -173,6 +173,7 @@ files:
|
|
173
173
|
- Rakefile
|
174
174
|
- bin/ztk
|
175
175
|
- lib/ztk.rb
|
176
|
+
- lib/ztk/background.rb
|
176
177
|
- lib/ztk/base.rb
|
177
178
|
- lib/ztk/benchmark.rb
|
178
179
|
- lib/ztk/command.rb
|
@@ -188,6 +189,7 @@ files:
|
|
188
189
|
- spec/spec_helper.rb
|
189
190
|
- spec/support/test-config.rb
|
190
191
|
- spec/support/test-template.txt.erb
|
192
|
+
- spec/ztk/background_spec.rb
|
191
193
|
- spec/ztk/base_spec.rb
|
192
194
|
- spec/ztk/benchmark_spec.rb
|
193
195
|
- spec/ztk/command_spec.rb
|
@@ -214,7 +216,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
214
216
|
version: '0'
|
215
217
|
segments:
|
216
218
|
- 0
|
217
|
-
hash:
|
219
|
+
hash: -2261439734103096284
|
218
220
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
219
221
|
none: false
|
220
222
|
requirements:
|
@@ -223,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
223
225
|
version: '0'
|
224
226
|
segments:
|
225
227
|
- 0
|
226
|
-
hash:
|
228
|
+
hash: -2261439734103096284
|
227
229
|
requirements: []
|
228
230
|
rubyforge_project:
|
229
231
|
rubygems_version: 1.8.24
|
@@ -234,6 +236,7 @@ test_files:
|
|
234
236
|
- spec/spec_helper.rb
|
235
237
|
- spec/support/test-config.rb
|
236
238
|
- spec/support/test-template.txt.erb
|
239
|
+
- spec/ztk/background_spec.rb
|
237
240
|
- spec/ztk/base_spec.rb
|
238
241
|
- spec/ztk/benchmark_spec.rb
|
239
242
|
- spec/ztk/command_spec.rb
|