actionview 4.2.10 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +141 -272
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/action_view/base.rb +33 -21
  6. data/lib/action_view/buffers.rb +1 -1
  7. data/lib/action_view/context.rb +1 -1
  8. data/lib/action_view/dependency_tracker.rb +52 -20
  9. data/lib/action_view/digestor.rb +86 -83
  10. data/lib/action_view/flows.rb +9 -11
  11. data/lib/action_view/gem_version.rb +3 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +8 -8
  13. data/lib/action_view/helpers/asset_tag_helper.rb +74 -38
  14. data/lib/action_view/helpers/asset_url_helper.rb +160 -59
  15. data/lib/action_view/helpers/atom_feed_helper.rb +16 -16
  16. data/lib/action_view/helpers/cache_helper.rb +90 -35
  17. data/lib/action_view/helpers/capture_helper.rb +7 -6
  18. data/lib/action_view/helpers/controller_helper.rb +3 -2
  19. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  20. data/lib/action_view/helpers/date_helper.rb +156 -108
  21. data/lib/action_view/helpers/debug_helper.rb +3 -4
  22. data/lib/action_view/helpers/form_helper.rb +475 -94
  23. data/lib/action_view/helpers/form_options_helper.rb +87 -47
  24. data/lib/action_view/helpers/form_tag_helper.rb +88 -57
  25. data/lib/action_view/helpers/javascript_helper.rb +10 -10
  26. data/lib/action_view/helpers/number_helper.rb +76 -59
  27. data/lib/action_view/helpers/output_safety_helper.rb +34 -4
  28. data/lib/action_view/helpers/record_tag_helper.rb +12 -99
  29. data/lib/action_view/helpers/rendering_helper.rb +3 -3
  30. data/lib/action_view/helpers/sanitize_helper.rb +17 -14
  31. data/lib/action_view/helpers/tag_helper.rb +198 -73
  32. data/lib/action_view/helpers/tags/base.rb +132 -97
  33. data/lib/action_view/helpers/tags/check_box.rb +17 -17
  34. data/lib/action_view/helpers/tags/collection_check_boxes.rb +9 -33
  35. data/lib/action_view/helpers/tags/collection_helpers.rb +68 -36
  36. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +3 -11
  37. data/lib/action_view/helpers/tags/collection_select.rb +2 -2
  38. data/lib/action_view/helpers/tags/date_select.rb +36 -36
  39. data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
  41. data/lib/action_view/helpers/tags/label.rb +5 -1
  42. data/lib/action_view/helpers/tags/password_field.rb +1 -1
  43. data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
  44. data/lib/action_view/helpers/tags/radio_button.rb +4 -4
  45. data/lib/action_view/helpers/tags/search_field.rb +12 -9
  46. data/lib/action_view/helpers/tags/select.rb +9 -9
  47. data/lib/action_view/helpers/tags/text_area.rb +1 -1
  48. data/lib/action_view/helpers/tags/text_field.rb +5 -6
  49. data/lib/action_view/helpers/tags/translator.rb +15 -13
  50. data/lib/action_view/helpers/text_helper.rb +47 -30
  51. data/lib/action_view/helpers/translation_helper.rb +60 -30
  52. data/lib/action_view/helpers/url_helper.rb +132 -104
  53. data/lib/action_view/helpers.rb +1 -1
  54. data/lib/action_view/layouts.rb +59 -54
  55. data/lib/action_view/log_subscriber.rb +56 -7
  56. data/lib/action_view/lookup_context.rb +76 -61
  57. data/lib/action_view/model_naming.rb +1 -1
  58. data/lib/action_view/path_set.rb +28 -19
  59. data/lib/action_view/railtie.rb +30 -6
  60. data/lib/action_view/record_identifier.rb +51 -25
  61. data/lib/action_view/renderer/abstract_renderer.rb +19 -15
  62. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +55 -0
  63. data/lib/action_view/renderer/partial_renderer.rb +208 -206
  64. data/lib/action_view/renderer/renderer.rb +2 -6
  65. data/lib/action_view/renderer/streaming_template_renderer.rb +46 -48
  66. data/lib/action_view/renderer/template_renderer.rb +65 -66
  67. data/lib/action_view/rendering.rb +16 -9
  68. data/lib/action_view/routing_url_for.rb +25 -17
  69. data/lib/action_view/tasks/cache_digests.rake +23 -0
  70. data/lib/action_view/template/error.rb +14 -13
  71. data/lib/action_view/template/handlers/builder.rb +7 -7
  72. data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
  73. data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
  74. data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
  75. data/lib/action_view/template/handlers/erb.rb +9 -76
  76. data/lib/action_view/template/handlers/html.rb +9 -0
  77. data/lib/action_view/template/handlers/raw.rb +1 -3
  78. data/lib/action_view/template/handlers.rb +8 -6
  79. data/lib/action_view/template/html.rb +2 -4
  80. data/lib/action_view/template/resolver.rb +133 -109
  81. data/lib/action_view/template/text.rb +5 -8
  82. data/lib/action_view/template/types.rb +15 -17
  83. data/lib/action_view/template.rb +51 -28
  84. data/lib/action_view/test_case.rb +32 -27
  85. data/lib/action_view/testing/resolvers.rb +29 -31
  86. data/lib/action_view/version.rb +1 -1
  87. data/lib/action_view/view_paths.rb +26 -32
  88. data/lib/action_view.rb +5 -5
  89. data/lib/assets/compiled/rails-ujs.js +685 -0
  90. metadata +23 -23
  91. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,7 +1,7 @@
