actionview 5.0.7.2 → 5.1.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 actionview might be problematic. Click here for more details.

Files changed (82) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +92 -384
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/action_view.rb +5 -5
  6. data/lib/action_view/base.rb +19 -19
  7. data/lib/action_view/buffers.rb +1 -1
  8. data/lib/action_view/context.rb +1 -1
  9. data/lib/action_view/dependency_tracker.rb +4 -5
  10. data/lib/action_view/digestor.rb +6 -7
  11. data/lib/action_view/flows.rb +5 -6
  12. data/lib/action_view/gem_version.rb +3 -3
  13. data/lib/action_view/helpers.rb +1 -1
  14. data/lib/action_view/helpers/active_model_helper.rb +8 -8
  15. data/lib/action_view/helpers/asset_tag_helper.rb +62 -36
  16. data/lib/action_view/helpers/asset_url_helper.rb +111 -49
  17. data/lib/action_view/helpers/atom_feed_helper.rb +12 -13
  18. data/lib/action_view/helpers/cache_helper.rb +34 -20
  19. data/lib/action_view/helpers/capture_helper.rb +2 -2
  20. data/lib/action_view/helpers/controller_helper.rb +3 -11
  21. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  22. data/lib/action_view/helpers/date_helper.rb +109 -107
  23. data/lib/action_view/helpers/debug_helper.rb +2 -3
  24. data/lib/action_view/helpers/form_helper.rb +406 -31
  25. data/lib/action_view/helpers/form_options_helper.rb +12 -12
  26. data/lib/action_view/helpers/form_tag_helper.rb +19 -18
  27. data/lib/action_view/helpers/javascript_helper.rb +6 -6
  28. data/lib/action_view/helpers/number_helper.rb +48 -46
  29. data/lib/action_view/helpers/output_safety_helper.rb +8 -8
  30. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  31. data/lib/action_view/helpers/sanitize_helper.rb +6 -8
  32. data/lib/action_view/helpers/tag_helper.rb +194 -77
  33. data/lib/action_view/helpers/tags/base.rb +121 -102
  34. data/lib/action_view/helpers/tags/check_box.rb +17 -17
  35. data/lib/action_view/helpers/tags/collection_check_boxes.rb +8 -8
  36. data/lib/action_view/helpers/tags/collection_helpers.rb +60 -60
  37. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +2 -2
  38. data/lib/action_view/helpers/tags/collection_select.rb +2 -2
  39. data/lib/action_view/helpers/tags/date_select.rb +36 -36
  40. data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
  41. data/lib/action_view/helpers/tags/label.rb +4 -0
  42. data/lib/action_view/helpers/tags/password_field.rb +1 -1
  43. data/lib/action_view/helpers/tags/radio_button.rb +4 -4
  44. data/lib/action_view/helpers/tags/select.rb +9 -9
  45. data/lib/action_view/helpers/tags/text_area.rb +1 -1
  46. data/lib/action_view/helpers/tags/text_field.rb +5 -5
  47. data/lib/action_view/helpers/tags/translator.rb +14 -12
  48. data/lib/action_view/helpers/text_helper.rb +20 -19
  49. data/lib/action_view/helpers/translation_helper.rb +6 -6
  50. data/lib/action_view/helpers/url_helper.rb +42 -38
  51. data/lib/action_view/layouts.rb +51 -47
  52. data/lib/action_view/log_subscriber.rb +24 -9
  53. data/lib/action_view/lookup_context.rb +19 -25
  54. data/lib/action_view/path_set.rb +19 -19
  55. data/lib/action_view/railtie.rb +3 -3
  56. data/lib/action_view/record_identifier.rb +6 -6
  57. data/lib/action_view/renderer/abstract_renderer.rb +17 -17
  58. data/lib/action_view/renderer/partial_renderer.rb +188 -187
  59. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +7 -1
  60. data/lib/action_view/renderer/streaming_template_renderer.rb +45 -47
  61. data/lib/action_view/renderer/template_renderer.rb +64 -66
  62. data/lib/action_view/rendering.rb +4 -5
  63. data/lib/action_view/routing_url_for.rb +9 -13
  64. data/lib/action_view/tasks/cache_digests.rake +7 -7
  65. data/lib/action_view/template.rb +26 -27
  66. data/lib/action_view/template/error.rb +5 -15
  67. data/lib/action_view/template/handlers.rb +4 -4
  68. data/lib/action_view/template/handlers/builder.rb +7 -7
  69. data/lib/action_view/template/handlers/erb.rb +9 -76
  70. data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
  71. data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
  72. data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
  73. data/lib/action_view/template/html.rb +2 -4
  74. data/lib/action_view/template/resolver.rb +107 -90
  75. data/lib/action_view/template/text.rb +5 -8
  76. data/lib/action_view/template/types.rb +1 -1
  77. data/lib/action_view/test_case.rb +20 -21
  78. data/lib/action_view/testing/resolvers.rb +29 -30
  79. data/lib/action_view/version.rb +1 -1
  80. data/lib/action_view/view_paths.rb +20 -8
  81. data/lib/assets/compiled/rails-ujs.js +648 -0
  82. metadata +19 -14
