errands 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/errands/alternate_private_access.rb +51 -0
- data/lib/errands/runner.rb +281 -96
- data/lib/errands/test_helpers/wrapper.rb +122 -0
- data/lib/errands/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b3ec45541ab232b30e76994f6f9e157e6ce0090
|
4
|
+
data.tar.gz: fab0fe7273f9ac5617597da2a114bbc4c1fceb05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8fc4027f696fc7b287b34f2fed5e9159ad7548c16ba9bfedd95e4a66854c854bde830b54dbc0c8ab2a0cc1b1317a3ed839e376974058b522a31046969ccccf14
|
7
|
+
data.tar.gz: 674b812a10089f7d5829fb2f1a53f633c648270a361f4a160f4fb51863cfc6d6164e6ba2e2d629db720a7a156ad726f2849032d7c51e12e160f5397cfb812931
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Errands
|
2
|
+
|
3
|
+
module AlternatePrivateAccess
|
4
|
+
|
5
|
+
def self.included(singleton)
|
6
|
+
class << singleton
|
7
|
+
attr_accessor :errands_store
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.extended(klass)
|
12
|
+
class << klass
|
13
|
+
attr_accessor :errands_store
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_store(store)
|
18
|
+
singleton_class.errands_store = store
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def our_store!(h = nil)
|
24
|
+
(Thread.main[singleton_class.errands_store] = h || {}).tap do |store|
|
25
|
+
if t = store[:threads]
|
26
|
+
t.singleton_class.include AlternatePrivateAccess
|
27
|
+
t.singleton_class.errands_store = singleton_class.errands_store
|
28
|
+
end
|
29
|
+
|
30
|
+
if r = Thread.main[singleton_class.errands_store][:receptors]
|
31
|
+
r.singleton_class.include AlternatePrivateAccess
|
32
|
+
r.singleton_class.errands_store = singleton_class.errands_store
|
33
|
+
|
34
|
+
def r.default(key)
|
35
|
+
self[key] = Errands::Receptors::Receptor.new(key).tap do |v|
|
36
|
+
v.singleton_class.include Errands::AlternatePrivateAccess
|
37
|
+
v.singleton_class.errands_store = singleton_class.errands_store
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def our
|
46
|
+
singleton_class.errands_store && Thread.main[singleton_class.errands_store]
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/errands/runner.rb
CHANGED
@@ -1,178 +1,363 @@
|
|
1
1
|
module Errands
|
2
2
|
|
3
|
-
module
|
3
|
+
module ThreadAccessor
|
4
4
|
|
5
|
-
|
5
|
+
def self.extended(klass)
|
6
|
+
klass.include PrivateAccess
|
7
|
+
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def thread_accessor(*accessors)
|
10
|
+
accessors.each do |a|
|
11
|
+
define_method a, -> { our[a] }
|
12
|
+
define_method "#{a}=", ->(v) { our[a] = v }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module PrivateAccess
|
17
|
+
|
18
|
+
def err(h = {})
|
19
|
+
his_store! Thread.current, h
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def our_store!(h = nil)
|
25
|
+
Thread.main[:errands] = h || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def his_store!(thread, h = nil)
|
29
|
+
thread[:errands] = h || {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def my
|
33
|
+
Thread.current[:errands]
|
34
|
+
end
|
35
|
+
|
36
|
+
def his(thread)
|
37
|
+
thread[:errands]
|
38
|
+
end
|
39
|
+
|
40
|
+
def our
|
41
|
+
Thread.main[:errands]
|
11
42
|
end
|
12
43
|
|
13
44
|
end
|
14
45
|
|
15
|
-
|
46
|
+
end
|
47
|
+
|
48
|
+
module Started
|
49
|
+
|
50
|
+
def start(*_)
|
51
|
+
new(*_).tap &:start
|
52
|
+
end
|
16
53
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
54
|
+
def run(*_)
|
55
|
+
new(*_).tap do |e|
|
56
|
+
Process.daemon if (callee = __callee__) == :daemon
|
57
|
+
startups << define_method(:startups_alternate_run) { { callee => true } } if __callee__ != __method__
|
58
|
+
e.run
|
21
59
|
end
|
22
60
|
end
|
23
61
|
|
24
|
-
|
25
|
-
|
62
|
+
alias_method :daemon, :run
|
63
|
+
alias_method :threaded_run, :run
|
64
|
+
alias_method :noop_run, :run
|
65
|
+
|
66
|
+
def started_workers(*_)
|
67
|
+
(@started_workers ||= [:worker]).concat _.map(&:to_sym).flatten
|
26
68
|
end
|
27
69
|
|
28
|
-
|
70
|
+
def startups
|
71
|
+
@startups ||= []
|
72
|
+
end
|
29
73
|
|
30
|
-
|
31
|
-
|
32
|
-
|
74
|
+
private
|
75
|
+
|
76
|
+
def default_workers(*_)
|
77
|
+
started_workers(*_).tap { |s| s.delete :worker }
|
78
|
+
end
|
33
79
|
|
34
|
-
|
35
|
-
|
80
|
+
end
|
81
|
+
|
82
|
+
class Receptors < Hash
|
83
|
+
|
84
|
+
class Receptor < Array
|
85
|
+
|
86
|
+
module Track
|
87
|
+
|
88
|
+
def track(v, r = nil)
|
89
|
+
v.__send__ "instance_variable_#{r ? :set : :get}", *["@receptor_track", r].compact
|
90
|
+
rescue => e
|
91
|
+
my.merge!(data: v, error: :tracking_error)
|
92
|
+
raise e
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
include ThreadAccessor::PrivateAccess
|
98
|
+
include Track
|
99
|
+
|
100
|
+
attr_reader :name
|
101
|
+
|
102
|
+
def initialize(name)
|
103
|
+
@name = name
|
104
|
+
end
|
105
|
+
|
106
|
+
def shift(*_)
|
107
|
+
my[:data] = super.tap { |value| my.merge! receptor_track: track(value), latency: empty? }
|
108
|
+
end
|
109
|
+
|
110
|
+
def <<(value)
|
111
|
+
return if value.nil?
|
112
|
+
track value, my[:receptor_track]
|
113
|
+
super.tap { our[:threads][@name] && our[:threads][@name].run }
|
36
114
|
end
|
115
|
+
|
37
116
|
end
|
38
117
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
118
|
+
def default(key)
|
119
|
+
self[key] = Receptor.new key
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
class Runners < Hash
|
125
|
+
|
126
|
+
include ThreadAccessor::PrivateAccess
|
127
|
+
|
128
|
+
def [](k)
|
129
|
+
v = super
|
130
|
+
v if v && v.alive?
|
42
131
|
end
|
43
132
|
|
44
|
-
def
|
45
|
-
|
133
|
+
def []=(k, v)
|
134
|
+
our[k] = super if v.is_a? Thread
|
46
135
|
end
|
47
136
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
137
|
+
def delete(k)
|
138
|
+
our.delete k
|
139
|
+
super
|
51
140
|
end
|
52
141
|
|
53
|
-
def
|
54
|
-
|
142
|
+
def stopping_order(all = false)
|
143
|
+
scope(:type, :starter).merge(scope(:type, :data_acquisition)).merge all ? self : {}
|
55
144
|
end
|
56
145
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
sleep 1
|
62
|
-
else
|
63
|
-
secure_check :worker, :join
|
64
|
-
worker
|
65
|
-
end
|
66
|
-
end
|
146
|
+
def key_sliced(*list)
|
147
|
+
select_keys = keys & list.flatten
|
148
|
+
typecast select { |k, v| select_keys.include? k }
|
149
|
+
end
|
67
150
|
|
68
|
-
|
69
|
-
|
151
|
+
def alive
|
152
|
+
typecast select { |k, v| self[k] }
|
153
|
+
end
|
154
|
+
|
155
|
+
def scope(s, value = true)
|
156
|
+
typecast select { |k, v| his(v)[s] == value }
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
def typecast(h)
|
162
|
+
self.class.new.merge! h
|
70
163
|
end
|
71
164
|
|
165
|
+
end
|
166
|
+
|
167
|
+
module LousyCompat
|
168
|
+
|
72
169
|
def worker
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
170
|
+
working :worker, :process, :job
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
module Runner
|
176
|
+
|
177
|
+
def self.included(klass)
|
178
|
+
klass.extend(ThreadAccessor).extend(Started)
|
179
|
+
klass.thread_accessor :events, :receptors, :threads
|
180
|
+
end
|
181
|
+
|
182
|
+
attr_accessor :running_mode
|
183
|
+
|
184
|
+
def start(options = startups)
|
185
|
+
our_store! options.merge(threads: Runners.new, receptors: Receptors.new)
|
186
|
+
starter
|
187
|
+
end
|
188
|
+
|
189
|
+
def run(options = startups)
|
190
|
+
start options unless started?
|
191
|
+
our.merge! events: receptors[:events]
|
192
|
+
our[:threaded_run] || our[:noop_run] ? running { main_loop } : main_loop
|
193
|
+
end
|
194
|
+
|
195
|
+
def starter(*_)
|
196
|
+
if our[:starter]
|
197
|
+
self.class.started_workers *_
|
198
|
+
elsif !our[:noop_run]
|
199
|
+
starting self.class.started_workers
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def starting(started)
|
204
|
+
puts ["Starting #{self.class} with :", our[:config], "workers : #{started}", "\n"].join("\n") unless our[:quiet]
|
85
205
|
|
86
|
-
|
87
|
-
|
206
|
+
running thread_name, loop: true, started: started, type: :starter do
|
207
|
+
Array(my[:started]).uniq.each { |s| threads[s] ||= send *(respond_to?(s, true) ? [s] : [:working, s]) }
|
208
|
+
sleep frequency || 1
|
88
209
|
end
|
89
210
|
end
|
90
211
|
|
91
|
-
def
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
212
|
+
def working(*_)
|
213
|
+
work_done, processing, data_acquisition = working_jargon *_
|
214
|
+
our[work_done] = false
|
215
|
+
|
216
|
+
running _.first, loop: true, type: :data_acquisition do
|
217
|
+
unless my[:stop] ||= our[work_done] = checked_send("#{work_done}?")
|
218
|
+
r = ready_receptor! processing
|
219
|
+
((r << send(data_acquisition)) && !my[:latency]) || sleep(frequency.to_i)
|
99
220
|
end
|
100
221
|
end
|
222
|
+
end
|
101
223
|
|
102
|
-
|
224
|
+
def exit_on_stop
|
225
|
+
stop
|
226
|
+
exit
|
103
227
|
end
|
104
228
|
|
105
|
-
def
|
106
|
-
|
229
|
+
def stop(*_)
|
230
|
+
[false, true].each do |all|
|
231
|
+
list = threads.key_sliced(_.any? ? _ : stopped_threads)
|
232
|
+
list.alive.each { |n, t| his(t)[:stop] = true }
|
233
|
+
list.stopping_order(all).alive.each { |n, t| exiting(n, !all || t.stop?) }
|
234
|
+
end
|
235
|
+
|
236
|
+
stopped?
|
237
|
+
threads.key_sliced(_.any? ? _ : stopped_threads).alive.empty?
|
107
238
|
end
|
108
239
|
|
109
240
|
def status
|
110
|
-
|
241
|
+
{}.tap { |s| threads.each { |name, t| s[name] = t.status } }
|
111
242
|
end
|
112
243
|
|
113
244
|
def wait_for(key, meth = nil, result = true)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
245
|
+
time = Time.now.to_f
|
246
|
+
loop {
|
247
|
+
break if @errands_wait_timeout && Time.now.to_f - time > @errands_wait_timeout
|
248
|
+
break if meth && our[key].respond_to?(meth, true) ?
|
249
|
+
((our[key].send(meth) == result) rescue nil) :
|
250
|
+
!!our[key] == result }
|
251
|
+
end
|
252
|
+
|
253
|
+
def stopped?
|
254
|
+
our[:stopped] = threads.key_sliced(stopped_threads).alive.empty?
|
119
255
|
end
|
120
256
|
|
121
|
-
def
|
122
|
-
|
257
|
+
def started?
|
258
|
+
!!our && !!threads && our[:started] = !stopped?
|
123
259
|
end
|
124
260
|
|
125
261
|
private
|
126
262
|
|
127
|
-
def
|
128
|
-
our
|
129
|
-
|
130
|
-
|
131
|
-
|
263
|
+
def frequency(name = nil)
|
264
|
+
our[:config] && our[:config][:frequencies] && our[:config][:frequencies][name || my[:name]]
|
265
|
+
end
|
266
|
+
|
267
|
+
def main_loop
|
268
|
+
rescued_loop do
|
269
|
+
(e = events.shift) ? errands(*e) : sleep(frequency(:main_loop) || 1)
|
132
270
|
end
|
133
271
|
end
|
134
272
|
|
135
|
-
def
|
136
|
-
|
273
|
+
def ready_receptor!(processing)
|
274
|
+
receptors[processing].tap { threads[processing] ||= spring processing }
|
275
|
+
end
|
137
276
|
|
138
|
-
|
139
|
-
|
140
|
-
|
277
|
+
def spring(processing)
|
278
|
+
running processing, loop: true, deletable: true do
|
279
|
+
data = receptors[my[:name]].shift || Thread.stop || receptors[my[:name]].shift
|
280
|
+
data && send(processing, data).tap do |r|
|
281
|
+
if my[:receptor_track] && my[:receptor_track][:receptor].name != my[:name]
|
282
|
+
my[:receptor_track][:receptor] << my[:receptor_track].merge(result: r).reject { |k, v| k == :receptor }
|
283
|
+
end
|
284
|
+
end
|
141
285
|
end
|
142
286
|
end
|
143
287
|
|
144
|
-
def
|
288
|
+
def errands(errand, *_)
|
289
|
+
running("#{thread_name(1)}_#{errand}".to_sym, deletable: true) { send errand, *_ }
|
290
|
+
end
|
291
|
+
|
292
|
+
def running(name = thread_name, options = {}, &block)
|
145
293
|
if @running_mode
|
146
294
|
send @running_mode, &block
|
147
295
|
else
|
148
|
-
|
296
|
+
threads[name] = Thread.new {
|
297
|
+
(my && my[:name] && (my[:named] = true)) || Thread.stop || (my[:named] = true)
|
298
|
+
r = my[:result] = my[:loop] ? rescued_loop(&block) : block.call
|
299
|
+
["stop_#{name}", our[name] && "stop_#{his(our[name])[:type]}"].compact.each { |s| checked_send s }
|
300
|
+
my[:deletable] && threads.delete(name)
|
301
|
+
r
|
302
|
+
}.tap { |t|
|
303
|
+
his_store! t, { name: name, time: Time.now.to_f, stop: false, type: :any, receptor_track: my && my.delete(:receptor_track) }.merge(options)
|
304
|
+
t.run unless his(t)[:named]
|
305
|
+
}
|
149
306
|
end
|
150
307
|
end
|
151
308
|
|
309
|
+
def exiting(name, force = true)
|
310
|
+
force && Thread.current == our[name] ? errands(:exiting, name) : our[name] && (force || our[name].stop?) && our[name].exit
|
311
|
+
wait_for name, :alive?, false
|
312
|
+
end
|
313
|
+
|
314
|
+
def stopped_threads
|
315
|
+
our[:stopped_threads] || threads.keys.reject { |k| k.to_s =~ /^errands_.+_stop$/}
|
316
|
+
end
|
317
|
+
|
152
318
|
def thread_name(caller_depth = 2)
|
153
319
|
caller_locations(caller_depth, 1).first.base_label.dup.tap { |n|
|
154
320
|
n << "_" << Time.now.to_f.to_s.sub('.', '_') if n.end_with? 's'
|
155
321
|
}.to_sym
|
156
322
|
end
|
157
323
|
|
158
|
-
def
|
159
|
-
|
160
|
-
|
324
|
+
def rescued_loop
|
325
|
+
loop { our["#{my[:name]}_iteration".to_sym] = begin
|
326
|
+
my[:stop] ? break : yield; Time.now
|
327
|
+
rescue => e
|
328
|
+
log_error e, my[:data], my
|
329
|
+
end }
|
330
|
+
end
|
331
|
+
|
332
|
+
def checked_send(meth, recipient = self, *_)
|
333
|
+
recipient.respond_to?(meth, true) && (recipient.send(meth, *_) rescue nil)
|
161
334
|
end
|
162
335
|
|
163
|
-
def
|
164
|
-
|
336
|
+
def working_jargon(started, processing = nil, data_acquisition = nil)
|
337
|
+
[ "#{started}_done".to_sym,
|
338
|
+
processing || "#{started}_process".to_sym,
|
339
|
+
data_acquisition || "#{started}_data_acquisition".to_sym ]
|
165
340
|
end
|
166
341
|
|
167
|
-
def log_error(e)
|
168
|
-
puts e.message
|
342
|
+
def log_error(e, data, *_)
|
343
|
+
puts(e) || puts(e.message) || puts(data) || puts(e.backtrace) || puts(_) if our[:verbose]
|
169
344
|
end
|
170
345
|
|
171
|
-
def
|
172
|
-
|
346
|
+
def startups
|
347
|
+
self.class.startups
|
348
|
+
.dup
|
349
|
+
.tap { |s| s << :startup if respond_to?(:startup, true) }
|
350
|
+
.uniq
|
351
|
+
.inject({}) { |s, m| extended_merge(s, __send__(m)) }
|
173
352
|
end
|
174
353
|
|
175
|
-
def
|
354
|
+
def extended_merge(from, to)
|
355
|
+
from.tap do |f|
|
356
|
+
to.keys.each do |k|
|
357
|
+
f[k] = f[k].is_a?(Hash) && to[k].is_a?(Hash) ? extended_merge(f[k], to[k]) : to[k]
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
176
361
|
|
177
362
|
end
|
178
363
|
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'errands/alternate_private_access'
|
2
|
+
|
3
|
+
module Errands
|
4
|
+
|
5
|
+
module TestHelpers
|
6
|
+
|
7
|
+
module OurStore
|
8
|
+
|
9
|
+
def initialize(*_)
|
10
|
+
s = if _.size == 1 && _.first.is_a?(Hash)
|
11
|
+
_.first.delete(:startup).tap { _.pop if _.first.empty? }
|
12
|
+
elsif _.last.is_a?(Hash)
|
13
|
+
_.pop[:startup]
|
14
|
+
end
|
15
|
+
|
16
|
+
our_store! (s.is_a?(Hash) ? s : send(s)) || {}
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
module ResetStartedWorkers
|
24
|
+
|
25
|
+
def reset_started_workers
|
26
|
+
@started_workers = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
module StopAll
|
32
|
+
|
33
|
+
def stopped_threads
|
34
|
+
threads.keys.reject { |k| k.to_s =~ /^errands_.+_stop$/}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class Wrapper
|
40
|
+
|
41
|
+
class Vanilla
|
42
|
+
|
43
|
+
extend ThreadAccessor::PrivateAccess
|
44
|
+
|
45
|
+
class << self
|
46
|
+
|
47
|
+
def theirs
|
48
|
+
our
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
include Errands::AlternatePrivateAccess
|
56
|
+
|
57
|
+
def self.helper
|
58
|
+
@instance = new
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.help(helped, options = {}, &block)
|
62
|
+
helper
|
63
|
+
#~ @instance.theirs_reset! unless options[:reset] == false
|
64
|
+
@instance.help helped, &block
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
set_store :errands_test
|
69
|
+
our_store!
|
70
|
+
end
|
71
|
+
|
72
|
+
def theirs
|
73
|
+
Vanilla.theirs
|
74
|
+
end
|
75
|
+
|
76
|
+
def help(helped)
|
77
|
+
(our[:helped] = helped).tap do |i|
|
78
|
+
i.instance_variable_set '@errands_wait_timeout', 10
|
79
|
+
i.start unless i.started?
|
80
|
+
yield i if block_given?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def helped(i = nil)
|
85
|
+
i ? our[:helped] = i : our[:helped]
|
86
|
+
end
|
87
|
+
|
88
|
+
def push_event(e)
|
89
|
+
theirs && theirs[:events] && theirs[:events] << e
|
90
|
+
end
|
91
|
+
|
92
|
+
def theirs_reset!
|
93
|
+
theirs && theirs.clear
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.after
|
97
|
+
threads_cleanup
|
98
|
+
|
99
|
+
if @instance
|
100
|
+
@instance.stop_helped if @instance.helped
|
101
|
+
@instance.theirs_reset!
|
102
|
+
end
|
103
|
+
|
104
|
+
@instance = nil
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.threads_cleanup
|
108
|
+
while (t = Thread.list.select { |t| t[:errands] } - [Thread.main]).any?
|
109
|
+
t.each &:exit
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def stop_helped
|
114
|
+
helped.stop
|
115
|
+
helped.wait_for :stopped
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
data/lib/errands/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: errands
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lacravate
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -61,7 +61,9 @@ extensions: []
|
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
63
|
- lib/errands.rb
|
64
|
+
- lib/errands/alternate_private_access.rb
|
64
65
|
- lib/errands/runner.rb
|
66
|
+
- lib/errands/test_helpers/wrapper.rb
|
65
67
|
- lib/errands/version.rb
|
66
68
|
homepage: https://github.com/lacravate/errands
|
67
69
|
licenses: []
|