controll 0.2.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 (128) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +19 -0
  4. data/Gemfile.lock +134 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +320 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/controll.gemspec +184 -0
  10. data/lib/controll.rb +14 -0
  11. data/lib/controll/assistant.rb +19 -0
  12. data/lib/controll/command.rb +24 -0
  13. data/lib/controll/commander.rb +24 -0
  14. data/lib/controll/errors.rb +1 -0
  15. data/lib/controll/executor.rb +6 -0
  16. data/lib/controll/executor/base.rb +16 -0
  17. data/lib/controll/executor/notificator.rb +12 -0
  18. data/lib/controll/flow_handler.rb +11 -0
  19. data/lib/controll/flow_handler/base.rb +19 -0
  20. data/lib/controll/flow_handler/control.rb +85 -0
  21. data/lib/controll/flow_handler/errors.rb +5 -0
  22. data/lib/controll/flow_handler/event_helper.rb +18 -0
  23. data/lib/controll/flow_handler/redirect.rb +51 -0
  24. data/lib/controll/flow_handler/redirect/action.rb +45 -0
  25. data/lib/controll/flow_handler/redirect/mapper.rb +41 -0
  26. data/lib/controll/flow_handler/render.rb +51 -0
  27. data/lib/controll/helper.rb +101 -0
  28. data/lib/controll/helper/event_matcher.rb +21 -0
  29. data/lib/controll/helper/hash_access.rb +26 -0
  30. data/lib/controll/helper/notify.rb +74 -0
  31. data/lib/controll/helper/params.rb +20 -0
  32. data/lib/controll/helper/path_resolver.rb +45 -0
  33. data/lib/controll/helper/session.rb +20 -0
  34. data/lib/controll/notify.rb +7 -0
  35. data/lib/controll/notify/base.rb +75 -0
  36. data/lib/controll/notify/flash.rb +52 -0
  37. data/lib/controll/notify/typed.rb +39 -0
  38. data/spec/acceptance/app_test.rb +156 -0
  39. data/spec/app/.gitignore +15 -0
  40. data/spec/app/Gemfile +6 -0
  41. data/spec/app/Gemfile.lock +108 -0
  42. data/spec/app/README.rdoc +261 -0
  43. data/spec/app/Rakefile +7 -0
  44. data/spec/app/app/controllers/application_controller.rb +6 -0
  45. data/spec/app/app/controllers/posts_controller.rb +52 -0
  46. data/spec/app/app/models/.gitkeep +0 -0
  47. data/spec/app/app/models/post.rb +88 -0
  48. data/spec/app/app/views/layouts/application.html.erb +13 -0
  49. data/spec/app/app/views/posts/_form.html.erb +31 -0
  50. data/spec/app/app/views/posts/edit.html.erb +6 -0
  51. data/spec/app/app/views/posts/index.html.erb +23 -0
  52. data/spec/app/app/views/posts/new.html.erb +5 -0
  53. data/spec/app/app/views/posts/show.html.erb +8 -0
  54. data/spec/app/config.ru +4 -0
  55. data/spec/app/config/application.rb +16 -0
  56. data/spec/app/config/boot.rb +6 -0
  57. data/spec/app/config/environment.rb +5 -0
  58. data/spec/app/config/environments/development.rb +21 -0
  59. data/spec/app/config/environments/test.rb +29 -0
  60. data/spec/app/config/initializers/backtrace_silencers.rb +7 -0
  61. data/spec/app/config/initializers/inflections.rb +15 -0
  62. data/spec/app/config/initializers/mime_types.rb +5 -0
  63. data/spec/app/config/initializers/secret_token.rb +7 -0
  64. data/spec/app/config/initializers/session_store.rb +8 -0
  65. data/spec/app/config/locales/en.yml +5 -0
  66. data/spec/app/config/routes.rb +62 -0
  67. data/spec/app/db/seeds.rb +7 -0
  68. data/spec/app/lib/assets/.gitkeep +0 -0
  69. data/spec/app/lib/tasks/.gitkeep +0 -0
  70. data/spec/app/log/.gitkeep +0 -0
  71. data/spec/app/public/404.html +26 -0
  72. data/spec/app/public/422.html +26 -0
  73. data/spec/app/public/500.html +25 -0
  74. data/spec/app/public/favicon.ico +0 -0
  75. data/spec/app/public/index.html +241 -0
  76. data/spec/app/public/javascripts/application.js +9663 -0
  77. data/spec/app/public/robots.txt +5 -0
  78. data/spec/app/public/stylesheets/application.css +83 -0
  79. data/spec/app/script/rails +6 -0
  80. data/spec/app/spec/controllers/posts_controller_spec.rb +59 -0
  81. data/spec/app/spec/isolated_spec_helper.rb +6 -0
  82. data/spec/app/spec/spec_helper.rb +5 -0
  83. data/spec/app/spec/unit/controllers/posts_controller_isolated_spec.rb +63 -0
  84. data/spec/app/spec/unit/controllers/posts_controller_spec.rb +59 -0
  85. data/spec/app/test/functional/.gitkeep +0 -0
  86. data/spec/app/test/functional/posts_controller_test.rb +67 -0
  87. data/spec/app/test/isolated_test_helper.rb +7 -0
  88. data/spec/app/test/test_helper.rb +6 -0
  89. data/spec/app/test/unit/.gitkeep +0 -0
  90. data/spec/app/test/unit/controllers/posts_controller_isolated_test.rb +71 -0
  91. data/spec/app/test/unit/controllers/posts_controller_test.rb +67 -0
  92. data/spec/app/vendor/assets/javascripts/.gitkeep +0 -0
  93. data/spec/app/vendor/assets/stylesheets/.gitkeep +0 -0
  94. data/spec/app/vendor/plugins/.gitkeep +0 -0
  95. data/spec/controll/asssistant_spec.rb +5 -0
  96. data/spec/controll/command_spec.rb +56 -0
  97. data/spec/controll/commander_spec.rb +68 -0
  98. data/spec/controll/executor/notificator_spec.rb +27 -0
  99. data/spec/controll/flow_handler/control_spec.rb +159 -0
  100. data/spec/controll/flow_handler/redirect/action_spec.rb +48 -0
  101. data/spec/controll/flow_handler/redirect/mapper_spec.rb +69 -0
  102. data/spec/controll/flow_handler/redirect_spec.rb +93 -0
  103. data/spec/controll/flow_handler/render_spec.rb +110 -0
  104. data/spec/controll/helper/event_matcher_spec.rb +21 -0
  105. data/spec/controll/helper/hash_access_spec.rb +25 -0
  106. data/spec/controll/helper/notify_spec.rb +48 -0
  107. data/spec/controll/helper/params_spec.rb +28 -0
  108. data/spec/controll/helper/path_resolver_spec.rb +49 -0
  109. data/spec/controll/helper/session_spec.rb +28 -0
  110. data/spec/controll/helper_spec.rb +108 -0
  111. data/spec/controll/notify/base_spec.rb +123 -0
  112. data/spec/controll/notify/flash_spec.rb +27 -0
  113. data/spec/controll/notify/message_handler.rb +72 -0
  114. data/spec/controll/notify/typed_spec.rb +28 -0
  115. data/spec/functional_test_helper.rb +25 -0
  116. data/spec/helper.rb +33 -0
  117. data/spec/rspec_controller_class.rb +15 -0
  118. data/spec/rspec_functional_helper.rb +25 -0
  119. data/spec/rspec_helper.rb +42 -0
  120. data/spec/spec_helper.rb +11 -0
  121. data/spec/test_helper.rb +183 -0
  122. data/spec/unit/functional_test_helper_test.rb +65 -0
  123. data/spec/unit/macros_test.rb +43 -0
  124. data/spec/unit/mixin_test.rb +147 -0
  125. data/spec/unit/rspec_functional_helper.rb +42 -0
  126. data/spec/unit/rspec_helper_test.rb +91 -0
  127. data/spec/unit/test_helper_test.rb +235 -0
  128. metadata +289 -0