@@ -1,4 +1,4 @@
1
- require 'zlib'
1
+ require "zlib"
2
2
 
3
3
  module ActionView
4
4
  # = Action View Asset URL Helpers
@@ -36,7 +36,7 @@ module ActionView
36
36
  # some asset downloads to wait for previous assets to finish before they can
37
37
  # begin. You can use the <tt>%d</tt> wildcard in the +asset_host+ to
38
38
  # distribute the requests over four hosts. For example,
39
- # <tt>assets%d.example.com<tt> will spread the asset requests over
39
+ # <tt>assets%d.example.com</tt> will spread the asset requests over
40
40
  # "assets0.example.com", ..., "assets3.example.com".
41
41
  #
42
42
  # image_tag("rails.png")
@@ -96,8 +96,8 @@ module ActionView
96
96
  # have SSL certificates for each of the asset hosts this technique allows you
97
97
  # to avoid warnings in the client about mixed media.
98
98
  # Note that the request parameter might not be supplied, e.g. when the assets
99
- # are precompiled via a Rake task. Make sure to use a Proc instead of a lambda,
100
- # since a Proc allows missing parameters and sets them to nil.
99
+ # are precompiled via a Rake task. Make sure to use a +Proc+ instead of a lambda,
100
+ # since a +Proc+ allows missing parameters and sets them to +nil+.
101
101
  #
102
102
  # config.action_controller.asset_host = Proc.new { |source, request|
103
103
  # if request && request.ssl?
@@ -117,31 +117,86 @@ module ActionView
117
117
  module AssetUrlHelper
118
118
  URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}i
119
119
 
120
- # Computes the path to asset in public directory. If :type
121
- # options is set, a file extension will be appended and scoped
122
- # to the corresponding public directory.
120
+ # This is the entry point for all assets.
121
+ # When using the asset pipeline (i.e. sprockets and sprockets-rails), the
122
+ # behavior is "enhanced". You can bypass the asset pipeline by passing in
123
+ # <tt>skip_pipeline: true</tt> to the options.
123
124
  #
124
125
  # All other asset *_path helpers delegate through this method.
125
126
  #