1
- require 'action_view/helpers/javascript_helper'
2
- require 'active_support/core_ext/array/access'
3
- require 'active_support/core_ext/hash/keys'
4
- require 'active_support/core_ext/string/output_safety'
1
+ require "action_view/helpers/javascript_helper"
2
+ require "active_support/core_ext/array/access"
3
+ require "active_support/core_ext/hash/keys"
4
+ require "active_support/core_ext/string/output_safety"
5
5
 
6
6
  module ActionView
7
7
  # = Action View URL Helpers
@@ -35,20 +35,30 @@ module ActionView
35
35
  when :back
36
36
  _back_url
37
37
  else
38
- raise ArgumentError, "arguments passed to url_for can't be handled. Please require " +
38
+ raise ArgumentError, "arguments passed to url_for can't be handled. Please require " \
39
39
  "routes or provide your own implementation"
40
40
  end
41
41
  end
42
42
 
43
43
  def _back_url # :nodoc:
44
- referrer = controller.respond_to?(:request) && controller.request.env["HTTP_REFERER"]
45
- referrer || 'javascript:history.back()'
44
+ _filtered_referrer || "javascript:history.back()"
46
45
  end
47
46
  protected :_back_url
48
47
 
49
- # Creates a link tag of the given +name+ using a URL created by the set of +options+.
48
+ def _filtered_referrer # :nodoc:
49
+ if controller.respond_to?(:request)
50
+ referrer = controller.request.env["HTTP_REFERER"]
51
+ if referrer && URI(referrer).scheme != "javascript"
52
+ referrer
53
+ end
54
+ end
55
+ rescue URI::InvalidURIError
56
+ end
57
+ protected :_filtered_referrer
58
+
59
+ # Creates an anchor element of the given +name+ using a URL created by the set of +options+.
50
60
  # See the valid options in the documentation for +url_for+. It's also possible to
51
- # pass a String instead of an options hash, which generates a link tag that uses the
61
+ # pass a String instead of an options hash, which generates an anchor element that uses the
52
62
  # value of the String as the href for the link. Using a <tt>:back</tt> Symbol instead
53
63
  # of an options hash will generate a link to the referrer (a JavaScript back link
54
64
  # will be used in place of a referrer if none exists). If +nil+ is passed as the name