@@ -0,0 +1,5 @@
1
+ module Controll::FlowHandler
2
+ class NoRedirectionFoundError < StandardError; end
3
+ class NoEventsDefinedError < StandardError; end
4
+ class BadPathError < StandardError; end
5
+ end
@@ -0,0 +1,18 @@
1
+ module Controll::FlowHandler
2
+ module EventHelper
3
+ def types
4
+ @types ||= [:notice, :error]
5
+ end
6
+
7
+ def normalize event
8
+ case event
9
+ when Symbol
10
+ Hashie::Mash.new name: event, type: :notice
11
+ when Hash, Hashie::Mash
12
+ event
13
+ else
14
+ raise Controll::InvalidEvent, "Event: #{event} could not be normalized, must be a Hash or Symbol"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,51 @@
1
+ require 'controll/flow_handler/base'
2
+
3
+ module Controll::FlowHandler
4
+ class Redirect < Base
5
+ autoload :Action, 'controll/flow_handler/redirect/action'
6
+ autoload :Mapper, 'controll/flow_handler/redirect/mapper'
7
+
8
+ def initialize path
9
+ super path
10
+ end
11
+
12
+ def perform controller
13
+ controller.do_redirect controller.send(path)
14
+ end
15
+
16
+ class << self
17
+ attr_accessor :redirections
18
+ attr_writer :redirect_maps, :action_clazz
19
+
20
+ def action event
21
+ path = action_clazz.new(event, redirections, types).map
22
+ self.new path unless path.blank?
23
+ end
24
+
25
+ def types
26
+ @types ||= [:notice, :error]
27
+ end
28
+
29
+ def redirections_for type = :notice
30
+ @redirections ||= {}
31
+ @redirections[type.to_sym] || {}
32
+ end
33
+
34
+ def set_redirections *args
35
+ type = args.first.kind_of?(Symbol) ? args.shift : :notice
36
+ @redirections ||= {}
37
+ @redirections[type.to_sym] = args.first
38
+ end
39
+
40
+ def set_types *names
41
+ @redirect_maps ||= names.flatten
42
+ end
43
+
44
+ protected
45
+
46
+ def action_clazz
47
+ @action_clazz ||= Controll::FlowHandler::Redirect::Action
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,45 @@
1
+ module Controll::FlowHandler
2
+ class Redirect < Base
3
+ class Action
4
+ attr_accessor :event, :redirections, :types
5
+
6
+ # event is a Hashie::Mash or simply a Symbol (default notice event)
7
+ def initialize event, redirections, types = []
8
+ raise ArgumentError, "Must take :event option, was: #{event}" if event.blank?
9
+ raise ArgumentError, "Must take non-empty :redirections option, was: #{redirections}" if redirections.blank?
10
+ @event = normalize event
11
+ @types = types unless types.blank?
12
+ @redirections = redirections
13
+ end
14
+
15
+ def map
16
+ if redirect.blank?
17
+ raise Controll::FlowHandler::NoRedirectionFoundError, "No redirection could be found for: #{event} in: #{redirections}"
18
+ end
19
+ redirect
20
+ end
21
+
22
+ protected
23
+
24
+ include Controll::FlowHandler::EventHelper
25
+
26
+ def redirect
27
+ @redirect ||= mapper(redirect_map).map
28
+ rescue StandardError => e
29
+ raise Controll::FlowHandler::NoRedirectionFoundError, "No redirection could be found for: #{event} in: #{redirections}. Cause: #{e}"
30
+ end
31
+
32
+ def redirect_map
33
+ @redirect_map ||= redirections[event.type] || {}
34
+ end
35
+
36
+ def mapper redirect_map
37
+ @mapper ||= mapper_class.new event, redirect_map
38
+ end
39
+
40
+ def mapper_class
41
+ Controll::FlowHandler::Redirect::Mapper
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,41 @@
1
+ module Controll::FlowHandler
2
+ class Redirect < Base
3
+ class Mapper
4
+ attr_reader :redirect_map, :event
5
+
6
+ def initialize event, redirect_map
7
+ @event ||= normalize event
8
+
9
+ unless valid_map? redirect_map
10
+ raise ArgumentError, "Invalid redirect map: #{redirect_map}, must be a Hash"
11
+ end
12
+ @redirect_map ||= redirect_map
13
+ end
14
+
15
+ # An events can also be a Symbol,
16
+ # in which case it is a :notice event
17
+ def map
18
+ redirect_map.each do |path, events|
19
+ return path.to_s if valid? events
20
+ end
21
+ raise Controll::FlowHandler::NoRedirectionFoundError, "No path could be found for event: #{event} in map: #{redirect_map}"
22
+ end
23
+
24
+ protected
25
+
26
+ include Controll::FlowHandler::EventHelper
27
+
28
+ def valid_map? redirect_map
29
+ redirect_map.kind_of?(Hash) && !redirect_map.blank?
30
+ end
31
+
32
+ def valid? events
33
+ matcher(event).match?(events)
34
+ end
35
+
36
+ def matcher event
37
+ @matcher ||= Controll::Helper::EventMatcher.new event
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ require 'controll/flow_handler/base'
2
+
3
+ module Controll::FlowHandler
4
+ class Render < Base
5
+ class NoEventsDefinedError < StandardError; end
6
+ class BadPathError < StandardError; end
7
+
8
+ def initialize path #, events = []
9
+ super path
10
+ # @events = events
11
+ end
12
+
13
+ def perform controller
14
+ raise BadPathError, "Bad path: #{path}" if path.blank?
15
+ controller.render controller.send(path)
16
+ end
17
+
18
+ class << self
19
+ def action event, path = nil
20
+ raise Controll::FlowHandler::NoEventsDefinedError, "You must define a #{self}#events class method that returns a render map" unless respond_to?(:events)
21
+ raise Controll::FlowHandler::NoEventsDefinedError, "The #{self}#events class method must return a render map, was #{events}" if events.blank?
22
+ event = normalize event
23
+ self.new(path || default_path) if events.include? event.name
24
+ end
25
+
26
+ def default_path
27
+ raise NotImplementedError, "You must set a default_path or override the #{self}#action class method"
28
+ end
29
+
30
+ # http://bugs.ruby-lang.org/issues/1082
31
+ # hello.singleton_class
32
+ # Instead of always having to write:
33
+ # (class << hello; self; end)
34
+ def set_default_path str = nil, &block
35
+ (class << self; self; end).send :define_method, :default_path do
36
+ block_given? ? yield : str
37
+ end
38
+ end
39
+
40
+ def set_events *args, &block
41
+ (class << self; self; end).send :define_method, :events do
42
+ block_given? ? yield : args.flatten
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ include Controll::FlowHandler::EventHelper
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,101 @@
1
+ module Controll
2
+ module Helper
3
+ autoload :Notify, 'controll/helper/notify'
4
+ autoload :HashAccess, 'controll/helper/hash_access'
5
+ autoload :Params, 'controll/helper/params'
6
+ 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
+ end
101
+ end
@@ -0,0 +1,21 @@
1
+ module Controll::Helper
2
+ class EventMatcher
3
+ attr_reader :event
4
+
5
+ def initialize event
6
+ @event = normalize event
7
+ end
8
+
9
+ def match? events
10
+ normalized(events).include? event.name
11
+ end
12
+
13
+ protected
14
+
15
+ include Controll::FlowHandler::EventHelper
16
+
17
+ def normalized events
18
+ [events].flatten.map(&:to_sym)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ module Controll::Helper
2
+ module HashAccess
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def hash_access_methods *args
7
+ options = args.extract_options!
8
+ hash_name = options[:hash]
9
+ names = args
10
+
11
+ raise ArgumentError, "Must take a :hash option indicating the hash name to access" unless hash_name
12
+ raise ArgumentError, "Must take one or more names of methods to create" if names.blank?
13
+
14
+ names.each do |name|
15
+ define_method name do
16
+ unless instance_variable_get("@#{name}")
17
+ instance_variable_set "@#{name}", (send(hash_name)[name.to_sym]) || options[:default]
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ alias_method :hash_access_method, :hash_access_methods
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,74 @@
1
+ module Controll
2
+ module Helper
3
+ module Notify
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attr_writer :notification_types
8
+
9
+ notification_types.each do |type|
10
+ define_method "create_#{type}" do |*args|
11
+ create_notification args.first, type.to_sym, args.extract_options!
12
+ end
13
+ end
14
+ end
15
+
16
+ # msg stack
17
+ def notifications
18
+ @notifications ||= []
19
+ end
20
+
21
+ def main_event
22
+ notifications.last || create_notice(:success)
23
+ end
24
+
25
+ def notify name, type = nil, options = {}
26
+ notifications << create_notification(name, type, options)
27
+ self # enable method chaining on controller
28
+ end
29
+
30
+ protected
31
+
32
+ def error name = :error, options = {}
33
+ notify name, :error, options
34
+ end
35
+
36
+ def success name = :success, options = {}
37
+ notify name, :success, options
38
+ end
39
+
40
+ def create_notification name, type = nil, options = {}
41
+ type ||= :notice
42
+ raise ArgumentError, "Not a valid notification type: #{type}, must be one of: #{valid_notification_types}" unless valid_notification_type?(type)
43
+ Hashie::Mash.new(name: name, type: type, options: options)
44
+ end
45
+ alias_method :create_event, :create_notification
46
+
47
+ def valid_notification_type? type
48
+ notification_types.include? type.to_sym
49
+ end
50
+
51
+ def notification_types
52
+ return self.class.notification_types if self.class.respond_to? :notification_types
53
+ Controll::Notify::Flash.types
54
+ end
55
+
56
+ # allows customization of notification types
57
+ module ClassMethods
58
+ def notification_types
59
+ @notification_types ||= default_notification_types
60
+ end
61
+
62
+ def default_notification_types
63
+ Controll::Notify::Flash.types
64
+ end
65
+ end
66
+
67
+ def process_notifications
68
+ notifications.each do |message|
69
+ message_handler.send(message.type).notify message.name, message.options
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end