126
- # asset_path "application.js" # => /assets/application.js
127
- # asset_path "application", type: :javascript # => /assets/application.js
128
- # asset_path "application", type: :stylesheet # => /assets/application.css
129
- # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
127
+ # === With the asset pipeline
128
+ #
129
+ # All options passed to +asset_path+ will be passed to +compute_asset_path+
130
+ # which is implemented by sprockets-rails.
131
+ #
132
+ # asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js"
133
+ #
134
+ # === Without the asset pipeline (<tt>skip_pipeline: true</tt>)
135
+ #
136
+ # Accepts a <tt>type</tt> option that can specify the asset's extension. No error
137
+ # checking is done to verify the source passed into +asset_path+ is valid
138
+ # and that the file exists on disk.
139
+ #
140
+ # asset_path("application.js", skip_pipeline: true) # => "application.js"
141
+ # asset_path("filedoesnotexist.png", skip_pipeline: true) # => "filedoesnotexist.png"
142
+ # asset_path("application", type: :javascript, skip_pipeline: true) # => "/javascripts/application.js"
143
+ # asset_path("application", type: :stylesheet, skip_pipeline: true) # => "/stylesheets/application.css"
144
+ #
145
+ # === Options applying to all assets
146
+ #
147
+ # Below lists scenarios that apply to +asset_path+ whether or not you're
148
+ # using the asset pipeline.
149
+ #
150
+ # - All fully qualified urls are returned immediately. This bypasses the
151
+ # asset pipeline and all other behavior described.
152
+ #
153
+ # asset_path("http://www.example.com/js/xmlhr.js") # => "http://www.example.com/js/xmlhr.js"
154
+ #
155
+ # - All assets that begin with a forward slash are assumed to be full
156
+ # urls and will not be expanded. This will bypass the asset pipeline.
157
+ #
158
+ # asset_path("/foo.png") # => "/foo.png"
159
+ #
160
+ # - All blank strings will be returned immediately. This bypasses the
161
+ # asset pipeline and all other behavior described.
162
+ #
163
+ # asset_path("") # => ""
164
+ #
165
+ # - If <tt>config.relative_url_root</tt> is specified, all assets will have that
166
+ # root prepended.
167
+ #
168
+ # Rails.application.config.relative_url_root = "bar"
169
+ # asset_path("foo.js", skip_pipeline: true) # => "bar/foo.js"
170
+ #
171
+ # - A different asset host can be specified via <tt>config.action_controller.asset_host</tt>
172
+ # this is commonly used in conjunction with a CDN.
173
+ #
174
+ # Rails.application.config.action_controller.asset_host = "assets.example.com"
175
+ # asset_path("foo.js", skip_pipeline: true) # => "http://assets.example.com/foo.js"
176
+ #
177
+ # - An extension name can be specified manually with <tt>extname</tt>.
178
+ #
179
+ # asset_path("foo", skip_pipeline: true, extname: ".js") # => "/foo.js"
180
+ # asset_path("foo.css", skip_pipeline: true, extname: ".js") # => "/foo.css.js"
130
181
  def asset_path(source, options = {})
131
182
  raise ArgumentError, "nil is not a valid asset source" if source.nil?
132
183
 
133
184
  source = source.to_s
134
- return "" unless source.present?
135
- return source if source =~ URI_REGEXP
185
+ return "" if source.blank?
186
+ return source if URI_REGEXP.match?(source)
136
187
 
137
- tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, ''.freeze)
188
+ tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, "".freeze)
138
189
 
139
190
  if extname = compute_asset_extname(source, options)
140
191
  source = "#{source}#{extname}"
141
192
  end
142
193
 
143
194
  if source[0] != ?/
144
- source = compute_asset_path(source, options)
195
+ if options[:skip_pipeline]
196
+ source = public_compute_asset_path(source, options)
197
+ else
198
+ source = compute_asset_path(source, options)
199
+ end
145
200
  end
146
201
 
147
202
  relative_url_root = defined?(config.relative_url_root) && config.relative_url_root
@@ -168,31 +223,35 @@ module ActionView
168
223
  # asset_url "application.js", host: "http://cdn.example.com" # => http://cdn.example.com/assets/application.js
169
224
  #
170
225
  def asset_url(source, options = {})
171
- path_to_asset(source, options.merge(:protocol => :request))
226
+ path_to_asset(source, options.merge(protocol: :request))
172
227
  end
173
228
  alias_method :url_to_asset, :asset_url # aliased to avoid conflicts with an asset_url named route
174
229
 
175
230
  ASSET_EXTENSIONS = {
176
- javascript: '.js',
177
- stylesheet: '.css'
231
+ javascript: ".js",
232
+ stylesheet: ".css"
178
233
  }
179
234
 
180
- # Compute extname to append to asset path. Returns nil if
235
+ # Compute extname to append to asset path. Returns +nil+ if
181
236
  # nothing should be added.
182
237
  def compute_asset_extname(source, options = {})
183
238
  return if options[:extname] == false
184
239
  extname = options[:extname] || ASSET_EXTENSIONS[options[:type]]
185
- extname if extname && File.extname(source) != extname
240
+ if extname && File.extname(source) != extname
241
+ extname
242
+ else
243
+ nil
244
+ end
186
245
  end
187
246
 
188
247
  # Maps asset types to public directory.
189
248
  ASSET_PUBLIC_DIRECTORIES = {
190
- audio: '/audios',
191
- font: '/fonts',
192
- image: '/images',
193
- javascript: '/javascripts',
194
- stylesheet: '/stylesheets',
195
- video: '/videos'
249
+ audio: "/audios",
250
+ font: "/fonts",
251
+ image: "/images",
252
+ javascript: "/javascripts",
253
+ stylesheet: "/stylesheets",
254
+ video: "/videos"
196
255
  }
