actionpack 3.2.22.5 → 4.0.0.beta1

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

Potentially problematic release.


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

Files changed (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,4 +1,3 @@
1
- require 'active_support/core_ext/object/blank'
2
1
  require 'active_support/core_ext/string/output_safety'
3
2
 
4
3
  module ActionView
@@ -13,7 +12,6 @@ module ActionView
13
12
  # The capture method allows you to extract part of a template into a
14
13
  # variable. You can then use this variable anywhere in your templates or layout.
15
14
  #
16
- # ==== Examples
17
15
  # The capture method can be used in ERB templates...
18
16
  #
19
17
  # <% @greeting = capture do %>
@@ -44,14 +42,12 @@ module ActionView
44
42
  end
45
43
 
46
44
  # Calling content_for stores a block of markup in an identifier for later use.
47
- # You can make subsequent calls to the stored content in other templates, helper modules
48
- # or the layout by passing the identifier as an argument to <tt>content_for</tt>.
45
+ # In order to access this stored content in other templates, helper modules
46
+ # or the layout, you would pass the identifier as an argument to <tt>content_for</tt>.
49
47
  #
50
48
  # Note: <tt>yield</tt> can still be used to retrieve the stored content, but calling
51
49
  # <tt>yield</tt> doesn't work in helper modules, while <tt>content_for</tt> does.
52
50
  #
53
- # ==== Examples
54
- #
55
51
  # <% content_for :not_authorized do %>
56
52
  # alert('You are not authorized to do that!')
57
53
  # <% end %>
@@ -76,13 +72,14 @@ module ActionView
76
72
  #
77
73
  # <%= stored_content %>
78
74
  #
79
- # You can use the <tt>yield</tt> syntax alongside an existing call to <tt>yield</tt> in a layout. For example:
75
+ # You can also use the <tt>yield</tt> syntax alongside an existing call to
76
+ # <tt>yield</tt> in a layout. For example:
80
77
  #
81
78
  # <%# This is the layout %>
82
79
  # <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
83
80
  # <head>
84
- # <title>My Website</title>
85
- # <%= yield :script %>
81
+ # <title>My Website</title>
82
+ # <%= yield :script %>
86
83
  # </head>
87
84
  # <body>
88
85
  # <%= yield %>
@@ -96,12 +93,12 @@ module ActionView
96
93
  # Please login!
97
94
  #
98
95
  # <% content_for :script do %>
99
- # <script type="text/javascript">alert('You are not authorized to view this page!')</script>
96
+ # <script>alert('You are not authorized to view this page!')</script>
100
97
  # <% end %>
101
98
  #
102
99
  # Then, in another view, you could to do something like this:
103
100
  #
104
- # <%= link_to 'Logout', :action => 'logout', :remote => true %>
101
+ # <%= link_to 'Logout', action: 'logout', remote: true %>
105
102
  #
106
103
  # <% content_for :script do %>
107
104
  # <%= javascript_include_tag :defaults %>
@@ -110,33 +107,53 @@ module ActionView
110
107
  # That will place +script+ tags for your default set of JavaScript files on the page;
111
108
  # this technique is useful if you'll only be using these scripts in a few views.
112
109
  #
113
- # Note that content_for concatenates the blocks it is given for a particular
110
+ # Note that content_for concatenates (default) the blocks it is given for a particular
114
111
  # identifier in order. For example:
115
112
  #
116
113
  # <% content_for :navigation do %>
117
- # <li><%= link_to 'Home', :action => 'index' %></li>
114
+ # <li><%= link_to 'Home', action: 'index' %></li>
118
115
  # <% end %>
119
116
  #
120
- # <%# Add some other content, or use a different template: %>
117
+ # And in other place:
121
118
  #
122
119
  # <% content_for :navigation do %>
123
- # <li><%= link_to 'Login', :action => 'login' %></li>
120
+ # <li><%= link_to 'Login', action: 'login' %></li>
124
121
  # <% end %>
125
122
  #
126
123
  # Then, in another template or layout, this code would render both links in order:
127
124
  #
128
125
  # <ul><%= content_for :navigation %></ul>
129
126
  #
127
+ # If the flush parameter is true content_for replaces the blocks it is given. For example:
128
+ #
129
+ # <% content_for :navigation do %>
130
+ # <li><%= link_to 'Home', action: 'index' %></li>
131
+ # <% end %>
132
+ #
133
+ # <%# Add some other content, or use a different template: %>
134
+ #
135
+ # <% content_for :navigation, flush: true do %>
136
+ # <li><%= link_to 'Login', action: 'login' %></li>
137
+ # <% end %>
138
+ #
139
+ # Then, in another template or layout, this code would render only the last link:
140
+ #
141
+ # <ul><%= content_for :navigation %></ul>
142
+ #
130
143
  # Lastly, simple content can be passed as a parameter:
131
144
  #
132
145
  # <% content_for :script, javascript_include_tag(:defaults) %>
133
146
  #
134
- # WARNING: content_for is ignored in caches. So you shouldn't use it
135
- # for elements that will be fragment cached.
136
- def content_for(name, content = nil, &block)
147
+ # WARNING: content_for is ignored in caches. So you shouldn't use it for elements that will be fragment cached.
148
+ def content_for(name, content = nil, options = {}, &block)
137
149
  if content || block_given?
138
- content = capture(&block) if block_given?
139
- @view_flow.append(name, content) if content
150
+ if block_given?
151
+ options = content if content
152
+ content = capture(&block)
153
+ end
154
+ if content
155
+ options[:flush] ? @view_flow.set(name, content) : @view_flow.append(name, content)
156
+ end
140
157
  nil
141
158
  else
142
159
  @view_flow.get(name)
@@ -154,18 +171,14 @@ module ActionView
154
171
  result unless content
155
172
  end
156
173
 
157
- # content_for? simply checks whether any content has been captured yet using content_for
174
+ # content_for? checks whether any content has been captured yet using `content_for`.
158
175
  # Useful to render parts of your layout differently based on what is in your views.
159
176
  #
160
- # ==== Examples
161
- #
162
- # Perhaps you will use different css in you layout if no content_for :right_column
163
- #
164
177
  # <%# This is the layout %>
165
178
  # <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
166
179
  # <head>
167
- # <title>My Website</title>
168
- # <%= yield :script %>
180
+ # <title>My Website</title>
181
+ # <%= yield :script %>
169
182
  # </head>
170
183
  # <body class="<%= content_for?(:right_col) ? 'one-column' : 'two-column' %>">
171
184
  # <%= yield %>
@@ -181,7 +194,7 @@ module ActionView
181
194
  def with_output_buffer(buf = nil) #:nodoc:
182
195
  unless buf
183
196
  buf = ActionView::OutputBuffer.new
184
- buf.force_encoding(output_buffer.encoding) if output_buffer.respond_to?(:encoding) && buf.respond_to?(:force_encoding)
197
+ buf.force_encoding(output_buffer.encoding) if output_buffer
185
198
  end
186
199
  self.output_buffer, old_buffer = buf, output_buffer
187
200
  yield
@@ -193,7 +206,7 @@ module ActionView
193
206
  # Add the output buffer to the response body and start a new one.
194
207
  def flush_output_buffer #:nodoc:
195
208
  if output_buffer && !output_buffer.empty?
196
- response.body_parts << output_buffer
209
+ response.stream.write output_buffer
197
210
  self.output_buffer = output_buffer.respond_to?(:clone_empty) ? output_buffer.clone_empty : output_buffer[0, 0]
198
211
  nil
199
212
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/string/strip'
2
-
3
1
  module ActionView
4
2
  # = Action View CSRF Helper
5
3
  module Helpers
@@ -1,5 +1,6 @@
1
1
  require 'date'
2
2
  require 'action_view/helpers/tag_helper'
3
+ require 'active_support/core_ext/array/extract_options'
3
4
  require 'active_support/core_ext/date/conversions'
4
5
  require 'active_support/core_ext/hash/slice'
5
6
  require 'active_support/core_ext/object/with_options'
@@ -12,14 +13,14 @@ module ActionView
12
13
  # elements. All of the select-type methods share a number of common options that are as follows:
13
14
  #
14
15
  # * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday"
15
- # would give birthday[month] instead of date[month] if passed to the <tt>select_month</tt> method.
16
+ # would give \birthday[month] instead of \date[month] if passed to the <tt>select_month</tt> method.
16
17
  # * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date.
17
18
  # * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true,
18
19
  # the <tt>select_month</tt> method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead
19
- # of "date[month]".
20
+ # of \date[month].
20
21
  module DateHelper
21
22
  # Reports the approximate distance in time between two Time, Date or DateTime objects or integers as seconds.
22
- # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs.
23
+ # Pass <tt>include_seconds: true</tt> if you want more detailed approximations when distance < 1 min, 29 secs.
23
24
  # Distances are reported based on the following table:
24
25
  #
25
26
  # 0 <-> 29 secs # => less than a minute
@@ -29,14 +30,15 @@ module ActionView
29
30
  # 89 mins, 30 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
30
31
  # 23 hrs, 59 mins, 30 secs <-> 41 hrs, 59 mins, 29 secs # => 1 day
31
32
  # 41 hrs, 59 mins, 30 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
32
- # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
33
+ # 29 days, 23 hrs, 59 mins, 30 secs <-> 44 days, 23 hrs, 59 mins, 29 secs # => about 1 month
34
+ # 44 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 2 months
33
35
  # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
34
36
  # 1 yr <-> 1 yr, 3 months # => about 1 year
35
37
  # 1 yr, 3 months <-> 1 yr, 9 months # => over 1 year
36
38
  # 1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years
37
39
  # 2 yrs <-> max time or date # => (same rules as 1 yr)
38
40
  #
39
- # With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds:
41
+ # With <tt>include_seconds: true</tt> and the difference < 1 minute 29 seconds:
40
42
  # 0-4 secs # => less than 5 seconds
41
43
  # 5-9 secs # => less than 10 seconds
42
44
  # 10-19 secs # => less than 20 seconds
@@ -44,43 +46,49 @@ module ActionView
44
46
  # 40-59 secs # => less than a minute
45
47
  # 60-89 secs # => 1 minute
46
48
  #
47
- # ==== Examples
48
49
  # from_time = Time.now
49
- # distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
50
- # distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
51
- # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
52
- # distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
53
- # distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years
54
- # distance_of_time_in_words(from_time, from_time + 60.hours) # => 3 days
55
- # distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute
56
- # distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute
57
- # distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
58
- # distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
59
- # distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years
50
+ # distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
51
+ # distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
52
+ # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
53
+ # distance_of_time_in_words(from_time, from_time + 15.seconds, include_seconds: true) # => less than 20 seconds
54
+ # distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years
55
+ # distance_of_time_in_words(from_time, from_time + 60.hours) # => 3 days
56
+ # distance_of_time_in_words(from_time, from_time + 45.seconds, include_seconds: true) # => less than a minute
57
+ # distance_of_time_in_words(from_time, from_time - 45.seconds, include_seconds: true) # => less than a minute
58
+ # distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
59
+ # distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
60
+ # distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years
60
61
  # distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years
61
62
  #
62
63
  # to_time = Time.now + 6.years + 19.days
63
- # distance_of_time_in_words(from_time, to_time, true) # => about 6 years
64
- # distance_of_time_in_words(to_time, from_time, true) # => about 6 years
65
- # distance_of_time_in_words(Time.now, Time.now) # => less than a minute
66
- #
67
- def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
64
+ # distance_of_time_in_words(from_time, to_time, include_seconds: true) # => about 6 years
65
+ # distance_of_time_in_words(to_time, from_time, include_seconds: true) # => about 6 years
66
+ # distance_of_time_in_words(Time.now, Time.now) # => less than a minute
67
+ def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {})
68
+ if include_seconds_or_options.is_a?(Hash)
69
+ options = include_seconds_or_options
70
+ else
71
+ ActiveSupport::Deprecation.warn "distance_of_time_in_words and time_ago_in_words now accept :include_seconds " +
72
+ "as a part of options hash, not a boolean argument"
73
+ options[:include_seconds] ||= !!include_seconds_or_options
74
+ end
75
+
68
76
  options = {
69
- :scope => :'datetime.distance_in_words',
77
+ scope: :'datetime.distance_in_words'
70
78
  }.merge!(options)
