actionview 4.1.13 → 6.1.3.1

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 (124) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +181 -359
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +12 -6
  5. data/lib/action_view/base.rb +115 -43
  6. data/lib/action_view/buffers.rb +22 -4
  7. data/lib/action_view/cache_expiry.rb +52 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +61 -21
  10. data/lib/action_view/digestor.rb +89 -84
  11. data/lib/action_view/flows.rb +12 -13
  12. data/lib/action_view/gem_version.rb +6 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +16 -11
  14. data/lib/action_view/helpers/asset_tag_helper.rb +311 -105
  15. data/lib/action_view/helpers/asset_url_helper.rb +197 -80
  16. data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
  17. data/lib/action_view/helpers/cache_helper.rb +109 -45
  18. data/lib/action_view/helpers/capture_helper.rb +20 -22
  19. data/lib/action_view/helpers/controller_helper.rb +15 -4
  20. data/lib/action_view/helpers/csp_helper.rb +26 -0
  21. data/lib/action_view/helpers/csrf_helper.rb +8 -6
  22. data/lib/action_view/helpers/date_helper.rb +245 -140
  23. data/lib/action_view/helpers/debug_helper.rb +14 -17
  24. data/lib/action_view/helpers/form_helper.rb +875 -148
  25. data/lib/action_view/helpers/form_options_helper.rb +128 -82
  26. data/lib/action_view/helpers/form_tag_helper.rb +253 -91
  27. data/lib/action_view/helpers/javascript_helper.rb +37 -15
  28. data/lib/action_view/helpers/number_helper.rb +100 -77
  29. data/lib/action_view/helpers/output_safety_helper.rb +42 -10
  30. data/lib/action_view/helpers/rendering_helper.rb +26 -15
  31. data/lib/action_view/helpers/sanitize_helper.rb +79 -164
  32. data/lib/action_view/helpers/tag_helper.rb +277 -64
  33. data/lib/action_view/helpers/tags/base.rb +143 -92
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -19
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -30
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +4 -3
  41. data/lib/action_view/helpers/tags/date_field.rb +3 -2
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -37
  43. data/lib/action_view/helpers/tags/datetime_field.rb +14 -5
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +41 -22
  51. data/lib/action_view/helpers/tags/month_field.rb +3 -2
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +24 -0
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -6
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +3 -0
  58. data/lib/action_view/helpers/tags/select.rb +11 -10
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +7 -1
  61. data/lib/action_view/helpers/tags/text_field.rb +11 -7
  62. data/lib/action_view/helpers/tags/time_field.rb +3 -2
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +39 -0
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +3 -2
  68. data/lib/action_view/helpers/tags.rb +4 -1
  69. data/lib/action_view/helpers/text_helper.rb +80 -45
  70. data/lib/action_view/helpers/translation_helper.rb +148 -67
  71. data/lib/action_view/helpers/url_helper.rb +289 -147
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +68 -63
  74. data/lib/action_view/log_subscriber.rb +80 -13
  75. data/lib/action_view/lookup_context.rb +137 -92
  76. data/lib/action_view/model_naming.rb +4 -2
  77. data/lib/action_view/path_set.rb +30 -16
  78. data/lib/action_view/railtie.rb +62 -13
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +152 -13
  81. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  82. data/lib/action_view/renderer/object_renderer.rb +34 -0
  83. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
  84. data/lib/action_view/renderer/partial_renderer.rb +61 -261
  85. data/lib/action_view/renderer/renderer.rb +67 -6
  86. data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
  87. data/lib/action_view/renderer/template_renderer.rb +83 -75
  88. data/lib/action_view/rendering.rb +73 -46
  89. data/lib/action_view/routing_url_for.rb +54 -17
  90. data/lib/action_view/tasks/cache_digests.rake +25 -0
  91. data/lib/action_view/template/error.rb +44 -29
  92. data/lib/action_view/template/handlers/builder.rb +12 -13
  93. data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
  94. data/lib/action_view/template/handlers/erb.rb +23 -89
  95. data/lib/action_view/template/handlers/html.rb +11 -0
  96. data/lib/action_view/template/handlers/raw.rb +4 -4
  97. data/lib/action_view/template/handlers.rb +22 -9
  98. data/lib/action_view/template/html.rb +10 -11
  99. data/lib/action_view/template/inline.rb +22 -0
  100. data/lib/action_view/template/raw_file.rb +25 -0
  101. data/lib/action_view/template/renderable.rb +24 -0
  102. data/lib/action_view/template/resolver.rb +267 -181
  103. data/lib/action_view/template/sources/file.rb +17 -0
  104. data/lib/action_view/template/sources.rb +13 -0
  105. data/lib/action_view/template/text.rb +8 -10
  106. data/lib/action_view/template/types.rb +18 -18
  107. data/lib/action_view/template.rb +109 -99
  108. data/lib/action_view/test_case.rb +73 -53
  109. data/lib/action_view/testing/resolvers.rb +24 -33
  110. data/lib/action_view/unbound_template.rb +31 -0
  111. data/lib/action_view/version.rb +3 -1
  112. data/lib/action_view/view_paths.rb +74 -44
  113. data/lib/action_view.rb +14 -9
  114. data/lib/assets/compiled/rails-ujs.js +746 -0
  115. metadata +71 -26
  116. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  117. data/lib/action_view/tasks/dependencies.rake +0 -23
  118. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  119. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  120. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  121. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  122. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  123. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
  124. data/lib/action_view/vendor/html-scanner.rb +0 -20
@@ -1,25 +1,36 @@
1
- require 'active_support/core_ext/module/attr_internal'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attr_internal"
2
4
 
3
5
  module ActionView