197
256
 
198
257
  # Computes asset path to public directory. Plugins and
@@ -202,6 +261,7 @@ module ActionView
202
261
  dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || ""
203
262
  File.join(dir, source)
204
263
  end
264
+ alias :public_compute_asset_path :compute_asset_path
205
265
 
206
266
  # Pick an asset host for this source. Returns +nil+ if no host is set,
207
267
  # the host if no wildcard is set, the host interpolated with the
@@ -213,19 +273,21 @@ module ActionView
213
273
  host = options[:host]
214
274
  host ||= config.asset_host if defined? config.asset_host
215
275
 
216
- if host.respond_to?(:call)
217
- arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
218
- args = [source]
219
- args << request if request && (arity > 1 || arity < 0)
220
- host = host.call(*args)
221
- elsif host =~ /%d/
222
- host = host % (Zlib.crc32(source) % 4)
276
+ if host
277
+ if host.respond_to?(:call)
278
+ arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
279
+ args = [source]
280
+ args << request if request && (arity > 1 || arity < 0)
281
+ host = host.call(*args)
282
+ elsif host.include?("%d")
283
+ host = host % (Zlib.crc32(source) % 4)
284
+ end
223
285
  end
224
286
 
225
287
  host ||= request.base_url if request && options[:protocol] == :request
226
288
  return unless host
227
289
 
228
- if host =~ URI_REGEXP
290
+ if URI_REGEXP.match?(host)
229
291
  host
230
292
  else
231
293
  protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative)
@@ -251,7 +313,7 @@ module ActionView
251
313
  # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
252
314
  # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
253
315
  def javascript_path(source, options = {})
254
- path_to_asset(source, {type: :javascript}.merge!(options))
316
+ path_to_asset(source, { type: :javascript }.merge!(options))
255
317
  end
256
318
  alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
257
319
 
@@ -263,7 +325,7 @@ module ActionView
263
325
  # javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/dir/xmlhr.js
264
326
  #
265
327
  def javascript_url(source, options = {})
266
- url_to_asset(source, {type: :javascript}.merge!(options))
328
+ url_to_asset(source, { type: :javascript }.merge!(options))
267
329
  end
268
330
  alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route
269
331
 
@@ -278,7 +340,7 @@ module ActionView
278
340
  # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
279
341
  # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
280
342
  def stylesheet_path(source, options = {})
281
- path_to_asset(source, {type: :stylesheet}.merge!(options))
343
+ path_to_asset(source, { type: :stylesheet }.merge!(options))
282
344
  end
283
345
  alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
284
346
 
@@ -290,7 +352,7 @@ module ActionView
290
352
  # stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/css/style.css
291
353
  #
292
354
  def stylesheet_url(source, options = {})
293
- url_to_asset(source, {type: :stylesheet}.merge!(options))
355
+ url_to_asset(source, { type: :stylesheet }.merge!(options))
294
356
  end
295
357
  alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route
296
358
 
@@ -308,7 +370,7 @@ module ActionView
308
370
  # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
309
371
  # plugin authors are encouraged to do so.
310
372
  def image_path(source, options = {})
311
- path_to_asset(source, {type: :image}.merge!(options))
373
+ path_to_asset(source, { type: :image }.merge!(options))
312
374
  end
313
375
  alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
314
376
 
@@ -320,7 +382,7 @@ module ActionView
320
382
  # image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/edit.png
321
383
  #
322
384
  def image_url(source, options = {})
323
- url_to_asset(source, {type: :image}.merge!(options))
385
+ url_to_asset(source, { type: :image }.merge!(options))
324
386
  end
325
387
  alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route
326
388
 
@@ -334,7 +396,7 @@ module ActionView
334
396
  # video_path("/trailers/hd.avi") # => /trailers/hd.avi
335
397
  # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
336
398
  def video_path(source, options = {})
337
- path_to_asset(source, {type: :video}.merge!(options))
399
+ path_to_asset(source, { type: :video }.merge!(options))
338
400
  end
339
401
  alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route
340
402
 
@@ -346,9 +408,9 @@ module ActionView
346
408
  # video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/hd.avi
347
409
  #
348
410
  def video_url(source, options = {})