71
79
 
72
80
  from_time = from_time.to_time if from_time.respond_to?(:to_time)
73
81
  to_time = to_time.to_time if to_time.respond_to?(:to_time)
74
- distance = (to_time.to_f - from_time.to_f).abs
75
- distance_in_minutes = (distance / 60.0).round
76
- distance_in_seconds = distance.round
82
+ from_time, to_time = to_time, from_time if from_time > to_time
83
+ distance_in_minutes = ((to_time - from_time)/60.0).round
84
+ distance_in_seconds = (to_time - from_time).round
77
85
 
78
86
  I18n.with_options :locale => options[:locale], :scope => options[:scope] do |locale|
79
87
  case distance_in_minutes
80
88
  when 0..1
81
89
  return distance_in_minutes == 0 ?
82
90
  locale.t(:less_than_x_minutes, :count => 1) :
83
- locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds
91
+ locale.t(:x_minutes, :count => distance_in_minutes) unless options[:include_seconds]
84
92
 
85
93
  case distance_in_seconds
86
94
  when 0..4 then locale.t :less_than_x_seconds, :count => 5
@@ -91,26 +99,35 @@ module ActionView
91
99
  else locale.t :x_minutes, :count => 1
92
100
  end
93
101
 
94
- when 2..44 then locale.t :x_minutes, :count => distance_in_minutes
95
- when 45..89 then locale.t :about_x_hours, :count => 1
96
- when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
97
- when 1440..2519 then locale.t :x_days, :count => 1
98
- when 2520..43199 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round
99
- when 43200..86399 then locale.t :about_x_months, :count => 1
100
- when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
102
+ when 2...45 then locale.t :x_minutes, :count => distance_in_minutes
103
+ when 45...90 then locale.t :about_x_hours, :count => 1
104
+ # 90 mins up to 24 hours
105
+ when 90...1440 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
106
+ # 24 hours up to 42 hours
107
+ when 1440...2520 then locale.t :x_days, :count => 1
108
+ # 42 hours up to 30 days
109
+ when 2520...43200 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round
110
+ # 30 days up to 60 days
111
+ when 43200...86400 then locale.t :about_x_months, :count => (distance_in_minutes.to_f / 43200.0).round
112
+ # 60 days up to 365 days
113
+ when 86400...525600 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
101
114
  else