4
- module Helpers
6
+ module Helpers #:nodoc:
5
7
  # This module keeps all methods and behavior in ActionView
6
8
  # that simply delegates to the controller.
7
9
  module ControllerHelper #:nodoc:
8
10
  attr_internal :controller, :request
9
11
 
10
- delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers,
11
- :flash, :action_name, :controller_name, :controller_path, :to => :controller
12
+ CONTROLLER_DELEGATES = [:request_forgery_protection_token, :params,
13
+ :session, :cookies, :response, :headers, :flash, :action_name,
14
+ :controller_name, :controller_path]
15
+
16
+ delegate(*CONTROLLER_DELEGATES, to: :controller)
12
17
 
13
18
  def assign_controller(controller)
14
19
  if @_controller = controller
15
20
  @_request = controller.request if controller.respond_to?(:request)
16
21
  @_config = controller.config.inheritable_copy if controller.respond_to?(:config)
22
+ @_default_form_builder = controller.default_form_builder if controller.respond_to?(:default_form_builder)
17
23
  end
18
24
  end
19
25
 
20
26
  def logger
21
27
  controller.logger if controller.respond_to?(:logger)
22
28
  end
29
+
30
+ def respond_to?(method_name, include_private = false)
31
+ return controller.respond_to?(method_name) if CONTROLLER_DELEGATES.include?(method_name.to_sym)
32
+ super
33
+ end
23
34
  end
24
35
  end
25
36
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ # = Action View CSP Helper
5
+ module Helpers #:nodoc:
6
+ module CspHelper
7
+ # Returns a meta tag "csp-nonce" with the per-session nonce value
8
+ # for allowing inline <script> tags.
9
+ #
10
+ # <head>
11
+ # <%= csp_meta_tag %>
12
+ # </head>
13
+ #
14
+ # This is used by the Rails UJS helper to create dynamically
15
+ # loaded inline <script> elements.
16
+ #
17
+ def csp_meta_tag(**options)
18
+ if content_security_policy?
19
+ options[:name] = "csp-nonce"
20
+ options[:content] = content_security_policy_nonce
21
+ tag("meta", options)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  # = Action View CSRF Helper
3
- module Helpers
5
+ module Helpers #:nodoc:
4
6
  module CsrfHelper
5
7
  # Returns meta tags "csrf-param" and "csrf-token" with the name of the cross-site
6
8
  # request forgery protection parameter and token, respectively.
@@ -14,14 +16,14 @@ module ActionView
14
16
  #
15
17
  # You don't need to use these tags for regular forms as they generate their own hidden fields.
16
18
  #
17
- # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the
18
- # "X-CSRF-Token" HTTP header. If you are using jQuery with jquery-rails this happens automatically.
19
+ # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the
20
+ # "X-CSRF-Token" HTTP header. If you are using rails-ujs this happens automatically.
19
21
  #
20
22
  def csrf_meta_tags
21
- if protect_against_forgery?
23
+ if defined?(protect_against_forgery?) && protect_against_forgery?
22
24
  [
23
- tag('meta', :name => 'csrf-param', :content => request_forgery_protection_token),
24
- tag('meta', :name => 'csrf-token', :content => form_authenticity_token)
25
+ tag("meta", name: "csrf-param", content: request_forgery_protection_token),
26
+ tag("meta", name: "csrf-token", content: form_authenticity_token)
25
27
  ].join("\n").html_safe
26
28
  end
27
29
  end
@@ -1,12 +1,15 @@
1
- require 'date'
2
- require 'action_view/helpers/tag_helper'
3
- require 'active_support/core_ext/array/extract_options'
4
- require 'active_support/core_ext/date/conversions'
5
- require 'active_support/core_ext/hash/slice'
6
- require 'active_support/core_ext/object/with_options'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "action_view/helpers/tag_helper"
5
+ require "active_support/core_ext/array/extract_options"
6
+ require "active_support/core_ext/date/conversions"
7
+ require "active_support/core_ext/hash/slice"
8
+ require "active_support/core_ext/object/acts_like"
9
+ require "active_support/core_ext/object/with_options"
7
10
 
8
11
  module ActionView
9
- module Helpers
12
+ module Helpers #:nodoc:
10
13
  # = Action View Date Helpers
11
14
  #
12
15
  # The Date Helper primarily creates select/option tags for different kinds of dates and times or date and time
@@ -19,6 +22,10 @@ module ActionView
19
22
  # the <tt>select_month</tt> method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead
20
23
  # of \date[month].
21
24
  module DateHelper
25
+ MINUTES_IN_YEAR = 525600
26
+ MINUTES_IN_QUARTER_YEAR = 131400
27
+ MINUTES_IN_THREE_QUARTERS_YEAR = 394200
28
+
22
29
  # Reports the approximate distance in time between two Time, Date or DateTime objects or integers as seconds.
23
30
  # Pass <tt>include_seconds: true</tt> if you want more detailed approximations when distance < 1 min, 29 secs.
24
31
  # Distances are reported based on the following table:
@@ -64,71 +71,88 @@ module ActionView
64
71
  # distance_of_time_in_words(from_time, to_time, include_seconds: true) # => about 6 years
65
72
  # distance_of_time_in_words(to_time, from_time, include_seconds: true) # => about 6 years
66
73
  # distance_of_time_in_words(Time.now, Time.now) # => less than a minute
