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
@@ -0,0 +1,70 @@
1
+ module Controll::Flow
2
+ class Master
3
+ autoload :Macros, 'controll/flow/master/macros'
4
+ autoload :Executor, 'controll/flow/master/executor'
5
+
6
+ include Macros
7
+
8
+ attr_reader :controller, :action, :options
9
+
10
+ def initialize controller, options = {}
11
+ @controller = controller
12
+ @options = options
13
+ end
14
+
15
+ # Uses Executor to execute each registered ActionHandler, such ad Renderer and Redirecter
16
+ # The first ActionHandler matching the event returns an appropriate Action
17
+ # In case no ActionHandler matches, the Fallback action is returned
18
+ def execute
19
+ @action = executor.execute || fallback
20
+ @action.set_errors errors
21
+ @action
22
+ end
23
+
24
+ def executor
25
+ @executor ||= Executor.new controller, executor_options
26
+ end
27
+
28
+ def executor_options
29
+ {event: event, action_handlers: action_handlers}
30
+ end
31
+
32
+ delegate :errors, to: :executor
33
+
34
+ class << self
35
+ def action_handlers
36
+ @action_handlers ||= []
37
+ end
38
+
39
+ def add_action_handler name
40
+ @action_handlers ||= []
41
+ @action_handlers << name.to_s.underscore.to_sym
42
+ end
43
+
44
+ def valid_handler? handler_type
45
+ raise ArgumentError, "Must be a String or Symbol, was: #{handler_type}" if handler_type.blank?
46
+ valid_handlers.include? handler_type.to_sym
47
+ end
48
+
49
+ def valid_handlers
50
+ [:renderer, :redirecter]
51
+ end
52
+
53
+ def mapper_types
54
+ [:simple, :complex]
55
+ end
56
+ end
57
+
58
+ protected
59
+
60
+ delegate :command!, to: :controller
61
+
62
+ def action_handlers
63
+ self.class.action_handlers
64
+ end
65
+
66
+ def event
67
+ raise Controll::Flow::EventNotImplementedError, 'You must define an #event method that returns an event (or Symbol). You can use an Executor for this.'
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,15 @@
1
+ require 'controll/flow/errors'
2
+
3
+ module Controll
4
+ module Flow
5
+ autoload :Master, 'controll/flow/master'
6
+ autoload :Action, 'controll/flow/action'
7
+ autoload :EventMapper, 'controll/flow/event_mapper'
8
+ autoload :ActionMapper, 'controll/flow/action_mapper'
9
+ end
10
+ end
11
+
12
+ module Flows
13
+ Master = Controll::Flow::Master
14
+ Flow = Controll::Flow::Master
15
+ end
@@ -0,0 +1,31 @@
1
+ module Controll
2
+ module Focused
3
+ module Enabler
4
+ include Controll::Enabler
5
+
6
+ def execute
7
+ action.perform
8
+ end
9
+
10
+ def self.assistant_methods *names
11
+ delegate names, to: :assistant
12
+ end
13
+
14
+ protected
15
+
16
+ # the action resulting from executing the flow.
17
+ # Should be an instance of either:
18
+ # - Fallback
19
+ # - Redirecter
20
+ # - Renderer
21
+ def action
22
+ @action ||= flow.execute
23
+ end
24
+
25
+ # @flowhandler ||= Controll::Flow::Master.new self
26
+ def flow
27
+ raise NotImplementedError, '#flow must return the Controll::Flow::Master instance to be used'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,101 +1,7 @@
1
1
  module Controll
2
2
  module Helper
3
- autoload :Notify, 'controll/helper/notify'
4
3
  autoload :HashAccess, 'controll/helper/hash_access'
5
4
  autoload :Params, 'controll/helper/params'
6
5
  autoload :Session, 'controll/helper/session'
