actionpack 5.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +429 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +57 -0
  5. data/lib/abstract_controller.rb +27 -0
  6. data/lib/abstract_controller/asset_paths.rb +12 -0
  7. data/lib/abstract_controller/base.rb +265 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/caching/fragments.rb +166 -0
  10. data/lib/abstract_controller/callbacks.rb +212 -0
  11. data/lib/abstract_controller/collector.rb +43 -0
  12. data/lib/abstract_controller/error.rb +6 -0
  13. data/lib/abstract_controller/helpers.rb +194 -0
  14. data/lib/abstract_controller/logger.rb +14 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +20 -0
  16. data/lib/abstract_controller/rendering.rb +127 -0
  17. data/lib/abstract_controller/translation.rb +31 -0
  18. data/lib/abstract_controller/url_for.rb +35 -0
  19. data/lib/action_controller.rb +66 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/api/api_rendering.rb +16 -0
  22. data/lib/action_controller/base.rb +276 -0
  23. data/lib/action_controller/caching.rb +46 -0
  24. data/lib/action_controller/form_builder.rb +50 -0
  25. data/lib/action_controller/log_subscriber.rb +78 -0
  26. data/lib/action_controller/metal.rb +256 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  28. data/lib/action_controller/metal/conditional_get.rb +274 -0
  29. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  30. data/lib/action_controller/metal/cookies.rb +16 -0
  31. data/lib/action_controller/metal/data_streaming.rb +152 -0
  32. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  34. data/lib/action_controller/metal/exceptions.rb +53 -0
  35. data/lib/action_controller/metal/flash.rb +61 -0
  36. data/lib/action_controller/metal/force_ssl.rb +99 -0
  37. data/lib/action_controller/metal/head.rb +60 -0
  38. data/lib/action_controller/metal/helpers.rb +123 -0
  39. data/lib/action_controller/metal/http_authentication.rb +519 -0
  40. data/lib/action_controller/metal/implicit_render.rb +73 -0
  41. data/lib/action_controller/metal/instrumentation.rb +107 -0
  42. data/lib/action_controller/metal/live.rb +312 -0
  43. data/lib/action_controller/metal/mime_responds.rb +313 -0
  44. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  45. data/lib/action_controller/metal/params_wrapper.rb +293 -0
  46. data/lib/action_controller/metal/redirecting.rb +133 -0
  47. data/lib/action_controller/metal/renderers.rb +181 -0
  48. data/lib/action_controller/metal/rendering.rb +122 -0
  49. data/lib/action_controller/metal/request_forgery_protection.rb +445 -0
  50. data/lib/action_controller/metal/rescue.rb +28 -0
  51. data/lib/action_controller/metal/streaming.rb +223 -0
  52. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  53. data/lib/action_controller/metal/testing.rb +16 -0
  54. data/lib/action_controller/metal/url_for.rb +58 -0
  55. data/lib/action_controller/railtie.rb +89 -0
  56. data/lib/action_controller/railties/helpers.rb +24 -0
  57. data/lib/action_controller/renderer.rb +117 -0
  58. data/lib/action_controller/template_assertions.rb +11 -0
  59. data/lib/action_controller/test_case.rb +629 -0
  60. data/lib/action_dispatch.rb +112 -0
  61. data/lib/action_dispatch/http/cache.rb +222 -0
  62. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  63. data/lib/action_dispatch/http/filter_parameters.rb +84 -0
  64. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  65. data/lib/action_dispatch/http/headers.rb +132 -0
  66. data/lib/action_dispatch/http/mime_negotiation.rb +175 -0
  67. data/lib/action_dispatch/http/mime_type.rb +342 -0
  68. data/lib/action_dispatch/http/mime_types.rb +50 -0
  69. data/lib/action_dispatch/http/parameter_filter.rb +86 -0
  70. data/lib/action_dispatch/http/parameters.rb +126 -0
  71. data/lib/action_dispatch/http/rack_cache.rb +63 -0
  72. data/lib/action_dispatch/http/request.rb +430 -0
  73. data/lib/action_dispatch/http/response.rb +519 -0
  74. data/lib/action_dispatch/http/upload.rb +84 -0
  75. data/lib/action_dispatch/http/url.rb +350 -0
  76. data/lib/action_dispatch/journey.rb +7 -0
  77. data/lib/action_dispatch/journey/formatter.rb +189 -0
  78. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  79. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  80. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  81. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  82. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  83. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  84. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  85. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  86. data/lib/action_dispatch/journey/parser.rb +199 -0
  87. data/lib/action_dispatch/journey/parser.y +50 -0
  88. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  89. data/lib/action_dispatch/journey/path/pattern.rb +198 -0
  90. data/lib/action_dispatch/journey/route.rb +203 -0
  91. data/lib/action_dispatch/journey/router.rb +156 -0
  92. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  93. data/lib/action_dispatch/journey/routes.rb +82 -0
  94. data/lib/action_dispatch/journey/scanner.rb +64 -0
  95. data/lib/action_dispatch/journey/visitors.rb +268 -0
  96. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  97. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  98. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  99. data/lib/action_dispatch/middleware/callbacks.rb +36 -0
  100. data/lib/action_dispatch/middleware/cookies.rb +685 -0
  101. data/lib/action_dispatch/middleware/debug_exceptions.rb +205 -0
  102. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  103. data/lib/action_dispatch/middleware/exception_wrapper.rb +147 -0
  104. data/lib/action_dispatch/middleware/executor.rb +21 -0
  105. data/lib/action_dispatch/middleware/flash.rb +300 -0
  106. data/lib/action_dispatch/middleware/public_exceptions.rb +57 -0
  107. data/lib/action_dispatch/middleware/reloader.rb +12 -0
  108. data/lib/action_dispatch/middleware/remote_ip.rb +183 -0
  109. data/lib/action_dispatch/middleware/request_id.rb +43 -0
  110. data/lib/action_dispatch/middleware/session/abstract_store.rb +92 -0
  111. data/lib/action_dispatch/middleware/session/cache_store.rb +54 -0
  112. data/lib/action_dispatch/middleware/session/cookie_store.rb +118 -0
  113. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +28 -0
  114. data/lib/action_dispatch/middleware/show_exceptions.rb +62 -0
  115. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  116. data/lib/action_dispatch/middleware/stack.rb +116 -0
  117. data/lib/action_dispatch/middleware/static.rb +130 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +161 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  138. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  139. data/lib/action_dispatch/railtie.rb +55 -0
  140. data/lib/action_dispatch/request/session.rb +234 -0
  141. data/lib/action_dispatch/request/utils.rb +78 -0
  142. data/lib/action_dispatch/routing.rb +260 -0
  143. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  144. data/lib/action_dispatch/routing/inspector.rb +225 -0
  145. data/lib/action_dispatch/routing/mapper.rb +2267 -0
  146. data/lib/action_dispatch/routing/polymorphic_routes.rb +352 -0
  147. data/lib/action_dispatch/routing/redirection.rb +201 -0
  148. data/lib/action_dispatch/routing/route_set.rb +890 -0
  149. data/lib/action_dispatch/routing/routes_proxy.rb +69 -0
  150. data/lib/action_dispatch/routing/url_for.rb +236 -0
  151. data/lib/action_dispatch/system_test_case.rb +147 -0
  152. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  153. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  154. data/lib/action_dispatch/system_testing/server.rb +31 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  157. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  158. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  159. data/lib/action_dispatch/testing/assertions.rb +24 -0
  160. data/lib/action_dispatch/testing/assertions/response.rb +107 -0
  161. data/lib/action_dispatch/testing/assertions/routing.rb +222 -0
  162. data/lib/action_dispatch/testing/integration.rb +652 -0
  163. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  164. data/lib/action_dispatch/testing/test_process.rb +50 -0
  165. data/lib/action_dispatch/testing/test_request.rb +71 -0
  166. data/lib/action_dispatch/testing/test_response.rb +53 -0
  167. data/lib/action_pack.rb +26 -0
  168. data/lib/action_pack/gem_version.rb +17 -0
  169. data/lib/action_pack/version.rb +10 -0
  170. metadata +318 -0
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AbstractController
4
+ # = Abstract Controller Callbacks
5
+ #
6
+ # Abstract Controller provides hooks during the life cycle of a controller action.
7
+ # Callbacks allow you to trigger logic during this cycle. Available callbacks are:
8
+ #
9
+ # * <tt>after_action</tt>
10
+ # * <tt>append_after_action</tt>
11
+ # * <tt>append_around_action</tt>
12
+ # * <tt>append_before_action</tt>
13
+ # * <tt>around_action</tt>
14
+ # * <tt>before_action</tt>
15
+ # * <tt>prepend_after_action</tt>
16
+ # * <tt>prepend_around_action</tt>
17
+ # * <tt>prepend_before_action</tt>
18
+ # * <tt>skip_after_action</tt>
19
+ # * <tt>skip_around_action</tt>
20
+ # * <tt>skip_before_action</tt>
21
+ #
22
+ # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
23
+ #
24
+ module Callbacks
25
+ extend ActiveSupport::Concern
26
+
27
+ # Uses ActiveSupport::Callbacks as the base functionality. For
28
+ # more details on the whole callback system, read the documentation
29
+ # for ActiveSupport::Callbacks.
30
+ include ActiveSupport::Callbacks
31
+
32
+ included do
33
+ define_callbacks :process_action,
34
+ terminator: ->(controller, result_lambda) { result_lambda.call; controller.performed? },
35
+ skip_after_callbacks_if_terminated: true
36
+ end
37
+
38
+ # Override <tt>AbstractController::Base#process_action</tt> to run the
39
+ # <tt>process_action</tt> callbacks around the normal behavior.
40
+ def process_action(*args)
41
+ run_callbacks(:process_action) do
42
+ super
43
+ end
44
+ end
45
+
46
+ module ClassMethods
47
+ # If +:only+ or +:except+ are used, convert the options into the
48
+ # +:if+ and +:unless+ options of ActiveSupport::Callbacks.
49
+ #
50
+ # The basic idea is that <tt>:only => :index</tt> gets converted to
51
+ # <tt>:if => proc {|c| c.action_name == "index" }</tt>.
52
+ #
53
+ # Note that <tt>:only</tt> has priority over <tt>:if</tt> in case they
54
+ # are used together.
55
+ #
56
+ # only: :index, if: -> { true } # the :if option will be ignored.
57
+ #
58
+ # Note that <tt>:if</tt> has priority over <tt>:except</tt> in case they
59
+ # are used together.
60
+ #
61
+ # except: :index, if: -> { true } # the :except option will be ignored.
62
+ #
63
+ # ==== Options
64
+ # * <tt>only</tt> - The callback should be run only for this action.
65
+ # * <tt>except</tt> - The callback should be run for all actions except this action.
66
+ def _normalize_callback_options(options)
67
+ _normalize_callback_option(options, :only, :if)
68
+ _normalize_callback_option(options, :except, :unless)
69
+ end
70
+
71
+ def _normalize_callback_option(options, from, to) # :nodoc:
72
+ if from = options[from]
73
+ _from = Array(from).map(&:to_s).to_set
74
+ from = proc { |c| _from.include? c.action_name }
75
+ options[to] = Array(options[to]).unshift(from)
76
+ end
77
+ end
78
+
79
+ # Take callback names and an optional callback proc, normalize them,
80
+ # then call the block with each callback. This allows us to abstract
81
+ # the normalization across several methods that use it.
82
+ #
83
+ # ==== Parameters
84
+ # * <tt>callbacks</tt> - An array of callbacks, with an optional
85
+ # options hash as the last parameter.
86
+ # * <tt>block</tt> - A proc that should be added to the callbacks.
87
+ #
88
+ # ==== Block Parameters
89
+ # * <tt>name</tt> - The callback to be added.
90
+ # * <tt>options</tt> - A hash of options to be used when adding the callback.
91
+ def _insert_callbacks(callbacks, block = nil)
92
+ options = callbacks.extract_options!
93
+ _normalize_callback_options(options)
94
+ callbacks.push(block) if block
95
+ callbacks.each do |callback|
96
+ yield callback, options
97
+ end
98
+ end
99
+
100
+ ##
101
+ # :method: before_action
102
+ #
103
+ # :call-seq: before_action(names, block)
104
+ #
105
+ # Append a callback before actions. See _insert_callbacks for parameter details.
106
+
107
+ ##
108
+ # :method: prepend_before_action
109
+ #
110
+ # :call-seq: prepend_before_action(names, block)
111
+ #
112
+ # Prepend a callback before actions. See _insert_callbacks for parameter details.
113
+
114
+ ##
115
+ # :method: skip_before_action
116
+ #
117
+ # :call-seq: skip_before_action(names)
118
+ #
119
+ # Skip a callback before actions. See _insert_callbacks for parameter details.
120
+
121
+ ##
122
+ # :method: append_before_action
123
+ #
124
+ # :call-seq: append_before_action(names, block)
125
+ #
126
+ # Append a callback before actions. See _insert_callbacks for parameter details.
127
+
128
+ ##
129
+ # :method: after_action
130
+ #
131
+ # :call-seq: after_action(names, block)
132
+ #
133
+ # Append a callback after actions. See _insert_callbacks for parameter details.
134
+
135
+ ##
136
+ # :method: prepend_after_action
137
+ #
138
+ # :call-seq: prepend_after_action(names, block)
139
+ #
140
+ # Prepend a callback after actions. See _insert_callbacks for parameter details.
141
+
142
+ ##
143
+ # :method: skip_after_action
144
+ #
145
+ # :call-seq: skip_after_action(names)
146
+ #
147
+ # Skip a callback after actions. See _insert_callbacks for parameter details.
148
+
149
+ ##
150
+ # :method: append_after_action
151
+ #
152
+ # :call-seq: append_after_action(names, block)
153
+ #
154
+ # Append a callback after actions. See _insert_callbacks for parameter details.
155
+
156
+ ##
157
+ # :method: around_action
158
+ #
159
+ # :call-seq: around_action(names, block)
160
+ #
161
+ # Append a callback around actions. See _insert_callbacks for parameter details.
162
+
163
+ ##
164
+ # :method: prepend_around_action
165
+ #
166
+ # :call-seq: prepend_around_action(names, block)
167
+ #
168
+ # Prepend a callback around actions. See _insert_callbacks for parameter details.
169
+
170
+ ##
171
+ # :method: skip_around_action
172
+ #
173
+ # :call-seq: skip_around_action(names)
174
+ #
175
+ # Skip a callback around actions. See _insert_callbacks for parameter details.
176
+
177
+ ##
178
+ # :method: append_around_action
179
+ #
180
+ # :call-seq: append_around_action(names, block)
181
+ #
182
+ # Append a callback around actions. See _insert_callbacks for parameter details.
183
+
184
+ # set up before_action, prepend_before_action, skip_before_action, etc.
185
+ # for each of before, after, and around.
186
+ [:before, :after, :around].each do |callback|
187
+ define_method "#{callback}_action" do |*names, &blk|
188
+ _insert_callbacks(names, blk) do |name, options|
189
+ set_callback(:process_action, callback, name, options)
190
+ end
191
+ end
192
+
193
+ define_method "prepend_#{callback}_action" do |*names, &blk|
194
+ _insert_callbacks(names, blk) do |name, options|
195
+ set_callback(:process_action, callback, name, options.merge(prepend: true))
196
+ end
197
+ end
198
+
199
+ # Skip a before, after or around callback. See _insert_callbacks
200
+ # for details on the allowed parameters.
201
+ define_method "skip_#{callback}_action" do |*names|
202
+ _insert_callbacks(names) do |name, options|
203
+ skip_callback(:process_action, callback, name, options)
204
+ end
205
+ end
206
+
207
+ # *_action is the same as append_*_action
208
+ alias_method :"append_#{callback}_action", :"#{callback}_action"
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/http/mime_type"
4
+
5
+ module AbstractController
6
+ module Collector
7
+ def self.generate_method_for_mime(mime)
8
+ sym = mime.is_a?(Symbol) ? mime : mime.to_sym
9
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
10
+ def #{sym}(*args, &block)
11
+ custom(Mime[:#{sym}], *args, &block)
12
+ end
13
+ RUBY
14
+ end
15
+
16
+ Mime::SET.each do |mime|
17
+ generate_method_for_mime(mime)
18
+ end
19
+
20
+ Mime::Type.register_callback do |mime|
21
+ generate_method_for_mime(mime) unless instance_methods.include?(mime.to_sym)
22
+ end
23
+
24
+ private
25
+
26
+ def method_missing(symbol, &block)
27
+ unless mime_constant = Mime[symbol]
28
+ raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
29
+ "http://guides.rubyonrails.org/action_controller_overview.html#restful-downloads. " \
30
+ "If you meant to respond to a variant like :tablet or :phone, not a custom format, " \
31
+ "be sure to nest your variant response within a format response: " \
32
+ "format.html { |html| html.tablet { ... } }"
33
+ end
34
+
35
+ if Mime::SET.include?(mime_constant)
36
+ AbstractController::Collector.generate_method_for_mime(mime_constant)
37
+ send(symbol, &block)
38
+ else
39
+ super
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AbstractController
4
+ class Error < StandardError #:nodoc:
5
+ end
6
+ end
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/dependencies"
4
+
5
+ module AbstractController
6
+ module Helpers
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :_helpers, default: Module.new
11
+ class_attribute :_helper_methods, default: Array.new
12
+ end
13
+
14
+ class MissingHelperError < LoadError
15
+ def initialize(error, path)
16
+ @error = error
17
+ @path = "helpers/#{path}.rb"
18
+ set_backtrace error.backtrace
19
+
20
+ if error.path =~ /^#{path}(\.rb)?$/
21
+ super("Missing helper file helpers/%s.rb" % path)
22
+ else
23
+ raise error
24
+ end
25
+ end
26
+ end
27
+
28
+ module ClassMethods
29
+ # When a class is inherited, wrap its helper module in a new module.
30
+ # This ensures that the parent class's module can be changed
31
+ # independently of the child class's.
32
+ def inherited(klass)
33
+ helpers = _helpers
34
+ klass._helpers = Module.new { include helpers }
35
+ klass.class_eval { default_helper_module! } unless klass.anonymous?
36
+ super
37
+ end
38
+
39
+ # Declare a controller method as a helper. For example, the following
40
+ # makes the +current_user+ and +logged_in?+ controller methods available
41
+ # to the view:
42
+ # class ApplicationController < ActionController::Base
43
+ # helper_method :current_user, :logged_in?
44
+ #
45
+ # def current_user
46
+ # @current_user ||= User.find_by(id: session[:user])
47
+ # end
48
+ #
49
+ # def logged_in?
50
+ # current_user != nil
51
+ # end
52
+ # end
53
+ #
54
+ # In a view:
55
+ # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
56
+ #
57
+ # ==== Parameters
58
+ # * <tt>method[, method]</tt> - A name or names of a method on the controller
59
+ # to be made available on the view.
60
+ def helper_method(*meths)
61
+ meths.flatten!
62
+ self._helper_methods += meths
63
+
64
+ meths.each do |meth|
65
+ _helpers.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
66
+ def #{meth}(*args, &blk) # def current_user(*args, &blk)
67
+ controller.send(%(#{meth}), *args, &blk) # controller.send(:current_user, *args, &blk)
68
+ end # end
69
+ ruby_eval
70
+ end
71
+ end
72
+
73
+ # The +helper+ class method can take a series of helper module names, a block, or both.
74
+ #
75
+ # ==== Options
76
+ # * <tt>*args</tt> - Module, Symbol, String
77
+ # * <tt>block</tt> - A block defining helper methods
78
+ #
79
+ # When the argument is a module it will be included directly in the template class.
80
+ # helper FooHelper # => includes FooHelper
81
+ #
82
+ # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file
83
+ # and include the module in the template class. The second form illustrates how to include custom helpers
84
+ # when working with namespaced controllers, or other cases where the file containing the helper definition is not
85
+ # in one of Rails' standard load paths:
86
+ # helper :foo # => requires 'foo_helper' and includes FooHelper
87
+ # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
88
+ #
89
+ # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
90
+ # to the template.
91
+ #
92
+ # # One line
93
+ # helper { def hello() "Hello, world!" end }
94
+ #
95
+ # # Multi-line
96
+ # helper do
97
+ # def foo(bar)
98
+ # "#{bar} is the very best"
99
+ # end
100
+ # end
101
+ #
102
+ # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
103
+ # +symbols+, +strings+, +modules+ and blocks.
104
+ #
105
+ # helper(:three, BlindHelper) { def mice() 'mice' end }
106
+ #
107
+ def helper(*args, &block)
108
+ modules_for_helpers(args).each do |mod|
109
+ add_template_helper(mod)
110
+ end
111
+
112
+ _helpers.module_eval(&block) if block_given?
113
+ end
114
+
115
+ # Clears up all existing helpers in this class, only keeping the helper
116
+ # with the same name as this class.
117
+ def clear_helpers
118
+ inherited_helper_methods = _helper_methods
119
+ self._helpers = Module.new
120
+ self._helper_methods = Array.new
121
+
122
+ inherited_helper_methods.each { |meth| helper_method meth }
123
+ default_helper_module! unless anonymous?
124
+ end
125
+
126
+ # Returns a list of modules, normalized from the acceptable kinds of
127
+ # helpers with the following behavior:
128
+ #
129
+ # String or Symbol:: :FooBar or "FooBar" becomes "foo_bar_helper",
130
+ # and "foo_bar_helper.rb" is loaded using require_dependency.
131
+ #
132
+ # Module:: No further processing
133
+ #
134
+ # After loading the appropriate files, the corresponding modules
135
+ # are returned.
136
+ #
137
+ # ==== Parameters
138
+ # * <tt>args</tt> - An array of helpers
139
+ #
140
+ # ==== Returns
141
+ # * <tt>Array</tt> - A normalized list of modules for the list of
142
+ # helpers provided.
143
+ def modules_for_helpers(args)
144
+ args.flatten.map! do |arg|
145
+ case arg
146
+ when String, Symbol
147
+ file_name = "#{arg.to_s.underscore}_helper"
148
+ begin
149
+ require_dependency(file_name)
150
+ rescue LoadError => e
151
+ raise AbstractController::Helpers::MissingHelperError.new(e, file_name)
152
+ end
153
+
154
+ mod_name = file_name.camelize
155
+ begin
156
+ mod_name.constantize
157
+ rescue LoadError
158
+ # dependencies.rb gives a similar error message but its wording is
159
+ # not as clear because it mentions autoloading. To the user all it
160
+ # matters is that a helper module couldn't be loaded, autoloading
161
+ # is an internal mechanism that should not leak.
162
+ raise NameError, "Couldn't find #{mod_name}, expected it to be defined in helpers/#{file_name}.rb"
163
+ end
164
+ when Module
165
+ arg
166
+ else
167
+ raise ArgumentError, "helper must be a String, Symbol, or Module"
168
+ end
169
+ end
170
+ end
171
+
172
+ private
173
+ # Makes all the (instance) methods in the helper module available to templates
174
+ # rendered through this controller.
175
+ #
176
+ # ==== Parameters
177
+ # * <tt>module</tt> - The module to include into the current helper module
178
+ # for the class
179
+ def add_template_helper(mod)
180
+ _helpers.module_eval { include mod }
181
+ end
182
+
183
+ def default_helper_module!
184
+ module_name = name.sub(/Controller$/, "".freeze)
185
+ module_path = module_name.underscore
186
+ helper module_path
187
+ rescue LoadError => e
188
+ raise e unless e.is_missing? "helpers/#{module_path}_helper"
189
+ rescue NameError => e
190
+ raise e unless e.missing_name? "#{module_name}Helper"
191
+ end
192
+ end
193
+ end
194
+ end