controll 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/README.md +253 -93
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/controll.gemspec +121 -84
  5. data/lib/controll/assistant/param_assistant.rb +23 -0
  6. data/lib/controll/assistant/session_assistant.rb +23 -0
  7. data/lib/controll/assistant.rb +9 -7
  8. data/lib/controll/commander.rb +16 -3
  9. data/lib/controll/enabler/macros.rb +75 -0
  10. data/lib/controll/enabler/maps.rb +15 -0
  11. data/lib/controll/enabler/notify.rb +43 -0
  12. data/lib/controll/enabler/path_handler.rb +49 -0
  13. data/lib/controll/enabler/path_resolver.rb +47 -0
  14. data/lib/controll/enabler.rb +49 -0
  15. data/lib/controll/engine.rb +9 -0
  16. data/lib/controll/errors.rb +4 -1
  17. data/lib/controll/event/helper.rb +20 -0
  18. data/lib/controll/{helper/event_matcher.rb → event/matcher.rb} +3 -3
  19. data/lib/controll/event.rb +60 -0
  20. data/lib/controll/events.rb +48 -0
  21. data/lib/controll/executor/base.rb +3 -7
  22. data/lib/controll/executor/controlled.rb +36 -0
  23. data/lib/controll/executor/delegator.rb +6 -0
  24. data/lib/controll/executor.rb +8 -1
  25. data/lib/controll/flow/action/base.rb +30 -0
  26. data/lib/controll/flow/action/fallback.rb +25 -0
  27. data/lib/controll/flow/action/path_action.rb +24 -0
  28. data/lib/controll/flow/action.rb +7 -0
  29. data/lib/controll/flow/action_mapper/base.rb +13 -0
  30. data/lib/controll/flow/action_mapper/complex.rb +52 -0
  31. data/lib/controll/flow/action_mapper/simple.rb +54 -0
  32. data/lib/controll/flow/action_mapper.rb +7 -0
  33. data/lib/controll/flow/errors.rb +16 -0
  34. data/lib/controll/flow/event_mapper/path_finder.rb +36 -0
  35. data/lib/controll/flow/event_mapper/util.rb +43 -0
  36. data/lib/controll/flow/event_mapper.rb +6 -0
  37. data/lib/controll/flow/master/executor.rb +57 -0
  38. data/lib/controll/flow/master/macros.rb +66 -0
  39. data/lib/controll/flow/master.rb +70 -0
  40. data/lib/controll/flow.rb +15 -0
  41. data/lib/controll/focused/enabler.rb +31 -0
  42. data/lib/controll/helper.rb +0 -94
  43. data/lib/controll/macros.rb +12 -0
  44. data/lib/controll/notify/base.rb +22 -43
  45. data/lib/controll/notify/flash.rb +3 -3
  46. data/lib/controll/notify/macros.rb +57 -0
  47. data/lib/controll/notify/message/handler.rb +36 -0
  48. data/lib/controll/notify/message/resolver.rb +28 -0
  49. data/lib/controll/notify/message/translator.rb +45 -0
  50. data/lib/controll/notify/message.rb +25 -0
  51. data/lib/controll/notify/typed.rb +13 -22
  52. data/lib/controll/notify.rb +11 -4
  53. data/lib/controll.rb +8 -2
  54. data/lib/generators/controll/assistant_generator.rb +27 -0
  55. data/lib/generators/controll/executor_generator.rb +23 -0
  56. data/lib/generators/controll/flow_handler_generator.rb +21 -0
  57. data/lib/generators/controll/notifier_generator.rb +21 -0
  58. data/lib/generators/controll/setup_generator.rb +37 -0
  59. data/lib/generators/controll/templates/assistant.tt +10 -0
  60. data/lib/generators/controll/templates/commander.tt +15 -0
  61. data/lib/generators/controll/templates/executor.tt +14 -0
  62. data/lib/generators/controll/templates/flow_handler.tt +26 -0
  63. data/lib/generators/controll/templates/notifier.tt +31 -0
  64. data/spec/acceptance/app_test.rb +1 -1
  65. data/spec/controll/assistant/param_assistant_spec.rb +31 -0
  66. data/spec/controll/assistant/session_assistant_spec.rb +31 -0
  67. data/spec/controll/assistant_spec.rb +26 -0
  68. data/spec/controll/command_spec.rb +4 -4
  69. data/spec/controll/enabler/macros_spec.rb +76 -0
  70. data/spec/controll/enabler/maps_spec.rb +31 -0
  71. data/spec/controll/{helper → enabler}/notify_spec.rb +7 -17
  72. data/spec/controll/enabler/path_handler_spec.rb +24 -0
  73. data/spec/controll/enabler/path_resolver_spec.rb +87 -0
  74. data/spec/controll/enabler_spec.rb +30 -0
  75. data/spec/controll/event/helper_spec.rb +33 -0
  76. data/spec/controll/{helper/event_matcher_spec.rb → event/matcher_spec.rb} +4 -3
  77. data/spec/controll/event_spec.rb +66 -0
  78. data/spec/controll/events_spec.rb +23 -0
  79. data/spec/controll/executor/controlled_spec.rb +36 -0
  80. data/spec/controll/executor/{notificator_spec.rb → delegator_spec.rb} +4 -4
  81. data/spec/controll/flow/action_mapper/complex_spec.rb +102 -0
  82. data/spec/controll/flow/action_mapper/fallback_spec.rb +34 -0
  83. data/spec/controll/{flow_handler/render_spec.rb → flow/action_mapper/simple_spec.rb} +25 -22
  84. data/spec/controll/{flow_handler/redirect/action_spec.rb → flow/event_mapper/path_finder_spec.rb} +10 -10
  85. data/spec/controll/{flow_handler/redirect/mapper_spec.rb → flow/event_mapper/util_spec.rb} +9 -9
  86. data/spec/controll/flow/master/executor_spec.rb +56 -0
  87. data/spec/{app/app/models/.gitkeep → controll/flow/master/macros_spec.rb} +0 -0
  88. data/spec/controll/flow/master_spec.rb +157 -0
  89. data/spec/controll/notify/base_spec.rb +6 -12
  90. data/spec/controll/notify/message/handler_spec.rb +27 -0
  91. data/spec/controll/notify/message/resolver_spec.rb +53 -0
  92. data/spec/controll/notify/message/translator_spec.rb +46 -0
  93. data/spec/controll/notify/message_spec.rb +4 -0
  94. data/spec/controll/notify/{message_handler.rb → services_notifier.rb} +3 -5
  95. data/spec/controll/notify/typed_spec.rb +2 -2
  96. data/spec/{app → controll_app}/.gitignore +0 -0
  97. data/spec/{app → controll_app}/Gemfile +0 -0
  98. data/spec/{app → controll_app}/Gemfile.lock +0 -0
  99. data/spec/{app → controll_app}/README.rdoc +0 -0
  100. data/spec/{app → controll_app}/Rakefile +0 -0
  101. data/spec/controll_app/app/controll/commanders/services_commander.rb +5 -0
  102. data/spec/controll_app/app/controll/executors/services_executor.rb +4 -0
  103. data/spec/controll_app/app/controll/flows/create_services.rb +9 -0
  104. data/spec/controll_app/app/controll/notifiers/services_notifier.rb +9 -0
  105. data/spec/{app → controll_app}/app/controllers/application_controller.rb +0 -1
  106. data/spec/controll_app/app/controllers/services_controller.rb +8 -0
  107. data/spec/{app/lib/assets → controll_app/app/models}/.gitkeep +0 -0
  108. data/spec/{app → controll_app}/app/models/post.rb +0 -0
  109. data/spec/{app → controll_app}/app/views/layouts/application.html.erb +0 -0
  110. data/spec/{app → controll_app}/app/views/posts/_form.html.erb +0 -0
  111. data/spec/{app → controll_app}/app/views/posts/edit.html.erb +0 -0
  112. data/spec/{app → controll_app}/app/views/posts/index.html.erb +0 -0
  113. data/spec/{app → controll_app}/app/views/posts/new.html.erb +0 -0
  114. data/spec/{app → controll_app}/app/views/posts/show.html.erb +0 -0
  115. data/spec/{app → controll_app}/config/application.rb +1 -1
  116. data/spec/{app → controll_app}/config/boot.rb +0 -0
  117. data/spec/{app → controll_app}/config/environment.rb +0 -0
  118. data/spec/{app → controll_app}/config/environments/development.rb +0 -0
  119. data/spec/{app → controll_app}/config/environments/test.rb +0 -0
  120. data/spec/{app → controll_app}/config/initializers/backtrace_silencers.rb +0 -0
  121. data/spec/{app → controll_app}/config/initializers/inflections.rb +0 -0
  122. data/spec/{app → controll_app}/config/initializers/mime_types.rb +0 -0
  123. data/spec/{app → controll_app}/config/initializers/secret_token.rb +0 -0
  124. data/spec/{app → controll_app}/config/initializers/session_store.rb +0 -0
  125. data/spec/{app → controll_app}/config/locales/en.yml +0 -0
  126. data/spec/controll_app/config/routes.rb +5 -0
  127. data/spec/{app → controll_app}/config.ru +0 -0
  128. data/spec/{app → controll_app}/db/seeds.rb +0 -0
  129. data/spec/{app/lib/tasks → controll_app/log}/.gitkeep +0 -0
  130. data/spec/{app → controll_app}/public/404.html +0 -0
  131. data/spec/{app → controll_app}/public/422.html +0 -0
  132. data/spec/{app → controll_app}/public/500.html +0 -0
  133. data/spec/{app → controll_app}/public/favicon.ico +0 -0
  134. data/spec/{app → controll_app}/public/index.html +0 -0
  135. data/spec/{app → controll_app}/public/javascripts/application.js +0 -0
  136. data/spec/{app → controll_app}/public/robots.txt +0 -0
  137. data/spec/{app → controll_app}/public/stylesheets/application.css +0 -0
  138. metadata +122 -85
  139. data/lib/controll/executor/notificator.rb +0 -12
  140. data/lib/controll/flow_handler/base.rb +0 -19
  141. data/lib/controll/flow_handler/control.rb +0 -85
  142. data/lib/controll/flow_handler/errors.rb +0 -5
  143. data/lib/controll/flow_handler/event_helper.rb +0 -18
  144. data/lib/controll/flow_handler/redirect/action.rb +0 -45
  145. data/lib/controll/flow_handler/redirect/mapper.rb +0 -41
  146. data/lib/controll/flow_handler/redirect.rb +0 -51
  147. data/lib/controll/flow_handler/render.rb +0 -51
  148. data/lib/controll/flow_handler.rb +0 -11
  149. data/lib/controll/helper/notify.rb +0 -74
  150. data/lib/controll/helper/path_resolver.rb +0 -45
  151. data/spec/app/app/controllers/posts_controller.rb +0 -52
  152. data/spec/app/config/routes.rb +0 -62
  153. data/spec/app/log/.gitkeep +0 -0
  154. data/spec/app/script/rails +0 -6
  155. data/spec/app/spec/controllers/posts_controller_spec.rb +0 -59
  156. data/spec/app/spec/isolated_spec_helper.rb +0 -6
  157. data/spec/app/spec/spec_helper.rb +0 -5
  158. data/spec/app/spec/unit/controllers/posts_controller_isolated_spec.rb +0 -63
  159. data/spec/app/spec/unit/controllers/posts_controller_spec.rb +0 -59
  160. data/spec/app/test/functional/.gitkeep +0 -0
  161. data/spec/app/test/functional/posts_controller_test.rb +0 -67
  162. data/spec/app/test/isolated_test_helper.rb +0 -7
  163. data/spec/app/test/test_helper.rb +0 -6
  164. data/spec/app/test/unit/.gitkeep +0 -0
  165. data/spec/app/test/unit/controllers/posts_controller_isolated_test.rb +0 -71
  166. data/spec/app/test/unit/controllers/posts_controller_test.rb +0 -67
  167. data/spec/app/vendor/assets/javascripts/.gitkeep +0 -0
  168. data/spec/app/vendor/assets/stylesheets/.gitkeep +0 -0
  169. data/spec/app/vendor/plugins/.gitkeep +0 -0
  170. data/spec/controll/asssistant_spec.rb +0 -5
  171. data/spec/controll/flow_handler/control_spec.rb +0 -159
  172. data/spec/controll/flow_handler/redirect_spec.rb +0 -93
  173. data/spec/controll/helper/path_resolver_spec.rb +0 -49
  174. data/spec/controll/helper_spec.rb +0 -108