7
- autoload :PathResolver, 'controll/helper/path_resolver'
8
- autoload :EventMatcher, 'controll/helper/event_matcher'
9
-
10
- include Controll::Helper::Notify
11
- include Controll::Helper::Params
12
-
13
- extend ActiveSupport::Concern
14
-
15
- delegate :command, :command!, :use_command, to: :commander
16
-
17
- module ClassMethods
18
- # TODO: refactor - all use exactly the same pattern - can be generated!
19
- def commander name, options = {}
20
- define_method :commander do
21
- unless instance_variable_get("@commander")
22
- clazz = "#{name.to_s.camelize}Commander".constantize
23
- instance_variable_set "@commander", clazz.new(self, options)
24
- end
25
- end
26
- end
27
-
28
- def message_handler name, options = {}
29
- define_method :message_handler do
30
- unless instance_variable_get("@message_handler")
31
- clazz = "#{name.to_s.camelize}MessageHandler".constantize
32
- instance_variable_set "@message_handler", clazz.new(self, options)
33
- end
34
- end
35
- end
36
-
37
- def assistant name, options = {}
38
- define_method :assistant do
39
- unless instance_variable_get("@assistant")
40
- clazz = "#{name.to_s.camelize}Assistant".constantize
41
- instance_variable_set "@assistant", clazz.new(self, options)
42
- end
43
- end
44
- end
45
-
46
- def flow_handler name, options = {}
47
- define_method :flow_handler do
48
- unless instance_variable_get("@flow_handler")
49
- clazz = "#{name.to_s.camelize}FlowHandler".constantize
50
- instance_variable_set "@flow_handler", clazz.new(self, options)
51
- end
52
- end
53
- end
54
-
55
- def delegate_assistant name, options = {}
56
- define_method :assistant do
57
- unless instance_variable_get("@assistant")
58
- clazz = "#{name.to_s.camelize}DelegateAssistant".constantize
59
- instance_variable_set "@assistant", clazz.new(self, options)
60
- end
61
- end
62
- end
63
-
64
- def redirect_map map = {}
65
- @redirect_map ||= map
66
- end
67
-
68
- def render_map map = {}
69
- @render_map ||= map
70
- end
71
- end
72
-
73
- def do_redirect *args
74
- options = args.extract_options!
75
- path = path_resolver.extract_path(:redirect_map, *args)
76
- process_notifications
77
- redirect_to path, *args
78
- end
79
-
80
- def do_render *args
81
- options = args.extract_options!
82
- path = path_resolver.extract_path :render_paths, *args
83
- process_notifications
84
- render path, *args
85
- end
86
-
87
- protected
88
-
89
- def redirect_map
90
- self.class.redirect_map
91
- end
92
-
93
- def render_paths
94
- self.class.render_map
95
- end
96
-
97
- def path_resolver
98
- @path_resolver ||= PathResolver.new self
99
- end
100
6
  end
101
7
  end
@@ -0,0 +1,12 @@
1
+ module Controll
2
+ module Macros
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def enable_controll
7
+ clazz = self.ancestors.include?(::Imperator::Command) ? Controll::Focused::Enabler : Controll::Enabler
8
+ self.send :include, clazz
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,14 +1,16 @@
1
- require 'liquid'
2
1
  require 'controll/notify/flash'
3
2
 
4
3
  module Controll
5
4
  module Notify
6
5
  class Base < Flash
7
- class NotifyMappingError < StandardError; end
6
+ Message = Controll::Notify::Message
7
+
8
+ attr_reader :name
8
9
 
9
10
  def notify name, options = {}
10
- @options.merge! options if options.kind_of? Hash
11
- signal notify_msg(name)
11
+ @options.merge! options
12
+ @name = name
13
+ signal message_resolver.resolve
12
14
  end
13
15
 
14
16
  def self.inherited(base)
@@ -16,7 +18,9 @@ module Controll
16
18
  end
17
19
 
18
20
  module ClassMethods
19
- attr_reader :signal_type
21
+ def signal_type
22
+ @signal_type ||= self.name.demodulize.sub(/Handler$/, '').underscore.to_sym
23
+ end
20
24
 
21
25
  def type name
22
26
  @signal_type = name
@@ -25,51 +29,26 @@ module Controll
25
29
 
26
30
  protected
27
31
 