@@ -95,10 +105,9 @@ module ActionView
95
105
  # driver to prompt with the question specified (in this case, the
96
106
  # resulting text would be <tt>question?</tt>. If the user accepts, the
97
107
  # link is processed normally, otherwise no action is taken.
98
- # * <tt>:disable_with</tt> - Value of this parameter will be
99
- # used as the value for a disabled version of the submit
100
- # button when the form is submitted. This feature is provided
101
- # by the unobtrusive JavaScript driver.
108
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the
109
+ # name for a disabled version of the link. This feature is provided by
110
+ # the unobtrusive JavaScript driver.
102
111
  #
103
112
  # ==== Examples
104
113
  # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
@@ -172,6 +181,11 @@ module ActionView
172
181
  #
173
182
  # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
174
183
  # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
184
+ #
185
+ # Also you can set any link attributes such as <tt>target</tt>, <tt>rel</tt>, <tt>type</tt>:
186
+ #
187
+ # link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow"
188
+ # # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
175
189
  def link_to(name = nil, options = nil, html_options = nil, &block)
176
190
  html_options, options, name = options, name, block if block_given?
177
191
  options ||= {}
@@ -179,9 +193,9 @@ module ActionView
179
193
  html_options = convert_options_to_data_attributes(options, html_options)
180
194
 
181
195
  url = url_for(options)
182
- html_options['href'] ||= url
196
+ html_options["href".freeze] ||= url
183
197
 
184
- content_tag(:a, name || url, html_options, &block)
198
+ content_tag("a".freeze, name || url, html_options, &block)
185
199
  end
186
200
 
187
201
  # Generates a form containing a single button that submits to the URL created
@@ -280,42 +294,46 @@ module ActionView
280
294
  html_options, options = options, name if block_given?
281
295
  options ||= {}
282
296
  html_options ||= {}
283
-
284
297
  html_options = html_options.stringify_keys
285
- convert_boolean_attributes!(html_options, %w(disabled))
286
298
 
287
299
  url = options.is_a?(String) ? options : url_for(options)
288
- remote = html_options.delete('remote')
289
- params = html_options.delete('params')
290
-
291
- method = html_options.delete('method').to_s
292
- method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.html_safe
293
-
294
- form_method = method == 'get' ? 'get' : 'post'
295
- form_options = html_options.delete('form') || {}
296
- form_options[:class] ||= html_options.delete('form_class') || 'button_to'
297
- form_options.merge!(method: form_method, action: url)
298
- form_options.merge!("data-remote" => "true") if remote
299
-
300
- request_token_tag = form_method == 'post' ? token_tag : ''
300
+ remote = html_options.delete("remote")
301
+ params = html_options.delete("params")
302
+
303
+ method = html_options.delete("method").to_s
304
+ method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".freeze.html_safe
305
+
306
+ form_method = method == "get" ? "get" : "post"
307
+ form_options = html_options.delete("form") || {}
308
+ form_options[:class] ||= html_options.delete("form_class") || "button_to"
309
+ form_options[:method] = form_method
310
+ form_options[:action] = url
311
+ form_options[:'data-remote'] = true if remote
312
+
313
+ request_token_tag = if form_method == "post"
314
+ request_method = method.empty? ? "post" : method
315
+ token_tag(nil, form_options: { action: url, method: request_method })
316
+ else
317
+ "".freeze
318
+ end
301
319
 
302
320
  html_options = convert_options_to_data_attributes(options, html_options)
303
- html_options['type'] = 'submit'
321
+ html_options["type"] = "submit"
304
322
 
305
323
  button = if block_given?
306
- content_tag('button', html_options, &block)
324
+ content_tag("button", html_options, &block)
307
325
  else
308
- html_options['value'] = name || url
309
- tag('input', html_options)
326
+ html_options["value"] = name || url
327
+ tag("input", html_options)
310
328
  end
311
329
 
312
330
  inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
313
331
  if params
