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
@@ -1,5 +1,5 @@
1
- module Controll::Helper
2
- class EventMatcher
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::FlowHandler::EventHelper
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 :initiator, :options
4
+ attr_accessor :controller, :options
5
5
 
6
- def initialize initiator, options = {}
7
- @initiator = initiator
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
@@ -0,0 +1,6 @@
1
+ module Controll
2
+ module Executor
3
+ class Delegator < Controll::Assistant
4
+ end
5
+ end
6
+ end
@@ -1,6 +1,13 @@
1
1
  module Controll
2
2
  module Executor
3
3
  autoload :Base, 'controll/executor/base'
4
- autoload :Notificator, 'controll/executor/notificator'
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,7 @@
1
+ module Controll::Flow
2
+ module Action
3
+ autoload :Base, 'controll/flow/action/base'
4
+ autoload :PathAction, 'controll/flow/action/path_action'
5
+ autoload :Fallback, 'controll/flow/action/fallback'
6
+ end
7
+ 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,7 @@
1
+ module Controll::Flow
2
+ module ActionMapper
3
+ autoload :Base, 'controll/flow/action_mapper/base'
4
+ autoload :Simple, 'controll/flow/action_mapper/simple'
5
+ autoload :Complex, 'controll/flow/action_mapper/complex'
6
+ end
7
+ 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,6 @@
1
+ module Controll::Flow
2
+ module EventMapper
3
+ autoload :Util, 'controll/flow/event_mapper/util'
4
+ autoload :PathFinder, 'controll/flow/event_mapper/path_finder'
5
+ end
6
+ 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