74
+ #
75
+ # With the <tt>scope</tt> option, you can define a custom scope for Rails
76
+ # to look up the translation.
77
+ #
78
+ # For example you can define the following in your locale (e.g. en.yml).
79
+ #
80
+ # datetime:
81
+ # distance_in_words:
82
+ # short:
83
+ # about_x_hours:
84
+ # one: 'an hour'
85
+ # other: '%{count} hours'
86
+ #
87
+ # See https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en.yml
88
+ # for more examples.
89
+ #
90
+ # Which will then result in the following:
91
+ #
92
+ # from_time = Time.now
93
+ # distance_of_time_in_words(from_time, from_time + 50.minutes, scope: 'datetime.distance_in_words.short') # => "an hour"
94
+ # distance_of_time_in_words(from_time, from_time + 3.hours, scope: 'datetime.distance_in_words.short') # => "3 hours"
67
95
  def distance_of_time_in_words(from_time, to_time = 0, options = {})
68
96
  options = {
69
97
  scope: :'datetime.distance_in_words'
70
98
  }.merge!(options)
71
99
 
72
- from_time = from_time.to_time if from_time.respond_to?(:to_time)
73
- to_time = to_time.to_time if to_time.respond_to?(:to_time)
100
+ from_time = normalize_distance_of_time_argument_to_time(from_time)
101
+ to_time = normalize_distance_of_time_argument_to_time(to_time)
74
102
  from_time, to_time = to_time, from_time if from_time > to_time
75
- distance_in_minutes = ((to_time - from_time)/60.0).round
103
+ distance_in_minutes = ((to_time - from_time) / 60.0).round
76
104
  distance_in_seconds = (to_time - from_time).round
77
105
 
78
- I18n.with_options :locale => options[:locale], :scope => options[:scope] do |locale|
106
+ I18n.with_options locale: options[:locale], scope: options[:scope] do |locale|
79
107
  case distance_in_minutes
80
- when 0..1
81
- return distance_in_minutes == 0 ?
82
- locale.t(:less_than_x_minutes, :count => 1) :
83
- locale.t(:x_minutes, :count => distance_in_minutes) unless options[:include_seconds]
84
-
85
- case distance_in_seconds
86
- when 0..4 then locale.t :less_than_x_seconds, :count => 5
87
- when 5..9 then locale.t :less_than_x_seconds, :count => 10
88
- when 10..19 then locale.t :less_than_x_seconds, :count => 20
89
- when 20..39 then locale.t :half_a_minute
90
- when 40..59 then locale.t :less_than_x_minutes, :count => 1
91
- else locale.t :x_minutes, :count => 1
92
- end
93
-
94
- when 2...45 then locale.t :x_minutes, :count => distance_in_minutes
95
- when 45...90 then locale.t :about_x_hours, :count => 1
108
+ when 0..1
109
+ return distance_in_minutes == 0 ?
110
+ locale.t(:less_than_x_minutes, count: 1) :
111
+ locale.t(:x_minutes, count: distance_in_minutes) unless options[:include_seconds]
112
+
113
+ case distance_in_seconds
114
+ when 0..4 then locale.t :less_than_x_seconds, count: 5
115
+ when 5..9 then locale.t :less_than_x_seconds, count: 10
116
+ when 10..19 then locale.t :less_than_x_seconds, count: 20
117
+ when 20..39 then locale.t :half_a_minute
118
+ when 40..59 then locale.t :less_than_x_minutes, count: 1
119
+ else locale.t :x_minutes, count: 1
120
+ end
121
+
122
+ when 2...45 then locale.t :x_minutes, count: distance_in_minutes
123
+ when 45...90 then locale.t :about_x_hours, count: 1
96
124
  # 90 mins up to 24 hours
97
- when 90...1440 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
125
+ when 90...1440 then locale.t :about_x_hours, count: (distance_in_minutes.to_f / 60.0).round
98
126
  # 24 hours up to 42 hours
99
- when 1440...2520 then locale.t :x_days, :count => 1
127
+ when 1440...2520 then locale.t :x_days, count: 1
100
128
  # 42 hours up to 30 days
101
- when 2520...43200 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round
129
+ when 2520...43200 then locale.t :x_days, count: (distance_in_minutes.to_f / 1440.0).round
102
130
  # 30 days up to 60 days
103
- when 43200...86400 then locale.t :about_x_months, :count => (distance_in_minutes.to_f / 43200.0).round
131
+ when 43200...86400 then locale.t :about_x_months, count: (distance_in_minutes.to_f / 43200.0).round
104
132
  # 60 days up to 365 days
105
- when 86400...525600 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
133
+ when 86400...525600 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round
134
+ else
135
+ from_year = from_time.year
136
+ from_year += 1 if from_time.month >= 3
137
+ to_year = to_time.year
138
+ to_year -= 1 if to_time.month < 3
139
+ leap_years = (from_year > to_year) ? 0 : (from_year..to_year).count { |x| Date.leap?(x) }
140
+ minute_offset_for_leap_year = leap_years * 1440
141
+ # Discount the leap year days when calculating year distance.
142
+ # e.g. if there are 20 leap year days between 2 dates having the same day
143
+ # and month then the based on 365 days calculation
144
+ # the distance in years will come out to over 80 years when in written
145
+ # English it would read better as about 80 years.
146
+ minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
147
+ remainder = (minutes_with_offset % MINUTES_IN_YEAR)
148
+ distance_in_years = (minutes_with_offset.div MINUTES_IN_YEAR)
149
+ if remainder < MINUTES_IN_QUARTER_YEAR
150
+ locale.t(:about_x_years, count: distance_in_years)
151
+ elsif remainder < MINUTES_IN_THREE_QUARTERS_YEAR
152
+ locale.t(:over_x_years, count: distance_in_years)
106
153
  else