102
- fyear = from_time.year
103
- fyear += 1 if from_time.month >= 3
104
- tyear = to_time.year
105
- tyear -= 1 if to_time.month < 3
106
- leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
107
- minute_offset_for_leap_year = leap_years * 1440
108
- # Discount the leap year days when calculating year distance.
109
- # e.g. if there are 20 leap year days between 2 dates having the same day
110
- # and month then the based on 365 days calculation
111
- # the distance in years will come out to over 80 years when in written
112
- # english it would read better as about 80 years.
113
- minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
115
+ if from_time.acts_like?(:time) && to_time.acts_like?(:time)
116
+ fyear = from_time.year
117
+ fyear += 1 if from_time.month >= 3
118
+ tyear = to_time.year
119
+ tyear -= 1 if to_time.month < 3
120
+ leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
121
+ minute_offset_for_leap_year = leap_years * 1440
122
+ # Discount the leap year days when calculating year distance.
123
+ # e.g. if there are 20 leap year days between 2 dates having the same day
124
+ # and month then the based on 365 days calculation
125
+ # the distance in years will come out to over 80 years when in written
126
+ # english it would read better as about 80 years.
127
+ minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
128
+ else
129
+ minutes_with_offset = distance_in_minutes
130
+ end
114
131
  remainder = (minutes_with_offset % 525600)
115
132
  distance_in_years = (minutes_with_offset.div 525600)
116
133
  if remainder < 131400
@@ -126,16 +143,22 @@ module ActionView
126
143
 
127
144
  # Like <tt>distance_of_time_in_words</tt>, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
128
145
  #
129
- # ==== Examples
130
- # time_ago_in_words(3.minutes.from_now) # => 3 minutes
131
- # time_ago_in_words(Time.now - 15.hours) # => about 15 hours
132
- # time_ago_in_words(Time.now) # => less than a minute
146
+ # time_ago_in_words(3.minutes.from_now) # => 3 minutes
147
+ # time_ago_in_words(3.minutes.ago) # => 3 minutes
148
+ # time_ago_in_words(Time.now - 15.hours) # => about 15 hours
149
+ # time_ago_in_words(Time.now) # => less than a minute
150
+ # time_ago_in_words(Time.now, include_seconds: true) # => less than 5 seconds
133
151
  #
134
152
  # from_time = Time.now - 3.days - 14.minutes - 25.seconds
135
153
  # time_ago_in_words(from_time) # => 3 days
136
154
  #
137
- def time_ago_in_words(from_time, include_seconds = false, options = {})
138
- distance_of_time_in_words(from_time, Time.now, include_seconds, options)
155
+ # from_time = (3.days + 14.minutes + 25.seconds).ago
156
+ # time_ago_in_words(from_time) # => 3 days
157
+ #
158
+ # Note that you cannot pass a <tt>Numeric</tt> value to <tt>time_ago_in_words</tt>.
159
+ #
160
+ def time_ago_in_words(from_time, include_seconds_or_options = {})
161
+ distance_of_time_in_words(from_time, Time.now, include_seconds_or_options)
139
162
  end
140
163
 
141
164
  alias_method :distance_of_time_in_words_to_now, :time_ago_in_words
@@ -143,10 +166,11 @@ module ActionView
143
166
  # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based
144
167
  # attribute (identified by +method+) on an object assigned to the template (identified by +object+).
145
168
  #
146
- #
147
169
  # ==== Options
148
170
  # * <tt>:use_month_numbers</tt> - Set to true if you want to use month numbers rather than month names (e.g.
149
171
  # "2" instead of "February").
172
+ # * <tt>:use_two_digit_numbers</tt> - Set to true if you want to display two digit month and day numbers (e.g.
173
+ # "02" instead of "February" and "08" instead of "8").
150
174
  # * <tt>:use_short_month</tt> - Set to true if you want to use abbreviated month names instead of full
151
175
  # month names (e.g. "Feb" instead of "February").
152
176
  # * <tt>:add_month_numbers</tt> - Set to true if you want to use both month numbers and month names (e.g.
@@ -165,60 +189,70 @@ module ActionView
165
189
  # as a hidden field instead of showing a select field.
166
190
  # * <tt>:order</tt> - Set to an array containing <tt>:day</tt>, <tt>:month</tt> and <tt>:year</tt> to
167
191
  # customize the order in which the select fields are shown. If you leave out any of the symbols, the respective
168
- # select will not be shown (like when you set <tt>:discard_xxx => true</tt>. Defaults to the order defined in
192
+ # select will not be shown (like when you set <tt>discard_xxx: true</tt>. Defaults to the order defined in
169
193
  # the respective locale (e.g. [:year, :month, :day] in the en locale that ships with Rails).
170
194
  # * <tt>:include_blank</tt> - Include a blank option in every select field so it's possible to set empty
171
195
  # dates.
172
196
  # * <tt>:default</tt> - Set a default date if the affected date isn't set or is nil.
197
+ # * <tt>:selected</tt> - Set a date that overrides the actual value.
173
198
  # * <tt>:disabled</tt> - Set to true if you want show the select fields as disabled.
174
199
  # * <tt>:prompt</tt> - Set to true (for a generic prompt), a prompt string or a hash of prompt strings
175
200
  # for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt> and <tt>:second</tt>.
176
201
  # Setting this option prepends a select option with a generic prompt (Day, Month, Year, Hour, Minute, Seconds)
177
202
  # or the given prompt string.
203
+ # * <tt>:with_css_classes</tt> - Set to true if you want assign different styles for 'select' tags. This option
204
+ # automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second' for your 'select' tags.
178
205
  #
179
206
  # If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
180
207
  #
181
208
  # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
182
209
  #
183
- # ==== Examples
184
210
  # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute.
185
211
  # date_select("article", "written_on")
186
212
  #
187
213
  # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute,
188
214
  # # with the year in the year drop down box starting at 1995.
189
- # date_select("article", "written_on", :start_year => 1995)
215
+ # date_select("article", "written_on", start_year: 1995)
190
216
  #
191
217
  # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute,
192
218
  # # with the year in the year drop down box starting at 1995, numbers used for months instead of words,
193
219
  # # and without a day select box.
194
- # date_select("article", "written_on", :start_year => 1995, :use_month_numbers => true,
195
- # :discard_day => true, :include_blank => true)
220
+ # date_select("article", "written_on", start_year: 1995, use_month_numbers: true,
221
+ # discard_day: true, include_blank: true)
222
+ #
223
+ # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute,
224
+ # # with two digit numbers used for months and days.
225
+ # date_select("article", "written_on", use_two_digit_numbers: true)
196
226
  #
197
227
  # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute
198
228
  # # with the fields ordered as day, month, year rather than month, day, year.