data/README.md CHANGED
@@ -1,14 +1,24 @@
1
1
  # Controll
2
2
 
3
- Some nice and nifty utilities to help you manage complex controller logic.
3
+ Some nice and nifty utilities to help you manage complex controller logic.
4
+
5
+ ## Requirements
6
+
7
+ This gem is designed for Rails 3+ and currently only supports (has been tested with) Ruby 1.9+. The gem is under development but stable releases will be pushed to rubygems. Note that older versions may not support the same API described in the README. Go back in history and/or browse the code for that specific version.
8
+
9
+ Enjoy :)
4
10
 
5
11
  ## Background
6
12
 
7
- This gem contains logic extracted from my `oauth_assist` gem/engine which again was a response to this article [oauth pure tutorial](http://www.communityguides.eu/articles/16).
13
+ This gem contains logic extracted from my [oauth_assist](https://github.com/kristianmandrup/oauth_assist) gem (and engine) which was a response to this article [oauth pure tutorial](http://www.communityguides.eu/articles/16).
14
+
15
+ Note that the *oauth_assist* gem is not yet fully functional and done, as it "awaits" a stable release of this gem. Please feel free to help out in this effort!
8
16
 
9
17
  ## Justification
10
18
 
11
- As you can see, the following `#create` REST action is a nightmare of complexity and flow control leading to various different flash messages and redirect/render depending on various outcomes... there MUST be a better way!
19
+ As you can see, the following `#create` REST action is a nightmare of complexity and flow control leading to various different flash messages and redirect/render depending on various outcomes...
20
+
21
+ Then I naturally thought: *There MUST be a better way!*
12
22
 
13
23
  ```ruby
14
24
  def create
@@ -77,22 +87,51 @@ end
77
87
  Using the tools contained in `controll` the above logic can be encapsulated like this:
78
88
 
79
89
  ```ruby
80
- def create
81
- FlowHandler::CreateService.new(self).execute
90
+ class ServicesController < ApplicationController
91
+ include Controll::Enabler
92
+
93
+ def create
94
+ execute # action.perform
95
+ end
82
96
  end
83
97
  ```
84
98
 
85
- A `FlowHandler` can use Executors to encapsulate execution logic, which again can execute Commands that encapsulate business logic related to the user Session or models (data).
99
+ A `Flow` can use Executors to encapsulate execution logic, which again can execute Commands that encapsulate business logic related to the user Session or models (data).
100
+
101
+ The Flow takes the last event on the event stack and consults the ActionPaths registered, usually a Redirecter and Renderer. An ActionPath is a type of Action which can return a path. The Flow initiates an Executor which iterates the ActionPaths to find the first one which can match the event.
102
+
103
+ The first one with a match is returned as the Action, which the controller can then perform in order to either render or redirect.
104
+
105
+ If none of the ActionPaths can match the event, a Fallback Action is returned. The controller should then be configured to handle a Fallback Action appropriately.
86
106
 
87
- The FlowHandler can manage Redirect, Render and Notifications in a standardized, much more Object Oriented fashion, which adheres to the Single Responsibility pattern.
107
+ Controll has built in Notification Management which work both for flash messages (or other types of notifications) and as return codes for use in flow-control logic.
88
108
 
89
- Controll has built in notification management which work both for flash messages (or other types of notifications) and as return codes for use in flow-control logic.
109
+ All events in the event stack are processed and can fx be put on the flash hash according to event type, fx `flash[:error]` for an `:error` event etc.
90
110
 
91
- Using the `controll` helpers, you can avoid the typical Rails anti-pattern of Thick controllers, without bloating your Models with unrelated model logic or pulling in various Helper modules which pollute the space of the Controller anyhow!
111
+ The Notification system works by mapping events to messages in a central location, similar to mapping events to paths.
112
+
113
+ Using these Controll artifacts/systems, you can avoid the typical Rails anti-pattern of Thick controllers, without bloating your Models with unrelated model logic or pulling in various Helper modules which pollute the space of the Controller!
92
114
 
93
115
  ## Usage
94
116
 
95
- In your controller include the `Controll::Helper` helper module.
117
+ The recommended approach to handle complex Controller logic using Controll:
118
+
119
+ * Enable Controll on Controller
120
+ * Configure Controller with Flow, Commander and Notifier
121
+
122
+ * Create Commands for Commander
123
+ * Define events corresponding to commands
124
+ * Configure Commander with Command methods
125
+
126
+ * Create Flow
127
+ * Configure Flow with Render and Redirect event mappings
128
+
129
+ * Create Notifier
130
+ * Configure Notifier with Event handlers and event -> message mappings
131
+
132
+ ## Controll enabling a Controller
133
+
134
+ In your controller include the `Controll::Enabler` module.
96
135
 
97
136
  ```ruby
98
137
  class ServicesController < ApplicationController
@@ -100,7 +139,7 @@ class ServicesController < ApplicationController
100
139
  protect_from_forgery :except => :create
101
140
 
102
141
  # see 'controll' gem
103
- include Controll::Helper
142
+ include Controll::Enabler
104
143
  end
105
144
  ```
106
145
 
@@ -108,87 +147,159 @@ Better yet, to make it available for all controllers, include it in your Applica
108
147
 
109
148
  ```ruby
110
149
  class ApplicationController
111
- include Controll::Helper
150
+ include Controll::Enabler
112
151
  end
113
152
  ```
114
153
 
115
- In your Controller you should define a MessageHandler and Commander to be used.
154
+ You can also include the `Controll::Macros` module in a base Controller class of your choosing, fx:
155
+
156
+ ```ruby
157
+ class ApplicationController
158
+ include Controll::Macros
159
+ end
160
+ ```
161
+
162
+ Then you can use the `#enable_controll` macro in any subclass Controller class:
116
163
 
117
164
  ```ruby
118
165
  class ServicesController < ApplicationController
119
- include Controll::Helper
166
+ enable_controll
167
+ end
168
+ ```
169
+
170
+ ## Controll configuration
171
+
172
+ In your Controller you should define a Notifier and Commander to be used.
173
+
174
+ ```ruby
175
+ class ServicesController < ApplicationController
176
+ enable_controll
120
177
 
121
178
  ...
122
179
 
123
180
  protected
124
181
 
125
- message_handler :services
182
+ notifier :services
126
183
  commander :services
184
+
185
+ # or simply (using naming convention)
186
+ controll :notifier, :commander
187
+
188
+ def create
189
+ create_action.perform
190
+ end
191
+
192
+ protected
193
+
194
+ def create_action
195
+ @create_action ||= Flows::CreateService.new(self)
196
+ end
197
+
198
+ fallback do |event|
199
+ event == :no_auth ? render(:text => omniauth.to_yaml) : fallback_action
200
+ end
201
+
202
+ def fallback_action
203
+ redirect_to root_url
204
+ end
127
205
  end
128
206
  ```
129
207
 
130
- The Commander is where you register a set of related commands, typically for a specific controller.
208
+ ### Focused Controller config
209
+
210
+ In case you use Focused Controller, this can be strutctured even better like this:
131
211
 
132
212
  ```ruby
133
- class ServicesCommander < Controll::Commander
213
+ class ServicesController
134
214
 
135
- # register commands with controller
136
- commands :cancel_commit, :create_account, :signout
215
+ # could be extracted into "global" namespace for reuse across controllers...
216
+ module ControllAction
217
+ extend ActiveSupport::Concern
218
+
219
+ included do
220
+ controll :notifier, :commander, :flow
221
+ end
137
222
 
138
- def sign_in_command
139
- @sign_in_command ||= SignInCommand.new auth_hash: auth_hash, user_id: user_id, service_id: service_id, service_hash: service_hash, initiator: self
223
+ def fallback_action
224
+ redirect_to root_url
225
+ end
140
226
  end
141
227
 
142
- # delegations
143
- controller_methods :auth_hash, :user_id, :service_id, :service_hash
228
+ class Create < FocusedAction
229
+ include ControllAction
230
+
231
+ run do
232
+ execute
233
+ end
234
+
235
+ protected
236
+
237
+ fallback do |event|
238
+ event == :no_auth ? render(:text => omniauth.to_yaml) : fallback_action
239
+ end
240
+ end
144
241
  end
145
242
  ```
146
243
 
147
- The `#commands` class macro can be used to create command methods that only take the initiator (in this case the controller) as argument.
244
+ *Wow! Now we're talking!!!!*
148
245
 
149
- For how to implement the commands, see the `imperator` gem, or see the `oauth_assist` engine for a full example.
246
+ ## Creating a Commander
150
247
 
151
- We will implement this MessageHandler later when we know which notifications and errors we want to use/issue.
248
+ The Commander is your command center for a group of related commands. Typically you will want to define a Commander for a specific controller if the controller has more than 3 commands. If you put your Commander under the `Commanders` namespace (module) you get direct access to the Commander constant to be used as subclass.
152
249
 
153
- For Controller actions that require complex flow control, use a FlowHandler:
250
+ The Commander should contain a group of command methods that are conceptually in the same "category", fx all the command for a particular controller.
154
251
 
155
252
  ```ruby
156
- module Controll::FlowHandler
157
- class CreateService < Control
158
- protected
253
+ module Commanders
254
+ class Services < Commander
255
+ # create basic command methods
256
+ command_methods :cancel_commit, :create_account, :signout
257
+
258
+ # create custom command method with custom argument hash
259
+ def sign_in_command
260
+ @sign_in_command ||= SignInCommand.new auth_hash: auth_hash, user_id: user_id, service_id: service_id, service_hash: service_hash, initiator: self
261
+ end
159
262
 
160
- # use for more advanced render/redirect logic (fx when using paths with arguments)
161
- def use_alternatives
263
+ command_method :sign_out do
264
+ @sign_out_command ||= SignOutCommand.new user_id: user_id, service_id: service_id, service_hash: service_hash, initiator: self
162
265
  end
163
266
 
164
- def use_fallback
165
- event == :no_auth ? do_render(:text => omniauth.to_yaml) : fallback_action
166
- end
267
+ # delegations (alias for initiator_methods )
268
+ controller_methods :auth_hash, :user_id, :service_id, :service_hash
269
+ end
270
+ end
271
+ ```
167
272
 
168
- def action_handlers
169
- [Redirect, Render]
170
- end
273
+ The `Commander class extends `Imperator::Command::MethodFactory` making `#command_method` and `#command_methods` available. These class macros can be used to create command methods that only take the initiator (in this case the controller) as argument.
171
274
 
172
- def event
173
- @event ||= authentication
174
- end
275
+ For how to implement the Commands themselves, see the [imperator-ext](https://github.com/kristianmandrup/imperator-ext) gem.
175
276
 
176
- def authentication
177
- @authentication ||= Authenticator.new(controller).execute
178
- end
277
+ ## Flows
179
278
 
180
- class Render < Controll::FlowHandler::Render
181
- def self.default_path
182
- :signup_services_path
183
- end
279
+ For Controller actions that require complex flow control, use a Flow:
184
280
 
185
- def self.events
186
- [:signed_in_new_user]
281
+ ```ruby
282
+ module Flows
283
+ class CreateService < Flow
284
+
285
+ # event method that returns the event to be processed by the flow handler
286
+ event do
287
+ Executors::Authenticator.new(controller).execute
288
+ end
289
+
290
+ # configuration of the Renderer ActionHandler
291
+ # will return a Renderer Action if it matches the event
292
+ renderer :simple do
293
+ events :signed_in_new_user, :signed_in do
294
+ signup_services_path
187
295
  end
188
296
  end
189
297
 
190
- class Redirect < Controll::FlowHandler::Render
191
- def self.redirections
298
+ # configuration of the Redirecter ActionHandler
299
+ # will return a Redirecter Action if it matches the event
300
+ redirecter :complex do
301
+ # redirection mappings for :notice events
302
+ event_map :notice do
192
303
  {
193
304
  signup_services_path: :signed_in_new_user
194
305
  services_path: [:signed_in_connect, :signed_in_new_connect]
@@ -196,39 +307,56 @@ module Controll::FlowHandler
196
307
  }
197
308
  end
198
309
 
199
- def self.error_redirections
200
- {
201
- signin_path: [:error, :invalid, :auth_error]
202
- }
203
- end
310
+ # redirection mappings for :error events
311
+ event_map :error, signin_path: [:error, :invalid, :auth_error]
204
312
  end
205
313
  end
206
314
  end
207
315
  ```
208
316
 
209
- In the `Redirect` class we are setting up a mapping for various path, specifying which notifications/event should cause a redirect to that path.
317
+ The `#renderer` and `#redirector` macros will each create a Class of the same name that inherit from Controll::Flow::ActionMapper::Simple or Controll::Flow::ActionMapper::Complex.
318
+ You can also define these classes directly yourself instead of using the macros.
319
+ The *simple* action mapper maps a list of events to a single path and otherwise falls back.
320
+ The complex action mapper maps the event to an event hash for each registered event type.
210
321
 
211
- If you are rendering or redirecting to paths that take arguments, you can either extend the `#action` class method of your Redirect or Render class implementation or you can define a `#use_alternatives` method in your `FlowHandler` that contains this particular flow logic. You can also use the `#use_fallback` method for this purpose.
322
+ In the `Redirecter` class we are setting up a mapping for various paths, for each path specifying which events should cause a redirect to that path.
212
323
 
213
- ## The Authenticator Executor
324
+ If you are rendering or redirecting to paths that take arguments, you can either extend the `#action` class method of your Redirect or Render class implementation or you can define a `#use_alternatives` method in your `Flow` that contains this particular flow logic.
214
325
 
215
- The `Authenticator` inherits from `Executor::Notificator` which uses `#method_missing` in order to delegate any missing method back to the initiator of the Executor, in this case the FlowHandler. The `#result` call at the end of `#execute` ensures that the last notification event is returned, to be used for deciding what to render or where to redirect (see FlowHandler).
326
+ Note: For mapping paths that take arguments, there should be an option to take a block (closure) to be late-evaluated on the controller context ;)
327
+
328
+ ## The Executor
329
+
330
+ The `Authenticator` class shown below inherits from `Executor::Notificator` which uses `#method_missing` in order to delegate any missing method back to the controller of the Executor. The Flow passed in the controller. This means that calls can be executed directly on the controller, such as making notifications etc.
331
+
332
+ The `#result` call at the end of `#execute` ensures that the last notification event is returned, to be used for deciding what to render or where to redirect (see Flow).
216
333
 
217
334
  ```ruby
218
- module Controll::Executor
219
- class Authenticator < Notificator
335
+ module Executors
336
+ class Authenticator < Controlled
337
+
338
+ # ensures pattern:
339
+ # - perform validations and only execute command if no error
220
340
  def execute
221
- # creates an error notification named :error
222
- error and return unless valid_params?
341
+ super
342
+ result
343
+ end
223
344
 
224
- # creates an error notification named :auth_invalid
225
- error(:auth_invalid) and return unless auth_valid?
345
+ protected
346
+
347
+ controller_methods :omniauth, :service, :auth_hash, :auth_valid?
226
348
 
349
+ def do_command
227
350
  command! :sign_in
228
- result
229
351
  end
230
352
 
231
- protected
353
+ def validations
354
+ # creates an error notification named :error
355
+ error and return unless valid_params?
356
+
357
+ # creates an error notification named :auth_invalid
358
+ error(:auth_invalid) and return unless auth_valid?
359
+ end
232
360
 
233
361
  def valid_params?
234
362
  omniauth and service and auth_hash
@@ -237,25 +365,32 @@ module Controll::Executor
237
365
  end
238
366
  ```
239
367
 
240
- To encapsulate more complex busines logic affecting the user Session or Model data, we execute an the Imperator Command (see `imperator` gem) called :sign_in that we registered in the Commander of the Controller.
368
+ Alternatively you can use the execute block macro to generate the `#execute` instance method and ensure that it ends by returning result.
369
+
370
+ ```ruby
371
+ execute do
372
+ # error/validation checks? ...
373
+ command! :sign_in
374
+ end
375
+ ```
376
+
377
+ To encapsulate more complex busines logic affecting the user Session or Model data, we execute an Imperator Command (see `imperator` gem) called :sign_in that we registered in the Commander of the Controller.
241
378
 
242
379
  ## Notifier
243
380
 
244
- Now we are finally ready to define the message handler for each notification event we have defined (this should ideally be done as you define each event!).
381
+ Now we are finally ready to define the notifier to handle the different types of notification events.
245
382
 
246
383
  The example below demonstrates several different ways you can define messages for events:
247
384
 
248
385
  * using the `#messages` method to return a hash of mappings.
249
- * define a method for the event name that returns a String (w argument replacement)
250
- * i18n locale mapping [msghandler name].[notification type].[event name].
386
+ * define a method for the event name that returns a String (handles argument replacement)
387
+ * i18n locale mapping `[handler class path].[notification type].[event name]`.
251
388
 
252
389
  ```ruby
253
- module Controll::Notify
390
+ module Notifiers
254
391
  class Services < Typed
255
- class ErrorMsg < Controll::Notify::Base
256
- type :error
257
-
258
- def messages
392
+ handler :error do
393
+ messages do
259
394
  {
260
395
  must_sign_in: 'You need to sign in before accessing this page!',
261
396
 
@@ -267,35 +402,33 @@ You have not been signed in.},
267
402
  }
268
403
  end
269
404
 
270
- def auth_error!
271
- 'Error while authenticating via ' + service_name + '. The service did not return valid data.'
405
+ msg :auth_error! do
406
+ "Error while authenticating via #{service_name}. The service did not return valid data."
272
407
  end
273
408
 
274
- def auth_invalid!
409
+ msg :auth_invalid! do
275
410
  'Error while authenticating via {{full_route}}. The service returned invalid data for the user id.'
276
411
  end
277
412
  end
278
413
 
279
414
 
280
- class NoticeMsg < Controll::Notify::Base
281
- type :notice
282
-
415
+ handler :notice do
283
416
  # for :signed_in and :signed_out - defined in locale file under:
417
+ # notifiers:
418
+ # services:
419
+ # notice:
420
+ # signed_in: 'Your account has been created and you have been signed in!'
421
+ # signed_out: 'You have been signed out!'
284
422
 
285
- # services:
286
- # notice:
287
- # signed_in: 'Your account has been created and you have been signed in!'
288
- # signed_out: 'You have been signed out!'
289
-
290
- def already_connected
423
+ msg :already_connected do
291
424
  'Your account at {{provider_name}} is already connected with this site.'
292
425
  end
293
426
 
294
- def account_added
427
+ msg :account_added do
295
428
  'Your {{provider_name}} account has been added for signing in at this site.'
296
429
  end
297
430
 
298
- def sign_in_success
431
+ msg :sign_in_success do
299
432
  'Signed in successfully via {{provider_name}}.'
300
433
  end
301
434
  end
@@ -303,6 +436,33 @@ You have not been signed in.},
303
436
  end
304
437
  ```
305
438
 
439
+ ## Rails Generators
440
+
441
+ ### Setup generator
442
+
443
+ `$ rails g controll:setup`
444
+
445
+ Generate only specific controll folders
446
+
447
+ `$ rails g controll:setup commanders notifiers`
448
+
449
+ ### Controll artifact generators
450
+
451
+ * assistant
452
+ * executor
453
+ * flow
454
+ * notifier
455
+
456
+ Example usage:
457
+
458
+ `$ rails g controll:flow create_service`
459
+
460
+ Use `-h` for help on any specific controller for more usage options and info.
461
+
462
+ ## Notice
463
+
464
+ Due to a lot of recent API changes in order to simplify and improve usage, the README docs for the API might potentially contain a few inconsistencies with the code. Please notify me if you spot one. Thanks. See the specs and/or code in order to see the real API in this case.
465
+
306
466
  ## Contributing to controll
307
467
 
308
468
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
@@ -313,7 +473,7 @@ end
313
473
  * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
314
474
  * 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.
315
475
 
316
- == Copyright
476
+ ## Copyright
317
477
 
318
478
  Copyright (c) 2012 Kristian Mandrup. See LICENSE.txt for
319
479
  further details.
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ Jeweler::Tasks.new do |gem|
18
18
  gem.homepage = "http://github.com/kristianmandrup/controll"
19
19
  gem.license = "MIT"
20
20
  gem.summary = %Q{Utils for handling complex Controller/Business logic}
21
- gem.description = %Q{FlowHandler, Executor, Notifier and more, all tied together tool pack}
21
+ gem.description = %Q{Flow, Executor, Notifier and more, all tied together tool pack}
22
22
  gem.email = "kmandrup@gmail.com"
23
23
  gem.authors = ["Kristian Mandrup"]
24
24
  # dependencies defined in Gemfile
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0