314
- params.each do |param_name, value|
315
- inner_tags.safe_concat tag(:input, type: "hidden", name: param_name, value: value.to_param)
332
+ to_form_params(params).each do |param|
333
+ inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value])
316
334
  end
317
335
  end
318
- content_tag('form', inner_tags, form_options)
336
+ content_tag("form", inner_tags, form_options)
319
337
  end
320
338
 
321
339
  # Creates a link tag of the given +name+ using a URL created by the set of
@@ -428,6 +446,7 @@ module ActionView
428
446
  # * <tt>:body</tt> - Preset the body of the email.
429
447
  # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
430
448
  # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
449
+ # * <tt>:reply_to</tt> - Preset the Reply-To field of the email.
431
450
  #
432
451
  # ==== Obfuscation
433
452
  # Prior to Rails 4.0, +mail_to+ provided options for encoding the address
@@ -457,73 +476,64 @@ module ActionView
457
476
  html_options, name = name, nil if block_given?
458
477
  html_options = (html_options || {}).stringify_keys
459
478
 
460
- extras = %w{ cc bcc body subject }.map! { |item|
461
- option = html_options.delete(item) || next
462
- "#{item}=#{Rack::Utils.escape_path(option)}"
479
+ extras = %w{ cc bcc body subject reply_to }.map! { |item|
480
+ option = html_options.delete(item).presence || next
481
+ "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
463
482
  }.compact
464
- extras = extras.empty? ? '' : '?' + extras.join('&')
483
+ extras = extras.empty? ? "".freeze : "?" + extras.join("&")
465
484
 
466
- encoded_email_address = ERB::Util.url_encode(email_address ? email_address.to_str : '').gsub("%40", "@")
485
+ encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@")
467
486
  html_options["href"] = "mailto:#{encoded_email_address}#{extras}"
468
487
 
469
- content_tag(:a, name || email_address, html_options, &block)
488
+ content_tag("a".freeze, name || email_address, html_options, &block)
470
489
  end
471
490
 
472
491
  # True if the current request URI was generated by the given +options+.
473
492
  #
474
493
  # ==== Examples
475
- # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc</tt> action.
494
+ # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc&page=1</tt> action.
476
495
  #
477
496
  # current_page?(action: 'process')
478
497
  # # => false
479
498
  #
480
- # current_page?(controller: 'shop', action: 'checkout')
481
- # # => true
482
- #
483
- # current_page?(controller: 'shop', action: 'checkout', order: 'asc')
484
- # # => false
485
- #
486
499
  # current_page?(action: 'checkout')
487
500
  # # => true
488
501
  #
489
502
  # current_page?(controller: 'library', action: 'checkout')
490
503
  # # => false
491
504
  #
492
- # current_page?('http://www.example.com/shop/checkout')
493
- # # => true
494
- #
495
- # current_page?('/shop/checkout')
505
+ # current_page?(controller: 'shop', action: 'checkout')
496
506
  # # => true
497
507
  #
498
- # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc&page=1</tt> action.
499
- #
500
- # current_page?(action: 'process')
508
+ # current_page?(controller: 'shop', action: 'checkout', order: 'asc')
501
509
  # # => false
502
510
  #
503
- # current_page?(controller: 'shop', action: 'checkout')
504
- # # => true
505
- #
506
511
  # current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '1')
507
512
  # # => true
508
513
  #
509
514
  # current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '2')
510
515
  # # => false
511
516
  #
512
- # current_page?(controller: 'shop', action: 'checkout', order: 'desc')
517
+ # current_page?('http://www.example.com/shop/checkout')
518
+ # # => true
519
+ #
520
+ # current_page?('http://www.example.com/shop/checkout', check_parameters: true)
513
521
  # # => false
514
522
  #
515
- # current_page?(action: 'checkout')
523
+ # current_page?('/shop/checkout')
516
524
  # # => true
517
525
  #
518
- # current_page?(controller: 'library', action: 'checkout')
519
- # # => false
526
+ # current_page?('http://www.example.com/shop/checkout?order=desc&page=1')
527
+ # # => true
520
528
  #
521
529
  # Let's say we're in the <tt>http://www.example.com/products</tt> action with method POST in case of invalid product.
522
530
  #
523
531
  # current_page?(controller: 'product', action: 'index')
524
532
  # # => false
525
533
  #
526
- def current_page?(options)
534
+ # We can also pass in the symbol arguments instead of strings.
535
+ #
536
+ def current_page?(options, check_parameters: false)
527
537
  unless request
528
538
  raise "You cannot use helpers that need to determine the current " \
529
539
  "page unless your view context provides a Request object " \
@@ -532,15 +542,19 @@ module ActionView
532
542
 
533
543
  return false unless request.get? || request.head?
534
544
 
545
+ check_parameters ||= options.is_a?(Hash) && options.delete(:check_parameters)
535
546
  url_string = URI.parser.unescape(url_for(options)).force_encoding(Encoding::BINARY)
536
547
 
537
548
  # We ignore any extra parameters in the request_uri if the
538
549
  # submitted url doesn't have any either. This lets the function
539
550
  # work with things like ?order=asc
540
- request_uri = url_string.index("?") ? request.fullpath : request.path
551
+ # the behaviour can be disabled with check_parameters: true
552
+ request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
541
553
  request_uri = URI.parser.unescape(request_uri).force_encoding(Encoding::BINARY)
542
554
 
543
- if url_string =~ /^\w+:\/\//
555
+ url_string.chomp!("/") if url_string.start_with?("/") && url_string != "/"
556
+
557
+ if %r{^\w+://}.match?(url_string)
544
558
  url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
545
559
  else
546
560
  url_string == request_uri
@@ -551,70 +565,84 @@ module ActionView
551
565
  def convert_options_to_data_attributes(options, html_options)
552
566
  if html_options
553
567
  html_options = html_options.stringify_keys
554
- html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
568
+ html_options["data-remote"] = "true".freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options)
555
569
 
556
- method = html_options.delete('method')
570
+ method = html_options.delete("method".freeze)
557
571
 
558
572
  add_method_to_attributes!(html_options, method) if method
559
573
 
560
574
  html_options
561
575
  else
562
- link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
576
+ link_to_remote_options?(options) ? { "data-remote" => "true".freeze } : {}
563
577
  end
564
578
  end
565
579
 
566
580
  def link_to_remote_options?(options)
567
581
  if options.is_a?(Hash)
568
- options.delete('remote') || options.delete(:remote)
582
+ options.delete("remote".freeze) || options.delete(:remote)
569
583
  end
570
584
  end
571
585
 
572
586
  def add_method_to_attributes!(html_options, method)
573
- if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
574
- html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip
587
+ if method && method.to_s.downcase != "get".freeze && html_options["rel".freeze] !~ /nofollow/
588
+ html_options["rel".freeze] = "#{html_options["rel".freeze]} nofollow".lstrip
575
589
  end
576
- html_options["data-method"] = method
590
+ html_options["data-method".freeze] = method
577
591
  end
578
592
 
579
- # Processes the +html_options+ hash, converting the boolean
580
- # attributes from true/false form into the form required by
581
- # HTML/XHTML. (An attribute is considered to be boolean if
582
- # its name is listed in the given +bool_attrs+ array.)
583
- #
584
- # More specifically, for each boolean attribute in +html_options+
585
- # given as:
593
+ def token_tag(token = nil, form_options: {})
594
+ if token != false && protect_against_forgery?
595
+ token ||= form_authenticity_token(form_options: form_options)
596
+ tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
597
+ else
598
+ "".freeze
599
+ end
600
+ end
601
+
602
+ def method_tag(method)
603
+ tag("input", type: "hidden", name: "_method", value: method.to_s)
604
+ end
605
+
606
+ # Returns an array of hashes each containing :name and :value keys
607
+ # suitable for use as the names and values of form input fields:
586
608
  #
587
- # "attr" => bool_value
609
+ # to_form_params(name: 'David', nationality: 'Danish')
610
+ # # => [{name: :name, value: 'David'}, {name: 'nationality', value: 'Danish'}]
588
611
  #
589
- # if the associated +bool_value+ evaluates to true, it is
590
- # replaced with the attribute's name; otherwise the attribute is
591
- # removed from the +html_options+ hash. (See the XHTML 1.0 spec,
592
- # section 4.5 "Attribute Minimization" for more:
593
- # http://www.w3.org/TR/xhtml1/#h-4.5)
612
+ # to_form_params(country: {name: 'Denmark'})
613
+ # # => [{name: 'country[name]', value: 'Denmark'}]
594
614
  #
595
- # Returns the updated +html_options+ hash, which is also modified
596
- # in place.
615
+ # to_form_params(countries: ['Denmark', 'Sweden']})
616
+ # # => [{name: 'countries[]', value: 'Denmark'}, {name: 'countries[]', value: 'Sweden'}]
597
617
  #
598
- # Example:
618
+ # An optional namespace can be passed to enclose key names:
599
619
  #
600
- # convert_boolean_attributes!( html_options,
601
- # %w( checked disabled readonly ) )
602
- def convert_boolean_attributes!(html_options, bool_attrs)
603
- bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
604
- html_options
605
- end
620
+ # to_form_params({ name: 'Denmark' }, 'country')
621
+ # # => [{name: 'country[name]', value: 'Denmark'}]
622
+ def to_form_params(attribute, namespace = nil)
623
+ attribute = if attribute.respond_to?(:permitted?)
624
+ attribute.to_h
625
+ else
626
+ attribute
627
+ end
606
628
 
607
- def token_tag(token=nil)
608
- if token != false && protect_against_forgery?
609
- token ||= form_authenticity_token
610
- tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
629
+ params = []
630
+ case attribute
631
+ when Hash
632
+ attribute.each do |key, value|
633
+ prefix = namespace ? "#{namespace}[#{key}]" : key
634
+ params.push(*to_form_params(value, prefix))
635
+ end
636
+ when Array
637
+ array_prefix = "#{namespace}[]"
638
+ attribute.each do |value|
639
+ params.push(*to_form_params(value, array_prefix))
640
+ end
611
641
  else
612
- ''
642
+ params << { name: namespace, value: attribute.to_param }
613
643
  end
614
- end
615
644
 
616
- def method_tag(method)
617
- tag('input', type: 'hidden', name: '_method', value: method.to_s)
645
+ params.sort_by { |pair| pair[:name] }
618
646
  end
619
647
  end
620
648
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/benchmarkable'
1
+ require "active_support/benchmarkable"
2
2
 
3
3
  module ActionView #:nodoc:
4
4
  module Helpers #:nodoc:
@@ -91,16 +91,16 @@ module ActionView
91
91
  # layout false
92
92
  #
93
93
  # In these examples, we have three implicit lookup scenarios:
94
- # * The BankController uses the "bank" layout.
95
- # * The ExchangeController uses the "exchange" layout.
96
- # * The CurrencyController inherits the layout from BankController.
94
+ # * The +BankController+ uses the "bank" layout.
95
+ # * The +ExchangeController+ uses the "exchange" layout.
96
+ # * The +CurrencyController+ inherits the layout from BankController.
97
97
  #
98
98
  # However, when a layout is explicitly set, the explicitly set layout wins:
99
- # * The InformationController uses the "information" layout, explicitly set.
100
- # * The TellerController also uses the "information" layout, because the parent explicitly set it.
101
- # * The EmployeeController uses the "employee" layout, because it set the layout to nil, resetting the parent configuration.
102
- # * The VaultController chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
103
- # * The TillController does not use a layout at all.
99
+ # * The +InformationController+ uses the "information" layout, explicitly set.
100
+ # * The +TellerController+ also uses the "information" layout, because the parent explicitly set it.
101
+ # * The +EmployeeController+ uses the "employee" layout, because it set the layout to +nil+, resetting the parent configuration.
102
+ # * The +VaultController+ chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
103
+ # * The +TillController+ does not use a layout at all.
104
104
  #
105
105
  # == Types of layouts
106
106
  #
@@ -148,8 +148,8 @@ module ActionView
148
148
  # The template will be looked always in <tt>app/views/layouts/</tt> folder. But you can point
149
149
  # <tt>layouts</tt> folder direct also. <tt>layout "layouts/demo"</tt> is the same as <tt>layout "demo"</tt>.
150
150
  #
151
- # Setting the layout to nil forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists.
152
- # Setting it to nil is useful to re-enable template lookup overriding a previous configuration set in the parent:
151
+ # Setting the layout to +nil+ forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists.
152
+ # Setting it to +nil+ is useful to re-enable template lookup overriding a previous configuration set in the parent:
153
153
  #
154
154
  # class ApplicationController < ActionController::Base
155
155
  # layout "application"
@@ -204,7 +204,7 @@ module ActionView
204
204
  include ActionView::Rendering
205
205
 
206
206
  included do
207
- class_attribute :_layout, :_layout_conditions, :instance_accessor => false
207
+ class_attribute :_layout, :_layout_conditions, instance_accessor: false
208
208
  self._layout = nil
209
209
  self._layout_conditions = {}
210
210
  _write_layout_method
@@ -223,36 +223,39 @@ module ActionView
223
223
  module LayoutConditions # :nodoc:
224
224
  private
225
225
 
226
- # Determines whether the current action has a layout definition by
227
- # checking the action name against the :only and :except conditions
228
- # set by the <tt>layout</tt> method.
229
- #
230
- # ==== Returns
231
- # * <tt> Boolean</tt> - True if the action has a layout definition, false otherwise.
232
- def _conditional_layout?
233
- return unless super
234
-
235
- conditions = _layout_conditions
236
-
237
- if only = conditions[:only]
238
- only.include?(action_name)
239
- elsif except = conditions[:except]
240
- !except.include?(action_name)
241
- else
242
- true
226
+ # Determines whether the current action has a layout definition by
227
+ # checking the action name against the :only and :except conditions
228
+ # set by the <tt>layout</tt> method.
229
+ #
230
+ # ==== Returns
231
+ # * <tt>Boolean</tt> - True if the action has a layout definition, false otherwise.
232
+ def _conditional_layout?
233
+ return unless super
234
+
235
+ conditions = _layout_conditions
236
+
237
+ if only = conditions[:only]
238
+ only.include?(action_name)
239
+ elsif except = conditions[:except]
240
+ !except.include?(action_name)
241
+ else
242
+ true
243
+ end
243
244
  end
244
- end
245
245
  end
246
246
 
247
247
  # Specify the layout to use for this class.
248
248
  #
249
249
  # If the specified layout is a:
250
250
  # String:: the String is the template name
251
- # Symbol:: call the method specified by the symbol, which will return the template name
251
+ # Symbol:: call the method specified by the symbol
252
+ # Proc:: call the passed Proc
252
253
  # false:: There is no layout
253
254
  # true:: raise an ArgumentError
254
255
  # nil:: Force default layout behavior with inheritance
255
256
  #
257
+ # Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true+ or +nil+
258
+ # with the same meaning as described above.
256
259
  # ==== Parameters
257
260
  # * <tt>layout</tt> - The layout to use.
258
261
  #
@@ -262,7 +265,7 @@ module ActionView
262
265
  def layout(layout, conditions = {})
263
266
  include LayoutConditions unless conditions.empty?
264
267
 
265
- conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
268
+ conditions.each { |k, v| conditions[k] = Array(v).map(&:to_s) }
266
269
  self._layout_conditions = conditions
267
270
 
268
271
  self._layout = layout
@@ -276,8 +279,8 @@ module ActionView
276
279
  def _write_layout_method # :nodoc:
277
280
  remove_possible_method(:_layout)
278
281
 
279
- prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
280
- default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}).first || super"
282
+ prefixes = /\blayouts/.match?(_implied_layout_name) ? [] : ["layouts"]
283
+ default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}, false, [], { formats: formats }).first || super"
281
284
  name_clause = if name
