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
@@ -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