349
- url_to_asset(source, {type: :video}.merge!(options))
411
+ url_to_asset(source, { type: :video }.merge!(options))
350
412
  end
351
- alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route
413
+ alias_method :url_to_video, :video_url # aliased to avoid conflicts with a video_url named route
352
414
 
353
415
  # Computes the path to an audio asset in the public audios directory.
354
416
  # Full paths from the document root will be passed through.
@@ -360,7 +422,7 @@ module ActionView
360
422
  # audio_path("/sounds/horse.wav") # => /sounds/horse.wav
361
423
  # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
362
424
  def audio_path(source, options = {})
363
- path_to_asset(source, {type: :audio}.merge!(options))
425
+ path_to_asset(source, { type: :audio }.merge!(options))
364
426
  end
365
427
  alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
366
428
 
@@ -372,7 +434,7 @@ module ActionView
372
434
  # audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/horse.wav
373
435
  #
374
436
  def audio_url(source, options = {})
375
- url_to_asset(source, {type: :audio}.merge!(options))
437
+ url_to_asset(source, { type: :audio }.merge!(options))
376
438
  end
377
439
  alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route
378
440
 
@@ -385,9 +447,9 @@ module ActionView
385
447
  # font_path("/dir/font.ttf") # => /dir/font.ttf
386
448
  # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
387
449
  def font_path(source, options = {})
388
- path_to_asset(source, {type: :font}.merge!(options))
450
+ path_to_asset(source, { type: :font }.merge!(options))
389
451
  end
390
- alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route
452
+ alias_method :path_to_font, :font_path # aliased to avoid conflicts with a font_path named route
391
453
 
392
454
  # Computes the full URL to a font asset.
393
455
  # This will use +font_path+ internally, so most of their behaviors will be the same.
@@ -397,9 +459,9 @@ module ActionView
397
459
  # font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/font.ttf
398
460
  #
399
461
  def font_url(source, options = {})
400
- url_to_asset(source, {type: :font}.merge!(options))
462
+ url_to_asset(source, { type: :font }.merge!(options))
401
463
  end
402
- alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route
464
+ alias_method :url_to_font, :font_url # aliased to avoid conflicts with a font_url named route
403
465
  end
404
466
  end
405
467
  end
@@ -1,4 +1,4 @@
1
- require 'set'
1
+ require "set"
2
2
 
3
3
  module ActionView
4
4
  # = Action View Atom Feed Helpers
@@ -103,7 +103,7 @@ module ActionView
103
103
  xml = options.delete(:xml) || eval("xml", block.binding)
104
104
  xml.instruct!
105
105
  if options[:instruct]
106
- options[:instruct].each do |target,attrs|
106
+ options[:instruct].each do |target, attrs|
107
107
  if attrs.respond_to?(:keys)
108
108
  xml.instruct!(target, attrs)
109
109
  elsif attrs.respond_to?(:each)
@@ -112,13 +112,13 @@ module ActionView
112
112
  end
113
113
  end
114
114
 
115
- feed_opts = {"xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom'}
116
- feed_opts.merge!(options).reject!{|k,v| !k.to_s.match(/^xml/)}
115
+ feed_opts = { "xml:lang" => options[:language] || "en-US", "xmlns" => "http://www.w3.org/2005/Atom" }
116
+ feed_opts.merge!(options).reject! { |k, v| !k.to_s.match(/^xml/) }
117
117
 
118
118
  xml.feed(feed_opts) do
119
119
  xml.id(options[:id] || "tag:#{request.host},#{options[:schema_date]}:#{request.fullpath.split(".")[0]}")
120
- xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:root_url] || (request.protocol + request.host_with_port))
121
- xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url)
120
+ xml.link(rel: "alternate", type: "text/html", href: options[:root_url] || (request.protocol + request.host_with_port))
121
+ xml.link(rel: "self", type: "application/atom+xml", href: options[:url] || request.url)
122
122
 
123
123
  yield AtomFeedBuilder.new(xml, self, options)
124
124
  end
@@ -138,7 +138,7 @@ module ActionView
138
138
  def method_missing(method, *arguments, &block)
139
139
  if xhtml_block?(method, arguments)
140
140
  @xml.__send__(method, *arguments) do
141
- @xml.div(:xmlns => 'http://www.w3.org/1999/xhtml') do |xhtml|
141
+ @xml.div(xmlns: "http://www.w3.org/1999/xhtml") do |xhtml|
142
142
  block.call(xhtml)