199
- # date_select("article", "written_on", :order => [:day, :month, :year])
229
+ # date_select("article", "written_on", order: [:day, :month, :year])
200
230
  #
201
231
  # # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute
202
232
  # # lacking a year field.
203
- # date_select("user", "birthday", :order => [:month, :day])
233
+ # date_select("user", "birthday", order: [:month, :day])
204
234
  #
205
235
  # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute
206
236
  # # which is initially set to the date 3 days from the current date
207
- # date_select("article", "written_on", :default => 3.days.from_now)
237
+ # date_select("article", "written_on", default: 3.days.from_now)
238
+ #
239
+ # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute
240
+ # # which is set in the form with todays date, regardless of the value in the Active Record object.
241
+ # date_select("article", "written_on", selected: Date.today)
208
242
  #
209
243
  # # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute
210
244
  # # that will have a default day of 20.
211
- # date_select("credit_card", "bill_due", :default => { :day => 20 })
245
+ # date_select("credit_card", "bill_due", default: { day: 20 })
212
246
  #
213
247
  # # Generates a date select with custom prompts.
214
- # date_select("article", "written_on", :prompt => { :day => 'Select day', :month => 'Select month', :year => 'Select year' })
248
+ # date_select("article", "written_on", prompt: { day: 'Select day', month: 'Select month', year: 'Select year' })
215
249
  #
216
250
  # The selects are prepared for multi-parameter assignment to an Active Record object.
217
251
  #
218
252
  # 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
219
253
  # all month choices are valid.
220
254
  def date_select(object_name, method, options = {}, html_options = {})
221
- InstanceTag.new(object_name, method, self, options.delete(:object)).to_date_select_tag(options, html_options)
255
+ Tags::DateSelect.new(object_name, method, self, options, html_options).render
222
256
  end
223
257
 
224
258
  # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a
@@ -232,31 +266,30 @@ module ActionView
232
266
  #
233
267
  # If anything is passed in the html_options hash it will be applied to every select tag in the set.
234
268
  #
235
- # ==== Examples
236
269
  # # Creates a time select tag that, when POSTed, will be stored in the article variable in the sunrise attribute.
237
270
  # time_select("article", "sunrise")
238
271
  #
239
272
  # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the article variables in
240
273
  # # the sunrise attribute.
241
- # time_select("article", "start_time", :include_seconds => true)
274
+ # time_select("article", "start_time", include_seconds: true)
242
275
  #
243
276
  # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45.
244
- # time_select 'game', 'game_time', {:minute_step => 15}
277
+ # time_select 'game', 'game_time', {minute_step: 15}
245
278
  #
246
- # # Creates a time select tag with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
247
- # time_select("article", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'})
248
- # time_select("article", "written_on", :prompt => {:hour => true}) # generic prompt for hours
249
- # time_select("article", "written_on", :prompt => true) # generic prompts for all
279
+ # # Creates a time select tag with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
280
+ # time_select("article", "written_on", prompt: {hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds'})
281
+ # time_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
282
+ # time_select("article", "written_on", prompt: true) # generic prompts for all
250
283
  #
251
284
  # # You can set :ampm option to true which will show the hours as: 12 PM, 01 AM .. 11 PM.
252
- # time_select 'game', 'game_time', {:ampm => true}
285
+ # time_select 'game', 'game_time', {ampm: true}
253
286
  #
254
287
  # The selects are prepared for multi-parameter assignment to an Active Record object.
255
288
  #
256
289
  # 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
257
290
  # all month choices are valid.
258
291
  def time_select(object_name, method, options = {}, html_options = {})
259
- InstanceTag.new(object_name, method, self, options.delete(:object)).to_time_select_tag(options, html_options)
292
+ Tags::TimeSelect.new(object_name, method, self, options, html_options).render
260
293
  end
261
294
 
262
295
  # Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a
@@ -265,34 +298,33 @@ module ActionView
265
298
  #
266
299
  # If anything is passed in the html_options hash it will be applied to every select tag in the set.
267
300
  #
268
- # ==== Examples
269
301
  # # Generates a datetime select that, when POSTed, will be stored in the article variable in the written_on
270
302
  # # attribute.
271
303
  # datetime_select("article", "written_on")
272
304
  #
273
305
  # # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
274
306
  # # article variable in the written_on attribute.
275
- # datetime_select("article", "written_on", :start_year => 1995)
307
+ # datetime_select("article", "written_on", start_year: 1995)
276
308
  #
277
309
  # # Generates a datetime select with a default value of 3 days from the current time that, when POSTed, will
278
310
  # # be stored in the trip variable in the departing attribute.
279
- # datetime_select("trip", "departing", :default => 3.days.from_now)
311
+ # datetime_select("trip", "departing", default: 3.days.from_now)
280
312
  #
281
313
  # # Generate a datetime select with hours in the AM/PM format
282
- # datetime_select("article", "written_on", :ampm => true)
314
+ # datetime_select("article", "written_on", ampm: true)
283
315
  #
284
316
  # # Generates a datetime select that discards the type that, when POSTed, will be stored in the article variable
285
317
  # # as the written_on attribute.
286
- # datetime_select("article", "written_on", :discard_type => true)
318
+ # datetime_select("article", "written_on", discard_type: true)
287
319
  #
288
- # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
289
- # datetime_select("article", "written_on", :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
290
- # datetime_select("article", "written_on", :prompt => {:hour => true}) # generic prompt for hours
291
- # datetime_select("article", "written_on", :prompt => true) # generic prompts for all
320
+ # # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
321
+ # datetime_select("article", "written_on", prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
322
+ # datetime_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
323
+ # datetime_select("article", "written_on", prompt: true) # generic prompts for all
292
324
  #
293
325
  # The selects are prepared for multi-parameter assignment to an Active Record object.
294
326
  def datetime_select(object_name, method, options = {}, html_options = {})
295
- InstanceTag.new(object_name, method, self, options.delete(:object)).to_datetime_select_tag(options, html_options)
327
+ Tags::DatetimeSelect.new(object_name, method, self, options, html_options).render
296
328
  end
297
329
 
298
330
  # Returns a set of html select-tags (one for year, month, day, hour, minute, and second) pre-selected with the
@@ -304,7 +336,6 @@ module ActionView
304
336
  #
305
337
  # If anything is passed in the html_options hash it will be applied to every select tag in the set.
306
338
  #
307
- # ==== Examples
308
339
  # my_date_time = Time.now + 4.days
309
340
  #
310
341
  # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today).
@@ -315,33 +346,32 @@ module ActionView
315
346
  #
316
347
  # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
317
348
  # # with the fields ordered year, month, day rather than month, day, year.
318
- # select_datetime(my_date_time, :order => [:year, :month, :day])
349
+ # select_datetime(my_date_time, order: [:year, :month, :day])
319
350
  #
320
351
  # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
321
352
  # # with a '/' between each date field.
322
- # select_datetime(my_date_time, :date_separator => '/')
353
+ # select_datetime(my_date_time, date_separator: '/')
323
354
  #
324
355
  # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
325
356
  # # with a date fields separated by '/', time fields separated by '' and the date and time fields
326
357
  # # separated by a comma (',').
