controll 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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