28
- def notify_msg name, opts = {}
29
- opts = options.merge(opts).stringify_keys
30
-
31
- msg = send(name) if respond_to? name
32
- msg ||= messages[name.to_sym] if respond_to? :messages
33
- msg ||= name.to_sym
34
-
35
- # if name is not mapped to a message, it could well be, that the
36
- # event should not generate a nofification message
37
- return nil if !msg
38
-
39
- # try various approaches!
40
- case msg
41
- when Symbol
42
- translate msg, opts
43
- when String
44
- msg.strip!
45
- return replace_args(msg, opts) if msg =~ /{{.*}}/
46
- msg
47
- else
48
- msg_error!
49
- end
50
- rescue
32
+ def message_resolver
33
+ @message_resolver ||= Message::Resolver.new self, message
51
34
  end
52
35
 
53
- def msg_error!
54
- raise NotifyMappingError, "Notify message could not be generated for: #{name}"
55
- end
36
+ def message
37
+ @message ||= Message.new text, options
38
+ end
56
39
 
57
- def translate msg, opts = {}
58
- I18n.t i18n_key(msg), opts.symbolize_keys
40
+ def text
41
+ @text ||= resolve_text(name) || key
59
42
  end
60
43
 
61
- def replace_args msg, opts
62
- # Parses and compiles the template
63
- Liquid::Template.parse(msg).render(opts)
44
+ def key
45
+ @key ||= name.to_sym
64
46
  end
65
47
 
66
- def i18n_key msg
67
- parts = self.class.name.split('::')
68
- middle = parts[1..-2].join('.').underscore
69
- type = parts.last.sub(/Msg$/, '').underscore
70
- ns = [middle, type].join('.').sub /^./, ''
71
- [ns,msg].join('.')
72
- end
48
+ def resolve_text name
49
+ return send(name) if respond_to? name
50
+ messages[name.to_sym] if respond_to? :messages
51
+ end
73
52
  end
74
53
  end
75
54
  end
@@ -20,11 +20,11 @@ module Controll
20
20
  attr_writer :types
21
21
 
22
22
  def types
23
- @types ||= [:notice, :error, :warning, :success]
23
+ @types ||= Controll::Event.valid_types
24
24
  end
25
25
 
26
26
  def add_types *types
27
- @types += types.flatten
27
+ @types += types if types.all? {|type| type.kind_of? Symbol}
28
28
  end
29
29
  alias_method :add_type, :add_types
30
30
  end
@@ -41,7 +41,7 @@ module Controll
41
41
  end
42
42
 
43
43
  def types
44
- self.class.types
44
+ self.class.types.map(&:to_sym)
45
45
  end
46
46
 
47
47
  def signal_type