327
- # select_datetime(my_date_time, :date_separator => '/', :time_separator => '', :datetime_separator => ',')
358
+ # select_datetime(my_date_time, date_separator: '/', time_separator: '', datetime_separator: ',')
328
359
  #
329
360
  # # Generates a datetime select that discards the type of the field and defaults to the datetime in
330
361
  # # my_date_time (four days after today)
331
- # select_datetime(my_date_time, :discard_type => true)
362
+ # select_datetime(my_date_time, discard_type: true)
332
363
  #
333
364
  # # Generate a datetime field with hours in the AM/PM format
334
- # select_datetime(my_date_time, :ampm => true)
365
+ # select_datetime(my_date_time, ampm: true)
335
366
  #
336
367
  # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
337
368
  # # prefixed with 'payday' rather than 'date'
338
- # select_datetime(my_date_time, :prefix => 'payday')
339
- #
340
- # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
341
- # select_datetime(my_date_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
342
- # select_datetime(my_date_time, :prompt => {:hour => true}) # generic prompt for hours
343
- # select_datetime(my_date_time, :prompt => true) # generic prompts for all
369
+ # select_datetime(my_date_time, prefix: 'payday')
344
370
  #
371
+ # # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
372
+ # select_datetime(my_date_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
373
+ # select_datetime(my_date_time, prompt: {hour: true}) # generic prompt for hours
374
+ # select_datetime(my_date_time, prompt: true) # generic prompts for all
345
375
  def select_datetime(datetime = Time.current, options = {}, html_options = {})
346
376
  DateTimeSelector.new(datetime, options, html_options).select_datetime
347
377
  end
@@ -353,7 +383,6 @@ module ActionView
353
383
  #
354
384
  # If anything is passed in the html_options hash it will be applied to every select tag in the set.
355
385
  #
356
- # ==== Examples
357
386
  # my_date = Time.now + 6.days
358
387
  #
359
388
  # # Generates a date select that defaults to the date in my_date (six days after today).
@@ -364,25 +393,24 @@ module ActionView
364
393
  #
365
394
  # # Generates a date select that defaults to the date in my_date (six days after today)
366
395
  # # with the fields ordered year, month, day rather than month, day, year.
367
- # select_date(my_date, :order => [:year, :month, :day])
396
+ # select_date(my_date, order: [:year, :month, :day])
368
397
  #
369
398
  # # Generates a date select that discards the type of the field and defaults to the date in
370
399
  # # my_date (six days after today).
371
- # select_date(my_date, :discard_type => true)
400
+ # select_date(my_date, discard_type: true)
372
401
  #
373
402
  # # Generates a date select that defaults to the date in my_date,
374
403
  # # which has fields separated by '/'.
375
- # select_date(my_date, :date_separator => '/')
404
+ # select_date(my_date, date_separator: '/')
376
405
  #
377
406
  # # Generates a date select that defaults to the datetime in my_date (six days after today)
378
407
  # # prefixed with 'payday' rather than 'date'.
379
- # select_date(my_date, :prefix => 'payday')
380
- #
381
- # # Generates a date select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
382
- # select_date(my_date, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
383
- # select_date(my_date, :prompt => {:hour => true}) # generic prompt for hours
384
- # select_date(my_date, :prompt => true) # generic prompts for all
408
+ # select_date(my_date, prefix: 'payday')
385
409
  #
410
+ # # Generates a date select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
411
+ # select_date(my_date, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
412
+ # select_date(my_date, prompt: {hour: true}) # generic prompt for hours
413
+ # select_date(my_date, prompt: true) # generic prompts for all
386
414
  def select_date(date = Date.current, options = {}, html_options = {})
387
415
  DateTimeSelector.new(date, options, html_options).select_date
388
416
  end
@@ -393,7 +421,6 @@ module ActionView
393
421
  #
394
422
  # If anything is passed in the html_options hash it will be applied to every select tag in the set.
395
423
  #
396
- # ==== Examples
397
424
  # my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds
398
425
  #
399
426
  # # Generates a time select that defaults to the time in my_time.
@@ -404,24 +431,26 @@ module ActionView
404
431
  #
405
432
  # # Generates a time select that defaults to the time in my_time,
406
433
  # # which has fields separated by ':'.
407
- # select_time(my_time, :time_separator => ':')
434
+ # select_time(my_time, time_separator: ':')
408
435
  #
409
436
  # # Generates a time select that defaults to the time in my_time,
410
437
  # # that also includes an input for seconds.
411
- # select_time(my_time, :include_seconds => true)
438
+ # select_time(my_time, include_seconds: true)
412
439
  #
413
440
  # # Generates a time select that defaults to the time in my_time, that has fields
414
441
  # # separated by ':' and includes an input for seconds.
415
- # select_time(my_time, :time_separator => ':', :include_seconds => true)
442
+ # select_time(my_time, time_separator: ':', include_seconds: true)
416
443
  #
417
444
  # # Generate a time select field with hours in the AM/PM format
418
- # select_time(my_time, :ampm => true)
445
+ # select_time(my_time, ampm: true)
419
446
  #
420
- # # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
421
- # select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
422
- # select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours
423
- # select_time(my_time, :prompt => true) # generic prompts for all
447
+ # # Generates a time select field with hours that range from 2 to 14
448
+ # select_time(my_time, start_hour: 2, end_hour: 14)
424
449
  #
450
+ # # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
451
+ # select_time(my_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
452
+ # select_time(my_time, prompt: {hour: true}) # generic prompt for hours
453
+ # select_time(my_time, prompt: true) # generic prompts for all
425
454
  def select_time(datetime = Time.current, options = {}, html_options = {})
426
455
  DateTimeSelector.new(datetime, options, html_options).select_time
427
456
  end
@@ -430,7 +459,6 @@ module ActionView
430
459
  # The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
431
460
  # Override the field name using the <tt>:field_name</tt> option, 'second' by default.
432
461
  #
433
- # ==== Examples
434
462
  # my_time = Time.now + 16.minutes
435
463
  #
436
464
  # # Generates a select field for seconds that defaults to the seconds for the time in my_time.
@@ -441,12 +469,11 @@ module ActionView
441
469
  #
442
470
  # # Generates a select field for seconds that defaults to the seconds for the time in my_time
443
471
  # # that is named 'interval' rather than 'second'.
444
- # select_second(my_time, :field_name => 'interval')
472
+ # select_second(my_time, field_name: 'interval')
445
473
  #
446
- # # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a
474
+ # # Generates a select field for seconds with a custom prompt. Use <tt>prompt: true</tt> for a
447
475
  # # generic prompt.
448
- # select_second(14, :prompt => 'Choose seconds')
449
- #
476
+ # select_second(14, prompt: 'Choose seconds')
450
477
  def select_second(datetime, options = {}, html_options = {})
451
478
  DateTimeSelector.new(datetime, options, html_options).select_second
452
479
  end
@@ -456,7 +483,6 @@ module ActionView
456
483
  # selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
457
484
  # Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
458
485
  #
459
- # ==== Examples
460
486
  # my_time = Time.now + 6.hours
461
487
  #
462
488
  # # Generates a select field for minutes that defaults to the minutes for the time in my_time.
@@ -467,12 +493,11 @@ module ActionView
467
493
  #