143
143
  end
144
144
  end
@@ -153,7 +153,7 @@ module ActionView
153
153
  def xhtml_block?(method, arguments)
154
154
  if XHTML_TAG_NAMES.include?(method.to_s)
155
155
  last = arguments.last
156
- last.is_a?(Hash) && last[:type].to_s == 'xhtml'
156
+ last.is_a?(Hash) && last[:type].to_s == "xhtml"
157
157
  end
158
158
  end
159
159
  end
@@ -163,7 +163,7 @@ module ActionView
163
163
  @xml, @view, @feed_options = xml, view, feed_options
164
164
  end
165
165
 
166
- # Accepts a Date or Time object and inserts it in the proper format. If nil is passed, current time in UTC is used.
166
+ # Accepts a Date or Time object and inserts it in the proper format. If +nil+ is passed, current time in UTC is used.
167
167
  def updated(date_or_time = nil)
168
168
  @xml.updated((date_or_time || Time.now.utc).xmlschema)
169
169
  end
@@ -174,7 +174,7 @@ module ActionView
174
174
  #
175
175
  # * <tt>:published</tt>: Time first published. Defaults to the created_at attribute on the record if one such exists.
176
176
  # * <tt>:updated</tt>: Time of update. Defaults to the updated_at attribute on the record if one such exists.
177
- # * <tt>:url</tt>: The URL for this entry or false or nil for not having a link tag. Defaults to the polymorphic_url for the record.
177
+ # * <tt>:url</tt>: The URL for this entry or +false+ or +nil+ for not having a link tag. Defaults to the +polymorphic_url+ for the record.
178
178
  # * <tt>:id</tt>: The ID for this entry. Defaults to "tag:#{@view.request.host},#{@feed_options[:schema_date]}:#{record.class}/#{record.id}"
179
179
  # * <tt>:type</tt>: The TYPE for this entry. Defaults to "text/html".
180
180
  def entry(record, options = {})
@@ -189,16 +189,15 @@ module ActionView
189
189
  @xml.updated((options[:updated] || record.updated_at).xmlschema)
190
190
  end
191
191
 
192
- type = options.fetch(:type, 'text/html')
192
+ type = options.fetch(:type, "text/html")
193
193
 
194
194
  url = options.fetch(:url) { @view.polymorphic_url(record) }
195
- @xml.link(:rel => 'alternate', :type => type, :href => url) if url
195
+ @xml.link(rel: "alternate", type: type, href: url) if url
196
196
 
197
197
  yield AtomBuilder.new(@xml)
198
198
  end
199
199
  end
200
200
  end
201
-
202
201
  end
203
202
  end
204
203
  end
@@ -41,11 +41,11 @@ module ActionView
41
41
  #
42
42
  # ==== \Template digest
43
43
  #
44
- # The template digest that's added to the cache key is computed by taking an md5 of the
44
+ # The template digest that's added to the cache key is computed by taking an MD5 of the
45
45
  # contents of the entire template file. This ensures that your caches will automatically
46
46
  # expire when you change the template file.
47
47
  #
48
- # Note that the md5 is taken of the entire template file, not just what's within the
48
+ # Note that the MD5 is taken of the entire template file, not just what's within the
49
49
  # cache do/end call. So it's possible that changing something outside of that call will
50
50
  # still expire the cache.
51
51
  #
@@ -69,11 +69,11 @@ module ActionView
69
69
  # render 'comments/comments'
70
70
  # render('comments/comments')
71
71
  #
72
- # render "header" => render("comments/header")
72
+ # render "header" translates to render("comments/header")
73
73
  #
74
- # render(@topic) => render("topics/topic")
75
- # render(topics) => render("topics/topic")
76
- # render(message.topics) => render("topics/topic")
74
+ # render(@topic) translates to render("topics/topic")
75
+ # render(topics) translates to render("topics/topic")
76
+ # render(message.topics) translates to render("topics/topic")
77
77
  #
78
78
  # It's not possible to derive all render calls like that, though.
79
79
  # Here are a few examples of things that can't be derived:
@@ -88,7 +88,7 @@ module ActionView
88
88
  #
89
89
  # === Explicit dependencies
90
90
  #