282
285
  default_behavior
283
286
  else
@@ -286,7 +289,8 @@ module ActionView
286
289
  RUBY
287
290
  end
288
291
 
289
- layout_definition = case _layout
292
+ layout_definition = \
293
+ case _layout
290
294
  when String
291
295
  _layout.inspect
292
296
  when Symbol
@@ -313,10 +317,10 @@ module ActionView
313
317
  raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil"
314
318
  when nil
315
319
  name_clause
316
- end
320
+ end
317
321
 
318
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
319
- def _layout
322
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
323
+ def _layout(formats)
320
324
  if _conditional_layout?
321
325
  #{layout_definition}
322
326
  else
@@ -329,14 +333,14 @@ module ActionView
329
333
 
330
334
  private
331
335
 
332
- # If no layout is supplied, look for a template named the return
333
- # value of this method.
334
- #
335
- # ==== Returns
336
- # * <tt>String</tt> - A template name
337
- def _implied_layout_name # :nodoc:
338
- controller_path
339
- end
336
+ # If no layout is supplied, look for a template named the return
337
+ # value of this method.
338
+ #
339
+ # ==== Returns
340
+ # * <tt>String</tt> - A template name
341
+ def _implied_layout_name
342
+ controller_path
343
+ end
340
344
  end
341
345
 