468
494
  # # Generates a select field for minutes that defaults to the minutes for the time in my_time
469
495
  # # that is named 'moment' rather than 'minute'.
470
- # select_minute(my_time, :field_name => 'moment')
496
+ # select_minute(my_time, field_name: 'moment')
471
497
  #
472
- # # Generates a select field for minutes with a custom prompt. Use <tt>:prompt => true</tt> for a
498
+ # # Generates a select field for minutes with a custom prompt. Use <tt>prompt: true</tt> for a
473
499
  # # generic prompt.
474
- # select_minute(14, :prompt => 'Choose minutes')
475
- #
500
+ # select_minute(14, prompt: 'Choose minutes')
476
501
  def select_minute(datetime, options = {}, html_options = {})
477
502
  DateTimeSelector.new(datetime, options, html_options).select_minute
478
503
  end
@@ -481,7 +506,6 @@ module ActionView
481
506
  # The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
482
507
  # Override the field name using the <tt>:field_name</tt> option, 'hour' by default.
483
508
  #
484
- # ==== Examples
485
509
  # my_time = Time.now + 6.hours
486
510
  #
487
511
  # # Generates a select field for hours that defaults to the hour for the time in my_time.
@@ -492,24 +516,26 @@ module ActionView
492
516
  #
493
517
  # # Generates a select field for hours that defaults to the hour for the time in my_time
494
518
  # # that is named 'stride' rather than 'hour'.
495
- # select_hour(my_time, :field_name => 'stride')
519
+ # select_hour(my_time, field_name: 'stride')
496
520
  #
497
- # # Generates a select field for hours with a custom prompt. Use <tt>:prompt => true</tt> for a
521
+ # # Generates a select field for hours with a custom prompt. Use <tt>prompt: true</tt> for a
498
522
  # # generic prompt.
499
- # select_hour(13, :prompt => 'Choose hour')
523
+ # select_hour(13, prompt: 'Choose hour')
500
524
  #
501
525
  # # Generate a select field for hours in the AM/PM format
502
- # select_hour(my_time, :ampm => true)
526
+ # select_hour(my_time, ampm: true)
503
527
  #
528
+ # # Generates a select field that includes options for hours from 2 to 14.
529
+ # select_hour(my_time, start_hour: 2, end_hour: 14)
504
530
  def select_hour(datetime, options = {}, html_options = {})
505
531
  DateTimeSelector.new(datetime, options, html_options).select_hour
506
532
  end
507
533
 
508
534
  # Returns a select tag with options for each of the days 1 through 31 with the current day selected.
509
535
  # The <tt>date</tt> can also be substituted for a day number.
536
+ # If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
510
537
  # Override the field name using the <tt>:field_name</tt> option, 'day' by default.
511
538
  #
512
- # ==== Examples
513
539
  # my_date = Time.now + 2.days
514
540
  #
515
541
  # # Generates a select field for days that defaults to the day for the date in my_date.
@@ -518,14 +544,16 @@ module ActionView
518
544
  # # Generates a select field for days that defaults to the number given.
519
545
  # select_day(5)
520
546
  #
547
+ # # Generates a select field for days that defaults to the number given, but displays it with two digits.
548
+ # select_day(5, use_two_digit_numbers: true)
549
+ #
521
550
  # # Generates a select field for days that defaults to the day for the date in my_date
522
551
  # # that is named 'due' rather than 'day'.
523
- # select_day(my_time, :field_name => 'due')
552
+ # select_day(my_time, field_name: 'due')
524
553
  #
525
- # # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a
554
+ # # Generates a select field for days with a custom prompt. Use <tt>prompt: true</tt> for a
526
555
  # # generic prompt.
527
- # select_day(5, :prompt => 'Choose day')
528
- #
556
+ # select_day(5, prompt: 'Choose day')
529
557
  def select_day(date, options = {}, html_options = {})
530
558
  DateTimeSelector.new(date, options, html_options).select_day
531
559
  end
@@ -537,37 +565,40 @@ module ActionView
537
565
  # want both numbers and names, set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer
538
566
  # to show month names as abbreviations, set the <tt>:use_short_month</tt> key in +options+ to true. If you want
539
567
  # to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
568
+ # If you want to display months with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
540
569
  # Override the field name using the <tt>:field_name</tt> option, 'month' by default.
541
570
  #
542
- # ==== Examples
543
571
  # # Generates a select field for months that defaults to the current month that
544
572
  # # will use keys like "January", "March".
545
573
  # select_month(Date.today)
546
574
  #
547
575
  # # Generates a select field for months that defaults to the current month that
548
576
  # # is named "start" rather than "month".
549
- # select_month(Date.today, :field_name => 'start')
577
+ # select_month(Date.today, field_name: 'start')
550
578
  #
551
579
  # # Generates a select field for months that defaults to the current month that
552
580
  # # will use keys like "1", "3".
553
- # select_month(Date.today, :use_month_numbers => true)
581
+ # select_month(Date.today, use_month_numbers: true)
554
582
  #
555
583
  # # Generates a select field for months that defaults to the current month that
556
584
  # # will use keys like "1 - January", "3 - March".
557
- # select_month(Date.today, :add_month_numbers => true)
585
+ # select_month(Date.today, add_month_numbers: true)
558
586
  #
559
587
  # # Generates a select field for months that defaults to the current month that
560
588
  # # will use keys like "Jan", "Mar".
561
- # select_month(Date.today, :use_short_month => true)
589
+ # select_month(Date.today, use_short_month: true)
562
590
  #
563
591
  # # Generates a select field for months that defaults to the current month that
564
592
  # # will use keys like "Januar", "Marts."
565
- # select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
593
+ # select_month(Date.today, use_month_names: %w(Januar Februar Marts ...))
566
594
  #
567
- # # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a
568
- # # generic prompt.
569
- # select_month(14, :prompt => 'Choose month')
595
+ # # Generates a select field for months that defaults to the current month that
596
+ # # will use keys with two digit numbers like "01", "03".
597
+ # select_month(Date.today, use_two_digit_numbers: true)
570
598
  #
599
+ # # Generates a select field for months with a custom prompt. Use <tt>prompt: true</tt> for a
600
+ # # generic prompt.
601
+ # select_month(14, prompt: 'Choose month')
571
602
  def select_month(date, options = {}, html_options = {})
572
603
  DateTimeSelector.new(date, options, html_options).select_month
573
604
  end
@@ -578,50 +609,53 @@ module ActionView
578
609
  # greater than <tt>:end_year</tt>. The <tt>date</tt> can also be substituted for a year given as a number.
579
610
  # Override the field name using the <tt>:field_name</tt> option, 'year' by default.
580
611
  #
581
- # ==== Examples
582
612
  # # Generates a select field for years that defaults to the current year that
583
613
  # # has ascending year values.
584
- # select_year(Date.today, :start_year => 1992, :end_year => 2007)
614
+ # select_year(Date.today, start_year: 1992, end_year: 2007)
585
615
  #
586
616
  # # Generates a select field for years that defaults to the current year that
587
617
  # # is named 'birth' rather than 'year'.
588
- # select_year(Date.today, :field_name => 'birth')
618
+ # select_year(Date.today, field_name: 'birth')
589
619
  #
