Permalink
Browse files

major refactor again :)

  • Loading branch information...
1 parent a15dd8b commit ff8594d567b170597f771e522e1417114a86f3c5 @kristianmandrup committed Aug 16, 2012
View
113 README.md
@@ -112,7 +112,7 @@ class ApplicationController
end
```
-In your Controller you should define a MessageHandler and Commander to be used.
+In your Controller you should define a Notifier and Commander to be used.
```ruby
class ServicesController < ApplicationController
@@ -122,85 +122,73 @@ class ServicesController < ApplicationController
protected
- message_handler :services
+ notifier :services
commander :services
+
+ # or simply
+ controll :notifier, :commander
end
```
The Commander is where you register a set of related commands, typically for a specific controller.
```ruby
-class ServicesCommander < Controll::Commander
+module Commanders
+ class Services < Commander
- # register commands with controller
- commands :cancel_commit, :create_account, :signout
+ # register commands with controller
+ commands :cancel_commit, :create_account, :signout
- def sign_in_command
- @sign_in_command ||= SignInCommand.new auth_hash: auth_hash, user_id: user_id, service_id: service_id, service_hash: service_hash, initiator: self
- end
+ def sign_in_command
+ @sign_in_command ||= SignInCommand.new auth_hash: auth_hash, user_id: user_id, service_id: service_id, service_hash: service_hash, initiator: self
+ end
- # delegations
- controller_methods :auth_hash, :user_id, :service_id, :service_hash
+ command_method :sign_out do
+ @sign_out_command ||= SignOutCommand.new user_id: user_id, service_id: service_id, service_hash: service_hash, initiator: self
+ end
+
+ # delegations
+ controller_methods :auth_hash, :user_id, :service_id, :service_hash
+ end
end
```
The `#commands` class macro can be used to create command methods that only take the initiator (in this case the controller) as argument.
-For how to implement the commands, see the `imperator` gem, or see the `oauth_assist` engine for a full example.
+For how to implement the commands, see the `imperator` gem, or see the `oauth_assist` engine for a full example. There are now also nice macros available for creating command methods! The `Commander class extends `Imperator::Command::MethodFactory` making `#command_method` available-
-We will implement this MessageHandler later when we know which notifications and errors we want to use/issue.
+We will implement this Notifier later when we know which notifications and errors we want to use/issue.
+
+## FlowHandlers
For Controller actions that require complex flow control, use a FlowHandler:
```ruby
-module Controll::FlowHandler
+module FlowHandlers
class CreateService < Control
- protected
-
- # use for more advanced render/redirect logic (fx when using paths with arguments)
- def use_alternatives
- end
-
- def use_fallback
+ fallback do
event == :no_auth ? do_render(:text => omniauth.to_yaml) : fallback_action
end
- def action_handlers
- [Redirect, Render]
+ event do
+ Executors::Authenticator.new(controller).execute
end
- def event
- @event ||= authentication
+ renderer do
+ default_path :signup_services_path
+ events :signed_in_new_user, :signed_in
end
- def authentication
- @authentication ||= Authenticator.new(controller).execute
- end
-
- class Render < Controll::FlowHandler::Render
- def self.default_path
- :signup_services_path
- end
-
- def self.events
- [:signed_in_new_user]
- end
- end
-
- class Redirect < Controll::FlowHandler::Render
- def self.redirections
+ redirecter do
+ redirections :notice do
{
signup_services_path: :signed_in_new_user
services_path: [:signed_in_connect, :signed_in_new_connect]
root_url: [:signed_in_user, :other]
}
end
- def self.error_redirections
- {
- signin_path: [:error, :invalid, :auth_error]
- }
- end
+ redirections :error, signin_path: [:error, :invalid, :auth_error]
end
end
end
@@ -215,7 +203,7 @@ If you are rendering or redirecting to paths that take arguments, you can either
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).
```ruby
-module Controll::Executor
+module Executors
class Authenticator < Notificator
def execute
# creates an error notification named :error
@@ -250,12 +238,10 @@ The example below demonstrates several different ways you can define messages fo
* i18n locale mapping [msghandler name].[notification type].[event name].
```ruby
-module Controll::Notify
+module Notifiers
class Services < Typed
- class ErrorMsg < Controll::Notify::Base
- type :error
-
- def messages
+ handler :error do
+ messages do
{
must_sign_in: 'You need to sign in before accessing this page!',
@@ -267,35 +253,34 @@ You have not been signed in.},
}
end
- def auth_error!
- 'Error while authenticating via ' + service_name + '. The service did not return valid data.'
+ msg :auth_error! do
+ "Error while authenticating via #{service_name}. The service did not return valid data."
end
- def auth_invalid!
+ msg :auth_invalid! do
'Error while authenticating via {{full_route}}. The service returned invalid data for the user id.'
end
end
- class NoticeMsg < Controll::Notify::Base
- type :notice
-
+ handler :notice do
# for :signed_in and :signed_out - defined in locale file under:
- # services:
- # notice:
- # signed_in: 'Your account has been created and you have been signed in!'
- # signed_out: 'You have been signed out!'
+ # notifiers:
+ # services:
+ # notice:
+ # signed_in: 'Your account has been created and you have been signed in!'
+ # signed_out: 'You have been signed out!'
- def already_connected
+ msg :already_connected do
'Your account at {{provider_name}} is already connected with this site.'
end
- def account_added
+ msg :account_added do
'Your {{provider_name}} account has been added for signing in at this site.'
end
- def sign_in_success
+ msg :sign_in_success do
'Signed in successfully via {{provider_name}}.'
end
end
@@ -21,4 +21,8 @@ def command! name, *args
alias_method :use_command, :command!
alias_method :perform_command, :command!
end
+end
+
+module Commanders
+ Commander = Controll::Commander
end
View
@@ -1,6 +1,13 @@
module Controll
module Executor
autoload :Base, 'controll/executor/base'
+ autoload :Delegator, 'controll/executor/delegator'
autoload :Notificator, 'controll/executor/notificator'
end
+end
+
+module Executors
+ Base = Controll::Executor::Base
+ Delegator = Controll::Executor::Delegator
+ Notificator = Controll::Executor::Notificator
end
@@ -7,10 +7,6 @@ def initialize initiator, options = {}
@initiator = initiator
@options = options
end
-
- def method_missing(meth, *args, &block)
- initiator.send(meth, *args, &block)
- end
end
end
end
@@ -0,0 +1,9 @@
+module Controll
+ module Executor
+ class Delegator < Base
+ def method_missing(meth, *args, &block)
+ initiator.send(meth, *args, &block)
+ end
+ end
+ end
+end
@@ -1,7 +1,7 @@
require 'controll/executor/base'
module Controll::Executor
- class Notificator < Base
+ class Notificator < Delegator
# return last notification or :success as result
# Hashie::Mash.new(name: name, type: type, options: options)
@@ -4,8 +4,13 @@ module Controll
module FlowHandler
autoload :Base, 'controll/flow_handler/base'
autoload :Control, 'controll/flow_handler/control'
- autoload :Redirect, 'controll/flow_handler/redirect'
- autoload :Render, 'controll/flow_handler/render'
+ autoload :Redirecter, 'controll/flow_handler/redirecter'
+ autoload :Renderer, 'controll/flow_handler/renderer'
autoload :EventHelper, 'controll/flow_handler/event_helper'
end
+end
+
+module FlowHandlers
+ Base = Controll::FlowHandler::Base
+ Control = Controll::FlowHandler::Control
end
@@ -11,6 +11,15 @@ def perform controller
end
class << self
+ # any subclass of Base should have an inherited(base) class method added
+ # which adds itself to the list of action_handler which the parent class
+ # (i.e class that subclass is contained in!) supports
+ def inherited(base)
+ (class << self; self; end).send :define_method, :inherited do |base|
+ base.parent.add_action_handler self.name.demodulize
+ end
+ end
+
def action event
raise NotImplementedError, 'You must implement the #action class method'
end
@@ -1,6 +1,11 @@
module Controll::FlowHandler
- class Control
- class ActionEventError < StandardError; end
+ class Control
+ autoload :Macros, 'controll/flow_handler/control/macros'
+ autoload :Executor, 'controll/flow_handler/control/executor'
+
+ ActionEventError = Controll::FlowHandler::ActionEventError
+
+ include Macros
attr_reader :controller, :action_handlers
@@ -10,76 +15,35 @@ def initialize controller, action_handlers = []
end
def execute
- use_action_handlers
- use_alternatives
- use_fallback if !executed?
+ executor.execute
+ fallback if !executed?
self
end
- def action_handlers
- @action_handlers ||= [:redirect, :render]
+ def executor
+ @executor ||= Executor.new self, action_handlers: action_handlers
end
- def executed?
- @executed
+ def action_handlers
+ @action_handlers ||= []
end
+ class << self
+ def add_action_handler name
+ @action_handlers ||= []
+ @action_handlers << name.to_s.underscore.to_sym
+ end
+
protected
delegate :command!, to: :controller
- # can be used to set up control logic that fall outside what can be done
- # with the basic action_handlers but can not be considered fall-back.
- def use_alternatives
- end
-
- def use_fallback
- end
-
def event
raise NotImplementedError, 'You must define an #event method that at least returns an event (Symbol). You can use an Executor for this.'
end
def fallback_action
do_redirect root_url
end
-
- NoEventsDefinedError = Controll::FlowHandler::Render::NoEventsDefinedError
- NoRedirectionFoundError = Controll::FlowHandler::Redirect::NoRedirectionFoundError
-
- def use_action_handlers
- errors = []
- action_handlers.each do |action_handler|
- begin
- action_handler_clazz = handler_class(action_handler)
- next unless action_handler_clazz
- action = action_handler_clazz.action(event)
- execute_with action
- return if executed?
- rescue NoEventsDefinedError => e
- errors << e
- rescue NoRedirectionFoundError => e
- errors << e
- end
- end
- raise ActionEventError, "#{errors.join ','}" unless errors.empty?
- end
-
- def handler_class action_handler
- clazz = "#{self.class}::#{action_handler.to_s.camelize}"
- clazz.constantize
- rescue NameError
- nil
- end
-
- def execute_with action
- return if !action
- action.perform(controller)
- executed!
- end
-
- def executed!
- @executed = true
- end
end
end
Oops, something went wrong.

0 comments on commit ff8594d

Please sign in to comment.