actionpack 3.2.22.5 → 4.0.0.beta1

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 (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2011 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2013 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -21,24 +21,24 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
- require 'active_support/ruby/shim'
25
- require 'active_support/core_ext/class/attribute_accessors'
26
-
24
+ require 'active_support'
25
+ require 'active_support/rails'
27
26
  require 'action_pack'
28
27
 
29
28
  module ActionView
30
29
  extend ActiveSupport::Autoload
31
30
 
32
31
  eager_autoload do
33
- autoload :AssetPaths
34
32
  autoload :Base
35
33
  autoload :Context
36
34
  autoload :CompiledTemplates, "action_view/context"
35
+ autoload :Digestor
37
36
  autoload :Helpers
38
37
  autoload :LookupContext
39
38
  autoload :PathSet
39
+ autoload :RecordIdentifier
40
+ autoload :RoutingUrlFor
40
41
  autoload :Template
41
- autoload :TestCase
42
42
 
43
43
  autoload_under "renderer" do
44
44
  autoload :Renderer
@@ -70,15 +70,24 @@ module ActionView
70
70
  autoload :MissingTemplate
71
71
  autoload :ActionViewError
72
72
  autoload :EncodingError
73
+ autoload :MissingRequestError
73
74
  autoload :TemplateError
74
75
  autoload :WrongEncodingError
75
76
  end
76
77
  end
77
78
 
79
+ autoload :TestCase
80
+
78
81
  ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*'
82
+
83
+ def self.eager_load!
84
+ super
85
+ ActionView::Template.eager_load!
86
+ end
79
87
  end
80
88
 
81
- require 'active_support/i18n'
82
89
  require 'active_support/core_ext/string/output_safety'
83
90
 
84
- I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
91
+ ActiveSupport.on_load(:i18n) do
92
+ I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
93
+ end
@@ -1,15 +1,12 @@
1
1
  require 'active_support/core_ext/module/attr_internal'
2
- require 'active_support/core_ext/module/delegation'
3
- require 'active_support/core_ext/class/attribute'
4
- require 'active_support/core_ext/array/wrap'
2
+ require 'active_support/core_ext/class/attribute_accessors'
5
3
  require 'active_support/ordered_options'
6
4
  require 'action_view/log_subscriber'
7
- require 'active_support/core_ext/module/deprecation'
8
5
 
9
6
  module ActionView #:nodoc:
10
7
  # = Action View Base
11
8
  #
12
- # Action View templates can be written in several ways. If the template file has a <tt>.erb</tt> extension then it uses a mixture of ERb
9
+ # Action View templates can be written in several ways. If the template file has a <tt>.erb</tt> extension then it uses a mixture of ERB
13
10
  # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> extension then Jim Weirich's Builder::XmlMarkup library is used.
14
11
  #
15
12
  # == ERB
@@ -58,7 +55,7 @@ module ActionView #:nodoc:
58
55
  #
59
56
  # You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values:
60
57
  #
61
- # <%= render "shared/header", { :headline => "Welcome", :person => person } %>
58
+ # <%= render "shared/header", { headline: "Welcome", person: person } %>
62
59
  #
63
60
  # These can now be accessed in <tt>shared/header</tt> with:
64
61
  #
@@ -141,14 +138,22 @@ module ActionView #:nodoc:
141
138
  # How to complete the streaming when an exception occurs.
142
139
  # This is our best guess: first try to close the attribute, then the tag.
143
140
  cattr_accessor :streaming_completion_on_exception
144
- @@streaming_completion_on_exception = %("><script type="text/javascript">window.location = "/500.html"</script></html>)
141
+ @@streaming_completion_on_exception = %("><script>window.location = "/500.html"</script></html>)
142
+
143
+ # Specify whether rendering within namespaced controllers should prefix
144
+ # the partial paths for ActiveModel objects with the namespace.
145
+ # (e.g., an Admin::PostsController would render @post using /admin/posts/_post.erb)
146
+ cattr_accessor :prefix_partial_path_with_controller_namespace
147
+ @@prefix_partial_path_with_controller_namespace = true
148
+
149
+ # Specify default_formats that can be rendered.
150
+ cattr_accessor :default_formats
145
151
 
146
- class_attribute :helpers
147
152
  class_attribute :_routes
153
+ class_attribute :logger
148
154
 
149
155
  class << self
150
156
  delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
151
- delegate :logger, :to => 'ActionController::Base', :allow_nil => true
152
157
 
153
158
  def cache_template_loading
154
159
  ActionView::Resolver.caching?
@@ -158,31 +163,9 @@ module ActionView #:nodoc:
158
163
  ActionView::Resolver.caching = value
159
164
  end
160
165
 
161
- def process_view_paths(value)
162
- value.is_a?(PathSet) ?
163
- value.dup : ActionView::PathSet.new(Array.wrap(value))
164
- end
165
- deprecate :process_view_paths
166
-
167
166
  def xss_safe? #:nodoc:
168
167
  true
169
168
  end
170
-
171
- # This method receives routes and helpers from the controller
172
- # and return a subclass ready to be used as view context.
173
- def prepare(routes, helpers) #:nodoc:
174
- Class.new(self) do
175
- if routes
176
- include routes.url_helpers
177
- include routes.mounted_helpers
178
- end
179
-
180
- if helpers
181
- include helpers
182
- self.helpers = helpers
183
- end
184
- end
185
- end
186
169
  end
187
170
 
188
171
  attr_accessor :view_renderer
@@ -198,11 +181,9 @@ module ActionView #:nodoc:
198
181
  def initialize(context = nil, assigns = {}, controller = nil, formats = nil) #:nodoc:
199
182
  @_config = ActiveSupport::InheritableOptions.new
200
183
 
201
- # Handle all these for backwards compatibility.
202
- # TODO Provide a new API for AV::Base and deprecate this one.
203
184
  if context.is_a?(ActionView::Renderer)
204
185
  @view_renderer = context
205
- elsif
186
+ else
206
187
  lookup_context = context.is_a?(ActionView::LookupContext) ?
207
188
  context : ActionView::LookupContext.new(context)
208
189
  lookup_context.formats = formats if formats
@@ -4,7 +4,7 @@ module ActionView
4
4
  class OutputBuffer < ActiveSupport::SafeBuffer #:nodoc:
5
5
  def initialize(*)
6
6
  super
7
- encode! if encoding_aware?
7
+ encode!
8
8
  end
9
9
 
10
10
  def <<(value)
@@ -5,7 +5,7 @@ module ActionView
5
5
 
6
6
  # = Action View Context
7
7
  #
8
- # Action View contexts are supplied to Action Controller to render template.
8
+ # Action View contexts are supplied to Action Controller to render a template.
9
9
  # The default Action View context is ActionView::Base.
10
10
  #
11
11
  # In order to work with ActionController, a Context must just include this module.
@@ -25,12 +25,12 @@ module ActionView
25
25
  end
26
26
 
27
27
  # Encapsulates the interaction with the view flow so it
28
- # returns the correct buffer on yield. This is usually
29
- # overwriten by helpers to add more behavior.
28
+ # returns the correct buffer on +yield+. This is usually
29
+ # overwritten by helpers to add more behavior.
30
30
  # :api: plugin
31
31
  def _layout_for(name=nil)
32
32
  name ||= :layout
33
33
  view_flow.get(name).html_safe
34
34
  end
35
35
  end
36
- end
36
+ end
@@ -0,0 +1,91 @@
1
+ require 'thread_safe'
2
+
3
+ module ActionView
4
+ class DependencyTracker
5
+ @trackers = ThreadSafe::Cache.new
6
+
7
+ def self.find_dependencies(name, template)
8
+ tracker = @trackers[template.handler]
9
+
10
+ if tracker.present?
11
+ tracker.call(name, template)
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+ def self.register_tracker(extension, tracker)
18
+ handler = Template.handler_for_extension(extension)
19
+ @trackers[handler] = tracker
20
+ end
21
+
22
+ def self.remove_tracker(handler)
23
+ @trackers.delete(handler)
24
+ end
25
+
26
+ class ERBTracker
27
+ EXPLICIT_DEPENDENCY = /# Template Dependency: (\S+)/
28
+
29
+ # Matches:
30
+ # render partial: "comments/comment", collection: commentable.comments
31
+ # render "comments/comments"
32
+ # render 'comments/comments'
33
+ # render('comments/comments')
34
+ #
35
+ # render(@topic) => render("topics/topic")
36
+ # render(topics) => render("topics/topic")
37
+ # render(message.topics) => render("topics/topic")
38
+ RENDER_DEPENDENCY = /
39
+ render\s* # render, followed by optional whitespace
40
+ \(? # start an optional parenthesis for the render call
41
+ (partial:|:partial\s+=>)?\s* # naming the partial, used with collection -- 1st capture
42
+ ([@a-z"'][@a-z_\/\."']+) # the template name itself -- 2nd capture
43
+ /x
44
+
45
+ def self.call(name, template)
46
+ new(name, template).dependencies
47
+ end
48
+
49
+ def initialize(name, template)
50
+ @name, @template = name, template
51
+ end
52
+
53
+ def dependencies
54
+ render_dependencies + explicit_dependencies
55
+ end
56
+
57
+ private
58
+ attr_reader :name, :template
59
+
60
+ def source
61
+ template.source
62
+ end
63
+
64
+ def directory
65
+ name.split("/")[0..-2].join("/")
66
+ end
67
+
68
+ def render_dependencies
69
+ source.scan(RENDER_DEPENDENCY).
70
+ collect(&:second).uniq.
71
+
72
+ # render(@topic) => render("topics/topic")
73
+ # render(topics) => render("topics/topic")
74
+ # render(message.topics) => render("topics/topic")
75
+ collect { |name| name.sub(/\A@?([a-z]+\.)*([a-z_]+)\z/) { "#{$2.pluralize}/#{$2.singularize}" } }.
76
+
77
+ # render("headline") => render("message/headline")
78
+ collect { |name| name.include?("/") ? name : "#{directory}/#{name}" }.
79
+
80
+ # replace quotes from string renders
81
+ collect { |name| name.gsub(/["']/, "") }
82
+ end
83
+
84
+ def explicit_dependencies
85
+ source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
86
+ end
87
+ end
88
+
89
+ register_tracker :erb, ERBTracker
90
+ end
91
+ end
@@ -0,0 +1,85 @@
1
+ require 'thread_safe'
2
+ require 'action_view/dependency_tracker'
3
+
4
+ module ActionView
5
+ class Digestor
6
+ cattr_reader(:cache)
7
+ @@cache = ThreadSafe::Cache.new
8
+
9
+ def self.digest(name, format, finder, options = {})
10
+ cache_key = [name, format] + Array.wrap(options[:dependencies])
11
+ @@cache[cache_key.join('.')] ||= begin
12
+ klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
13
+ klass.new(name, format, finder, options).digest
14
+ end
15
+ end
16
+
17
+ attr_reader :name, :format, :finder, :options
18
+
19
+ def initialize(name, format, finder, options={})
20
+ @name, @format, @finder, @options = name, format, finder, options
21
+ end
22
+
23
+ def digest
24
+ Digest::MD5.hexdigest("#{source}-#{dependency_digest}").tap do |digest|
25
+ logger.try :info, "Cache digest for #{name}.#{format}: #{digest}"
26
+ end
27
+ rescue ActionView::MissingTemplate
28
+ logger.try :error, "Couldn't find template for digesting: #{name}.#{format}"
29
+ ''
30
+ end
31
+
32
+ def dependencies
33
+ DependencyTracker.find_dependencies(name, template)
34
+ rescue ActionView::MissingTemplate
35
+ [] # File doesn't exist, so no dependencies
36
+ end
37
+
38
+ def nested_dependencies
39
+ dependencies.collect do |dependency|
40
+ dependencies = PartialDigestor.new(dependency, format, finder).nested_dependencies
41
+ dependencies.any? ? { dependency => dependencies } : dependency
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def logger
48
+ ActionView::Base.logger
49
+ end
50
+
51
+ def logical_name
52
+ name.gsub(%r|/_|, "/")
53
+ end
54
+
55
+ def partial?
56
+ false
57
+ end
58
+
59
+ def template
60
+ @template ||= finder.find(logical_name, [], partial?, formats: [ format ])
61
+ end
62
+
63
+ def source
64
+ template.source
65
+ end
66
+
67
+ def dependency_digest
68
+ template_digests = dependencies.collect do |template_name|
69
+ Digestor.digest(template_name, format, finder, partial: true)
70
+ end
71
+
72
+ (template_digests + injected_dependencies).join("-")
73
+ end
74
+
75
+ def injected_dependencies
76
+ Array.wrap(options[:dependencies])
77
+ end
78
+ end
79
+
80
+ class PartialDigestor < Digestor # :nodoc:
81
+ def partial?
82
+ true
83
+ end
84
+ end
85
+ end
@@ -22,11 +22,8 @@ module ActionView
22
22
  def append(key, value)
23
23
  @content[key] << value
24
24
  end
25
+ alias_method :append!, :append
25
26
 
26
- # Called by provide
27
- def append!(key, value)
28
- @content[key] << value
29
- end
30
27
  end
31
28
 
32
29
  class StreamingFlow < OutputFlow #:nodoc:
@@ -6,6 +6,7 @@ module ActionView #:nodoc:
6
6
 
7
7
  autoload :ActiveModelHelper
8
8
  autoload :AssetTagHelper
9
+ autoload :AssetUrlHelper
9
10
  autoload :AtomFeedHelper
10
11
  autoload :CacheHelper
11
12
  autoload :CaptureHelper
@@ -29,13 +30,10 @@ module ActionView #:nodoc:
29
30
 
30
31
  extend ActiveSupport::Concern
31
32
 
32
- included do
33
- extend SanitizeHelper::ClassMethods
34
- end
35
-
36
33
  include ActiveSupport::Benchmarkable
37
34
  include ActiveModelHelper
38
35
  include AssetTagHelper
36
+ include AssetUrlHelper
39
37
  include AtomFeedHelper
40
38
  include CacheHelper
41
39
  include CaptureHelper
@@ -1,6 +1,5 @@
1
1
  require 'active_support/core_ext/class/attribute_accessors'
2
2
  require 'active_support/core_ext/enumerable'
3
- require 'active_support/core_ext/object/blank'
4
3
 
5
4
  module ActionView
6
5
  # = Active Model Helpers
@@ -16,8 +15,8 @@ module ActionView
16
15
  end
17
16
  end
18
17
 
19
- %w(content_tag to_date_select_tag to_datetime_select_tag to_time_select_tag).each do |meth|
20
- module_eval "def #{meth}(*) error_wrapping(super) end", __FILE__, __LINE__
18
+ def content_tag(*)
19
+ error_wrapping(super)
21
20
  end
22
21
 
23
22
  def tag(type, options, *)
@@ -39,7 +38,7 @@ module ActionView
39
38
  private
40
39
 
41
40
  def object_has_errors?
42
- object.respond_to?(:errors) && object.errors.respond_to?(:full_messages) && error_message.any?
41
+ object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present?
43
42
  end
44
43
 
45
44
  def tag_generate_errors?(options)
@@ -1,6 +1,6 @@
1
- require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers'
2
- require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers'
3
- require 'action_view/helpers/asset_tag_helpers/asset_paths'
1
+ require 'active_support/core_ext/array/extract_options'
2
+ require 'active_support/core_ext/hash/keys'
3
+ require 'action_view/helpers/asset_url_helper'
4
4
  require 'action_view/helpers/tag_helper'
5
5
 
6
6
  module ActionView
@@ -11,192 +11,100 @@ module ActionView
11
11
  # the assets exist before linking to them:
12
12
  #
13
13
  # image_tag("rails.png")
14
- # # => <img alt="Rails" src="/images/rails.png?1230601161" />
14
+ # # => <img alt="Rails" src="/assets/rails.png" />
15
15
  # stylesheet_link_tag("application")
16
- # # => <link href="/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
16
+ # # => <link href="/assets/application.css?body=1" media="screen" rel="stylesheet" />
17
17
  #
18
- # === Using asset hosts
19
- #
20
- # By default, Rails links to these assets on the current host in the public
21
- # folder, but you can direct Rails to link to assets from a dedicated asset
22
- # server by setting ActionController::Base.asset_host in the application
23
- # configuration, typically in <tt>config/environments/production.rb</tt>.
24
- # For example, you'd define <tt>assets.example.com</tt> to be your asset
25
- # host this way:
26
- #
27
- # ActionController::Base.asset_host = "assets.example.com"
28
- #
29
- # Helpers take that into account:
30
- #
31
- # image_tag("rails.png")
32
- # # => <img alt="Rails" src="http://assets.example.com/images/rails.png?1230601161" />
33
- # stylesheet_link_tag("application")
34
- # # => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
35
- #
36
- # Browsers typically open at most two simultaneous connections to a single
37
- # host, which means your assets often have to wait for other assets to finish
38
- # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
39
- # +asset_host+. For example, "assets%d.example.com". If that wildcard is
40
- # present Rails distributes asset requests among the corresponding four hosts
41
- # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
42
- # will open eight simultaneous connections rather than two.
43
- #
44
- # image_tag("rails.png")
45
- # # => <img alt="Rails" src="http://assets0.example.com/images/rails.png?1230601161" />
46
- # stylesheet_link_tag("application")
47
- # # => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
48
- #
49
- # To do this, you can either setup four actual hosts, or you can use wildcard
50
- # DNS to CNAME the wildcard to a single asset host. You can read more about
51
- # setting up your DNS CNAME records from your ISP.
52
- #
53
- # Note: This is purely a browser performance optimization and is not meant
54
- # for server load balancing. See http://www.die.net/musings/page_load_time/
55
- # for background.
56
- #
57
- # Alternatively, you can exert more control over the asset host by setting
58
- # +asset_host+ to a proc like this:
59
- #
60
- # ActionController::Base.asset_host = Proc.new { |source|
61
- # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
62
- # }
63
- # image_tag("rails.png")
64
- # # => <img alt="Rails" src="http://assets1.example.com/images/rails.png?1230601161" />
65
- # stylesheet_link_tag("application")
66
- # # => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
67
- #
68
- # The example above generates "http://assets1.example.com" and
69
- # "http://assets2.example.com". This option is useful for example if
70
- # you need fewer/more than four hosts, custom host names, etc.
71
- #
72
- # As you see the proc takes a +source+ parameter. That's a string with the
73
- # absolute path of the asset with any extensions and timestamps in place,
74
- # for example "/images/rails.png?1230601161".
75
- #
76
- # ActionController::Base.asset_host = Proc.new { |source|
77
- # if source.starts_with?('/images')
78
- # "http://images.example.com"
79
- # else
80
- # "http://assets.example.com"
81
- # end
82
- # }
83
- # image_tag("rails.png")
84
- # # => <img alt="Rails" src="http://images.example.com/images/rails.png?1230601161" />
85
- # stylesheet_link_tag("application")
86
- # # => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
87
- #
88
- # Alternatively you may ask for a second parameter +request+. That one is
89
- # particularly useful for serving assets from an SSL-protected page. The
90
- # example proc below disables asset hosting for HTTPS connections, while
91
- # still sending assets for plain HTTP requests from asset hosts. If you don't
92
- # have SSL certificates for each of the asset hosts this technique allows you
93
- # to avoid warnings in the client about mixed media.
94
- #
95
- # ActionController::Base.asset_host = Proc.new { |source, request|
96
- # if request.ssl?
97
- # "#{request.protocol}#{request.host_with_port}"
98
- # else
99
- # "#{request.protocol}assets.example.com"
100
- # end
101
- # }
102
- #
103
- # You can also implement a custom asset host object that responds to +call+
104
- # and takes either one or two parameters just like the proc.
105
- #
106
- # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
107
- # "http://asset%d.example.com", "https://asset1.example.com"
108
- # )
109
- #
110
- # === Customizing the asset path
111
- #
112
- # By default, Rails appends asset's timestamps to all asset paths. This allows
113
- # you to set a cache-expiration date for the asset far into the future, but
114
- # still be able to instantly invalidate it by simply updating the file (and
115
- # hence updating the timestamp, which then updates the URL as the timestamp
116
- # is part of that, which in turn busts the cache).
117
- #
118
- # It's the responsibility of the web server you use to set the far-future
119
- # expiration date on cache assets that you need to take advantage of this
120
- # feature. Here's an example for Apache:
121
- #
122
- # # Asset Expiration
123
- # ExpiresActive On
124
- # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
125
- # ExpiresDefault "access plus 1 year"
126
- # </FilesMatch>
127
- #
128
- # Also note that in order for this to work, all your application servers must
129
- # return the same timestamps. This means that they must have their clocks
130
- # synchronized. If one of them drifts out of sync, you'll see different
131
- # timestamps at random and the cache won't work. In that case the browser
132
- # will request the same assets over and over again even thought they didn't
133
- # change. You can use something like Live HTTP Headers for Firefox to verify
134
- # that the cache is indeed working.
135
- #
136
- # This strategy works well enough for most server setups and requires the
137
- # least configuration, but if you deploy several application servers at
138
- # different times - say to handle a temporary spike in load - then the
139
- # asset time stamps will be out of sync. In a setup like this you may want
140
- # to set the way that asset paths are generated yourself.
141
- #
142
- # Altering the asset paths that Rails generates can be done in two ways.
143
- # The easiest is to define the RAILS_ASSET_ID environment variable. The
144
- # contents of this variable will always be used in preference to
145
- # calculated timestamps. A more complex but flexible way is to set
146
- # <tt>ActionController::Base.config.asset_path</tt> to a proc
147
- # that takes the unmodified asset path and returns the path needed for
148
- # your asset caching to work. Typically you'd do something like this in
149
- # <tt>config/environments/production.rb</tt>:
150
- #
151
- # # Normally you'd calculate RELEASE_NUMBER at startup.
152
- # RELEASE_NUMBER = 12345
153
- # config.action_controller.asset_path = proc { |asset_path|
154
- # "/release-#{RELEASE_NUMBER}#{asset_path}"
155
- # }
156
- #
157
- # This example would cause the following behavior on all servers no
158
- # matter when they were deployed:
159
- #
160
- # image_tag("rails.png")
161
- # # => <img alt="Rails" src="/release-12345/images/rails.png" />
162
- # stylesheet_link_tag("application")
163
- # # => <link href="/release-12345/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
164
- #
165
- # Changing the asset_path does require that your web servers have
166
- # knowledge of the asset template paths that you rewrite to so it's not
167
- # suitable for out-of-the-box use. To use the example given above you
168
- # could use something like this in your Apache VirtualHost configuration:
169
- #
170
- # <LocationMatch "^/release-\d+/(images|javascripts|stylesheets)/.*$">
171
- # # Some browsers still send conditional-GET requests if there's a
172
- # # Last-Modified header or an ETag header even if they haven't
173
- # # reached the expiry date sent in the Expires header.
174
- # Header unset Last-Modified
175
- # Header unset ETag
176
- # FileETag None
177
- #
178
- # # Assets requested using a cache-busting filename should be served
179
- # # only once and then cached for a really long time. The HTTP/1.1
180
- # # spec frowns on hugely-long expiration times though and suggests
181
- # # that assets which never expire be served with an expiration date
182
- # # 1 year from access.
183
- # ExpiresActive On
184
- # ExpiresDefault "access plus 1 year"
185
- # </LocationMatch>
186
- #
187
- # # We use cached-busting location names with the far-future expires
188
- # # headers to ensure that if a file does change it can force a new
189
- # # request. The actual asset filenames are still the same though so we
190
- # # need to rewrite the location from the cache-busting location to the
191
- # # real asset location so that we can serve it.
192
- # RewriteEngine On
193
- # RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]
194
18
  module AssetTagHelper
19
+ extend ActiveSupport::Concern
20
+
21
+ include AssetUrlHelper
195
22
  include TagHelper
196
- include JavascriptTagHelpers
197
- include StylesheetTagHelpers
23
+
24
+ # Returns an HTML script tag for each of the +sources+ provided.
25
+ #
26
+ # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
27
+ # to <tt>assets/javascripts</tt>, full paths are assumed to be relative to the document
28
+ # root. Relative paths are idiomatic, use absolute paths only when needed.
29
+ #
30
+ # When passing paths, the ".js" extension is optional.
31
+ #
32
+ # You can modify the HTML attributes of the script tag by passing a hash as the
33
+ # last argument.
34
+ #
35
+ # When the Asset Pipeline is enabled, you can pass the name of your manifest as
36
+ # source, and include other JavaScript or CoffeeScript files inside the manifest.
37
+ #
38
+ # javascript_include_tag "xmlhr"
39
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
40
+ #
41
+ # javascript_include_tag "xmlhr.js"
42
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
43
+ #
44
+ # javascript_include_tag "common.javascript", "/elsewhere/cools"
45
+ # # => <script src="/assets/common.javascript?1284139606"></script>
46
+ # # <script src="/elsewhere/cools.js?1423139606"></script>
47
+ #
48
+ # javascript_include_tag "http://www.example.com/xmlhr"
49
+ # # => <script src="http://www.example.com/xmlhr"></script>
50
+ #
51
+ # javascript_include_tag "http://www.example.com/xmlhr.js"
52
+ # # => <script src="http://www.example.com/xmlhr.js"></script>
53
+ #
54
+ def javascript_include_tag(*sources)
55
+ options = sources.extract_options!.stringify_keys
56
+ path_options = options.extract!('protocol').symbolize_keys
57
+
58
+ sources.uniq.map { |source|
59
+ tag_options = {
60
+ "src" => path_to_javascript(source, path_options)
61
+ }.merge(options)
62
+ content_tag(:script, "", tag_options)
63
+ }.join("\n").html_safe
64
+ end
65
+
66
+ # Returns a stylesheet link tag for the sources specified as arguments. If
67
+ # you don't specify an extension, <tt>.css</tt> will be appended automatically.
68
+ # You can modify the link attributes by passing a hash as the last argument.
69
+ # For historical reasons, the 'media' attribute will always be present and defaults
70
+ # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
71
+ # apply to all media types.
72
+ #
73
+ # stylesheet_link_tag "style"
74
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
75
+ #
76
+ # stylesheet_link_tag "style.css"
77
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
78
+ #
79
+ # stylesheet_link_tag "http://www.example.com/style.css"
80
+ # # => <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" />
81
+ #
82
+ # stylesheet_link_tag "style", media: "all"
83
+ # # => <link href="/assets/style.css" media="all" rel="stylesheet" />
84
+ #
85
+ # stylesheet_link_tag "style", media: "print"
86
+ # # => <link href="/assets/style.css" media="print" rel="stylesheet" />
87
+ #
88
+ # stylesheet_link_tag "random.styles", "/css/stylish"
89
+ # # => <link href="/assets/random.styles" media="screen" rel="stylesheet" />
90
+ # # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
91
+ #
92
+ def stylesheet_link_tag(*sources)
93
+ options = sources.extract_options!.stringify_keys
94
+ path_options = options.extract!('protocol').symbolize_keys
95
+
96
+ sources.uniq.map { |source|
97
+ tag_options = {
98
+ "rel" => "stylesheet",
99
+ "media" => "screen",
100
+ "href" => path_to_stylesheet(source, path_options)
101
+ }.merge(options)
102
+ tag(:link, tag_options)
103
+ }.join("\n").html_safe
104
+ end
105
+
198
106
  # Returns a link tag that browsers and news readers can use to auto-detect
199
- # an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or
107
+ # an RSS or Atom feed. The +type+ can either be <tt>:rss</tt> (default) or
200
108
  # <tt>:atom</tt>. Control the link options in url_for format using the
201
109
  # +url_options+. You can modify the LINK tag itself in +tag_options+.
202
110
  #
@@ -205,20 +113,27 @@ module ActionView
205
113
  # * <tt>:type</tt> - Override the auto-generated mime type
206
114
  # * <tt>:title</tt> - Specify the title of the link, defaults to the +type+
207
115
  #
208
- # ==== Examples
209
- # auto_discovery_link_tag # =>
210
- # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/action" />
211
- # auto_discovery_link_tag(:atom) # =>
212
- # <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.currenthost.com/controller/action" />
213
- # auto_discovery_link_tag(:rss, {:action => "feed"}) # =>
214
- # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/feed" />
215
- # auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
216
- # <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.currenthost.com/controller/feed" />
217
- # auto_discovery_link_tag(:rss, {:controller => "news", :action => "feed"}) # =>
218
- # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/news/feed" />
219
- # auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {:title => "Example RSS"}) # =>
220
- # <link rel="alternate" type="application/rss+xml" title="Example RSS" href="http://www.example.com/feed" />
116
+ # auto_discovery_link_tag
117
+ # # => <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/action" />
118
+ # auto_discovery_link_tag(:atom)
119
+ # # => <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.currenthost.com/controller/action" />
120
+ # auto_discovery_link_tag(:rss, {action: "feed"})
121
+ # # => <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/feed" />
122
+ # auto_discovery_link_tag(:rss, {action: "feed"}, {title: "My RSS"})
123
+ # # => <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.currenthost.com/controller/feed" />
124
+ # auto_discovery_link_tag(:rss, {controller: "news", action: "feed"})
125
+ # # => <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/news/feed" />
126
+ # auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {title: "Example RSS"})
127
+ # # => <link rel="alternate" type="application/rss+xml" title="Example RSS" href="http://www.example.com/feed" />
221
128
  def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
129
+ if !(type == :rss || type == :atom) && tag_options[:type].blank?
130
+ message = "You have passed type other than :rss or :atom to auto_discovery_link_tag and haven't supplied " +
131
+ "the :type option key. This behavior is deprecated and will be remove in Rails 4.1. You should pass " +
132
+ ":type option explicitly if you want to use other types, for example: " +
133
+ "auto_discovery_link_tag(:xml, '/feed.xml', :type => 'application/xml')"
134
+ ActiveSupport::Deprecation.warn message
135
+ end
136
+
222
137
  tag(
223
138
  "link",
224
139
  "rel" => tag_options[:rel] || "alternate",
@@ -228,29 +143,25 @@ module ActionView
228
143
  )
229
144
  end
230
145
 
231
- # <%= favicon_link_tag %>
232
- #
233
- # generates
234
- #
235
- # <link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
236
- #
237
- # You may specify a different file in the first argument:
146
+ # Returns a link loading a favicon file. You may specify a different file
147
+ # in the first argument. The helper accepts an additional options hash where
148
+ # you can override "rel" and "type".
238
149
  #
239
- # <%= favicon_link_tag '/myicon.ico' %>
240
- #
241
- # That's passed to +path_to_image+ as is, so it gives
242
- #
243
- # <link href="/myicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
150
+ # ==== Options
151
+ # * <tt>:rel</tt> - Specify the relation of this link, defaults to 'shortcut icon'
152
+ # * <tt>:type</tt> - Override the auto-generated mime type, defaults to 'image/vnd.microsoft.icon'
244
153
  #
245
- # The helper accepts an additional options hash where you can override "rel" and "type".
154
+ # favicon_link_tag '/myicon.ico'
155
+ # # => <link href="/assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
246
156
  #
247
- # For example, Mobile Safari looks for a different LINK tag, pointing to an image that
157
+ # Mobile Safari looks for a different <link> tag, pointing to an image that
248
158
  # will be used if you add the page to the home screen of an iPod Touch, iPhone, or iPad.
249
159
  # The following call would generate such a tag:
250
160
  #
251
- # <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %>
161
+ # favicon_link_tag '/mb-icon.png', rel: 'apple-touch-icon', type: 'image/png'
162
+ # # => <link href="/assets/mb-icon.png" rel="apple-touch-icon" type="image/png" />
252
163
  #
253
- def favicon_link_tag(source='/favicon.ico', options={})
164
+ def favicon_link_tag(source='favicon.ico', options={})
254
165
  tag('link', {
255
166
  :rel => 'shortcut icon',
256
167
  :type => 'image/vnd.microsoft.icon',
@@ -258,70 +169,8 @@ module ActionView
258
169
  }.merge(options.symbolize_keys))
259
170
  end
260
171
 
261
- # Computes the path to an image asset in the public images directory.
262
- # Full paths from the document root will be passed through.
263
- # Used internally by +image_tag+ to build the image path:
264
- #
265
- # image_path("edit") # => "/images/edit"
266
- # image_path("edit.png") # => "/images/edit.png"
267
- # image_path("icons/edit.png") # => "/images/icons/edit.png"
268
- # image_path("/icons/edit.png") # => "/icons/edit.png"
269
- # image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
270
- #
271
- # If you have images as application resources this method may conflict with their named routes.
272
- # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
273
- # plugin authors are encouraged to do so.
274
- def image_path(source)
275
- source.present? ? asset_paths.compute_public_path(source, 'images') : ""
276
- end
277
- alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
278
-
279
- # Computes the path to a video asset in the public videos directory.
280
- # Full paths from the document root will be passed through.
281
- # Used internally by +video_tag+ to build the video path.
282
- #
283
- # ==== Examples
284
- # video_path("hd") # => /videos/hd
285
- # video_path("hd.avi") # => /videos/hd.avi
286
- # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
287
- # video_path("/trailers/hd.avi") # => /trailers/hd.avi
288
- # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
289
- def video_path(source)
290
- asset_paths.compute_public_path(source, 'videos')
291
- end
292
- alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route
293
-
294
- # Computes the path to an audio asset in the public audios directory.
295
- # Full paths from the document root will be passed through.
296
- # Used internally by +audio_tag+ to build the audio path.
297
- #
298
- # ==== Examples
299
- # audio_path("horse") # => /audios/horse
300
- # audio_path("horse.wav") # => /audios/horse.wav
301
- # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
302
- # audio_path("/sounds/horse.wav") # => /sounds/horse.wav
303
- # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
304
- def audio_path(source)
305
- asset_paths.compute_public_path(source, 'audios')
306
- end
307
- alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
308
-
309
- # Computes the path to a font asset in the public fonts directory.
310
- # Full paths from the document root will be passed through.
311
- #
312
- # ==== Examples
313
- # font_path("font") # => /fonts/font
314
- # font_path("font.ttf") # => /fonts/font.ttf
315
- # font_path("dir/font.ttf") # => /fonts/dir/font.ttf
316
- # font_path("/dir/font.ttf") # => /dir/font.ttf
317
- # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
318
- def font_path(source)
319
- asset_paths.compute_public_path(source, 'fonts')
320
- end
321
- alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route
322
-
323
- # Returns an html image tag for the +source+. The +source+ can be a full
324
- # path or a file that exists in your public images directory.
172
+ # Returns an HTML image tag for the +source+. The +source+ can be a full
173
+ # path or a file.
325
174
  #
326
175
  # ==== Options
327
176
  # You can add HTML attributes using the +options+. The +options+ supports
@@ -329,32 +178,26 @@ module ActionView
329
178
  #
330
179
  # * <tt>:alt</tt> - If no alt text is given, the file name part of the
331
180
  # +source+ is used (capitalized and without the extension)
332
- # * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes
333
- # width="30" and height="45". <tt>:size</tt> will be ignored if the
334
- # value is not in the correct format.
335
- # * <tt>:mouseover</tt> - Set an alternate image to be used when the onmouseover
336
- # event is fired, and sets the original image to be replaced onmouseout.
337
- # This can be used to implement an easy image toggle that fires on onmouseover.
181
+ # * <tt>:size</tt> - Supplied as "{Width}x{Height}" or "{Number}", so "30x45" becomes
182
+ # width="30" and height="45", and "50" becomes width="50" and height="50".
183
+ # <tt>:size</tt> will be ignored if the value is not in the correct format.
338
184
  #
339
185
  # ==== Examples
340
- # image_tag("icon") # =>
341
- # <img src="/images/icon" alt="Icon" />
342
- # image_tag("icon.png") # =>
343
- # <img src="/images/icon.png" alt="Icon" />
344
- # image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # =>
345
- # <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" />
346
- # image_tag("/icons/icon.gif", :size => "16x16") # =>
347
- # <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
348
- # image_tag("/icons/icon.gif", :height => '32', :width => '32') # =>
349
- # <img alt="Icon" height="32" src="/icons/icon.gif" width="32" />
350
- # image_tag("/icons/icon.gif", :class => "menu_icon") # =>
351
- # <img alt="Icon" class="menu_icon" src="/icons/icon.gif" />
352
- # image_tag("mouse.png", :mouseover => "/images/mouse_over.png") # =>
353
- # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
354
- # image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # =>
355
- # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
356
- def image_tag(source, options = {})
357
- options.symbolize_keys!
186
+ #
187
+ # image_tag("icon")
188
+ # # => <img alt="Icon" src="/assets/icon" />
189
+ # image_tag("icon.png")
190
+ # # => <img alt="Icon" src="/assets/icon.png" />
191
+ # image_tag("icon.png", size: "16x10", alt: "Edit Entry")
192
+ # # => <img src="/assets/icon.png" width="16" height="10" alt="Edit Entry" />
193
+ # image_tag("/icons/icon.gif", size: "16")
194
+ # # => <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
195
+ # image_tag("/icons/icon.gif", height: '32', width: '32')
196
+ # # => <img alt="Icon" height="32" src="/icons/icon.gif" width="32" />
197
+ # image_tag("/icons/icon.gif", class: "menu_icon")
198
+ # # => <img alt="Icon" class="menu_icon" src="/icons/icon.gif" />
199
+ def image_tag(source, options={})
200
+ options = options.symbolize_keys
358
201
 
359
202
  src = options[:src] = path_to_image(source)
360
203
 
@@ -363,19 +206,32 @@ module ActionView
363
206
  end
364
207
 
365
208
  if size = options.delete(:size)
366
- options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
367
- end
368
-
369
- if mouseover = options.delete(:mouseover)
370
- options[:onmouseover] = "this.src='#{path_to_image(mouseover)}'"
371
- options[:onmouseout] = "this.src='#{src}'"
209
+ options[:width], options[:height] = size.split("x") if size =~ %r{\A\d+x\d+\z}
210
+ options[:width] = options[:height] = size if size =~ %r{\A\d+\z}
372
211
  end
373
212
 
374
213
  tag("img", options)
375
214
  end
376
215
 
216
+ # Returns a string suitable for an html image tag alt attribute.
217
+ # The +src+ argument is meant to be an image file path.
218
+ # The method removes the basename of the file path and the digest,
219
+ # if any. It also removes hyphens and underscores from file names and
220
+ # replaces them with spaces, returning a space-separated, titleized
221
+ # string.
222
+ #
223
+ # ==== Examples
224
+ #
225
+ # image_tag('rails.png')
226
+ # # => <img alt="Rails" src="/assets/rails.png" />
227
+ #
228
+ # image_tag('hyphenated-file-name.png')
229
+ # # => <img alt="Hyphenated file name" src="/assets/hyphenated-file-name.png" />
230
+ #
231
+ # image_tag('underscored_file_name.png')
232
+ # # => <img alt="Underscored file name" src="/assets/underscored_file_name.png" />
377
233
  def image_alt(src)
378
- File.basename(src, '.*').sub(/-[[:xdigit:]]{32}\z/, '').capitalize
234
+ File.basename(src, '.*').sub(/-[[:xdigit:]]{32}\z/, '').tr('-_', ' ').capitalize
379
235
  end
380
236
 
381
237
  # Returns an html video tag for the +sources+. If +sources+ is a string,
@@ -394,63 +250,65 @@ module ActionView
394
250
  # width="30" and height="45". <tt>:size</tt> will be ignored if the
395
251
  # value is not in the correct format.
396
252
  #
397
- # ==== Examples
398
- # video_tag("trailer") # =>
399
- # <video src="/videos/trailer" />
400
- # video_tag("trailer.ogg") # =>
401
- # <video src="/videos/trailer.ogg" />
402
- # video_tag("trailer.ogg", :controls => true, :autobuffer => true) # =>
403
- # <video autobuffer="autobuffer" controls="controls" src="/videos/trailer.ogg" />
404
- # video_tag("trailer.m4v", :size => "16x10", :poster => "screenshot.png") # =>
405
- # <video src="/videos/trailer.m4v" width="16" height="10" poster="/images/screenshot.png" />
406
- # video_tag("/trailers/hd.avi", :size => "16x16") # =>
407
- # <video src="/trailers/hd.avi" width="16" height="16" />
408
- # video_tag("/trailers/hd.avi", :height => '32', :width => '32') # =>
409
- # <video height="32" src="/trailers/hd.avi" width="32" />
410
- # video_tag(["trailer.ogg", "trailer.flv"]) # =>
411
- # <video><source src="trailer.ogg" /><source src="trailer.ogg" /><source src="trailer.flv" /></video>
412
- # video_tag(["trailer.ogg", "trailer.flv"] :size => "160x120") # =>
413
- # <video height="120" width="160"><source src="trailer.ogg" /><source src="trailer.flv" /></video>
414
- def video_tag(sources, options = {})
415
- options.symbolize_keys!
416
-
417
- options[:poster] = path_to_image(options[:poster]) if options[:poster]
253
+ # video_tag("trailer")
254
+ # # => <video src="/videos/trailer" />
255
+ # video_tag("trailer.ogg")
256
+ # # => <video src="/videos/trailer.ogg" />
257
+ # video_tag("trailer.ogg", controls: true, autobuffer: true)
258
+ # # => <video autobuffer="autobuffer" controls="controls" src="/videos/trailer.ogg" />
259
+ # video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png")
260
+ # # => <video src="/videos/trailer.m4v" width="16" height="10" poster="/assets/screenshot.png" />
261
+ # video_tag("/trailers/hd.avi", size: "16x16")
262
+ # # => <video src="/trailers/hd.avi" width="16" height="16" />
263
+ # video_tag("/trailers/hd.avi", height: '32', width: '32')
264
+ # # => <video height="32" src="/trailers/hd.avi" width="32" />
265
+ # video_tag("trailer.ogg", "trailer.flv")
266
+ # # => <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
267
+ # video_tag(["trailer.ogg", "trailer.flv"])
268
+ # # => <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
269
+ # video_tag(["trailer.ogg", "trailer.flv"], size: "160x120")
270
+ # # => <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
271
+ def video_tag(*sources)
272
+ multiple_sources_tag('video', sources) do |options|
273
+ options[:poster] = path_to_image(options[:poster]) if options[:poster]
418
274
 
419
- if size = options.delete(:size)
420
- options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
421
- end
422
-
423
- if sources.is_a?(Array)
424
- content_tag("video", options) do
425
- sources.map { |source| tag("source", :src => source) }.join.html_safe
275
+ if size = options.delete(:size)
276
+ options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
426
277
  end
427
- else
428
- options[:src] = path_to_video(sources)
429
- tag("video", options)
430
278
  end
431
279
  end
432
280
 
433
- # Returns an html audio tag for the +source+.
281
+ # Returns an HTML audio tag for the +source+.
434
282
  # The +source+ can be full path or file that exists in
435
283
  # your public audios directory.
436
284
  #
437
- # ==== Examples
438
- # audio_tag("sound") # =>
439
- # <audio src="/audios/sound" />
440
- # audio_tag("sound.wav") # =>
441
- # <audio src="/audios/sound.wav" />
442
- # audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
443
- # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
444
- def audio_tag(source, options = {})
445
- options.symbolize_keys!
446
- options[:src] = path_to_audio(source)
447
- tag("audio", options)
285
+ # audio_tag("sound")
286
+ # # => <audio src="/audios/sound" />
287
+ # audio_tag("sound.wav")
288
+ # # => <audio src="/audios/sound.wav" />
289
+ # audio_tag("sound.wav", autoplay: true, controls: true)
290
+ # # => <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
291
+ # audio_tag("sound.wav", "sound.mid")
292
+ # # => <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
293
+ def audio_tag(*sources)
294
+ multiple_sources_tag('audio', sources)
448
295
  end
449
296
 
450
297
  private
298
+ def multiple_sources_tag(type, sources)
299
+ options = sources.extract_options!.symbolize_keys
300
+ sources.flatten!
301
+
302
+ yield options if block_given?
451
303
 
452
- def asset_paths
453
- @asset_paths ||= AssetTagHelper::AssetPaths.new(config, controller)
304
+ if sources.size > 1
305
+ content_tag(type, options) do
306
+ safe_join sources.map { |source| tag("source", :src => send("path_to_#{type}", source)) }
307
+ end
308
+ else
309
+ options[:src] = send("path_to_#{type}", sources.first)
310
+ content_tag(type, nil, options)
311
+ end
454
312
  end
455
313
  end
456
314
  end