590
620
  # # Generates a select field for years that defaults to the current year that
591
621
  # # has descending year values.
592
- # select_year(Date.today, :start_year => 2005, :end_year => 1900)
622
+ # select_year(Date.today, start_year: 2005, end_year: 1900)
593
623
  #
594
624
  # # Generates a select field for years that defaults to the year 2006 that
595
625
  # # has ascending year values.
596
- # select_year(2006, :start_year => 2000, :end_year => 2010)
626
+ # select_year(2006, start_year: 2000, end_year: 2010)
597
627
  #
598
- # # Generates a select field for years with a custom prompt. Use <tt>:prompt => true</tt> for a
628
+ # # Generates a select field for years with a custom prompt. Use <tt>prompt: true</tt> for a
599
629
  # # generic prompt.
600
- # select_year(14, :prompt => 'Choose year')
601
- #
630
+ # select_year(14, prompt: 'Choose year')
602
631
  def select_year(date, options = {}, html_options = {})
603
632
  DateTimeSelector.new(date, options, html_options).select_year
604
633
  end
605
634
 
606
635
  # Returns an html time tag for the given date or time.
607
636
  #
608
- # ==== Examples
609
637
  # time_tag Date.today # =>
610
638
  # <time datetime="2010-11-04">November 04, 2010</time>
611
639
  # time_tag Time.now # =>
612
640
  # <time datetime="2010-11-04T17:55:45+01:00">November 04, 2010 17:55</time>
613
641
  # time_tag Date.yesterday, 'Yesterday' # =>
614
642
  # <time datetime="2010-11-03">Yesterday</time>
615
- # time_tag Date.today, :pubdate => true # =>
643
+ # time_tag Date.today, pubdate: true # =>
616
644
  # <time datetime="2010-11-04" pubdate="pubdate">November 04, 2010</time>
617
- #
618
- def time_tag(date_or_time, *args)
645
+ # time_tag Date.today, datetime: Date.today.strftime('%G-W%V') # =>
646
+ # <time datetime="2010-W44">November 04, 2010</time>
647
+ #
648
+ # <%= time_tag Time.now do %>
649
+ # <span>Right now</span>
650
+ # <% end %>
651
+ # # => <time datetime="2010-11-04T17:55:45+01:00"><span>Right now</span></time>
652
+ def time_tag(date_or_time, *args, &block)
619
653
  options = args.extract_options!
620
654
  format = options.delete(:format) || :long
621
655
  content = args.first || I18n.l(date_or_time, :format => format)
622
- datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.rfc3339
656
+ datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601
623
657
 
624
- content_tag(:time, content, options.reverse_merge(:datetime => datetime))
658
+ content_tag(:time, content, options.reverse_merge(:datetime => datetime), &block)
625
659
  end
626
660
  end
627
661
 
@@ -659,11 +693,7 @@ module ActionView
659
693
  @options[:discard_minute] ||= true if @options[:discard_hour]
660
694
  @options[:discard_second] ||= true unless @options[:include_seconds] && !@options[:discard_minute]
661
695
 
662
- # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
663
- # valid (otherwise it could be 31 and February wouldn't be a valid date)
664
- if @datetime && @options[:discard_day] && !@options[:discard_month]
665
- @datetime = @datetime.change(:day => 1)
666
- end
696
+ set_day_if_discarded
667
697
 
668
698
  if @options[:tag] && @options[:ignore_date]
669
699
  select_time
@@ -686,11 +716,7 @@ module ActionView
686
716
  @options[:discard_month] ||= true unless order.include?(:month)
687
717
  @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
688
718
 
689
- # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
690
- # valid (otherwise it could be 31 and February wouldn't be a valid date)
691
- if @datetime && @options[:discard_day] && !@options[:discard_month]
692
- @datetime = @datetime.change(:day => 1)
693
- end
719
+ set_day_if_discarded
694
720
 
695
721
  [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
696
722
 
@@ -733,7 +759,11 @@ module ActionView
733
759
  if @options[:use_hidden] || @options[:discard_hour]
734
760
  build_hidden(:hour, hour)
735
761
  else
736
- build_options_and_select(:hour, hour, :end => 23, :ampm => @options[:ampm])
762
+ options = {}
763
+ options[:ampm] = @options[:ampm] || false
764
+ options[:start] = @options[:start_hour] || 0
765
+ options[:end] = @options[:end_hour] || 23
766
+ build_options_and_select(:hour, hour, options)
737
767
  end
738
768
  end
739
769
 
@@ -792,6 +822,14 @@ module ActionView
792
822
  end
793
823
  end
794
824
 
825
+ # If the day is hidden, the day should be set to the 1st so all month and year choices are
826
+ # valid. Otherwise, February 31st or February 29th, 2011 can be selected, which are invalid.
827
+ def set_day_if_discarded
828
+ if @datetime && @options[:discard_day]
829
+ @datetime = @datetime.change(:day => 1)
830
+ end
831
+ end
832
+
795
833
  # Returns translated month names, but also ensures that a custom month
796
834
  # name array has a leading nil element.
797
835
  def month_names
@@ -822,6 +860,9 @@ module ActionView
822
860
  # If <tt>:use_month_numbers</tt> option is passed
823
861
  # month_name(1) => 1
824
862
  #
863
+ # If <tt>:use_two_month_numbers</tt> option is passed
864
+ # month_name(1) => '01'
865
+ #
825
866
  # If <tt>:add_month_numbers</tt> option is passed
826
867
  # month_name(1) => "1 - January"
827
868
  def month_name(number)
@@ -841,7 +882,16 @@ module ActionView
841
882
  end
842
883
 
843
884
  def translated_date_order
844
- I18n.translate(:'date.order', :locale => @options[:locale]) || []
885
+ date_order = I18n.translate(:'date.order', :locale => @options[:locale], :default => [])
886
+ date_order = date_order.map { |element| element.to_sym }
887
+
888
+ forbidden_elements = date_order - [:year, :month, :day]
889
+ if forbidden_elements.any?
890
+ raise StandardError,
891
+ "#{@options[:locale]}.date.order only accepts :year, :month and :day"
892
+ end
893
+
894
+ date_order
845
895
  end
846
896
 
847
897
  # Build full select tag from date type and options.
@@ -850,21 +900,30 @@ module ActionView
850
900
  end
851
901
 
852
902
  # Build select option html from date value and options.
853
- # build_options(15, :start => 1, :end => 31)
903
+ # build_options(15, start: 1, end: 31)
854
904
  # => "<option value="1">1</option>
855
905
  # <option value="2">2</option>
856
906
  # <option value="3">3</option>..."
857
907
  #
908
+ # If <tt>use_two_digit_numbers: true</tt> option is passed
909
+ # build_options(15, start: 1, end: 31, use_two_digit_numbers: true)
910
+ # => "<option value="1">01</option>
911
+ # <option value="2">02</option>
912
+ # <option value="3">03</option>..."
913
+ #
858
914
  # If <tt>:step</tt> options is passed
859
- # build_options(15, :start => 1, :end => 31, :step => 2)
915
+ # build_options(15, start: 1, end: 31, step: 2)
860
916
  # => "<option value="1">1</option>
861
917
  # <option value="3">3</option>
862
918
  # <option value="5">5</option>..."
863
919
  def build_options(selected, options = {})
920
+ options = {
921
+ leading_zeros: true, ampm: false, use_two_digit_numbers: false
922
+ }.merge!(options)
923
+
864
924
  start = options.delete(:start) || 0
865
925
  stop = options.delete(:end) || 59
866
926
  step = options.delete(:step) || 1
867
- options.reverse_merge!({:leading_zeros => true, :ampm => false, :use_two_digit_numbers => false})
868
927
  leading_zeros = options.delete(:leading_zeros)
869
928
 
870
929
  select_options = []
@@ -876,6 +935,7 @@ module ActionView
876
935
  text = options[:ampm] ? AMPM_TRANSLATION[i] : text
877
936
  select_options << content_tag(:option, text, tag_options)
878
937
  end
938
+
879
939
  (select_options.join("\n") + "\n").html_safe
880
940
  end
881
941
 
@@ -888,8 +948,9 @@ module ActionView
888
948
  select_options = {
889
949
  :id => input_id_from_type(type),
890
950
  :name => input_name_from_type(type)
891
- }.merge(@html_options)
892
- select_options.merge!(:disabled => 'disabled') if @options[:disabled]
951
+ }.merge!(@html_options)
952
+ select_options[:disabled] = 'disabled' if @options[:disabled]
953
+ select_options[:class] = type if @options[:with_css_classes]
893
954
 