107
- if from_time.acts_like?(:time) && to_time.acts_like?(:time)
108
- fyear = from_time.year
109
- fyear += 1 if from_time.month >= 3
110
- tyear = to_time.year
111
- tyear -= 1 if to_time.month < 3
112
- leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
113
- minute_offset_for_leap_year = leap_years * 1440
114
- # Discount the leap year days when calculating year distance.
115
- # e.g. if there are 20 leap year days between 2 dates having the same day
116
- # and month then the based on 365 days calculation
117
- # the distance in years will come out to over 80 years when in written
118
- # English it would read better as about 80 years.
119
- minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
120
- else
121
- minutes_with_offset = distance_in_minutes
122
- end
123
- remainder = (minutes_with_offset % 525600)
124
- distance_in_years = (minutes_with_offset.div 525600)
125
- if remainder < 131400
126
- locale.t(:about_x_years, :count => distance_in_years)
127
- elsif remainder < 394200
128
- locale.t(:over_x_years, :count => distance_in_years)
129
- else
130
- locale.t(:almost_x_years, :count => distance_in_years + 1)
131
- end
154
+ locale.t(:almost_x_years, count: distance_in_years + 1)
155
+ end
132
156
  end
133
157
  end
134
158
  end
@@ -149,8 +173,8 @@ module ActionView
149
173
  #
150
174
  # Note that you cannot pass a <tt>Numeric</tt> value to <tt>time_ago_in_words</tt>.
151
175
  #
152
- def time_ago_in_words(from_time, include_seconds_or_options = {})
153
- distance_of_time_in_words(from_time, Time.now, include_seconds_or_options)
176
+ def time_ago_in_words(from_time, options = {})
177
+ distance_of_time_in_words(from_time, Time.now, options)
154
178
  end
155
179
 
156
180
  alias_method :distance_of_time_in_words_to_now, :time_ago_in_words
@@ -173,12 +197,15 @@ module ActionView
173
197
  # and +:name+ (string). A format string would be something like "%{name} (%<number>02d)" for example.
174
198
  # See <tt>Kernel.sprintf</tt> for documentation on format sequences.
175
199
  # * <tt>:date_separator</tt> - Specifies a string to separate the date fields. Default is "" (i.e. nothing).
176
- # * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Date.today.year - 5</tt>if
200
+ # * <tt>:time_separator</tt> - Specifies a string to separate the time fields. Default is " : ".
201
+ # * <tt>:datetime_separator</tt>- Specifies a string to separate the date and time fields. Default is " &mdash; ".
202
+ # * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Date.today.year - 5</tt> if
177
203
  # you are creating new record. While editing existing record, <tt>:start_year</tt> defaults to
178
204
  # the current selected year minus 5.
179
205
  # * <tt>:end_year</tt> - Set the end year for the year select. Default is <tt>Date.today.year + 5</tt> if
180
206
  # you are creating new record. While editing existing record, <tt>:end_year</tt> defaults to
181
207
  # the current selected year plus 5.
208
+ # * <tt>:year_format</tt> - Set format of years for year select. Lambda should be passed.
182
209
  # * <tt>:discard_day</tt> - Set to true if you don't want to show a day select. This includes the day
183
210
  # as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
184
211
  # first of the given month in order to not create invalid dates like 31 February.
@@ -192,15 +219,18 @@ module ActionView
192
219
  # the respective locale (e.g. [:year, :month, :day] in the en locale that ships with Rails).
193
220
  # * <tt>:include_blank</tt> - Include a blank option in every select field so it's possible to set empty
194
221
  # dates.
195
- # * <tt>:default</tt> - Set a default date if the affected date isn't set or is nil.
222
+ # * <tt>:default</tt> - Set a default date if the affected date isn't set or is +nil+.
196
223
  # * <tt>:selected</tt> - Set a date that overrides the actual value.
197
224
  # * <tt>:disabled</tt> - Set to true if you want show the select fields as disabled.
198
225
  # * <tt>:prompt</tt> - Set to true (for a generic prompt), a prompt string or a hash of prompt strings
199
226
  # for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt> and <tt>:second</tt>.
200
227
  # Setting this option prepends a select option with a generic prompt (Day, Month, Year, Hour, Minute, Seconds)
201
228
  # or the given prompt string.
202
- # * <tt>:with_css_classes</tt> - Set to true if you want assign different styles for 'select' tags. This option
203
- # automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second' for your 'select' tags.
229
+ # * <tt>:with_css_classes</tt> - Set to true or a hash of strings. Use true if you want to assign generic styles for
230
+ # select tags. This automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second'. A hash of
231
+ # strings for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, <tt>:second</tt>
232
+ # will extend the select type with the given value. Use +html_options+ to modify every select tag in the set.
233
+ # * <tt>:use_hidden</tt> - Set to true if you only want to generate hidden input tags.
204
234
  #
205
235
  # If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
206
236
  #
@@ -236,7 +266,7 @@ module ActionView
236
266
  # date_select("article", "written_on", default: 3.days.from_now)
237
267
  #
238
268
  # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute
239
- # # which is set in the form with todays date, regardless of the value in the Active Record object.
269
+ # # which is set in the form with today's date, regardless of the value in the Active Record object.
240
270
  # date_select("article", "written_on", selected: Date.today)
241
271
  #
242
272
  # # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute
@@ -246,6 +276,9 @@ module ActionView
246
276
  # # Generates a date select with custom prompts.
247
277
  # date_select("article", "written_on", prompt: { day: 'Select day', month: 'Select month', year: 'Select year' })
248
278
  #
279
+ # # Generates a date select with custom year format.
280
+ # date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" })
281
+ #
249
282
  # The selects are prepared for multi-parameter assignment to an Active Record object.
250
283
  #
251
284
  # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