91
- # Some times you'll have template dependencies that can't be derived at all. This is typically
91
+ # Sometimes you'll have template dependencies that can't be derived at all. This is typically
92
92
  # the case when you have template rendering that happens in helpers. Here's an example:
93
93
  #
94
94
  # <%= render_sortable_todolists @project.todolists %>
@@ -118,7 +118,7 @@ module ActionView
118
118
  #
119
119
  # If you use a helper method, for example, inside a cached block and
120
120
  # you then update that helper, you'll have to bump the cache as well.
121
- # It doesn't really matter how you do it, but the md5 of the template file
121
+ # It doesn't really matter how you do it, but the MD5 of the template file
122
122
  # must change. One recommendation is to simply be explicit in a comment, like:
123
123
  #
124
124
  # <%# Helper Dependency Updated: May 6, 2012 at 6pm %>
@@ -130,9 +130,10 @@ module ActionView
130
130
  #
131
131
  # When rendering a collection of objects that each use the same partial, a `cached`
132
132
  # option can be passed.
133
+ #
133
134
  # For collections rendered such:
134
135
  #
135
- # <%= render partial: 'notifications/notification', collection: @notifications, cached: true %>
136
+ # <%= render partial: 'projects/project', collection: @projects, cached: true %>
136
137
  #
137
138
  # The `cached: true` will make Action View's rendering read several templates
138
139
  # from cache at once instead of one call per template.
@@ -142,13 +143,21 @@ module ActionView
142
143
  # Works great alongside individual template fragment caching.
143
144
  # For instance if the template the collection renders is cached like:
144
145
  #
145
- # # notifications/_notification.html.erb
146
- # <% cache notification do %>
146
+ # # projects/_project.html.erb
147
+ # <% cache project do %>
147
148
  # <%# ... %>
148
149
  # <% end %>
149
150
  #
150
151
  # Any collection renders will find those cached templates when attempting
151
152
  # to read multiple templates at once.
153
+ #
154
+ # If your collection cache depends on multiple sources (try to avoid this to keep things simple),
155
+ # you can name all these dependencies as part of a block that returns an array:
156
+ #
157
+ # <%= render partial: 'projects/project', collection: @projects, cached: -> project { [ project, current_user ] } %>
158
+ #
159
+ # This will include both records as part of the cache key and updating either of them will
160
+ # expire the cache.
152
161
  def cache(name = {}, options = {}, &block)
153
162
  if controller.respond_to?(:perform_caching) && controller.perform_caching
154
163
  name_options = options.slice(:skip_digest, :virtual_path)
@@ -202,12 +211,14 @@ module ActionView
202
211
  end
203
212
  end
204
213
 
214
+ attr_reader :cache_hit # :nodoc:
215
+
205
216
  private
206
217
 
207
- def fragment_name_with_digest(name, virtual_path) #:nodoc:
218
+ def fragment_name_with_digest(name, virtual_path)
208
219
  virtual_path ||= @virtual_path
209
220
  if virtual_path
210
- name = controller.url_for(name).split("://").last if name.is_a?(Hash)
221
+ name = controller.url_for(name).split("://").last if name.is_a?(Hash)
211
222
  digest = Digestor.digest name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies
212
223
  [ name, digest ]
213
224
  else
@@ -215,18 +226,21 @@ module ActionView
215
226
  end
216
227
  end
217
228
 
218
- # TODO: Create an object that has caching read/write on it
219
- def fragment_for(name = {}, options = nil, &block) #:nodoc:
220
- read_fragment_for(name, options) || write_fragment_for(name, options, &block)
229
+ def fragment_for(name = {}, options = nil, &block)
230
+ if content = read_fragment_for(name, options)
231
+ @cache_hit = true
232
+ content
233
+ else
234
+ @cache_hit = false
235
+ write_fragment_for(name, options, &block)
236
+ end
221
237
  end
222
238
 
223
- def read_fragment_for(name, options) #:nodoc:
239
+ def read_fragment_for(name, options)
224
240
  controller.read_fragment(name, options)
225
241
  end
226
242
 
227
- def write_fragment_for(name, options) #:nodoc:
228
- # VIEW TODO: Make #capture usable outside of ERB
229
- # This dance is needed because Builder can't use capture
243
+ def write_fragment_for(name, options)
230
244
  pos = output_buffer.length
231
245
  yield
232
246
  output_safe = output_buffer.html_safe?