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
@@ -1,5 +1,5 @@
|
|
1
|
-
module Controll
|
2
|
-
class
|
1
|
+
module Controll
|
2
|
+
class Event::Matcher
|
3
3
|
attr_reader :event
|
4
4
|
|
5
5
|
def initialize event
|
@@ -12,7 +12,7 @@ module Controll::Helper
|
|
12
12
|
|
13
13
|
protected
|
14
14
|
|
15
|
-
include Controll::
|
15
|
+
include Controll::Event::Helper
|
16
16
|
|
17
17
|
def normalized events
|
18
18
|
[events].flatten.map(&:to_sym)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Controll
|
2
|
+
class Event
|
3
|
+
autoload :Helper, 'controll/event/helper'
|
4
|
+
autoload :Matcher, 'controll/event/matcher'
|
5
|
+
|
6
|
+
class InvalidError < StandardError; end
|
7
|
+
|
8
|
+
attr_reader :name, :type, :options
|
9
|
+
|
10
|
+
def initialize name, *args
|
11
|
+
raise ArgumentError, "Event must have a name identifier" if name.blank?
|
12
|
+
@name = name.to_sym
|
13
|
+
@options = args.extract_options!
|
14
|
+
@type = (extract_type(args.first) || options[:type] || :notice).to_sym
|
15
|
+
raise ArgumentError, "Invalid type: #{@type} must be one of: #{self.class.valid_types}" unless self.class.valid_type? @type
|
16
|
+
@options.delete(:type) if options[:type] == @type
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.default_valid_types
|
20
|
+
[:notice, :error, :warning, :success]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.valid_types
|
24
|
+
@valid_types ||= default_valid_types
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.reset_types
|
28
|
+
@valid_types = default_valid_types
|
29
|
+
end
|
30
|
+
|
31
|
+
valid_types.each do |type|
|
32
|
+
define_method :"#{type}?" do
|
33
|
+
self.type == type.to_sym
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
attr_writer :valid_types
|
39
|
+
|
40
|
+
def valid_type? type
|
41
|
+
valid_types.map(&:to_sym).include? type.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_valid_types *types
|
45
|
+
@valid_types += types if types.all? {|type| type.kind_of? Symbol}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def extract_type arg
|
52
|
+
return arg.type if arg.respond_to? :type
|
53
|
+
arg.to_sym if type? arg
|
54
|
+
end
|
55
|
+
|
56
|
+
def type? arg
|
57
|
+
arg.kind_of?(String) || arg.kind_of?(Symbol)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Controll
|
2
|
+
class Events
|
3
|
+
include Enumerable
|
4
|
+
include Controll::Event::Helper
|
5
|
+
|
6
|
+
attr_reader :events
|
7
|
+
|
8
|
+
def initialize *events
|
9
|
+
@events = events.flatten.map{|event| normalize event }
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
events.each {|event| yield event }
|
14
|
+
end
|
15
|
+
|
16
|
+
def << event
|
17
|
+
events << event
|
18
|
+
end
|
19
|
+
|
20
|
+
def last
|
21
|
+
events.last
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.valid_types
|
25
|
+
Controll::Event.valid_types
|
26
|
+
end
|
27
|
+
|
28
|
+
# fx error? - returns if any event of type error
|
29
|
+
valid_types.each do |type|
|
30
|
+
meth = :"#{type}?"
|
31
|
+
define_method meth do
|
32
|
+
self.any? {|event| event.send(meth) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# fx errors - returns all events of type error
|
37
|
+
valid_types.each do |type|
|
38
|
+
meth = type.to_s.pluralize
|
39
|
+
define_method meth do
|
40
|
+
self.select {|event| event.send(:"#{type}?") }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_types
|
45
|
+
Controll::Event.valid_types
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,16 +1,12 @@
|
|
1
1
|
module Controll
|
2
2
|
module Executor
|
3
3
|
class Base
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :controller, :options
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
@
|
6
|
+
def initialize controller, options = {}
|
7
|
+
@controller = controller
|
8
8
|
@options = options
|
9
9
|
end
|
10
|
-
|
11
|
-
def method_missing(meth, *args, &block)
|
12
|
-
initiator.send(meth, *args, &block)
|
13
|
-
end
|
14
10
|
end
|
15
11
|
end
|
16
12
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'controll/executor/base'
|
2
|
+
|
3
|
+
module Controll::Executor
|
4
|
+
class Controlled < Delegator
|
5
|
+
|
6
|
+
def execute
|
7
|
+
validations
|
8
|
+
do_command unless error?
|
9
|
+
end
|
10
|
+
|
11
|
+
# return last notification or :success as result
|
12
|
+
# return <Event>
|
13
|
+
def result
|
14
|
+
main_event
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def execute &block
|
19
|
+
define_method :execute do
|
20
|
+
super
|
21
|
+
instance_eval &block
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def validations
|
30
|
+
end
|
31
|
+
|
32
|
+
def error?
|
33
|
+
notifications.error?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/controll/executor.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
module Controll
|
2
2
|
module Executor
|
3
3
|
autoload :Base, 'controll/executor/base'
|
4
|
-
autoload :
|
4
|
+
autoload :Controlled, 'controll/executor/controlled'
|
5
|
+
autoload :Delegator, 'controll/executor/delegator'
|
5
6
|
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Executors
|
10
|
+
Base = Controll::Executor::Base
|
11
|
+
Delegator = Controll::Executor::Delegator
|
12
|
+
Controlled = Controll::Executor::Controlled
|
6
13
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Controll::Flow::Action
|
2
|
+
class Base
|
3
|
+
attr_reader :path, :controller, :errors
|
4
|
+
|
5
|
+
def initialize controller, path
|
6
|
+
@controller = controller
|
7
|
+
@path = path.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_errors *errors
|
11
|
+
@errors = errors.flatten
|
12
|
+
end
|
13
|
+
|
14
|
+
def errors
|
15
|
+
@errors |= []
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def controller_action
|
21
|
+
@controller_action ||= "do_#{type}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def error_check!
|
25
|
+
unless controller.respond_to? controller_action
|
26
|
+
raise Controll::NotEnabled, "Controll::Enabler has not been included in #{controller.class}. Missing #{controller_action} method"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Controll::Flow::Action
|
2
|
+
class Fallback < Base
|
3
|
+
attr_reader :controller, :event
|
4
|
+
|
5
|
+
def initialize controller, event = nil
|
6
|
+
@controller = controller
|
7
|
+
@event = event if event
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform
|
11
|
+
error_check! if event
|
12
|
+
controller.do_fallback self
|
13
|
+
end
|
14
|
+
|
15
|
+
def type
|
16
|
+
:fallback
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def action controller, event = nil
|
21
|
+
self.new controller, event
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Controll::Flow::Action
|
2
|
+
class PathAction < Base
|
3
|
+
def perform
|
4
|
+
raise BadPathError, "Bad path: #{path}" if path.blank?
|
5
|
+
error_check!
|
6
|
+
controller.send controller_action, self
|
7
|
+
end
|
8
|
+
|
9
|
+
def resolved_path
|
10
|
+
controller.send(path)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
# useful for path helpers used in event maps
|
16
|
+
def method_missing(method_name, *args, &block)
|
17
|
+
if controller.respond_to? method_name
|
18
|
+
controller.send method_name, *args, &block
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Controll::Flow::ActionMapper
|
2
|
+
class Base
|
3
|
+
class << self
|
4
|
+
def path_action_class
|
5
|
+
Controll::Flow::Action::PathAction
|
6
|
+
end
|
7
|
+
|
8
|
+
def action controller, event
|
9
|
+
raise NotImplementedError, 'You must implement the #action class method'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Controll::Flow::ActionMapper
|
2
|
+
class Complex < Base
|
3
|
+
attr_reader :event_maps
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_writer :action_clazz
|
7
|
+
attr_reader :types, :event_maps
|
8
|
+
|
9
|
+
# this method could be generated whenever a class inherits from ActionHandler class?
|
10
|
+
def inherited base
|
11
|
+
if base.parent.respond_to? :add_action_handler
|
12
|
+
base.add_action_handler self.name.demodulize
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def action controller, event
|
17
|
+
action_types ||= types
|
18
|
+
path = path_finder(event).path
|
19
|
+
path_action_class.new controller, path unless path.blank?
|
20
|
+
end
|
21
|
+
|
22
|
+
# reader
|
23
|
+
def event_map_for type = :notice
|
24
|
+
@event_maps ||= {}
|
25
|
+
event_maps[type.to_sym] || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# writer
|
29
|
+
# also auto-adds type to types
|
30
|
+
def event_map *args, &block
|
31
|
+
@event_maps ||= {}
|
32
|
+
@types ||= []
|
33
|
+
return @event_maps if args.empty? && !block_given?
|
34
|
+
|
35
|
+
type = args.first.kind_of?(Symbol) ? args.shift : :notice
|
36
|
+
event_maps[type.to_sym] = block_given? ? instance_eval(&block) : args.first
|
37
|
+
@types << type unless types.include?(type)
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def path_finder event
|
43
|
+
raise Controll::Flow::NoMappingFoundError, "No event maps defined" if event_maps.blank?
|
44
|
+
path_finder_class.new event, event_maps, types
|
45
|
+
end
|
46
|
+
|
47
|
+
def path_finder_class
|
48
|
+
Controll::Flow::EventMapper::PathFinder
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Controll::Flow::ActionMapper
|
2
|
+
class Simple < Base
|
3
|
+
NoEventsDefinedError = Controll::Flow::NoEventsDefinedError
|
4
|
+
NoDefaultPathDefinedError = Controll::Flow::NoDefaultPathDefinedError
|
5
|
+
|
6
|
+
# TODO: Should combine with Redirecter style, allowing for multiple render path mappings!
|
7
|
+
# This is fx useful for Wizards etc. where one Controller can render to many views, depending on state
|
8
|
+
class << self
|
9
|
+
def inherited base
|
10
|
+
if base.parent.respond_to? :add_action_handler
|
11
|
+
base.add_action_handler self.name.demodulize
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def action controller, event, path = nil
|
16
|
+
check!
|
17
|
+
event = normalize event
|
18
|
+
path_action_class.new(controller, path || default_path) if events.include? event.name
|
19
|
+
end
|
20
|
+
|
21
|
+
# http://bugs.ruby-lang.org/issues/1082
|
22
|
+
# hello.singleton_class
|
23
|
+
# Instead of always having to write:
|
24
|
+
# (class << hello; self; end)
|
25
|
+
def default_path str = nil, &block
|
26
|
+
(class << self; self; end).send :define_method, :default_path do
|
27
|
+
block_given? ? instance_eval(&block) : str
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def events *args, &block
|
32
|
+
(class << self; self; end).send :define_method, :events do
|
33
|
+
args.flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
default_path(&block) if block_given?
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def check!
|
42
|
+
unless respond_to?(:events) && !events.blank?
|
43
|
+
raise NoEventsDefinedError, "You must define the events/actions that can be mapped by this class"
|
44
|
+
end
|
45
|
+
|
46
|
+
unless respond_to?(:default_path) && !default_path.blank?
|
47
|
+
raise NoDefaultPathDefinedError, "You must set a default_path to be routed to if no event/action matches"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
include Controll::Event::Helper
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Controll::Flow
|
2
|
+
class ActionEventError < StandardError; end
|
3
|
+
|
4
|
+
class EventNotImplementedError < StandardError; end
|
5
|
+
|
6
|
+
class PathActionError < StandardError; end
|
7
|
+
|
8
|
+
# Complex mapper
|
9
|
+
class NoMappingFoundError < PathActionError; end
|
10
|
+
|
11
|
+
# Simple mapper
|
12
|
+
class NoEventsDefinedError < PathActionError; end
|
13
|
+
class NoDefaultPathDefinedError < PathActionError; end
|
14
|
+
|
15
|
+
class BadPathError < PathActionError; end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Controll::Flow
|
2
|
+
module EventMapper
|
3
|
+
class PathFinder
|
4
|
+
attr_accessor :event, :maps, :types
|
5
|
+
|
6
|
+
NoMappingFoundError = Controll::Flow::NoMappingFoundError
|
7
|
+
|
8
|
+
# event <Event>
|
9
|
+
def initialize event, maps, types = []
|
10
|
+
raise ArgumentError, "Event argument must not be empty" if event.blank?
|
11
|
+
raise ArgumentError, "Maps argument must not be empty" if maps.blank?
|
12
|
+
@event = normalize event
|
13
|
+
@types = types unless types.blank?
|
14
|
+
@maps = maps
|
15
|
+
end
|
16
|
+
|
17
|
+
def path
|
18
|
+
@path ||= mapper.map_event
|
19
|
+
rescue StandardError => e
|
20
|
+
raise NoMappingFoundError, "No event mapping could be found for: #{event.inspect} in: #{maps}. Cause: #{e}"
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
include Controll::Event::Helper
|
26
|
+
|
27
|
+
def event_map
|
28
|
+
@event_map ||= maps[event.type] || {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def mapper
|
32
|
+
@mapper ||= Controll::Flow::EventMapper::Util.new event, event_map
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Controll::Flow
|
2
|
+
module EventMapper
|
3
|
+
class Util
|
4
|
+
attr_reader :event_map, :event
|
5
|
+
|
6
|
+
NoMappingFoundError = Controll::Flow::NoMappingFoundError
|
7
|
+
|
8
|
+
def initialize event, event_map
|
9
|
+
@event ||= normalize event
|
10
|
+
|
11
|
+
unless valid_map? event_map
|
12
|
+
raise ArgumentError, "Invalid redirect map: #{event_map}, must be a non-empty Hash"
|
13
|
+
end
|
14
|
+
@event_map ||= event_map
|
15
|
+
end
|
16
|
+
|
17
|
+
# An event can also be a Symbol,
|
18
|
+
# in which case it is a :notice event
|
19
|
+
def map_event
|
20
|
+
event_map.each do |path, events|
|
21
|
+
return path.to_s if valid? events
|
22
|
+
end
|
23
|
+
raise NoMappingFoundError, "No path could be found for event: #{event.inspect} in map: #{event_map}"
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
include Controll::Event::Helper
|
29
|
+
|
30
|
+
def valid_map? event_map
|
31
|
+
event_map.kind_of?(Hash) && !event_map.blank?
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid? events
|
35
|
+
matcher.match?(events)
|
36
|
+
end
|
37
|
+
|
38
|
+
def matcher
|
39
|
+
@matcher ||= Controll::Event::Matcher.new event
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Controll::Flow
|
2
|
+
class Master
|
3
|
+
class Executor < Controll::Executor::Base
|
4
|
+
Flow = Controll::Flow
|
5
|
+
|
6
|
+
NoEventsDefinedError = Flow::NoEventsDefinedError
|
7
|
+
NoMappingFoundError = Flow::NoMappingFoundError
|
8
|
+
|
9
|
+
attr_reader :event, :action_handlers
|
10
|
+
|
11
|
+
def initialize initiator, options
|
12
|
+
raise ArgumentError, "Must take an options arg" unless options.kind_of?(Hash)
|
13
|
+
raise ArgumentError, "Must take an :event option" unless options[:event]
|
14
|
+
raise ArgumentError, "Must take an :action_handlers option" unless options[:action_handlers]
|
15
|
+
super
|
16
|
+
@event = options[:event]
|
17
|
+
@action_handlers = options[:action_handlers]
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute
|
21
|
+
action_handlers.each do |action_handler|
|
22
|
+
begin
|
23
|
+
action_handler_clazz = handler_class(action_handler)
|
24
|
+
next unless action_handler_clazz
|
25
|
+
return action_handler_clazz.action(controller, event)
|
26
|
+
rescue NoEventsDefinedError => e
|
27
|
+
errors << e
|
28
|
+
rescue NoMappingFoundError => e
|
29
|
+
errors << e
|
30
|
+
end
|
31
|
+
end
|
32
|
+
fallback
|
33
|
+
end
|
34
|
+
|
35
|
+
def errors
|
36
|
+
@errors ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def fallback
|
42
|
+
fallback_class.new controller, event
|
43
|
+
end
|
44
|
+
|
45
|
+
def fallback_class
|
46
|
+
Flow::Action::Fallback
|
47
|
+
end
|
48
|
+
|
49
|
+
def handler_class action_handler
|
50
|
+
clazz = "#{initiator.class}::#{action_handler.to_s.camelize}"
|
51
|
+
clazz.constantize
|
52
|
+
rescue NameError
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Controll::Flow
|
2
|
+
class Master
|
3
|
+
module Macros
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def handler options = {}, &block
|
8
|
+
mapper_type = :simple if options[:simple]
|
9
|
+
mapper_type ||= :complex if options[:complex]
|
10
|
+
|
11
|
+
master_clazz = Controll::Flow::Master
|
12
|
+
|
13
|
+
unless mapper_type
|
14
|
+
raise ArgumentError, "You must specify mapper type, one of: #{master_clazz.mapper_types} in: #{options}"
|
15
|
+
end
|
16
|
+
|
17
|
+
handler_type = options.delete(mapper_type)
|
18
|
+
|
19
|
+
unless master_clazz.valid_handler? handler_type
|
20
|
+
raise ArgumentError, "Must one of: #{master_clazz.valid_handlers} was: #{handler_type}"
|
21
|
+
end
|
22
|
+
|
23
|
+
parent = "Controll::Flow::ActionMapper::#{mapper_type.to_s.camelize}".constantize
|
24
|
+
|
25
|
+
clazz_name = handler_type.to_s.camelize
|
26
|
+
context = self.kind_of?(Class) ? self : self.class
|
27
|
+
|
28
|
+
clazz = parent ? Class.new(parent) : Class.new
|
29
|
+
context.const_set clazz_name, clazz
|
30
|
+
clazz = context.const_get(clazz_name)
|
31
|
+
|
32
|
+
container_class_name = clazz.name.sub(/\.*(::\w+)$/, '')
|
33
|
+
container_class = container_class_name.constantize
|
34
|
+
container_class.add_action_handler clazz.name.demodulize
|
35
|
+
|
36
|
+
clazz.instance_eval(&block) if block_given?
|
37
|
+
clazz
|
38
|
+
end
|
39
|
+
|
40
|
+
def renderer mapper_type = :simple, options = {}, &block
|
41
|
+
handler options.merge(mapper_type => :renderer), &block
|
42
|
+
end
|
43
|
+
|
44
|
+
def redirecter mapper_type = :complex, options = {}, &block
|
45
|
+
handler options.merge(mapper_type => :redirecter), &block
|
46
|
+
end
|
47
|
+
|
48
|
+
def event &block
|
49
|
+
raise ArgumentError, "Must be called with a block" unless block_given?
|
50
|
+
define_method :event do
|
51
|
+
instance_variable_get("@event") || instance_variable_set("@event", instance_eval(&block))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# def set_action_handlers *names, &block
|
56
|
+
# raise ArgumentError, "Must be called with names of action handlers" if names.empty?
|
57
|
+
|
58
|
+
# define_method :action_handlers do
|
59
|
+
# value = block_given? ? instance_eval(&block) : names.flatten
|
60
|
+
# instance_variable_get("@action_handlers") || instance_variable_set("@action_handlers", value)
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|