342
346
  def _normalize_options(options) # :nodoc:
@@ -372,7 +376,7 @@ module ActionView
372
376
  end
373
377
 
374
378
  # This will be overwritten by _write_layout_method
375
- def _layout; end
379
+ def _layout(*); end
376
380
 
377
381
  # Determine the layout for a given name, taking into account the name type.
378
382
  #
@@ -382,8 +386,8 @@ module ActionView
382
386
  case name
383
387
  when String then _normalize_layout(name)
384
388
  when Proc then name
385
- when true then Proc.new { _default_layout(true) }
386
- when :default then Proc.new { _default_layout(false) }
389
+ when true then Proc.new { |formats| _default_layout(formats, true) }
390
+ when :default then Proc.new { |formats| _default_layout(formats, false) }
387
391
  when false, nil then nil
388
392
  else
389
393
  raise ArgumentError,
@@ -399,14 +403,15 @@ module ActionView
399
403
  # Optionally raises an exception if the layout could not be found.
400
404
  #
401
405
  # ==== Parameters
402
- # * <tt>require_layout</tt> - If set to true and layout is not found,
403
- # an ArgumentError exception is raised (defaults to false)
406
+ # * <tt>formats</tt> - The formats accepted to this layout
407
+ # * <tt>require_layout</tt> - If set to +true+ and layout is not found,
408
+ # an +ArgumentError+ exception is raised (defaults to +false+)
404
409
  #
405
410
  # ==== Returns
406
- # * <tt>template</tt> - The template object for the default layout (or nil)
407
- def _default_layout(require_layout = false)
411
+ # * <tt>template</tt> - The template object for the default layout (or +nil+)
412
+ def _default_layout(formats, require_layout = false)
408
413
  begin
409
- value = _layout if action_has_layout?
414
+ value = _layout(formats) if action_has_layout?
410
415
  rescue NameError => e
411
416
  raise e, "Could not render layout: #{e.message}"
412
417
  end
@@ -420,7 +425,7 @@ module ActionView
420
425
  end
421
426
 
422
427
  def _include_layout?(options)
423
- (options.keys & [:body, :text, :plain, :html, :inline, :partial]).empty? || options.key?(:layout)
428
+ (options.keys & [:body, :plain, :html, :inline, :partial]).empty? || options.key?(:layout)
424
429
  end
425
430
  end
426
431
  end