@@ -272,16 +305,16 @@ module ActionView
272
305
  # # the sunrise attribute.
273
306
  # time_select("article", "start_time", include_seconds: true)
274
307
  #
275
- # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45.
276
- # time_select 'game', 'game_time', {minute_step: 15}
308
+ # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30, and 45.
309
+ # time_select 'game', 'game_time', { minute_step: 15 }
277
310
  #
278
311
  # # Creates a time select tag with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
279
- # time_select("article", "written_on", prompt: {hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds'})
280
- # time_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
312
+ # time_select("article", "written_on", prompt: { hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds' })
313
+ # time_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
281
314
  # time_select("article", "written_on", prompt: true) # generic prompts for all
282
315
  #
283
316
  # # You can set :ampm option to true which will show the hours as: 12 PM, 01 AM .. 11 PM.
284
- # time_select 'game', 'game_time', {ampm: true}
317
+ # time_select 'game', 'game_time', { ampm: true }
285
318
  #
286
319
  # The selects are prepared for multi-parameter assignment to an Active Record object.
287
320
  #
@@ -317,8 +350,8 @@ module ActionView
317
350
  # datetime_select("article", "written_on", discard_type: true)
318
351
  #
319
352
  # # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
320
- # datetime_select("article", "written_on", prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
321
- # datetime_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
353
+ # datetime_select("article", "written_on", prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
354
+ # datetime_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
322
355
  # datetime_select("article", "written_on", prompt: true) # generic prompts for all
323
356
  #
324
357
  # The selects are prepared for multi-parameter assignment to an Active Record object.
@@ -326,7 +359,7 @@ module ActionView
326
359
  Tags::DatetimeSelect.new(object_name, method, self, options, html_options).render
327
360
  end
328
361
 
329
- # Returns a set of html select-tags (one for year, month, day, hour, minute, and second) pre-selected with the
362
+ # Returns a set of HTML select-tags (one for year, month, day, hour, minute, and second) pre-selected with the
330
363
  # +datetime+. It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with
331
364
  # an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not
332
365
  # supply a Symbol, it will be appended onto the <tt>:order</tt> passed in. You can also add
@@ -368,14 +401,14 @@ module ActionView
368
401
  # select_datetime(my_date_time, prefix: 'payday')
369
402
  #
370
403
  # # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
371
- # select_datetime(my_date_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
372
- # select_datetime(my_date_time, prompt: {hour: true}) # generic prompt for hours
404
+ # select_datetime(my_date_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
405
+ # select_datetime(my_date_time, prompt: { hour: true }) # generic prompt for hours
373
406
  # select_datetime(my_date_time, prompt: true) # generic prompts for all
374
407
  def select_datetime(datetime = Time.current, options = {}, html_options = {})
375
408
  DateTimeSelector.new(datetime, options, html_options).select_datetime
376
409
  end
377
410
 
378
- # Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
411
+ # Returns a set of HTML select-tags (one for year, month, and day) pre-selected with the +date+.
379
412
  # It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
380
413
  # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order.
381
414
  # If the array passed to the <tt>:order</tt> option does not contain all the three symbols, all tags will be hidden.
@@ -407,14 +440,14 @@ module ActionView
407
440
  # select_date(my_date, prefix: 'payday')
408
441
  #
409
442
  # # Generates a date select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
410
- # select_date(my_date, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
411
- # select_date(my_date, prompt: {hour: true}) # generic prompt for hours
443
+ # select_date(my_date, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
444
+ # select_date(my_date, prompt: { hour: true }) # generic prompt for hours
412
445
  # select_date(my_date, prompt: true) # generic prompts for all
413
446
  def select_date(date = Date.current, options = {}, html_options = {})
414
447
  DateTimeSelector.new(date, options, html_options).select_date
415
448
  end
416
449
 
417
- # Returns a set of html select-tags (one for hour and minute).
450
+ # Returns a set of HTML select-tags (one for hour and minute).
418
451
  # You can set <tt>:time_separator</tt> key to format the output, and
419
452
  # the <tt>:include_seconds</tt> option to include an input for seconds.
420
453
  #
@@ -447,8 +480,8 @@ module ActionView
447
480
  # select_time(my_time, start_hour: 2, end_hour: 14)
448
481
  #
449
482
  # # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
450
- # select_time(my_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
451
- # select_time(my_time, prompt: {hour: true}) # generic prompt for hours
483
+ # select_time(my_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
484
+ # select_time(my_time, prompt: { hour: true }) # generic prompt for hours
452
485
  # select_time(my_time, prompt: true) # generic prompts for all
453
486
  def select_time(datetime = Time.current, options = {}, html_options = {})
454
487
  DateTimeSelector.new(datetime, options, html_options).select_time
@@ -458,7 +491,7 @@ module ActionView
458
491
  # The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
459
492
  # Override the field name using the <tt>:field_name</tt> option, 'second' by default.
460
493
  #
461
- # my_time = Time.now + 16.minutes
494
+ # my_time = Time.now + 16.seconds
462
495
  #
463
496
  # # Generates a select field for seconds that defaults to the seconds for the time in my_time.
464
497
  # select_second(my_time)
@@ -482,7 +515,7 @@ module ActionView
482
515
  # selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
483
516
  # Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
484
517
  #
485
- # my_time = Time.now + 6.hours
518
+ # my_time = Time.now + 10.minutes
486
519
  #
487
520
  # # Generates a select field for minutes that defaults to the minutes for the time in my_time.
488
521
  # select_minute(my_time)
@@ -631,7 +664,7 @@ module ActionView
631
664
  DateTimeSelector.new(date, options, html_options).select_year
632
665
  end
633
666
 
