controll 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +253 -93
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/controll.gemspec +121 -84
- data/lib/controll/assistant/param_assistant.rb +23 -0
- data/lib/controll/assistant/session_assistant.rb +23 -0
- data/lib/controll/assistant.rb +9 -7
- data/lib/controll/commander.rb +16 -3
- data/lib/controll/enabler/macros.rb +75 -0
- data/lib/controll/enabler/maps.rb +15 -0
- data/lib/controll/enabler/notify.rb +43 -0
- data/lib/controll/enabler/path_handler.rb +49 -0
- data/lib/controll/enabler/path_resolver.rb +47 -0
- data/lib/controll/enabler.rb +49 -0
- data/lib/controll/engine.rb +9 -0
- data/lib/controll/errors.rb +4 -1
- data/lib/controll/event/helper.rb +20 -0
- data/lib/controll/{helper/event_matcher.rb → event/matcher.rb} +3 -3
- data/lib/controll/event.rb +60 -0
- data/lib/controll/events.rb +48 -0
- data/lib/controll/executor/base.rb +3 -7
- data/lib/controll/executor/controlled.rb +36 -0
- data/lib/controll/executor/delegator.rb +6 -0
- data/lib/controll/executor.rb +8 -1
- data/lib/controll/flow/action/base.rb +30 -0
- data/lib/controll/flow/action/fallback.rb +25 -0
- data/lib/controll/flow/action/path_action.rb +24 -0
- data/lib/controll/flow/action.rb +7 -0
- data/lib/controll/flow/action_mapper/base.rb +13 -0
- data/lib/controll/flow/action_mapper/complex.rb +52 -0
- data/lib/controll/flow/action_mapper/simple.rb +54 -0
- data/lib/controll/flow/action_mapper.rb +7 -0
- data/lib/controll/flow/errors.rb +16 -0
- data/lib/controll/flow/event_mapper/path_finder.rb +36 -0
- data/lib/controll/flow/event_mapper/util.rb +43 -0
- data/lib/controll/flow/event_mapper.rb +6 -0
- data/lib/controll/flow/master/executor.rb +57 -0
- data/lib/controll/flow/master/macros.rb +66 -0
- data/lib/controll/flow/master.rb +70 -0
- data/lib/controll/flow.rb +15 -0
- data/lib/controll/focused/enabler.rb +31 -0
- data/lib/controll/helper.rb +0 -94
- data/lib/controll/macros.rb +12 -0
- data/lib/controll/notify/base.rb +22 -43
- data/lib/controll/notify/flash.rb +3 -3
- data/lib/controll/notify/macros.rb +57 -0
- data/lib/controll/notify/message/handler.rb +36 -0
- data/lib/controll/notify/message/resolver.rb +28 -0
- data/lib/controll/notify/message/translator.rb +45 -0
- data/lib/controll/notify/message.rb +25 -0
- data/lib/controll/notify/typed.rb +13 -22
- data/lib/controll/notify.rb +11 -4
- data/lib/controll.rb +8 -2
- data/lib/generators/controll/assistant_generator.rb +27 -0
- data/lib/generators/controll/executor_generator.rb +23 -0
- data/lib/generators/controll/flow_handler_generator.rb +21 -0
- data/lib/generators/controll/notifier_generator.rb +21 -0
- data/lib/generators/controll/setup_generator.rb +37 -0
- data/lib/generators/controll/templates/assistant.tt +10 -0
- data/lib/generators/controll/templates/commander.tt +15 -0
- data/lib/generators/controll/templates/executor.tt +14 -0
- data/lib/generators/controll/templates/flow_handler.tt +26 -0
- data/lib/generators/controll/templates/notifier.tt +31 -0
- data/spec/acceptance/app_test.rb +1 -1
- data/spec/controll/assistant/param_assistant_spec.rb +31 -0
- data/spec/controll/assistant/session_assistant_spec.rb +31 -0
- data/spec/controll/assistant_spec.rb +26 -0
- data/spec/controll/command_spec.rb +4 -4
- data/spec/controll/enabler/macros_spec.rb +76 -0
- data/spec/controll/enabler/maps_spec.rb +31 -0
- data/spec/controll/{helper → enabler}/notify_spec.rb +7 -17
- data/spec/controll/enabler/path_handler_spec.rb +24 -0
- data/spec/controll/enabler/path_resolver_spec.rb +87 -0
- data/spec/controll/enabler_spec.rb +30 -0
- data/spec/controll/event/helper_spec.rb +33 -0
- data/spec/controll/{helper/event_matcher_spec.rb → event/matcher_spec.rb} +4 -3
- data/spec/controll/event_spec.rb +66 -0
- data/spec/controll/events_spec.rb +23 -0
- data/spec/controll/executor/controlled_spec.rb +36 -0
- data/spec/controll/executor/{notificator_spec.rb → delegator_spec.rb} +4 -4
- data/spec/controll/flow/action_mapper/complex_spec.rb +102 -0
- data/spec/controll/flow/action_mapper/fallback_spec.rb +34 -0
- data/spec/controll/{flow_handler/render_spec.rb → flow/action_mapper/simple_spec.rb} +25 -22
- data/spec/controll/{flow_handler/redirect/action_spec.rb → flow/event_mapper/path_finder_spec.rb} +10 -10
- data/spec/controll/{flow_handler/redirect/mapper_spec.rb → flow/event_mapper/util_spec.rb} +9 -9
- data/spec/controll/flow/master/executor_spec.rb +56 -0
- data/spec/{app/app/models/.gitkeep → controll/flow/master/macros_spec.rb} +0 -0
- data/spec/controll/flow/master_spec.rb +157 -0
- data/spec/controll/notify/base_spec.rb +6 -12
- data/spec/controll/notify/message/handler_spec.rb +27 -0
- data/spec/controll/notify/message/resolver_spec.rb +53 -0
- data/spec/controll/notify/message/translator_spec.rb +46 -0
- data/spec/controll/notify/message_spec.rb +4 -0
- data/spec/controll/notify/{message_handler.rb → services_notifier.rb} +3 -5
- data/spec/controll/notify/typed_spec.rb +2 -2
- data/spec/{app → controll_app}/.gitignore +0 -0
- data/spec/{app → controll_app}/Gemfile +0 -0
- data/spec/{app → controll_app}/Gemfile.lock +0 -0
- data/spec/{app → controll_app}/README.rdoc +0 -0
- data/spec/{app → controll_app}/Rakefile +0 -0
- data/spec/controll_app/app/controll/commanders/services_commander.rb +5 -0
- data/spec/controll_app/app/controll/executors/services_executor.rb +4 -0
- data/spec/controll_app/app/controll/flows/create_services.rb +9 -0
- data/spec/controll_app/app/controll/notifiers/services_notifier.rb +9 -0
- data/spec/{app → controll_app}/app/controllers/application_controller.rb +0 -1
- data/spec/controll_app/app/controllers/services_controller.rb +8 -0
- data/spec/{app/lib/assets → controll_app/app/models}/.gitkeep +0 -0
- data/spec/{app → controll_app}/app/models/post.rb +0 -0
- data/spec/{app → controll_app}/app/views/layouts/application.html.erb +0 -0
- data/spec/{app → controll_app}/app/views/posts/_form.html.erb +0 -0
- data/spec/{app → controll_app}/app/views/posts/edit.html.erb +0 -0
- data/spec/{app → controll_app}/app/views/posts/index.html.erb +0 -0
- data/spec/{app → controll_app}/app/views/posts/new.html.erb +0 -0
- data/spec/{app → controll_app}/app/views/posts/show.html.erb +0 -0
- data/spec/{app → controll_app}/config/application.rb +1 -1
- data/spec/{app → controll_app}/config/boot.rb +0 -0
- data/spec/{app → controll_app}/config/environment.rb +0 -0
- data/spec/{app → controll_app}/config/environments/development.rb +0 -0
- data/spec/{app → controll_app}/config/environments/test.rb +0 -0
- data/spec/{app → controll_app}/config/initializers/backtrace_silencers.rb +0 -0
- data/spec/{app → controll_app}/config/initializers/inflections.rb +0 -0
- data/spec/{app → controll_app}/config/initializers/mime_types.rb +0 -0
- data/spec/{app → controll_app}/config/initializers/secret_token.rb +0 -0
- data/spec/{app → controll_app}/config/initializers/session_store.rb +0 -0
- data/spec/{app → controll_app}/config/locales/en.yml +0 -0
- data/spec/controll_app/config/routes.rb +5 -0
- data/spec/{app → controll_app}/config.ru +0 -0
- data/spec/{app → controll_app}/db/seeds.rb +0 -0
- data/spec/{app/lib/tasks → controll_app/log}/.gitkeep +0 -0
- data/spec/{app → controll_app}/public/404.html +0 -0
- data/spec/{app → controll_app}/public/422.html +0 -0
- data/spec/{app → controll_app}/public/500.html +0 -0
- data/spec/{app → controll_app}/public/favicon.ico +0 -0
- data/spec/{app → controll_app}/public/index.html +0 -0
- data/spec/{app → controll_app}/public/javascripts/application.js +0 -0
- data/spec/{app → controll_app}/public/robots.txt +0 -0
- data/spec/{app → controll_app}/public/stylesheets/application.css +0 -0
- metadata +122 -85
- data/lib/controll/executor/notificator.rb +0 -12
- data/lib/controll/flow_handler/base.rb +0 -19
- data/lib/controll/flow_handler/control.rb +0 -85
- data/lib/controll/flow_handler/errors.rb +0 -5
- data/lib/controll/flow_handler/event_helper.rb +0 -18
- data/lib/controll/flow_handler/redirect/action.rb +0 -45
- data/lib/controll/flow_handler/redirect/mapper.rb +0 -41
- data/lib/controll/flow_handler/redirect.rb +0 -51
- data/lib/controll/flow_handler/render.rb +0 -51
- data/lib/controll/flow_handler.rb +0 -11
- data/lib/controll/helper/notify.rb +0 -74
- data/lib/controll/helper/path_resolver.rb +0 -45
- data/spec/app/app/controllers/posts_controller.rb +0 -52
- data/spec/app/config/routes.rb +0 -62
- data/spec/app/log/.gitkeep +0 -0
- data/spec/app/script/rails +0 -6
- data/spec/app/spec/controllers/posts_controller_spec.rb +0 -59
- data/spec/app/spec/isolated_spec_helper.rb +0 -6
- data/spec/app/spec/spec_helper.rb +0 -5
- data/spec/app/spec/unit/controllers/posts_controller_isolated_spec.rb +0 -63
- data/spec/app/spec/unit/controllers/posts_controller_spec.rb +0 -59
- data/spec/app/test/functional/.gitkeep +0 -0
- data/spec/app/test/functional/posts_controller_test.rb +0 -67
- data/spec/app/test/isolated_test_helper.rb +0 -7
- data/spec/app/test/test_helper.rb +0 -6
- data/spec/app/test/unit/.gitkeep +0 -0
- data/spec/app/test/unit/controllers/posts_controller_isolated_test.rb +0 -71
- data/spec/app/test/unit/controllers/posts_controller_test.rb +0 -67
- data/spec/app/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/app/vendor/plugins/.gitkeep +0 -0
- data/spec/controll/asssistant_spec.rb +0 -5
- data/spec/controll/flow_handler/control_spec.rb +0 -159
- data/spec/controll/flow_handler/redirect_spec.rb +0 -93
- data/spec/controll/helper/path_resolver_spec.rb +0 -49
- 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
|
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...
|
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
|
-
|
81
|
-
|
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 `
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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::
|
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::
|
150
|
+
include Controll::Enabler
|
112
151
|
end
|
113
152
|
```
|
114
153
|
|
115
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
213
|
+
class ServicesController
|
134
214
|
|
135
|
-
#
|
136
|
-
|
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
|
-
|
139
|
-
|
223
|
+
def fallback_action
|
224
|
+
redirect_to root_url
|
225
|
+
end
|
140
226
|
end
|
141
227
|
|
142
|
-
|
143
|
-
|
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
|
-
|
244
|
+
*Wow! Now we're talking!!!!*
|
148
245
|
|
149
|
-
|
246
|
+
## Creating a Commander
|
150
247
|
|
151
|
-
|
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
|
-
|
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
|
157
|
-
class
|
158
|
-
|
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
|
-
|
161
|
-
|
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
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
177
|
-
@authentication ||= Authenticator.new(controller).execute
|
178
|
-
end
|
277
|
+
## Flows
|
179
278
|
|
180
|
-
|
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
|
-
|
186
|
-
|
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
|
-
|
191
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
219
|
-
class Authenticator <
|
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
|
-
|
222
|
-
|
341
|
+
super
|
342
|
+
result
|
343
|
+
end
|
223
344
|
|
224
|
-
|
225
|
-
|
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
|
-
|
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
|
-
|
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
|
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 (
|
250
|
-
* i18n locale mapping [
|
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
|
390
|
+
module Notifiers
|
254
391
|
class Services < Typed
|
255
|
-
|
256
|
-
|
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
|
-
|
271
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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{
|
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.
|
1
|
+
0.3.0
|