894
955
  select_html = "\n"
895
956
  select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
@@ -900,7 +961,7 @@ module ActionView
900
961
  end
901
962
 
902
963
  # Builds a prompt option tag with supplied options or from default options.
903
- # prompt_option_tag(:month, :prompt => 'Select month')
964
+ # prompt_option_tag(:month, prompt: 'Select month')
904
965
  # => "<option value="">Select month</option>"
905
966
  def prompt_option_tag(type, options)
906
967
  prompt = case options
@@ -925,8 +986,8 @@ module ActionView
925
986
  :id => input_id_from_type(type),
926
987
  :name => input_name_from_type(type),
927
988
  :value => value
928
- }.merge(@html_options.slice(:disabled))
929
- select_options.merge!(:disabled => 'disabled') if @options[:disabled]
989
+ }.merge!(@html_options.slice(:disabled))
990
+ select_options[:disabled] = 'disabled' if @options[:disabled]
930
991
 
931
992
  tag(:input, select_options) + "\n".html_safe
932
993
  end
@@ -968,92 +1029,52 @@ module ActionView
968
1029
 
969
1030
  # Returns the separator for a given datetime component.
970
1031
  def separator(type)
1032
+ return "" if @options[:use_hidden]
1033
+
971
1034
  case type
972
- when :year
973
- @options[:discard_year] ? "" : @options[:date_separator]
974
- when :month
975
- @options[:discard_month] ? "" : @options[:date_separator]
976
- when :day
977
- @options[:discard_day] ? "" : @options[:date_separator]
1035
+ when :year, :month, :day
1036
+ @options[:"discard_#{type}"] ? "" : @options[:date_separator]
978
1037
  when :hour
979
1038
  (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
980
- when :minute
981
- @options[:discard_minute] ? "" : @options[:time_separator]
982
- when :second
983
- @options[:include_seconds] ? @options[:time_separator] : ""
1039
+ when :minute, :second
1040
+ @options[:"discard_#{type}"] ? "" : @options[:time_separator]
984
1041
  end
985
1042
  end
986
1043
  end
987
1044
 
988
- module DateHelperInstanceTag
989
- def to_date_select_tag(options = {}, html_options = {})
990
- datetime_selector(options, html_options).select_date.html_safe
991
- end
992
-
993
- def to_time_select_tag(options = {}, html_options = {})
994
- datetime_selector(options, html_options).select_time.html_safe
995
- end
996
-
997
- def to_datetime_select_tag(options = {}, html_options = {})
998
- datetime_selector(options, html_options).select_datetime.html_safe
999
- end
1000
-
1001
- private
1002
- def datetime_selector(options, html_options)
1003
- datetime = value(object) || default_datetime(options)
1004
- @auto_index ||= nil
1005
-
1006
- options = options.dup
1007
- options[:field_name] = @method_name
1008
- options[:include_position] = true
1009
- options[:prefix] ||= @object_name
1010
- options[:index] = @auto_index if @auto_index && !options.has_key?(:index)
1011
-
1012
- DateTimeSelector.new(datetime, options, html_options)
1013
- end
1014
-
1015
- def default_datetime(options)
1016
- return if options[:include_blank] || options[:prompt]
1017
-
1018
- case options[:default]
1019
- when nil
1020
- Time.current
1021
- when Date, Time
1022
- options[:default]
1023
- else
1024
- default = options[:default].dup
1025
-
1026
- # Rename :minute and :second to :min and :sec
1027
- default[:min] ||= default[:minute]
1028
- default[:sec] ||= default[:second]
1029
-
1030
- time = Time.current
1031
-
1032
- [:year, :month, :day, :hour, :min, :sec].each do |key|
1033
- default[key] ||= time.send(key)
1034
- end
1035
-
1036
- Time.utc_time(
1037
- default[:year], default[:month], default[:day],
1038
- default[:hour], default[:min], default[:sec]
1039
- )
1040
- end
1041
- end
1042
- end
1043
-
1044
- class InstanceTag #:nodoc:
1045
- include DateHelperInstanceTag
1046
- end
1047
-
1048
1045
  class FormBuilder
1046
+ # Wraps ActionView::Helpers::DateHelper#date_select for form builders:
1047
+ #
1048
+ # <%= form_for @person do |f| %>
1049
+ # <%= f.date_select :birth_date %>
1050
+ # <%= f.submit %>
1051
+ # <% end %>
1052
+ #
1053
+ # Please refer to the documentation of the base helper for details.
1049
1054
  def date_select(method, options = {}, html_options = {})
1050
1055
  @template.date_select(@object_name, method, objectify_options(options), html_options)
1051
1056
  end
1052
1057
 
1058
+ # Wraps ActionView::Helpers::DateHelper#time_select for form builders:
1059
+ #
1060
+ # <%= form_for @race do |f| %>
1061
+ # <%= f.time_select :average_lap %>
1062
+ # <%= f.submit %>
1063
+ # <% end %>
1064
+ #
1065
+ # Please refer to the documentation of the base helper for details.
1053
1066
  def time_select(method, options = {}, html_options = {})
1054
1067
  @template.time_select(@object_name, method, objectify_options(options), html_options)
1055
1068
  end
1056
1069
 
1070
+ # Wraps ActionView::Helpers::DateHelper#datetime_select for form builders:
1071
+ #
1072
+ # <%= form_for @person do |f| %>
1073
+ # <%= f.time_select :last_request_at %>
1074
+ # <%= f.submit %>
1075
+ # <% end %>
1076
+ #
1077
+ # Please refer to the documentation of the base helper for details.
1057
1078
  def datetime_select(method, options = {}, html_options = {})
1058
1079
  @template.datetime_select(@object_name, method, objectify_options(options), html_options)
1059
1080
  end