634
- # Returns an html time tag for the given date or time.
667
+ # Returns an HTML time tag for the given date or time.
635
668
  #
636
669
  # time_tag Date.today # =>
637
670
  # <time datetime="2010-11-04">November 04, 2010</time>
@@ -639,8 +672,6 @@ module ActionView
639
672
  # <time datetime="2010-11-04T17:55:45+01:00">November 04, 2010 17:55</time>
640
673
  # time_tag Date.yesterday, 'Yesterday' # =>
641
674
  # <time datetime="2010-11-03">Yesterday</time>
642
- # time_tag Date.today, pubdate: true # =>
643
- # <time datetime="2010-11-04" pubdate="pubdate">November 04, 2010</time>
644
675
  # time_tag Date.today, datetime: Date.today.strftime('%G-W%V') # =>
645
676
  # <time datetime="2010-W44">November 04, 2010</time>
646
677
  #
@@ -651,19 +682,29 @@ module ActionView
651
682
  def time_tag(date_or_time, *args, &block)
652
683
  options = args.extract_options!
653
684
  format = options.delete(:format) || :long
654
- content = args.first || I18n.l(date_or_time, :format => format)
655
- datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601
685
+ content = args.first || I18n.l(date_or_time, format: format)
656
686
 
657
- content_tag(:time, content, options.reverse_merge(:datetime => datetime), &block)
687
+ content_tag("time", content, options.reverse_merge(datetime: date_or_time.iso8601), &block)
658
688
  end
689
+
690
+ private
691
+ def normalize_distance_of_time_argument_to_time(value)
692
+ if value.is_a?(Numeric)
693
+ Time.at(value)
694
+ elsif value.respond_to?(:to_time)
695
+ value.to_time
696
+ else
697
+ raise ArgumentError, "#{value.inspect} can't be converted to a Time value"
698
+ end
699
+ end
659
700
  end
660
701
 
661
702
  class DateTimeSelector #:nodoc:
662
703
  include ActionView::Helpers::TagHelper
663
704
 
664
- DEFAULT_PREFIX = 'date'.freeze
705
+ DEFAULT_PREFIX = "date"
665
706
  POSITION = {
666
- :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6
707
+ year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6
667
708
  }.freeze
668
709
 
