bumbleworks 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +16 -1
- data/README.md +102 -34
- data/doc/GUIDE.md +12 -6
- data/lib/bumbleworks.rb +7 -21
- data/lib/bumbleworks/configuration.rb +0 -16
- data/lib/bumbleworks/participant_registration.rb +1 -1
- data/lib/bumbleworks/process_definition.rb +6 -2
- data/lib/bumbleworks/rake_tasks.rb +3 -0
- data/lib/bumbleworks/ruote.rb +3 -3
- data/lib/bumbleworks/support.rb +3 -2
- data/lib/bumbleworks/version.rb +1 -1
- data/lib/tasks/bumbleworks.rake +21 -0
- data/spec/fixtures/apps/with_default_directories/full_initializer.rb +2 -2
- data/spec/lib/bumbleworks/configuration_spec.rb +0 -15
- data/spec/lib/bumbleworks/process_definition_spec.rb +25 -10
- data/spec/lib/bumbleworks/ruote_spec.rb +1 -7
- data/spec/lib/bumbleworks/support_spec.rb +11 -17
- data/spec/lib/bumbleworks/task_spec.rb +1 -1
- data/spec/lib/bumbleworks_spec.rb +12 -37
- metadata +5 -9
- data/Gemfile.lock +0 -84
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -24,11 +24,35 @@ Or you can install it yourself using
|
|
24
24
|
|
25
25
|
## Configuration
|
26
26
|
|
27
|
+
#### Example Initializer File
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
Bumbleworks.configure do |c|
|
31
|
+
c.storage = Redis.new # requires bumbleworks-redis gem
|
32
|
+
# Or, for dev/test, if you don't have Redis set up yet:
|
33
|
+
# c.storage = {}
|
34
|
+
end
|
35
|
+
|
36
|
+
# this next block is optional - it's only needed
|
37
|
+
# if you want to load custom participants
|
38
|
+
Bumbleworks.register_participants do
|
39
|
+
# foo FooParticipant
|
40
|
+
# bar BarParticipant
|
41
|
+
# ...
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load all process definitions in lib/process_definitions
|
45
|
+
Bumbleworks.load_definitions!
|
46
|
+
|
47
|
+
# Start a worker in the background
|
48
|
+
Bumbleworks.start_worker!
|
49
|
+
```
|
50
|
+
|
27
51
|
### The Process Storage
|
28
52
|
|
29
53
|
Bumbleworks uses a dedicated key-value storage for process information; this is where all process instance state is stored. We consider it a best practice to keep this storage in a separate place from your business information; see Process vs. Business Information for more discussion.
|
30
54
|
|
31
|
-
Before you can load process definitions, register participants, and spin up workers in Bumbleworks, you need to configure Bumbleworks's process storage. Right now, Bumbleworks supports
|
55
|
+
Before you can load process definitions, register participants, and spin up workers in Bumbleworks, you need to configure Bumbleworks's process storage. Right now, Bumbleworks supports three storage methods - [Redis](http://redis.io/), [Sequel](http://sequel.rubyforge.org/) (an ORM that itself supports MySQL, Postgres, etc.), and a simple Hash (only for development and testing, since it won't persist )
|
32
56
|
|
33
57
|
#### Redis
|
34
58
|
|
@@ -44,8 +68,8 @@ If you want to use Redis:
|
|
44
68
|
|
45
69
|
```ruby
|
46
70
|
Bumbleworks.configure do |c|
|
47
|
-
|
48
|
-
|
71
|
+
c.storage = Redis.new(:host => '127.0.0.1', :db => 0, :thread_safe => true)
|
72
|
+
# ...
|
49
73
|
end
|
50
74
|
```
|
51
75
|
|
@@ -63,14 +87,16 @@ If you want to use Sequel:
|
|
63
87
|
|
64
88
|
```ruby
|
65
89
|
Bumbleworks.configure do |c|
|
66
|
-
|
67
|
-
|
90
|
+
c.storage = Sequel.connect('postgres://user:password@host:port/database_name')
|
91
|
+
# ...
|
68
92
|
end
|
69
93
|
```
|
70
94
|
|
71
|
-
### Process
|
95
|
+
### Process Definitions Directory
|
96
|
+
|
97
|
+
Bumbleworks uses [ruote](http://github.com/jmettraux/ruote), which allows process definitions to be written using a [Ruby DSL](http://ruote.rubyforge.org/definitions.html#ruby).
|
72
98
|
|
73
|
-
|
99
|
+
By default, your process definitions will be loaded from the `lib/process_definitions` directory at `Bumbleworks.root` (see Determining the Root Directory for more info). This directory can have as many subdirectories as you want, and Bumbleworks will load everything recursively; note, however, that the directory hierarchy doesn't mean anything to Bumbleworks, and is only for your own organization. The directory is configurable by setting Bumbleworks.definitions_directory:
|
74
100
|
|
75
101
|
```ruby
|
76
102
|
Bumbleworks.configure do |c|
|
@@ -79,24 +105,11 @@ Bumbleworks.configure do |c|
|
|
79
105
|
end
|
80
106
|
```
|
81
107
|
|
82
|
-
Note that if you override the default path, you can either specify an absolute path or a relative path - just use a leading slash if you want it to be interpreted as absolute.
|
108
|
+
Note that if you override the default path, you can either specify an absolute path or a relative path - just use a leading slash if you want it to be interpreted as absolute. Relative paths will be relative to `Bumbleworks.root`.
|
83
109
|
|
84
|
-
|
110
|
+
### Participant Class Directory
|
85
111
|
|
86
|
-
|
87
|
-
|
88
|
-
```ruby
|
89
|
-
Bumbleworks.register_participants do
|
90
|
-
update_status StatusChangerParticipant
|
91
|
-
acquire_lock LockerParticipant, 'action' => 'acquire'
|
92
|
-
release_lock LockerParticipant, 'action' => 'release'
|
93
|
-
notify_applicant ApplicantNotifierParticipant
|
94
|
-
end
|
95
|
-
```
|
96
|
-
|
97
|
-
By default, Bumbleworks will register a "catchall" participant at the end of your participant list, which will catch any workitems not picked up by a participant higher in the list. Those workitems then fall into ruote's StorageParticipant, from where Bumbleworks will assemble its task queue.
|
98
|
-
|
99
|
-
If your app has a `participants` or `app/participants` directory at the root (see Determining the Root Directory), Bumbleworks will require all files in that directory by default before running the `register_participants` block. You can customize this directory by setting Bumbleworks.participants_directory:
|
112
|
+
If your app has a `participants` or `app/participants` directory at the root (see Determining the Root Directory), Bumbleworks will require all files in that directory by default before running your `register_participants` block (see below). You can customize this directory by setting Bumbleworks.participants_directory:
|
100
113
|
|
101
114
|
```ruby
|
102
115
|
Bumbleworks.configure do |c|
|
@@ -107,30 +120,53 @@ end
|
|
107
120
|
|
108
121
|
### Determining the Root Directory
|
109
122
|
|
110
|
-
By default, Bumbleworks will attempt in several ways to find your root directory. In the most common cases (Rails, Sinatra,
|
123
|
+
By default, Bumbleworks will attempt in several ways to find your root directory. In the most common cases (Rails, Sinatra, or Rory), it usually won't have trouble guessing the directory.
|
124
|
+
|
125
|
+
If you're not using Rails, Sinatra, or Rory, Bumbleworks will complain when you call `bootstrap!` or `update!`, **unless** both your definitions directory and your participants directory (see above) are specified as absolute paths.
|
111
126
|
|
112
127
|
## Usage
|
113
128
|
|
114
|
-
###
|
129
|
+
### Loading Definitions and Participants
|
130
|
+
|
131
|
+
#### Process Definitions
|
115
132
|
|
116
|
-
|
133
|
+
Process definitions are just ruby files with blocks following Ruote's [Ruby DSL syntax](http://ruote.rubyforge.org/definitions.html#ruby). The only difference is that instead of `Ruote.define`, the method to call is `Bumbleworks.define_process`. No arguments are necessary - the name will be taken from the base name of the ruby file (e.g. 'foo.rb' defines a process named 'foo'). All process definition files should be in your app's `definitions_directory` (see above); they can be in subdirectories for your own organization, but all filenames must be unique within the `definition_directory`'s tree.
|
134
|
+
|
135
|
+
To actually load your process definitions from the directory:
|
117
136
|
|
118
137
|
```ruby
|
119
|
-
Bumbleworks.
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
138
|
+
Bumbleworks.load_definitions!
|
139
|
+
```
|
140
|
+
|
141
|
+
Keep in mind that any changed process definitions will overwrite previously loaded ones - in other words, after running this command successfully, all process definitions loaded into Bumbleworks will be in sync with the files in your definitions directory.
|
142
|
+
|
143
|
+
Process definitions will be named (and `launch`able) using the name of the file itself. Therefore, Bumbleworks will throw an exception if any files in your definitions directory (and subdirectories) have the same name.
|
124
144
|
|
125
|
-
|
145
|
+
#### Participants
|
146
|
+
|
147
|
+
Registering participants with Bumbleworks is done using `Bumbleworks.register_participants`, which takes a block, and follows [Ruote's #register syntax](http://ruote.rubyforge.org/participants.html#registering). For example:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
Bumbleworks.register_participants do
|
151
|
+
update_status StatusChangerParticipant
|
152
|
+
acquire_lock LockerParticipant, 'action' => 'acquire'
|
153
|
+
release_lock LockerParticipant, 'action' => 'release'
|
154
|
+
notify_applicant ApplicantNotifierParticipant
|
155
|
+
end
|
126
156
|
```
|
127
157
|
|
128
|
-
|
158
|
+
Unless you add it yourself, Bumbleworks will register a "catchall" participant at the end of your participant list, which will catch any workitems not picked up by a participant higher in the list. Those workitems then fall into ruote's StorageParticipant, from where Bumbleworks will assemble its task queue.
|
159
|
+
|
160
|
+
### Starting Work
|
161
|
+
|
162
|
+
Without running a "worker," Bumbleworks won't do anything behind the scenes - no workitems will proceed through their workflow, no schedules will be checked, etc. Running a worker is done using the following command:
|
129
163
|
|
130
164
|
```ruby
|
131
165
|
Bumbleworks.start_worker!
|
132
166
|
```
|
133
167
|
|
168
|
+
You can add this to the end of your initializer, but, while this is handy in development and testing, it's not a good practice to follow in production. In an actual production environment, you will likely have multiple workers running in their own threads, or even on separate servers. So the **preferred way** is to call the `Bumbleworks.start_worker!` method outside of the initializer, most likely in a Rake task that has your environment loaded.
|
169
|
+
|
134
170
|
> Strictly speaking, the entire environment doesn't need to be loaded; only Bumbleworks.storage needs to be set before starting a worker. However, it's best practice to configure Bumbleworks in one place, to ensure you don't get your storage configurations out of sync.
|
135
171
|
|
136
172
|
You can run as many workers as you want in parallel, and as long as they're accessing the same storage, no concurrency issues should arise.
|
@@ -157,4 +193,36 @@ Bumbleworks::Task.for_roles(['trombonist', 'admin']) # returns both tasks
|
|
157
193
|
|
158
194
|
Call Bumbleworks::Task#complete to finish a task and proceed to the next expression.
|
159
195
|
|
160
|
-
See the Bumbleworks::Task class for more details.
|
196
|
+
See the Bumbleworks::Task class for more details.
|
197
|
+
|
198
|
+
## Rake Tasks
|
199
|
+
|
200
|
+
*TODO: Actually implement these, so I'm not a liar.*
|
201
|
+
|
202
|
+
If you...
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
require 'bumbleworks/rake_tasks'
|
206
|
+
```
|
207
|
+
|
208
|
+
... in your Rakefile, Bumbleworks will give you a couple of rake tasks. Both of these rake tasks expect an `environment` Rake task to be specified that loads your application's environment (Rails, for example, gives you this automatically).
|
209
|
+
|
210
|
+
The tasks are:
|
211
|
+
|
212
|
+
1. `rake bumbleworks:start_worker`
|
213
|
+
|
214
|
+
This task starts a Bumbleworks worker, and does not return. It will expect Bumbleworks to be required and for Bumbleworks' storage to be configured.
|
215
|
+
|
216
|
+
2. `rake bumbleworks:reload_definitions`
|
217
|
+
|
218
|
+
All process definitions will be reloaded from the configured `definitions_directory`.
|
219
|
+
|
220
|
+
## Contributing
|
221
|
+
|
222
|
+
1. Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
223
|
+
1. Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
224
|
+
1. Fork the project.
|
225
|
+
1. Start a feature/bugfix branch.
|
226
|
+
1. Commit and push until you are happy with your contribution.
|
227
|
+
1. Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
228
|
+
1. Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
data/doc/GUIDE.md
CHANGED
@@ -66,10 +66,10 @@ Put the following in a `config/initializers/bumbleworks.rb` file:
|
|
66
66
|
|
67
67
|
Bumbleworks.configure do |c|
|
68
68
|
c.storage = {}
|
69
|
-
c.autostart_worker = true
|
70
69
|
end
|
71
70
|
|
72
|
-
Bumbleworks.
|
71
|
+
Bumbleworks.load_definitions!
|
72
|
+
Bumbleworks.start_worker!
|
73
73
|
```
|
74
74
|
|
75
75
|
#### The Bumbleworks Data Store
|
@@ -82,13 +82,19 @@ Bumbleworks needs its own data store, used only for process state. We'll explor
|
|
82
82
|
|
83
83
|
Out of the box, Bumbleworks supports three storage types - [Redis](http://redis.io), [Sequel](http://sequel.rubyforge.org), and a simple Ruby Hash. We're using the latter for now, since it requires no setup. You would never use the Hash storage type for production - it's in-memory and in-process, so it won't survive a restart and you can't run multiple workers. But for testing, it's ideal.
|
84
84
|
|
85
|
-
####
|
85
|
+
#### Loading Process Definitions
|
86
86
|
|
87
|
-
*
|
87
|
+
*Why are you yelling at me about loading definitions?*
|
88
88
|
|
89
|
-
|
89
|
+
The `Bumbleworks.load_definitions!` call loads all process definitions in the configured directory. See "Writing our First Process Definition" below for more on this.
|
90
90
|
|
91
|
-
|
91
|
+
#### Starting a Worker
|
92
|
+
|
93
|
+
*Okay, intelligent pants. What about `Bumbleworks.start_worker!`?*
|
94
|
+
|
95
|
+
In a production environment, your "workers" - Ruby processes that actually run the workflow, stepping through your process definitions and generating task queues, etc. - should be instantiated in separate daemon processes. To support this best practice, Bumbleworks doesn't ever automatically start a worker for you - this is something you'd most likely do through the provided rake task (`rake bumbleworks:start_worker`, if you're one of those nerds who likes to know stuff).
|
96
|
+
|
97
|
+
When we're developing locally or running tests, though, running a separate worker would be overkill. However, not running a worker means launching processes won't actually do anything, and you'll slowly succumb to a suffocating despair. For ease of development and testing, for now we're going to spin up a worker in the initializer with `Bumbleworks.start_worker!`, which (surprisingly) starts a worker.
|
92
98
|
|
93
99
|
## Writing our First Process Definition
|
94
100
|
|
data/lib/bumbleworks.rb
CHANGED
@@ -70,8 +70,7 @@ module Bumbleworks
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# @public
|
73
|
-
# Accepts a block for registering participants
|
74
|
-
# is envoked when start! is called. Note that a
|
73
|
+
# Accepts a block for registering participants. Note that a
|
75
74
|
# 'catchall Ruote::StorageParticipant' is always added to
|
76
75
|
# the end of the list (unless it is defined in the block).
|
77
76
|
#
|
@@ -82,18 +81,16 @@ module Bumbleworks
|
|
82
81
|
# plumber PlumberClass
|
83
82
|
# end
|
84
83
|
def register_participants(&block)
|
85
|
-
|
84
|
+
Bumbleworks::ParticipantRegistration.autoload_all
|
85
|
+
Bumbleworks::Ruote.register_participants(&block)
|
86
86
|
end
|
87
87
|
|
88
88
|
# @public
|
89
|
-
# Registers
|
90
|
-
#
|
91
|
-
# implicitly instantiates the storage, and might start a worker (if
|
92
|
-
# configuration.autostart_worker is true)
|
89
|
+
# Registers all process_definitions in the configured definitions_directory
|
90
|
+
# with the Ruote engine.
|
93
91
|
#
|
94
|
-
def
|
95
|
-
|
96
|
-
load_process_definitions
|
92
|
+
def load_definitions!
|
93
|
+
Bumbleworks::ProcessDefinition.create_all_from_directory!(definitions_directory)
|
97
94
|
end
|
98
95
|
|
99
96
|
# @public
|
@@ -113,16 +110,5 @@ module Bumbleworks
|
|
113
110
|
def launch!(process_definition_name, options = {})
|
114
111
|
Bumbleworks::Ruote.launch(process_definition_name, options)
|
115
112
|
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def autoload_and_register_participants
|
120
|
-
Bumbleworks::ParticipantRegistration.autoload_all
|
121
|
-
Bumbleworks::Ruote.register_participants(&@participant_block)
|
122
|
-
end
|
123
|
-
|
124
|
-
def load_process_definitions
|
125
|
-
Bumbleworks::ProcessDefinition.create_all_from_directory!(definitions_directory)
|
126
|
-
end
|
127
113
|
end
|
128
114
|
end
|
@@ -65,15 +65,6 @@ module Bumbleworks
|
|
65
65
|
#
|
66
66
|
define_setting :storage
|
67
67
|
|
68
|
-
# By default, a worker will NOT be started when the storage is initialized;
|
69
|
-
# this is the recommended practice since workers should be instantiated in
|
70
|
-
# their own threads, and multiple workers (even on different hosts) can run
|
71
|
-
# simultaneously. However, if you want a worker to start up immediately
|
72
|
-
# (useful for testing or development), set autostart_worker to true.
|
73
|
-
#
|
74
|
-
# default: false
|
75
|
-
define_setting :autostart_worker
|
76
|
-
|
77
68
|
def initialize
|
78
69
|
@storage_adapters = []
|
79
70
|
end
|
@@ -116,13 +107,6 @@ module Bumbleworks
|
|
116
107
|
end
|
117
108
|
end
|
118
109
|
|
119
|
-
# Whether or not we should start a worker when initializing the dashboard
|
120
|
-
# and storage. Only returns true if set explicitly to true.
|
121
|
-
#
|
122
|
-
def autostart_worker
|
123
|
-
@autostart_worker == true
|
124
|
-
end
|
125
|
-
|
126
110
|
# Add a storage adapter to the set of possible adapters. Takes an object
|
127
111
|
# that responds to `driver`, `use?`, `storage_class`, and `display_name`.
|
128
112
|
#
|
@@ -10,7 +10,7 @@ module Bumbleworks
|
|
10
10
|
#
|
11
11
|
def autoload_all(options = {})
|
12
12
|
options[:directory] ||= Bumbleworks.participants_directory
|
13
|
-
Bumbleworks::Support.all_files(options[:directory], :camelize => true) do |path, name|
|
13
|
+
Bumbleworks::Support.all_files(options[:directory], :camelize => true).each do |path, name|
|
14
14
|
Object.autoload name.to_sym, path
|
15
15
|
end
|
16
16
|
end
|
@@ -5,6 +5,7 @@ module Bumbleworks
|
|
5
5
|
class NotFound < StandardError; end
|
6
6
|
class FileNotFound < StandardError; end
|
7
7
|
class Invalid < StandardError; end
|
8
|
+
class DuplicatesInDirectory < StandardError; end
|
8
9
|
|
9
10
|
attr_reader :name, :definition, :tree
|
10
11
|
|
@@ -30,7 +31,6 @@ module Bumbleworks
|
|
30
31
|
errors = []
|
31
32
|
errors << "Name must be specified" unless @name
|
32
33
|
errors << "Definition or tree must be specified" unless @definition || @tree
|
33
|
-
errors << "Name is not unique" if Bumbleworks.dashboard.variables[@name]
|
34
34
|
begin
|
35
35
|
build_tree!
|
36
36
|
rescue Invalid
|
@@ -123,7 +123,11 @@ module Bumbleworks
|
|
123
123
|
#
|
124
124
|
def create_all_from_directory!(directory, opts = {})
|
125
125
|
added_names = []
|
126
|
-
Bumbleworks::Support.all_files(directory)
|
126
|
+
definition_files = Bumbleworks::Support.all_files(directory)
|
127
|
+
if definition_files.values.uniq.count != definition_files.count
|
128
|
+
raise DuplicatesInDirectory, "Definitions directory contains duplicate filenames"
|
129
|
+
end
|
130
|
+
definition_files.each do |path, basename|
|
127
131
|
puts "Registering process definition #{basename} from file #{path}" if opts[:verbose] == true
|
128
132
|
begin
|
129
133
|
create!(:name => basename, :definition => File.read(path))
|
data/lib/bumbleworks/ruote.rb
CHANGED
@@ -5,7 +5,7 @@ module Bumbleworks
|
|
5
5
|
class << self
|
6
6
|
def dashboard(options = {})
|
7
7
|
@dashboard ||= begin
|
8
|
-
context = if
|
8
|
+
context = if options[:start_worker] == true
|
9
9
|
::Ruote::Worker.new(storage)
|
10
10
|
else
|
11
11
|
storage
|
@@ -21,8 +21,8 @@ module Bumbleworks
|
|
21
21
|
dashboard.worker
|
22
22
|
end
|
23
23
|
|
24
|
-
def launch(name,
|
25
|
-
dashboard.launch(dashboard.variables[name],
|
24
|
+
def launch(name, *args)
|
25
|
+
dashboard.launch(dashboard.variables[name], *args)
|
26
26
|
end
|
27
27
|
|
28
28
|
def register_participants(&block)
|
data/lib/bumbleworks/support.rb
CHANGED
@@ -10,10 +10,11 @@ module Bumbleworks
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def all_files(directory, options = {})
|
13
|
-
Dir["#{directory}/**/*.rb"].
|
13
|
+
Dir["#{directory}/**/*.rb"].inject({}) do |memo, path|
|
14
14
|
name = File.basename(path, '.rb')
|
15
15
|
name = camelize(name) if options[:camelize] == true
|
16
|
-
|
16
|
+
memo[path] = name
|
17
|
+
memo
|
17
18
|
end
|
18
19
|
end
|
19
20
|
end
|
data/lib/bumbleworks/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
namespace :bumbleworks do
|
2
|
+
desc 'Start a Bumbleworks worker'
|
3
|
+
task :start_worker => :environment do
|
4
|
+
puts "Starting Bumbleworks worker..." if verbose == true
|
5
|
+
Bumbleworks.start_worker!(:join => true)
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Reload all process definitions from directory'
|
9
|
+
task :reload_definitions => :environment do
|
10
|
+
puts "Reloading all Bumbleworks process definitions..." if verbose == true
|
11
|
+
Bumbleworks.load_definitions!
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Launch a given Bumbleworks process'
|
15
|
+
task :launch, [:process] => :environment do |task, args|
|
16
|
+
process = args[:process]
|
17
|
+
raise ArgumentError, "Process name required" unless process
|
18
|
+
puts "Launching process '#{process}'..." if verbose == true
|
19
|
+
Bumbleworks.launch!(process)
|
20
|
+
end
|
21
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
Bumbleworks.configure! do |c|
|
2
2
|
c.root = File.dirname(__FILE__)
|
3
3
|
c.storage = {}
|
4
|
-
c.autostart_worker = true
|
5
4
|
end
|
6
5
|
|
7
6
|
Bumbleworks.register_participants do
|
@@ -9,4 +8,5 @@ Bumbleworks.register_participants do
|
|
9
8
|
molasses_maker MolassesParticipant
|
10
9
|
end
|
11
10
|
|
12
|
-
Bumbleworks.
|
11
|
+
Bumbleworks.load_definitions!
|
12
|
+
Bumbleworks.start_worker!
|
@@ -127,21 +127,6 @@ describe Bumbleworks::Configuration do
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
describe '#autostart_worker' do
|
131
|
-
it 'returns false by default' do
|
132
|
-
configuration.autostart_worker.should be_false
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'only returns true if set explicitly to true' do
|
136
|
-
configuration.autostart_worker = 'yes'
|
137
|
-
configuration.autostart_worker.should be_false
|
138
|
-
configuration.autostart_worker = 1
|
139
|
-
configuration.autostart_worker.should be_false
|
140
|
-
configuration.autostart_worker = true
|
141
|
-
configuration.autostart_worker.should be_true
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
130
|
describe '#clear!' do
|
146
131
|
it 'resets #root' do
|
147
132
|
configuration.root = '/Root'
|
@@ -72,13 +72,6 @@ describe Bumbleworks::ProcessDefinition do
|
|
72
72
|
pdef.validate!
|
73
73
|
}.to raise_error(described_class::Invalid, /Definition is not a valid process definition/)
|
74
74
|
end
|
75
|
-
|
76
|
-
it "raises error if name already taken" do
|
77
|
-
Bumbleworks.dashboard.variables['tasty_beans'] = 'A miraculous ingredient'
|
78
|
-
expect {
|
79
|
-
described_class.new(:name => 'tasty_beans').validate!
|
80
|
-
}.to raise_error(described_class::Invalid, /Name is not unique/)
|
81
|
-
end
|
82
75
|
end
|
83
76
|
|
84
77
|
describe "#save!" do
|
@@ -100,6 +93,14 @@ describe Bumbleworks::ProcessDefinition do
|
|
100
93
|
Bumbleworks.dashboard.variables['monkeys'].should ==
|
101
94
|
pdef.build_tree!
|
102
95
|
end
|
96
|
+
|
97
|
+
it "overwrites existing variable with new definition" do
|
98
|
+
Bumbleworks.dashboard.variables['monkeys'] = 'A miraculous ingredient'
|
99
|
+
pdef = described_class.new(:name => 'monkeys', :definition => valid_definition)
|
100
|
+
pdef.save!
|
101
|
+
Bumbleworks.dashboard.variables['monkeys'].should ==
|
102
|
+
pdef.build_tree!
|
103
|
+
end
|
103
104
|
end
|
104
105
|
|
105
106
|
describe ".find_by_name" do
|
@@ -136,11 +137,25 @@ describe Bumbleworks::ProcessDefinition do
|
|
136
137
|
}.to raise_error(described_class::Invalid)
|
137
138
|
end
|
138
139
|
|
140
|
+
it 'raises error if duplicate filenames are encountered' do
|
141
|
+
Bumbleworks::Support.stub(:all_files).and_return({
|
142
|
+
'Rhubarb Derailleur' => 'popular_side_dish',
|
143
|
+
'Cantonese Phrasebook' => 'popular_side_dish',
|
144
|
+
'Beans' => 'unpopular_side_dish'
|
145
|
+
})
|
146
|
+
expect {
|
147
|
+
described_class.create_all_from_directory!(definitions_path)
|
148
|
+
}.to raise_error(described_class::DuplicatesInDirectory)
|
149
|
+
end
|
150
|
+
|
139
151
|
it 'rolls back any processes defined within current transaction if error' do
|
140
152
|
Bumbleworks.dashboard.variables['keep_me'] = 'top_secret_cat_pics'
|
141
|
-
|
142
|
-
|
143
|
-
|
153
|
+
# stubbing here so we can explicitly set an order which will
|
154
|
+
# ensure we're testing rollback
|
155
|
+
Bumbleworks::Support.stub(:all_files).and_return({
|
156
|
+
definition_path('test_process') => 'test_process',
|
157
|
+
definition_path('a_list_of_jams') => 'a_list_of_jams'
|
158
|
+
})
|
144
159
|
expect {
|
145
160
|
described_class.create_all_from_directory!(definitions_path)
|
146
161
|
}.to raise_error
|
@@ -14,17 +14,11 @@ describe Bumbleworks::Ruote do
|
|
14
14
|
described_class.dashboard.should be_an_instance_of(Ruote::Dashboard)
|
15
15
|
end
|
16
16
|
|
17
|
-
it 'does not start a worker
|
17
|
+
it 'does not start a worker by default' do
|
18
18
|
Bumbleworks.storage = {}
|
19
19
|
described_class.dashboard.worker.should be_nil
|
20
20
|
end
|
21
21
|
|
22
|
-
it 'starts a worker if autostart is true' do
|
23
|
-
Bumbleworks.storage = {}
|
24
|
-
Bumbleworks.autostart_worker = true
|
25
|
-
described_class.dashboard.worker.should_not be_nil
|
26
|
-
end
|
27
|
-
|
28
22
|
it 'starts a worker if :start_worker option is true' do
|
29
23
|
Bumbleworks.storage = {}
|
30
24
|
described_class.dashboard(:start_worker => true).worker.should_not be_nil
|
@@ -12,29 +12,23 @@ describe Bumbleworks::Support do
|
|
12
12
|
describe ".all_files" do
|
13
13
|
let(:test_directory) { File.join(fixtures_path, 'definitions').to_s }
|
14
14
|
|
15
|
-
it "for given directory,
|
16
|
-
assembled_hash =
|
17
|
-
described_class.all_files(test_directory) do |path, name|
|
18
|
-
assembled_hash[name] = path
|
19
|
-
end
|
15
|
+
it "for given directory, creates hash of basename => path pairs" do
|
16
|
+
assembled_hash = described_class.all_files(test_directory)
|
20
17
|
|
21
|
-
assembled_hash['test_process'].should ==
|
22
|
-
|
23
|
-
assembled_hash['test_nested_process'].should ==
|
24
|
-
|
18
|
+
assembled_hash[File.join(fixtures_path, 'definitions', 'test_process.rb').to_s].should ==
|
19
|
+
'test_process'
|
20
|
+
assembled_hash[File.join(fixtures_path, 'definitions', 'nested_folder', 'test_nested_process.rb').to_s].should ==
|
21
|
+
'test_nested_process'
|
25
22
|
end
|
26
23
|
|
27
24
|
it "camelizes names if :camelize option is true " do
|
28
25
|
path = File.join(fixtures_path, 'definitions')
|
29
|
-
assembled_hash =
|
30
|
-
described_class.all_files(test_directory, :camelize => true) do |path, name|
|
31
|
-
assembled_hash[name] = path
|
32
|
-
end
|
26
|
+
assembled_hash = described_class.all_files(test_directory, :camelize => true)
|
33
27
|
|
34
|
-
assembled_hash['
|
35
|
-
|
36
|
-
assembled_hash['
|
37
|
-
|
28
|
+
assembled_hash[File.join(fixtures_path, 'definitions', 'test_process.rb').to_s].should ==
|
29
|
+
'TestProcess'
|
30
|
+
assembled_hash[File.join(fixtures_path, 'definitions', 'nested_folder', 'test_nested_process.rb').to_s].should ==
|
31
|
+
'TestNestedProcess'
|
38
32
|
end
|
39
33
|
end
|
40
34
|
end
|
@@ -10,15 +10,14 @@ describe Bumbleworks do
|
|
10
10
|
it 'allows multiple cumulative configuration blocks' do
|
11
11
|
described_class.configure do |c|
|
12
12
|
c.root = 'pickles'
|
13
|
-
c.autostart_worker = false
|
14
13
|
end
|
15
14
|
|
16
15
|
described_class.configure do |c|
|
17
|
-
c.
|
16
|
+
c.storage = 'nerfy'
|
18
17
|
end
|
19
18
|
|
20
19
|
described_class.configuration.root.should == 'pickles'
|
21
|
-
described_class.configuration.
|
20
|
+
described_class.configuration.storage.should == 'nerfy'
|
22
21
|
end
|
23
22
|
|
24
23
|
it 'requires a block' do
|
@@ -53,44 +52,20 @@ describe Bumbleworks do
|
|
53
52
|
end
|
54
53
|
|
55
54
|
describe '.register_participants' do
|
56
|
-
it '
|
57
|
-
|
58
|
-
|
59
|
-
described_class.instance_variable_get('@participant_block').should == participant_block
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe '.start!' do
|
64
|
-
before :each do
|
65
|
-
described_class.reset!
|
66
|
-
Bumbleworks::ParticipantRegistration.stub(:autoload_all)
|
67
|
-
described_class.stub(:load_process_definitions)
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'registers pre-configured participants with ruote' do
|
71
|
-
the_block = lambda {}
|
72
|
-
described_class.register_participants &the_block
|
55
|
+
it 'autoloads and registers participants' do
|
56
|
+
the_block = lambda { }
|
57
|
+
Bumbleworks::ParticipantRegistration.should_receive(:autoload_all)
|
73
58
|
Bumbleworks::Ruote.should_receive(:register_participants).with(&the_block)
|
74
|
-
described_class.
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'registers process definitions with dashboard' do
|
78
|
-
described_class.storage = {}
|
79
|
-
described_class.should_receive(:load_process_definitions)
|
80
|
-
described_class.start!
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'does not automatically start a worker by default' do
|
84
|
-
described_class.storage = {}
|
85
|
-
described_class.start!
|
86
|
-
Bumbleworks::Ruote.dashboard.worker.should be_nil
|
59
|
+
described_class.register_participants &the_block
|
87
60
|
end
|
61
|
+
end
|
88
62
|
|
89
|
-
|
63
|
+
describe '.load_definitions!' do
|
64
|
+
it 'creates all definitions from directory' do
|
65
|
+
described_class.stub(:definitions_directory).and_return(:defs_dir)
|
90
66
|
described_class.storage = {}
|
91
|
-
|
92
|
-
described_class.
|
93
|
-
Bumbleworks::Ruote.dashboard.worker.should_not be_nil
|
67
|
+
Bumbleworks::ProcessDefinition.should_receive(:create_all_from_directory!).with(:defs_dir)
|
68
|
+
described_class.load_definitions!
|
94
69
|
end
|
95
70
|
end
|
96
71
|
|
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.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2013-05-
|
15
|
+
date: 2013-05-21 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: ruote
|
@@ -158,7 +158,6 @@ files:
|
|
158
158
|
- .ruby-version
|
159
159
|
- .watchr
|
160
160
|
- Gemfile
|
161
|
-
- Gemfile.lock
|
162
161
|
- LICENSE.txt
|
163
162
|
- README.md
|
164
163
|
- Rakefile
|
@@ -170,12 +169,14 @@ files:
|
|
170
169
|
- lib/bumbleworks/hash_storage.rb
|
171
170
|
- lib/bumbleworks/participant_registration.rb
|
172
171
|
- lib/bumbleworks/process_definition.rb
|
172
|
+
- lib/bumbleworks/rake_tasks.rb
|
173
173
|
- lib/bumbleworks/ruote.rb
|
174
174
|
- lib/bumbleworks/storage_adapter.rb
|
175
175
|
- lib/bumbleworks/support.rb
|
176
176
|
- lib/bumbleworks/task.rb
|
177
177
|
- lib/bumbleworks/tree_builder.rb
|
178
178
|
- lib/bumbleworks/version.rb
|
179
|
+
- lib/tasks/bumbleworks.rake
|
179
180
|
- spec/fixtures/apps/with_default_directories/app/participants/honey_participant.rb
|
180
181
|
- spec/fixtures/apps/with_default_directories/app/participants/molasses_participant.rb
|
181
182
|
- spec/fixtures/apps/with_default_directories/config_initializer.rb
|
@@ -215,18 +216,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
215
216
|
- - ! '>='
|
216
217
|
- !ruby/object:Gem::Version
|
217
218
|
version: '0'
|
218
|
-
segments:
|
219
|
-
- 0
|
220
|
-
hash: -3888661442558670334
|
221
219
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
222
220
|
none: false
|
223
221
|
requirements:
|
224
222
|
- - ! '>='
|
225
223
|
- !ruby/object:Gem::Version
|
226
224
|
version: '0'
|
227
|
-
segments:
|
228
|
-
- 0
|
229
|
-
hash: -3888661442558670334
|
230
225
|
requirements: []
|
231
226
|
rubyforge_project:
|
232
227
|
rubygems_version: 1.8.23
|
@@ -260,3 +255,4 @@ test_files:
|
|
260
255
|
- spec/lib/bumbleworks_spec.rb
|
261
256
|
- spec/spec_helper.rb
|
262
257
|
- spec/support/path_helpers.rb
|
258
|
+
has_rdoc:
|
data/Gemfile.lock
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
bumbleworks (0.0.6)
|
5
|
-
ruote
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
blankslate (2.1.2.4)
|
11
|
-
columnize (0.3.6)
|
12
|
-
debugger (1.5.0)
|
13
|
-
columnize (>= 0.3.1)
|
14
|
-
debugger-linecache (~> 1.2.0)
|
15
|
-
debugger-ruby_core_source (~> 1.2.0)
|
16
|
-
debugger-linecache (1.2.0)
|
17
|
-
debugger-ruby_core_source (1.2.0)
|
18
|
-
diff-lcs (1.2.4)
|
19
|
-
file-tail (1.0.12)
|
20
|
-
tins (~> 0.5)
|
21
|
-
multi_json (1.7.3)
|
22
|
-
parslet (1.4.0)
|
23
|
-
blankslate (~> 2.0)
|
24
|
-
rake (10.0.4)
|
25
|
-
rspec (2.13.0)
|
26
|
-
rspec-core (~> 2.13.0)
|
27
|
-
rspec-expectations (~> 2.13.0)
|
28
|
-
rspec-mocks (~> 2.13.0)
|
29
|
-
rspec-core (2.13.1)
|
30
|
-
rspec-expectations (2.13.0)
|
31
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
32
|
-
rspec-mocks (2.13.1)
|
33
|
-
ruby2ruby (1.3.1)
|
34
|
-
ruby_parser (~> 2.0)
|
35
|
-
sexp_processor (~> 3.0)
|
36
|
-
ruby_parser (2.3.1)
|
37
|
-
sexp_processor (~> 3.0)
|
38
|
-
rufus-cloche (1.0.4)
|
39
|
-
rufus-json (>= 1.0.3)
|
40
|
-
rufus-dollar (1.0.4)
|
41
|
-
rufus-json (1.0.4)
|
42
|
-
rufus-mnemo (1.2.3)
|
43
|
-
rufus-scheduler (2.0.19)
|
44
|
-
tzinfo (>= 0.3.23)
|
45
|
-
rufus-treechecker (1.0.8)
|
46
|
-
ruby_parser (>= 2.0.5)
|
47
|
-
ruote (2.3.0.2)
|
48
|
-
blankslate (= 2.1.2.4)
|
49
|
-
parslet (= 1.4.0)
|
50
|
-
ruby_parser (~> 2.3)
|
51
|
-
rufus-cloche (>= 1.0.2)
|
52
|
-
rufus-dollar (>= 1.0.4)
|
53
|
-
rufus-json (>= 1.0.1)
|
54
|
-
rufus-mnemo (>= 1.2.2)
|
55
|
-
rufus-scheduler (>= 2.0.16)
|
56
|
-
rufus-treechecker (>= 1.0.8)
|
57
|
-
sourcify (= 0.5.0)
|
58
|
-
sexp_processor (3.2.0)
|
59
|
-
simplecov (0.7.1)
|
60
|
-
multi_json (~> 1.0)
|
61
|
-
simplecov-html (~> 0.7.1)
|
62
|
-
simplecov-html (0.7.1)
|
63
|
-
sourcify (0.5.0)
|
64
|
-
file-tail (>= 1.0.5)
|
65
|
-
ruby2ruby (>= 1.2.5)
|
66
|
-
ruby_parser (>= 2.0.5)
|
67
|
-
sexp_processor (>= 3.0.5)
|
68
|
-
sqlite3 (1.3.7)
|
69
|
-
tins (0.8.0)
|
70
|
-
tzinfo (0.3.37)
|
71
|
-
watchr (0.7)
|
72
|
-
|
73
|
-
PLATFORMS
|
74
|
-
ruby
|
75
|
-
|
76
|
-
DEPENDENCIES
|
77
|
-
bumbleworks!
|
78
|
-
bundler (~> 1.3)
|
79
|
-
debugger
|
80
|
-
rake
|
81
|
-
rspec
|
82
|
-
simplecov
|
83
|
-
sqlite3
|
84
|
-
watchr
|