bumbleworks 0.0.25 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
data/lib/bumbleworks/task.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "bumbleworks/tasks/base"
|
2
2
|
require "bumbleworks/workitem_entity_storage"
|
3
|
+
require "bumbleworks/task/finder"
|
3
4
|
|
4
5
|
module Bumbleworks
|
5
6
|
class Task
|
@@ -8,6 +9,7 @@ module Bumbleworks
|
|
8
9
|
class AlreadyClaimed < StandardError; end
|
9
10
|
class MissingWorkitem < StandardError; end
|
10
11
|
class NotCompletable < StandardError; end
|
12
|
+
class AvailabilityTimeout < StandardError; end
|
11
13
|
|
12
14
|
extend Forwardable
|
13
15
|
delegate [:sid, :fei, :fields, :params, :participant_name, :wfid, :wf_name] => :@workitem
|
@@ -29,24 +31,11 @@ module Bumbleworks
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
return [] unless identifiers.is_a?(Array)
|
38
|
-
workitems = identifiers.collect { |identifier|
|
39
|
-
storage_participant.by_participant(identifier)
|
40
|
-
}.flatten.uniq
|
41
|
-
from_workitems(workitems)
|
42
|
-
end
|
43
|
-
|
44
|
-
def for_claimant(token)
|
45
|
-
all.select { |t| t.claimant == token }
|
46
|
-
end
|
47
|
-
|
48
|
-
def all
|
49
|
-
from_workitems(storage_participant.all)
|
34
|
+
def method_missing(method, *args)
|
35
|
+
if Finder.new.respond_to?(method)
|
36
|
+
return Finder.new.send(method, *args)
|
37
|
+
end
|
38
|
+
super
|
50
39
|
end
|
51
40
|
|
52
41
|
def find_by_id(sid)
|
@@ -60,12 +49,6 @@ module Bumbleworks
|
|
60
49
|
def storage_participant
|
61
50
|
Bumbleworks.dashboard.storage_participant
|
62
51
|
end
|
63
|
-
|
64
|
-
def from_workitems(workitems)
|
65
|
-
workitems.map { |wi|
|
66
|
-
new(wi) if wi.params['task']
|
67
|
-
}.compact
|
68
|
-
end
|
69
52
|
end
|
70
53
|
|
71
54
|
def initialize(workitem)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Bumbleworks
|
2
|
+
class Task
|
3
|
+
class Finder
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(queries = [])
|
7
|
+
@queries = queries
|
8
|
+
end
|
9
|
+
|
10
|
+
def by_nickname(nickname)
|
11
|
+
@queries << proc { |wi| wi['fields']['params']['task'] == nickname }
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def for_roles(identifiers)
|
16
|
+
identifiers ||= []
|
17
|
+
@queries << proc { |wi| identifiers.include?(wi['participant_name']) }
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def for_role(identifier)
|
22
|
+
for_roles([identifier])
|
23
|
+
end
|
24
|
+
|
25
|
+
def for_claimant(token)
|
26
|
+
@queries << proc { |wi| wi['fields']['params']['claimant'] == token }
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def for_entity(entity)
|
31
|
+
@queries << proc { |wi|
|
32
|
+
(wi['fields'][:entity_type] || wi['fields']['entity_type']) == entity.class.name &&
|
33
|
+
(wi['fields'][:entity_id] || wi['fields']['entity_id']) == entity.identifier
|
34
|
+
}
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def all
|
39
|
+
workitems = Bumbleworks.dashboard.storage_participant.send(:do_select, {}) { |wi|
|
40
|
+
@queries.all? { |q| q.call(wi) }
|
41
|
+
}
|
42
|
+
from_workitems(workitems)
|
43
|
+
end
|
44
|
+
|
45
|
+
def each(&block)
|
46
|
+
all.each(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def empty?
|
50
|
+
all.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
def next_available(options = {})
|
54
|
+
options[:timeout] ||= 5
|
55
|
+
|
56
|
+
start_time = Time.now
|
57
|
+
while first.nil?
|
58
|
+
if (Time.now - start_time) > options[:timeout]
|
59
|
+
raise Bumbleworks::Task::AvailabilityTimeout, "No tasks found matching criteria in time"
|
60
|
+
end
|
61
|
+
sleep 0.1
|
62
|
+
end
|
63
|
+
first
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def from_workitems(workitems)
|
69
|
+
workitems.map { |wi|
|
70
|
+
Task.new(wi) if wi.params['task']
|
71
|
+
}.compact
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/bumbleworks/version.rb
CHANGED
@@ -5,8 +5,8 @@ module Bumbleworks
|
|
5
5
|
def entity(options = {})
|
6
6
|
@entity = nil if options[:reload] == true
|
7
7
|
@entity ||= if has_entity_fields?
|
8
|
-
klass = Bumbleworks::Support.constantize(
|
9
|
-
entity = klass.first_by_identifier(
|
8
|
+
klass = Bumbleworks::Support.constantize(entity_type)
|
9
|
+
entity = klass.first_by_identifier(entity_id)
|
10
10
|
end
|
11
11
|
raise EntityNotFound unless @entity
|
12
12
|
@entity
|
@@ -19,7 +19,17 @@ module Bumbleworks
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def has_entity_fields?
|
22
|
-
|
22
|
+
entity_id && entity_type
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def entity_id
|
28
|
+
workitem.fields[:entity_id] || workitem.fields['entity_id']
|
29
|
+
end
|
30
|
+
|
31
|
+
def entity_type
|
32
|
+
workitem.fields[:entity_type] || workitem.fields['entity_type']
|
23
33
|
end
|
24
34
|
end
|
25
35
|
end
|
@@ -91,7 +91,7 @@ describe Bumbleworks::Task do
|
|
91
91
|
it 'logs dispatch' do
|
92
92
|
Bumbleworks.launch!('planting_a_noodle')
|
93
93
|
Bumbleworks.dashboard.wait_for(:horse_feeder)
|
94
|
-
task = described_class.for_role('horse_feeder').
|
94
|
+
task = described_class.for_role('horse_feeder').first
|
95
95
|
log_entry = Bumbleworks.logger.entries.last[:entry]
|
96
96
|
log_entry[:action].should == :dispatch
|
97
97
|
log_entry[:target_type].should == 'Task'
|
@@ -230,9 +230,22 @@ describe Bumbleworks::Task do
|
|
230
230
|
end
|
231
231
|
|
232
232
|
describe '.for_role' do
|
233
|
-
it '
|
234
|
-
|
235
|
-
|
233
|
+
it 'returns all tasks for given role' do
|
234
|
+
Bumbleworks.define_process 'chalking' do
|
235
|
+
concurrence do
|
236
|
+
chalker :task => 'make_chalk_drawings'
|
237
|
+
hagrid :task => 'moan_endearingly'
|
238
|
+
chalker :task => 'chalk_it_good_baby'
|
239
|
+
end
|
240
|
+
end
|
241
|
+
Bumbleworks.launch!('chalking')
|
242
|
+
Bumbleworks.dashboard.wait_for(:chalker)
|
243
|
+
|
244
|
+
tasks = described_class.for_role('chalker')
|
245
|
+
tasks.map(&:nickname).should == [
|
246
|
+
'make_chalk_drawings',
|
247
|
+
'chalk_it_good_baby'
|
248
|
+
]
|
236
249
|
end
|
237
250
|
end
|
238
251
|
|
@@ -325,6 +338,39 @@ describe Bumbleworks::Task do
|
|
325
338
|
end
|
326
339
|
end
|
327
340
|
|
341
|
+
context '.for_entity' do
|
342
|
+
it 'returns all tasks associated with given entity' do
|
343
|
+
fake_sandwich = OpenStruct.new(:identifier => 'rubies')
|
344
|
+
Bumbleworks.define_process 'existential_pb_and_j' do
|
345
|
+
concurrence do
|
346
|
+
sandwich :task => 'be_made'
|
347
|
+
sandwich :task => 'contemplate_being'
|
348
|
+
end
|
349
|
+
end
|
350
|
+
Bumbleworks.launch!('existential_pb_and_j', :entity => fake_sandwich)
|
351
|
+
Bumbleworks.dashboard.wait_for(:sandwich)
|
352
|
+
tasks = described_class.for_entity(fake_sandwich)
|
353
|
+
tasks.should have(2).items
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context '.by_nickname' do
|
358
|
+
it 'returns all tasks with given nickname' do
|
359
|
+
Bumbleworks.define_process 'animal_disagreements' do
|
360
|
+
concurrence do
|
361
|
+
turtle :task => 'be_a_big_jerk'
|
362
|
+
goose :task => 'punch_turtle'
|
363
|
+
rabbit :task => 'punch_turtle'
|
364
|
+
end
|
365
|
+
end
|
366
|
+
Bumbleworks.launch!('animal_disagreements')
|
367
|
+
Bumbleworks.dashboard.wait_for(:rabbit)
|
368
|
+
tasks = described_class.by_nickname('punch_turtle')
|
369
|
+
tasks.should have(2).items
|
370
|
+
tasks.map(&:role).should =~ ['goose', 'rabbit']
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
328
374
|
context 'claiming things' do
|
329
375
|
before :each do
|
330
376
|
Bumbleworks.define_process 'planting_a_noodle' do
|
@@ -337,7 +383,7 @@ describe Bumbleworks::Task do
|
|
337
383
|
end
|
338
384
|
|
339
385
|
describe '#claim' do
|
340
|
-
it 'sets token on
|
386
|
+
it 'sets token on "claimant" param' do
|
341
387
|
@task.params['claimant'].should == 'boss'
|
342
388
|
end
|
343
389
|
|
@@ -515,4 +561,92 @@ describe Bumbleworks::Task do
|
|
515
561
|
end
|
516
562
|
end
|
517
563
|
end
|
564
|
+
|
565
|
+
describe 'chained queries' do
|
566
|
+
it 'allows for AND-ed chained finders' do
|
567
|
+
Bumbleworks.define_process 'the_big_kachunko' do
|
568
|
+
concurrence do
|
569
|
+
red :task => 'be_really_mad'
|
570
|
+
blue :task => 'be_a_bit_sad'
|
571
|
+
yellow :task => 'be_scared'
|
572
|
+
green :task => 'be_envious'
|
573
|
+
green :task => 'be_proud'
|
574
|
+
pink :task => 'be_proud'
|
575
|
+
end
|
576
|
+
end
|
577
|
+
Bumbleworks.launch!('the_big_kachunko')
|
578
|
+
Bumbleworks.dashboard.wait_for(:pink)
|
579
|
+
described_class.by_nickname('be_really_mad').first.claim('crayon_box')
|
580
|
+
described_class.by_nickname('be_a_bit_sad').first.claim('crayon_box')
|
581
|
+
described_class.by_nickname('be_scared').first.claim('crayon_box')
|
582
|
+
|
583
|
+
tasks = described_class.
|
584
|
+
for_roles(['green', 'pink']).
|
585
|
+
by_nickname('be_proud')
|
586
|
+
tasks.should have(2).items
|
587
|
+
tasks.map(&:nickname).should =~ ['be_proud', 'be_proud']
|
588
|
+
|
589
|
+
tasks = described_class.
|
590
|
+
for_claimant('crayon_box').
|
591
|
+
for_roles(['red', 'yellow', 'green'])
|
592
|
+
tasks.should have(2).items
|
593
|
+
tasks.map(&:nickname).should =~ ['be_really_mad', 'be_scared']
|
594
|
+
|
595
|
+
tasks = described_class.
|
596
|
+
for_claimant('crayon_box').
|
597
|
+
by_nickname('be_a_bit_sad').
|
598
|
+
for_role('blue')
|
599
|
+
tasks.should have(1).item
|
600
|
+
tasks.first.nickname.should == 'be_a_bit_sad'
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
describe 'method missing' do
|
605
|
+
it 'calls method on new Finder object' do
|
606
|
+
described_class::Finder.any_instance.stub(:shabam!).with(:yay).and_return(:its_a_me)
|
607
|
+
described_class.shabam!(:yay).should == :its_a_me
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'falls back to method missing if no finder method' do
|
611
|
+
expect {
|
612
|
+
described_class.kerplunk!(:oh_no)
|
613
|
+
}.to raise_error
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
describe '.next_available' do
|
618
|
+
it 'waits for one task to show up and returns it' do
|
619
|
+
Bumbleworks.define_process "lazy_bum_and_cool_guy" do
|
620
|
+
concurrence do
|
621
|
+
cool_guy :task => 'get_it_going_man'
|
622
|
+
sequence do
|
623
|
+
wait '2s'
|
624
|
+
bum :task => 'finally_get_a_round_tuit'
|
625
|
+
end
|
626
|
+
end
|
627
|
+
end
|
628
|
+
start_time = Time.now
|
629
|
+
Bumbleworks.launch!('lazy_bum_and_cool_guy')
|
630
|
+
task = described_class.for_role('bum').next_available
|
631
|
+
end_time = Time.now
|
632
|
+
task.nickname.should == 'finally_get_a_round_tuit'
|
633
|
+
(end_time - start_time).should >= 2
|
634
|
+
end
|
635
|
+
|
636
|
+
it 'times out if task does not appear in time' do
|
637
|
+
Bumbleworks.define_process "really_lazy_bum_and_cool_guy" do
|
638
|
+
concurrence do
|
639
|
+
cool_guy :task => 'good_golly_never_mind_you'
|
640
|
+
sequence do
|
641
|
+
wait '2s'
|
642
|
+
bum :task => 'whatever_these_socks_are_tasty'
|
643
|
+
end
|
644
|
+
end
|
645
|
+
end
|
646
|
+
Bumbleworks.launch!('really_lazy_bum_and_cool_guy')
|
647
|
+
expect {
|
648
|
+
described_class.for_role('bum').next_available(:timeout => 0.5)
|
649
|
+
}.to raise_error(Bumbleworks::Task::AvailabilityTimeout)
|
650
|
+
end
|
651
|
+
end
|
518
652
|
end
|
@@ -18,6 +18,11 @@ describe Bumbleworks::WorkitemEntityStorage do
|
|
18
18
|
feh.should have_entity_fields
|
19
19
|
end
|
20
20
|
|
21
|
+
it 'returns true if workitem fields include symbolized version of entity fields' do
|
22
|
+
feh = FakeEntityHolder.new(:entity_id => '1', :entity_type => 'SomeEntity')
|
23
|
+
feh.should have_entity_fields
|
24
|
+
end
|
25
|
+
|
21
26
|
it 'returns false if workitem fields do not include entity fields' do
|
22
27
|
feh = FakeEntityHolder.new
|
23
28
|
feh.should_not have_entity_fields
|
@@ -62,6 +67,11 @@ describe Bumbleworks::WorkitemEntityStorage do
|
|
62
67
|
feh.entity.identifier.should == '15'
|
63
68
|
end
|
64
69
|
|
70
|
+
it 'works with symbolized _id and _type fields' do
|
71
|
+
feh = FakeEntityHolder.new(:entity_id => '15', :entity_type => 'LovelyEntity')
|
72
|
+
feh.entity.identifier.should == '15'
|
73
|
+
end
|
74
|
+
|
65
75
|
it 'throw exception if entity fields not present' do
|
66
76
|
feh = FakeEntityHolder.new
|
67
77
|
expect {
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bumbleworks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.26
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -178,6 +178,7 @@ files:
|
|
178
178
|
- lib/bumbleworks/storage_participant.rb
|
179
179
|
- lib/bumbleworks/support.rb
|
180
180
|
- lib/bumbleworks/task.rb
|
181
|
+
- lib/bumbleworks/task/finder.rb
|
181
182
|
- lib/bumbleworks/tasks/base.rb
|
182
183
|
- lib/bumbleworks/tree_builder.rb
|
183
184
|
- lib/bumbleworks/version.rb
|
@@ -227,18 +228,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
227
228
|
- - ! '>='
|
228
229
|
- !ruby/object:Gem::Version
|
229
230
|
version: '0'
|
230
|
-
segments:
|
231
|
-
- 0
|
232
|
-
hash: -2155630126504321546
|
233
231
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
234
232
|
none: false
|
235
233
|
requirements:
|
236
234
|
- - ! '>='
|
237
235
|
- !ruby/object:Gem::Version
|
238
236
|
version: '0'
|
239
|
-
segments:
|
240
|
-
- 0
|
241
|
-
hash: -2155630126504321546
|
242
237
|
requirements: []
|
243
238
|
rubyforge_project:
|
244
239
|
rubygems_version: 1.8.23
|
@@ -277,3 +272,4 @@ test_files:
|
|
277
272
|
- spec/lib/bumbleworks_spec.rb
|
278
273
|
- spec/spec_helper.rb
|
279
274
|
- spec/support/path_helpers.rb
|
275
|
+
has_rdoc:
|