669
710
  AMPM_TRANSLATION = Hash[
@@ -679,8 +720,8 @@ module ActionView
679
720
  @options = options.dup
680
721
  @html_options = html_options.dup
681
722
  @datetime = datetime
682
- @options[:datetime_separator] ||= ' &mdash; '
683
- @options[:time_separator] ||= ' : '
723
+ @options[:datetime_separator] ||= " &mdash; "
724
+ @options[:time_separator] ||= " : "
684
725
  end
685
726
 
686
727
  def select_datetime
@@ -750,7 +791,7 @@ module ActionView
750
791
  if @options[:use_hidden] || @options[:discard_minute]
751
792
  build_hidden(:minute, min)
752
793
  else
753
- build_options_and_select(:minute, min, :step => @options[:minute_step])
794
+ build_options_and_select(:minute, min, step: @options[:minute_step])
754
795
  end
755
796
  end
756
797
 
@@ -770,7 +811,7 @@ module ActionView
770
811
  if @options[:use_hidden] || @options[:discard_day]
771
812
  build_hidden(:day, day || 1)
772
813
  else
773
- build_options_and_select(:day, day, :start => 1, :end => 31, :leading_zeros => false, :use_two_digit_numbers => @options[:use_two_digit_numbers])
814
+ build_options_and_select(:day, day, start: 1, end: 31, leading_zeros: false, use_two_digit_numbers: @options[:use_two_digit_numbers])
774
815
  end
775
816
  end
776
817
 
@@ -780,17 +821,17 @@ module ActionView
780
821
  else
781
822
  month_options = []
782
823
  1.upto(12) do |month_number|
783
- options = { :value => month_number }
824
+ options = { value: month_number }
784
825
  options[:selected] = "selected" if month == month_number
785
- month_options << content_tag(:option, month_name(month_number), options) + "\n"
826
+ month_options << content_tag("option", month_name(month_number), options) + "\n"
786
827
  end
787
828
  build_select(:month, month_options.join)
788
829
  end
789
830
  end
790
831
 
791
832
  def select_year
792
- if !@datetime || @datetime == 0
793
- val = '1'
833
+ if !year || @datetime == 0
834
+ val = "1"
794
835
  middle_year = Date.today.year
795
836
  else
796
837
  val = middle_year = year
@@ -810,14 +851,19 @@ module ActionView
810
851
  raise ArgumentError, "There are too many years options to be built. Are you sure you haven't mistyped something? You can provide the :max_years_allowed parameter."
811
852
  end
812
853
 
813
- build_options_and_select(:year, val, options)
854
+ build_select(:year, build_year_options(val, options))
814
855
  end
815
856
  end
816
857
 
817
858
  private
818
859
  %w( sec min hour day month year ).each do |method|
819
860
  define_method(method) do
820
- @datetime.kind_of?(Numeric) ? @datetime : @datetime.send(method) if @datetime
861
+ case @datetime
862
+ when Hash then @datetime[method.to_sym]
863
+ when Numeric then @datetime
864
+ when nil then nil
865
+ else @datetime.send(method)
866
+ end
821
867
  end
822
868
  end
823
869
 
@@ -825,12 +871,12 @@ module ActionView
825
871
  # valid. Otherwise, February 31st or February 29th, 2011 can be selected, which are invalid.
826
872
  def set_day_if_discarded
827
873
  if @datetime && @options[:discard_day]
828
- @datetime = @datetime.change(:day => 1)
874
+ @datetime = @datetime.change(day: 1)
829
875
  end
830
876
  end
831
877
 
832
878
  # Returns translated month names, but also ensures that a custom month
833
- # name array has a leading nil element.
879
+ # name array has a leading +nil+ element.
834
880
  def month_names
835
881
  @month_names ||= begin
836
882
  month_names = @options[:use_month_names] || translated_month_names
@@ -850,7 +896,7 @@ module ActionView
850
896
  # "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
851
897
  def translated_month_names
852
898
  key = @options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
853
- I18n.translate(key, :locale => @options[:locale])
899
+ I18n.translate(key, locale: @options[:locale])
854
900
  end
855
901
 
856
902
  # Looks up month names by number (1-based):
@@ -878,23 +924,38 @@ module ActionView
878
924
  if @options[:use_month_numbers]
879
925
  number
880
926
  elsif @options[:use_two_digit_numbers]
881
- '%02d' % number
927
+ "%02d" % number
882
928
  elsif @options[:add_month_numbers]
883
929
  "#{number} - #{month_names[number]}"
884
930
  elsif format_string = @options[:month_format_string]
885
- format_string % {number: number, name: month_names[number]}
931
+ format_string % { number: number, name: month_names[number] }
886
932
  else
887
933
  month_names[number]
888
934
  end
889
935
  end
890
936
 
937
+ # Looks up year names by number.
938
+ #
939
+ # year_name(1998) # => 1998
940
+ #
941
+ # If the <tt>:year_format</tt> option is passed:
942
+ #
943
+ # year_name(1998) # => "Heisei 10"
944
+ def year_name(number)
945
+ if year_format_lambda = @options[:year_format]
946
+ year_format_lambda.call(number)
947
+ else
948
+ number
949
+ end
950
+ end
951
+
891
952
  def date_order
892
953
  @date_order ||= @options[:order] || translated_date_order
893
954
  end
894
955
 
895
956
  def translated_date_order
896
- date_order = I18n.translate(:'date.order', :locale => @options[:locale], :default => [])
897
- date_order = date_order.map { |element| element.to_sym }
957
+ date_order = I18n.translate(:'date.order', locale: @options[:locale], default: [])
958
+ date_order = date_order.map(&:to_sym)
898
959
 
899
960
  forbidden_elements = date_order - [:year, :month, :day]
900
961
  if forbidden_elements.any?
@@ -910,7 +971,7 @@ module ActionView
910
971
  build_select(type, build_options(selected, options))
911
972
  end
912
973
 
913
- # Build select option html from date value and options.
974
+ # Build select option HTML from date value and options.
914
975
  # build_options(15, start: 1, end: 31)
915
976
  # => "<option value="1">1</option>
916
977
  # <option value="2">2</option>
@@ -940,52 +1001,96 @@ module ActionView
940
1001
  select_options = []
941
1002
  start.step(stop, step) do |i|
942
1003
  value = leading_zeros ? sprintf("%02d", i) : i
943
- tag_options = { :value => value }
1004
+ tag_options = { value: value }
944
1005
  tag_options[:selected] = "selected" if selected == i
945
1006
  text = options[:use_two_digit_numbers] ? sprintf("%02d", i) : value
946
1007
  text = options[:ampm] ? AMPM_TRANSLATION[i] : text
947
- select_options << content_tag(:option, text, tag_options)
1008
+ select_options << content_tag("option", text, tag_options)
948
1009
  end
949
1010
 
950
1011
  (select_options.join("\n") + "\n").html_safe
951
1012
  end
952
1013
 
953
- # Builds select tag from date type and html select options.
1014
+ # Build select option HTML for year.
1015
+ # If <tt>year_format</tt> option is not passed
1016
+ # build_year_options(1998, start: 1998, end: 2000)
1017
+ # => "<option value="1998" selected="selected">1998</option>
1018
+ # <option value="1999">1999</option>
1019
+ # <option value="2000">2000</option>"
1020
+ #
1021
+ # If <tt>year_format</tt> option is passed
1022
+ # build_year_options(1998, start: 1998, end: 2000, year_format: ->year { "Heisei #{ year - 1988 }" })
1023
+ # => "<option value="1998" selected="selected">Heisei 10</option>
1024
+ # <option value="1999">Heisei 11</option>
1025
+ # <option value="2000">Heisei 12</option>"
1026
+ def build_year_options(selected, options = {})
1027
+ start = options.delete(:start)
1028
+ stop = options.delete(:end)
1029
+ step = options.delete(:step)
1030
+
1031
+ select_options = []
1032
+ start.step(stop, step) do |value|
1033
+ tag_options = { value: value }
1034
+ tag_options[:selected] = "selected" if selected == value
1035
+ text = year_name(value)
1036
+ select_options << content_tag("option", text, tag_options)
1037
+ end
1038
+
1039
+ (select_options.join("\n") + "\n").html_safe
1040
+ end
1041
+
1042
+ # Builds select tag from date type and HTML select options.
954
1043
  # build_select(:month, "<option value="1">January</option>...")
955
1044
  # => "<select id="post_written_on_2i" name="post[written_on(2i)]">
956
1045
  # <option value="1">January</option>...
957
1046
  # </select>"
958
1047
  def build_select(type, select_options_as_html)
959
1048
  select_options = {
960
- :id => input_id_from_type(type),
961
- :name => input_name_from_type(type)
1049
+ id: input_id_from_type(type),
1050
+ name: input_name_from_type(type)
962
1051
  }.merge!(@html_options)
963
- select_options[:disabled] = 'disabled' if @options[:disabled]
964
- select_options[:class] = [select_options[:class], type].compact.join(' ') if @options[:with_css_classes]
1052
+ select_options[:disabled] = "disabled" if @options[:disabled]
1053
+ select_options[:class] = css_class_attribute(type, select_options[:class], @options[:with_css_classes]) if @options[:with_css_classes]
965
1054
 
966
- select_html = "\n"
967
- select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
1055
+ select_html = +"\n"
1056
+ select_html << content_tag("option", "", value: "", label: " ") + "\n" if @options[:include_blank]
968
1057
  select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
969
1058
  select_html << select_options_as_html
970
1059
 
971
- (content_tag(:select, select_html.html_safe, select_options) + "\n").html_safe
1060
+ (content_tag("select", select_html.html_safe, select_options) + "\n").html_safe
1061
+ end
1062
+
1063
+ # Builds the css class value for the select element
1064
+ # css_class_attribute(:year, 'date optional', { year: 'my-year' })
1065
+ # => "date optional my-year"
1066
+ def css_class_attribute(type, html_options_class, options) # :nodoc:
1067
+ css_class = \
1068
+ case options
1069
+ when Hash
1070
+ options[type.to_sym]
1071
+ else
1072
+ type
1073
+ end
1074
+
1075
+ [html_options_class, css_class].compact.join(" ")
972
1076
  end
973
1077
 
974
1078
  # Builds a prompt option tag with supplied options or from default options.
975
1079
  # prompt_option_tag(:month, prompt: 'Select month')
976
1080
  # => "<option value="">Select month</option>"
977
1081
  def prompt_option_tag(type, options)
978
- prompt = case options
1082
+ prompt = \
1083
+ case options
979
1084
  when Hash
980
- default_options = {:year => false, :month => false, :day => false, :hour => false, :minute => false, :second => false}
1085
+ default_options = { year: false, month: false, day: false, hour: false, minute: false, second: false }
981
1086
  default_options.merge!(options)[type.to_sym]
982
1087
  when String
983
1088
  options
984
1089
  else
985
- I18n.translate(:"datetime.prompts.#{type}", :locale => @options[:locale])
986
- end
1090
+ I18n.translate(:"datetime.prompts.#{type}", locale: @options[:locale])
1091
+ end
987
1092
 
988
- prompt ? content_tag(:option, prompt, :value => '') : ''
1093
+ prompt ? content_tag("option", prompt, value: "") : ""
989
1094
  end
990
1095
 
991
1096
  # Builds hidden input tag for date part and value.
@@ -993,12 +1098,12 @@ module ActionView
993
1098
  # => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />"
994
1099
  def build_hidden(type, value)
995
1100
  select_options = {
996
- :type => "hidden",
997
- :id => input_id_from_type(type),
998
- :name => input_name_from_type(type),
999
- :value => value
1101
+ type: "hidden",
1102
+ id: input_id_from_type(type),
1103
+ name: input_name_from_type(type),
1104
+ value: value
1000
1105
  }.merge!(@html_options.slice(:disabled))
1001
- select_options[:disabled] = 'disabled' if @options[:disabled]
1106
+ select_options[:disabled] = "disabled" if @options[:disabled]
1002
1107
 
1003
1108
  tag(:input, select_options) + "\n".html_safe
1004
1109
  end
@@ -1009,7 +1114,7 @@ module ActionView
1009
1114
  prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
1010
1115
  prefix += "[#{@options[:index]}]" if @options.has_key?(:index)
1011
1116
 
1012
- field_name = @options[:field_name] || type
1117
+ field_name = @options[:field_name] || type.to_s
1013
1118
  if @options[:include_position]
1014
1119
  field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)"
