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 CHANGED
@@ -1,2 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
1
9
  coverage
2
- pkg/*
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
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 two storage methods - [Redis](http://redis.io/) and [Sequel](http://sequel.rubyforge.org/) (an ORM that itself supports MySQL, Postgres, etc.).
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
- c.storage = Redis.new(:host => '127.0.0.1', :db => 0, :thread_safe => true)
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
- c.storage = Sequel.connect('postgres://user:password@host:port/database_name')
67
- # ...
90
+ c.storage = Sequel.connect('postgres://user:password@host:port/database_name')
91
+ # ...
68
92
  end
69
93
  ```
70
94
 
71
- ### Process Definition Loading
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
- 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). 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:
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
- ## Participant Class Registration
110
+ ### Participant Class Directory
85
111
 
86
- 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:
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, running via Rake), it usually won't have trouble guessing the directory.
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
- ### Starting Work
129
+ ### Loading Definitions and Participants
130
+
131
+ #### Process Definitions
115
132
 
116
- 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. To run a worker, you can either set the `autostart_worker` option in configuration, before starting Bumbleworks:
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.configure do |c|
120
- # ...
121
- # NOTE: NOT RECOMMENDED IN PRODUCTION!
122
- c.autostart_worker = true
123
- end
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
- Bumbleworks.start! # this will now start a worker automatically
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
- ... 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 do the following (most likely in a Rake task that has your environment loaded):
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.
@@ -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.start!
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
- #### Auto-starting Workers
85
+ #### Loading Process Definitions
86
86
 
87
- *Okay, intelligent pants. What about `c.autostart_worker = true`?*
87
+ *Why are you yelling at me about loading definitions?*
88
88
 
89
- 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.
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
- To support this best practice, we don't run a worker by default when you call `Bumbleworks.start!`. This means launching processes won't actually do anything, and you'll slowly succumb to a suffocating despair. For ease of development and testing, you can set `autostart_worker` to true, which will (surprisingly) automatically start a worker when you call `Bumbleworks.start!`.
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
 
@@ -70,8 +70,7 @@ module Bumbleworks
70
70
  end
71
71
 
72
72
  # @public
73
- # Accepts a block for registering participants which
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
- @participant_block = block
84
+ Bumbleworks::ParticipantRegistration.autoload_all
85
+ Bumbleworks::Ruote.register_participants(&block)
86
86
  end
87
87
 
88
88
  # @public
89
- # Registers participants and process_definitions with the Ruote engine.
90
- # Also calls Bumbleworks::Ruote.dashboard for the first time, which
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 start!
95
- autoload_and_register_participants
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) do |path, basename|
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))
@@ -0,0 +1,3 @@
1
+ Dir[File.join(File.dirname(__FILE__), '..', 'tasks', '*.rake')].each do |path|
2
+ load path
3
+ end
@@ -5,7 +5,7 @@ module Bumbleworks
5
5
  class << self
6
6
  def dashboard(options = {})
7
7
  @dashboard ||= begin
8
- context = if Bumbleworks.autostart_worker || options[:start_worker] == true
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, options)
25
- dashboard.launch(dashboard.variables[name], options)
24
+ def launch(name, *args)
25
+ dashboard.launch(dashboard.variables[name], *args)
26
26
  end
27
27
 
28
28
  def register_participants(&block)
@@ -10,10 +10,11 @@ module Bumbleworks
10
10
  end
11
11
 
12
12
  def all_files(directory, options = {})
13
- Dir["#{directory}/**/*.rb"].each do |path|
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
- yield path, name
16
+ memo[path] = name
17
+ memo
17
18
  end
18
19
  end
19
20
  end
@@ -1,3 +1,3 @@
1
1
  module Bumbleworks
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -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.start!
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
- Bumbleworks::Support.stub(:all_files).
142
- and_yield(definition_path('test_process'), 'test_process').
143
- and_yield(definition_path('a_list_of_jams'), 'a_list_of_jams')
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 if autostart is false' do
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, yields given block with path and name params" do
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
- File.join(fixtures_path, 'definitions', 'test_process.rb').to_s
23
- assembled_hash['test_nested_process'].should ==
24
- File.join(fixtures_path, 'definitions', 'nested_folder', 'test_nested_process.rb').to_s
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['TestProcess'].should ==
35
- File.join(fixtures_path, 'definitions', 'test_process.rb').to_s
36
- assembled_hash['TestNestedProcess'].should ==
37
- File.join(fixtures_path, 'definitions', 'nested_folder', 'test_nested_process.rb').to_s
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
@@ -3,9 +3,9 @@ describe Bumbleworks::Task do
3
3
 
4
4
  before :each do
5
5
  Bumbleworks.reset!
6
- Bumbleworks.autostart_worker = true
7
6
  Bumbleworks.storage = {}
8
7
  Bumbleworks::Ruote.register_participants
8
+ Bumbleworks.start_worker!
9
9
  end
10
10
 
11
11
  describe '.new' do
@@ -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.autostart_worker = true
16
+ c.storage = 'nerfy'
18
17
  end
19
18
 
20
19
  described_class.configuration.root.should == 'pickles'
21
- described_class.configuration.autostart_worker.should == true
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 'stores the block' do
57
- participant_block = lambda { bees_honey 'BeesHoney' }
58
- described_class.register_participants &participant_block
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.start!
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
- it 'starts a worker if autostart_worker config setting is true' do
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
- described_class.autostart_worker = true
92
- described_class.start!
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.6
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-14 00:00:00.000000000 Z
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:
@@ -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