errands 0.0.1 → 0.0.2
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/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: []
|