1015
1120
  end
@@ -1020,8 +1125,8 @@ module ActionView
1020
1125
  # Returns the id attribute for the input tag.
1021
1126
  # => "post_written_on_1i"
1022
1127
  def input_id_from_type(type)
1023
- id = input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
1024
- id = @options[:namespace] + '_' + id if @options[:namespace]
1128
+ id = input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, "_").gsub(/[\]\)]/, "")
1129
+ id = @options[:namespace] + "_" + id if @options[:namespace]
1025
1130
 
1026
1131
  id
1027
1132
  end
@@ -1029,11 +1134,11 @@ module ActionView
1029
1134
  # Given an ordering of datetime components, create the selection HTML
1030
1135
  # and join them with their appropriate separators.
1031
1136
  def build_selects_from_types(order)
1032
- select = ''
1137
+ select = +""
1033
1138
  first_visible = order.find { |type| !@options[:"discard_#{type}"] }
1034
- order.reverse.each do |type|
1139
+ order.reverse_each do |type|
1035
1140
  separator = separator(type) unless type == first_visible # don't add before first visible field
1036
- select.insert(0, separator.to_s + send("select_#{type}").to_s)
1141
+ select.insert(0, separator.to_s + public_send("select_#{type}").to_s)
1037
1142
  end
1038
1143
  select.html_safe
1039
1144
  end
@@ -1043,12 +1148,12 @@ module ActionView
1043
1148
  return "" if @options[:use_hidden]
1044
1149
 
1045
1150
  case type
1046
- when :year, :month, :day
1047
- @options[:"discard_#{type}"] ? "" : @options[:date_separator]
1048
- when :hour
1049
- (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
1050
- when :minute, :second
1051
- @options[:"discard_#{type}"] ? "" : @options[:time_separator]
1151
+ when :year, :month, :day
1152
+ @options[:"discard_#{type}"] ? "" : @options[:date_separator]
1153
+ when :hour
1154
+ (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
1155
+ when :minute, :second
1156
+ @options[:"discard_#{type}"] ? "" : @options[:time_separator]
1052
1157
  end
1053
1158
  end
1054
1159
  end