@@ -0,0 +1,57 @@
1
+ module Controll::Notify
2
+ module Macros
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def handler type, options = {}, &block
7
+ unless valid_type? type
8
+ raise ArgumentError, "Notification type must be any of: #{types}, was: #{type}"
9
+ end
10
+
11
+ clazz_name = "#{parent}::#{type.to_s.camelize}Handler"
12
+ parent = options[:parent] || Controll::Notify::Base
13
+
14
+ clazz = parent ? Class.new(parent) : Class.new
15
+ Object.const_set clazz_name, clazz
16
+ context = self.kind_of?(Class) ? self : self.class
17
+ clazz = context.const_get(clazz_name)
18
+
19
+ if block_given?
20
+ clazz.instance_eval &block
21
+ end
22
+ clazz
23
+ end
24
+
25
+ def messages hash = nil, &block
26
+ unless block_given? || !hash.blank?
27
+ raise ArgumentError, "Must be called with non-empty Hash or block"
28
+ end
29
+
30
+ define_method :messages do
31
+ block_given? ? instance_eval(&block) : hash
32
+ end
33
+ end
34
+
35
+ def message event_name, text = nil, &block
36
+ unless event_name.kind_of?(Symbol) || event_name.kind_of?(String)
37
+ raise ArgumentError, "First argument must be an event name, was: #{event_name}"
38
+ end
39
+
40
+ unless block_given? || !text.blank?
41
+ raise ArgumentError, "Must be called with non-empty String or block"
42
+ end
43
+
44
+ define_method event_name do
45
+ block_given? ? instance_eval(&block) : hash
46
+ end
47
+ end
48
+ alias_method :msg, :message
49
+
50
+ protected
51
+
52
+ def valid_type? type
53
+ types.include? type.to_sym
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,36 @@
1
+ require 'liquid'
2
+
3
+ module Controll::Notify
4
+ class Message
5
+ class Handler
6
+ attr_reader :message
7
+
8
+ def initialize message
9
+ @message = message
10
+ end
11
+
12
+ def handle
13
+ return args? ? replace_args : message.text
14
+ rescue StandardError
15
+ nil
16
+ end
17
+
18
+ protected
19
+
20
+ delegate :text, to: :message
21
+
22
+ def options
23
+ @options ||= message.options.stringify_keys
24
+ end
25
+
26
+ def args?
27
+ text =~ /{{.*}}/
28
+ end
29
+
30
+ def replace_args
31
+ # Parses and compiles the template
32
+ Liquid::Template.parse(text).render(options)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ module Controll::Notify
2
+ class Message
3
+ class Resolver
4
+ Message = Controll::Notify::Message
5
+
6
+ attr_reader :caller, :message
7
+
8
+ def initialize caller, message
9
+ @caller = caller
10
+ @message = message
11
+ end
12
+
13
+ def resolve
14
+ message.translate? ? translator.translate : message_handler.handle
15
+ end
16
+
17
+ protected
18
+
19
+ def message_handler
20
+ Message::Handler.new message
21
+ end
22
+
23
+ def translator
24
+ Message::Translator.new caller, message
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ module Controll
2
+ module Notify
3
+ class Message
4
+ class Translator
5
+ attr_reader :caller, :key, :options
6
+
7
+ def initialize caller, message
8
+ @caller = caller
9
+ @key = message.text
10
+ @options = message.options.symbolize_keys
11
+ end
12
+
13
+ def translate
14
+ I18n.t i18n_key, options
15
+ end
16
+
17
+ protected
18
+
19
+ def i18n_key
20
+ [namespace_key, key].join('.')
21
+ end
22
+
23
+ def namespace_key
24
+ [namespace, type].join('.').sub /^\\./, ''
25
+ end
26
+
27
+ def parts
28
+ @parts ||= caller.class.name.split('::')
29
+ end
30
+
31
+ def namespace
32
+ (parts.first == 'Notifiers' ? parts[1..-2] : parts[0..-2]).join('.').underscore
33
+ end
34
+
35
+ def type
36
+ parts.last.sub(/#{clazz_postfix}$/, '').underscore
37
+ end
38
+
39
+ def clazz_postfix
40
+ 'Handler'
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ module Controll::Notify
2
+ class Message
3
+ autoload :Translator, 'controll/notify/message/translator'
4
+ autoload :Handler, 'controll/notify/message/handler'
5
+ autoload :Resolver, 'controll/notify/message/resolver'
6
+
7
+ attr_reader :text, :options
8
+
9
+ def initialize text, options = {}
10
+ raise ArgumentError, "Message text must be a String or Symbol" unless valid_text? text
11
+ @text = text
12
+ @options = options
13
+ end
14
+
15
+ def translate?
16
+ text.kind_of? Symbol
17
+ end
18
+
19
+ protected
20
+
21
+ def valid_text? text
22
+ text.kind_of?(String) || text.kind_of?(Symbol)
23
+ end
24
+ end
25
+ end
@@ -3,36 +3,27 @@ require 'controll/notify/flash'
3
3
  module Controll
4
4
  module Notify
5
5
  class Typed < Flash
6
- class MissingNotifyClass < StandardError; end
6
+ class MissingNotifyHandlerClass < StandardError; end
7
7
 
8
- def notice
9
- raise MissingNotifyClass, "#{msg_class(:notice)} class missing" unless msg_class(:notice)
10
- @notice ||= msg_class(:notice).new flash #, options
11
- end
12
-
13
- def error
14
- raise MissingNotifyClass, "#{msg_class(:warning)} class missing" unless msg_class(:error)
15
- @error ||= msg_class(:error).new flash #, options
16
- end
17
-
18
- def success
19
- raise MissingNotifyClass, "#{msg_class(:success)} class missing" unless msg_class(:success)
20
- @success ||= msg_class(:success).new flash #, options
21
- end
8
+ include Controll::Notify::Macros
22
9
 
23
- def warning
24
- raise MissingNotifyClass, "#{msg_class(:warning)} class missing" unless msg_class(:warning)
25
- @warning ||= msg_class(:warning).new flash #, options
10
+ types.each do |type|
11
+ define_method type do
12
+ clazz = handler_class(type)
13
+ raise MissingNotifyHandlerClass, "#{clazz} class missing" unless clazz
14
+ var = "@#{type}"
15
+ instance_variable_get(var) || instance_variable_set(var, clazz.new(flash))
16
+ end
26
17
  end
27
18
 
28
19
  protected
29
20
 
30
- def msg_class name
31
- msg_classes[name] ||= "#{self.class}::#{name.to_s.camelize}Msg".constantize
21
+ def handler_class name
22
+ handler_classes[name] ||= "#{self.class}::#{name.to_s.camelize}Handler".constantize
32
23
  end
33
24
 
34
- def msg_classes
35
- @msg_classes ||= {}
25
+ def handler_classes
26
+ @handler_classes ||= {}
36
27
  end
37
28
  end
38
29
  end
@@ -1,7 +1,14 @@
1
1
  module Controll
2
2
  module Notify
3
- autoload :Base, 'controll/notify/base'
4
- autoload :Flash, 'controll/notify/flash'
5
- autoload :Typed, 'controll/notify/typed'
3
+ autoload :Base, 'controll/notify/base'
4
+ autoload :Flash, 'controll/notify/flash'
5
+ autoload :Typed, 'controll/notify/typed'
6
+ autoload :Macros, 'controll/notify/macros'
7
+ autoload :Message, 'controll/notify/message'
6
8
  end
7
- end
9
+ end
10
+
11
+ module Notifiers
12
+ Typed = Controll::Notify::Typed
13
+ Notifier = Controll::Notify::Typed
14
+ end
data/lib/controll.rb CHANGED
@@ -4,11 +4,17 @@ end
4
4
  require 'hashie'
5
5
  require 'imperator-ext'
6
6
  require 'controll/errors'
7
+ require 'controll/event'
8
+ require 'controll/events'
9
+ require 'controll/assistant'
7
10
  require 'controll/executor'
8
11
  require 'controll/notify'
9
- require 'controll/flow_handler'
12
+ require 'controll/flow'
10
13
  require 'controll/helper'
14
+ require 'controll/enabler'
11
15
  require 'controll/command'
12
16
  require 'controll/commander'
13
- require 'controll/assistant'
17
+ require 'controll/macros'
18
+
19
+ require 'controll/engine' if defined?(::Rails::Engine)
14
20
 
@@ -0,0 +1,27 @@
1
+ module Controll
2
+ module Generators
3
+ class AssistantGenerator < ::Rails::Generators::NamedBase
4
+ desc 'Generates an Assitant'
5
+
6
+ class_option :delegate, type: :boolean, default: false
7
+
8
+ def main_flow
9
+ template "assistant.tt", "app/controll/assistants/#{file_name}.rb"
10
+ end
11
+
12
+ protected
13
+
14
+ def delegate?
15
+ options[:delegate]
16
+ end
17
+
18
+ def parent_class
19
+ name.include?('::') ? "::Controll::#{parent_class_name}" : parent_class_name
20
+ end
21
+
22
+ def parent_class_name
23
+ delegate? 'DelegateAssistant' : 'Assistant'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Controll
2
+ module Generators
3
+ class ExecutorGenerator < ::Rails::Generators::NamedBase
4
+ desc 'Generates an Executor'
5
+
6
+ class_option :type, default: 'base', desc: 'The type of executor'
7
+
8
+ def main_flow
9
+ template 'executor.tt', "app/controll/executors/#{file_name}.rb"
10
+ end
11
+
12
+ protected
13
+
14
+ def parent_class
15
+ name.include?('::') ? "::Controll::Executor::#{parent_class_name}" : parent_class_name
16
+ end
17
+
18
+ def parent_class_name
19
+ (options[:type] || 'base').camelize
20
+ end
21
+ end
22
+ end
23
+ end