actionpack 3.1.0.beta1 → 3.1.0.rc1

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 (52) hide show
  1. data/CHANGELOG +57 -4
  2. data/README.rdoc +5 -5
  3. data/lib/abstract_controller/base.rb +25 -13
  4. data/lib/abstract_controller/callbacks.rb +2 -2
  5. data/lib/abstract_controller/layouts.rb +3 -3
  6. data/lib/abstract_controller/rendering.rb +22 -6
  7. data/lib/abstract_controller/url_for.rb +6 -0
  8. data/lib/abstract_controller/view_paths.rb +1 -1
  9. data/lib/action_controller/log_subscriber.rb +3 -1
  10. data/lib/action_controller/metal/compatibility.rb +4 -7
  11. data/lib/action_controller/metal/implicit_render.rb +7 -9
  12. data/lib/action_controller/metal/instrumentation.rb +1 -1
  13. data/lib/action_controller/metal/params_wrapper.rb +37 -26
  14. data/lib/action_controller/metal/request_forgery_protection.rb +4 -1
  15. data/lib/action_controller/metal/responder.rb +6 -1
  16. data/lib/action_controller/metal/url_for.rb +21 -0
  17. data/lib/action_controller/test_case.rb +6 -1
  18. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +1 -1
  19. data/lib/action_dispatch/http/cache.rb +12 -14
  20. data/lib/action_dispatch/http/rack_cache.rb +6 -2
  21. data/lib/action_dispatch/http/response.rb +41 -15
  22. data/lib/action_dispatch/http/url.rb +1 -1
  23. data/lib/action_dispatch/middleware/cookies.rb +3 -3
  24. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +1 -1
  25. data/lib/action_dispatch/routing.rb +3 -3
  26. data/lib/action_dispatch/routing/mapper.rb +33 -28
  27. data/lib/action_dispatch/routing/route_set.rb +6 -3
  28. data/lib/action_dispatch/routing/url_for.rb +4 -4
  29. data/lib/action_dispatch/testing/assertions/selector.rb +1 -1
  30. data/lib/action_dispatch/testing/performance_test.rb +6 -13
  31. data/lib/action_dispatch/testing/test_process.rb +1 -1
  32. data/lib/action_pack/version.rb +1 -1
  33. data/lib/action_view.rb +1 -0
  34. data/lib/action_view/base.rb +5 -5
  35. data/lib/action_view/helpers/asset_paths.rb +0 -1
  36. data/lib/action_view/helpers/atom_feed_helper.rb +6 -6
  37. data/lib/action_view/helpers/cache_helper.rb +1 -1
  38. data/lib/action_view/helpers/capture_helper.rb +6 -2
  39. data/lib/action_view/helpers/date_helper.rb +119 -75
  40. data/lib/action_view/helpers/form_helper.rb +26 -36
  41. data/lib/action_view/helpers/form_options_helper.rb +2 -2
  42. data/lib/action_view/helpers/form_tag_helper.rb +6 -6
  43. data/lib/action_view/helpers/translation_helper.rb +4 -4
  44. data/lib/action_view/helpers/url_helper.rb +1 -1
  45. data/lib/action_view/lookup_context.rb +5 -5
  46. data/lib/action_view/path_set.rb +1 -1
  47. data/lib/action_view/template.rb +5 -5
  48. data/lib/action_view/template/error.rb +2 -0
  49. data/lib/action_view/template/handlers/erb.rb +0 -1
  50. data/lib/action_view/template/resolver.rb +37 -25
  51. data/lib/sprockets/railtie.rb +3 -3
  52. metadata +8 -8
@@ -224,6 +224,7 @@ module ActionDispatch
224
224
  self.valid_conditions.push(:controller, :action)
225
225
 
226
226
  @append = []
227
+ @prepend = []
227
228
  @disable_clear_and_finalize = false
228
229
  clear!
229
230
  end
@@ -232,7 +233,6 @@ module ActionDispatch
232
233
  clear! unless @disable_clear_and_finalize
233
234
  eval_block(block)
234
235
  finalize! unless @disable_clear_and_finalize
235
-
236
236
  nil
237
237
  end
238
238
 
@@ -240,6 +240,10 @@ module ActionDispatch
240
240
  @append << block
241
241
  end
242
242
 
243
+ def prepend(&block)
244
+ @prepend << block
245
+ end
246
+
243
247
  def eval_block(block)
244
248
  if block.arity == 1
245
249
  raise "You are using the old router DSL which has been removed in Rails 3.1. " <<
@@ -262,8 +266,6 @@ module ActionDispatch
262
266
  end
263
267
 
264
268
  def clear!
265
- # Clear the controller cache so we may discover new ones
266
- @controller_constraints = nil
267
269
  @finalized = false
268
270
  routes.clear
269
271
  named_routes.clear
@@ -271,6 +273,7 @@ module ActionDispatch
271
273
  :parameters_key => PARAMETERS_KEY,
272
274
  :request_class => request_class
273
275
  )
276
+ @prepend.each { |blk| eval_block(blk) }
274
277
  end
275
278
 
276
279
  def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
@@ -131,10 +131,10 @@ module ActionDispatch
131
131
  #
132
132
  # Examples:
133
133
  #
134
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080' # => 'http://somehost.org:8080/tasks/testing'
135
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok'
136
- # url_for :controller => 'tasks', :action => 'testing', :trailing_slash=>true # => 'http://somehost.org/tasks/testing/'
137
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33'
134
+ # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080' # => 'http://somehost.org:8080/tasks/testing'
135
+ # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok'
136
+ # url_for :controller => 'tasks', :action => 'testing', :trailing_slash => true # => 'http://somehost.org/tasks/testing/'
137
+ # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33'
138
138
  def url_for(options = nil)
139
139
  case options
140
140
  when String
@@ -169,7 +169,7 @@ module ActionDispatch
169
169
  # assert_select "title", "Welcome"
170
170
  #
171
171
  # # Page title is "Welcome" and there is only one title element
172
- # assert_select "title", {:count=>1, :text=>"Welcome"},
172
+ # assert_select "title", {:count => 1, :text => "Welcome"},
173
173
  # "Wrong title or more than one title element"
174
174
  #
175
175
  # # Page contains no forms
@@ -1,17 +1,10 @@
1
1
  require 'active_support/testing/performance'
2
2
 
3
- begin
4
- module ActionDispatch
5
- # An integration test that runs a code profiler on your test methods.
6
- # Profiling output for combinations of each test method, measurement, and
7
- # output format are written to your tmp/performance directory.
8
- #
9
- # By default, process_time is measured and both flat and graph_html output
10
- # formats are written, so you'll have two output files per test method.
11
- class PerformanceTest < ActionDispatch::IntegrationTest
12
- include ActiveSupport::Testing::Performance
13
- end
3
+ module ActionDispatch
4
+ # An integration test that runs a code profiler on your test methods.
5
+ # Profiling output for combinations of each test method, measurement, and
6
+ # output format are written to your tmp/performance directory.
7
+ class PerformanceTest < ActionDispatch::IntegrationTest
8
+ include ActiveSupport::Testing::Performance
14
9
  end
15
- rescue NameError
16
- $stderr.puts "Specify ruby-prof as application's dependency in Gemfile to run benchmarks."
17
10
  end
@@ -29,7 +29,7 @@ module ActionDispatch
29
29
  @response.redirect_url
30
30
  end
31
31
 
32
- # Shortcut for <tt>ARack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
32
+ # Shortcut for <tt>Rack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
33
33
  #
34
34
  # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
35
35
  #
@@ -3,7 +3,7 @@ module ActionPack
3
3
  MAJOR = 3
4
4
  MINOR = 1
5
5
  TINY = 0
6
- PRE = "beta1"
6
+ PRE = "rc1"
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
9
  end
@@ -50,6 +50,7 @@ module ActionView
50
50
  autoload :Resolver
51
51
  autoload :PathResolver
52
52
  autoload :FileSystemResolver
53
+ autoload :OptimizedFileSystemResolver
53
54
  autoload :FallbackFileSystemResolver
54
55
  end
55
56
 
@@ -85,11 +85,11 @@ module ActionView #:nodoc:
85
85
  #
86
86
  # Here are some basic examples:
87
87
  #
88
- # xml.em("emphasized") # => <em>emphasized</em>
89
- # xml.em { xml.b("emph & bold") } # => <em><b>emph &amp; bold</b></em>
90
- # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
91
- # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
92
- # # NOTE: order of attributes is not specified.
88
+ # xml.em("emphasized") # => <em>emphasized</em>
89
+ # xml.em { xml.b("emph & bold") } # => <em><b>emph &amp; bold</b></em>
90
+ # xml.a("A Link", "href" => "http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
91
+ # xml.target("name" => "compile", "option" => "fast") # => <target option="fast" name="compile"\>
92
+ # # NOTE: order of attributes is not specified.
93
93
  #
94
94
  # Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following:
95
95
  #
@@ -1,5 +1,4 @@
1
1
  require 'active_support/core_ext/file'
2
- require 'action_view/helpers/asset_paths'
3
2
 
4
3
  module ActionView
5
4
  module Helpers
@@ -34,7 +34,7 @@ module ActionView
34
34
  # feed.title("My great blog!")
35
35
  # feed.updated(@posts.first.created_at)
36
36
  #
37
- # for post in @posts
37
+ # @posts.each do |post|
38
38
  # feed.entry(post) do |entry|
39
39
  # entry.title(post.title)
40
40
  # entry.content(post.body, :type => 'html')
@@ -66,7 +66,7 @@ module ActionView
66
66
  # feed.updated((@posts.first.created_at))
67
67
  # feed.tag!(openSearch:totalResults, 10)
68
68
  #
69
- # for post in @posts
69
+ # @posts.each do |post|
70
70
  # feed.entry(post) do |entry|
71
71
  # entry.title(post.title)
72
72
  # entry.content(post.body, :type => 'html')
@@ -81,8 +81,8 @@ module ActionView
81
81
  #
82
82
  # The Atom spec defines five elements (content rights title subtitle
83
83
  # summary) which may directly contain xhtml content if :type => 'xhtml'
84
- # is specified as an attribute. If so, this helper will take care of
85
- # the enclosing div and xhtml namespace declaration. Example usage:
84
+ # is specified as an attribute. If so, this helper will take care of
85
+ # the enclosing div and xhtml namespace declaration. Example usage:
86
86
  #
87
87
  # entry.summary :type => 'xhtml' do |xhtml|
88
88
  # xhtml.p pluralize(order.line_items.count, "line item")
@@ -91,8 +91,8 @@ module ActionView
91
91
  # end
92
92
  #
93
93
  #
94
- # atom_feed yields an AtomFeedBuilder instance. Nested elements yield
95
- # an AtomBuilder instance.
94
+ # <tt>atom_feed</tt> yields an +AtomFeedBuilder+ instance. Nested elements yield
95
+ # an +AtomBuilder+ instance.
96
96
  def atom_feed(options = {}, &block)
97
97
  if options[:schema_date]
98
98
  options[:schema_date] = options[:schema_date].strftime("%Y-%m-%d") if options[:schema_date].respond_to?(:strftime)
@@ -3,7 +3,7 @@ module ActionView
3
3
  module Helpers
4
4
  module CacheHelper
5
5
  # This helper exposes a method for caching fragments of a view
6
- # rather than an entire action or page. This technique is useful
6
+ # rather than an entire action or page. This technique is useful
7
7
  # caching pieces like menus, lists of newstopics, static HTML
8
8
  # fragments, and so on. This method takes a block that contains
9
9
  # the content you wish to cache.
@@ -135,8 +135,12 @@ module ActionView
135
135
  # for elements that will be fragment cached.
136
136
  def content_for(name, content = nil, &block)
137
137
  content = capture(&block) if block_given?
138
- result = @view_flow.append(name, content) if content
139
- result unless content
138
+ if content
139
+ @view_flow.append(name, content)
140
+ nil
141
+ else
142
+ @view_flow.get(name)
143
+ end
140
144
  end
141
145
 
142
146
  # The same as +content_for+ but when used with streaming flushes
@@ -12,14 +12,14 @@ module ActionView
12
12
  # select-type methods share a number of common options that are as follows:
13
13
  #
14
14
  # * <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 select_month method.
15
+ # would give birthday[month] instead of date[month] if passed to the <tt>select_month</tt> method.
16
16
  # * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date.
17
17
  # * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true,
18
- # the select_month method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of
19
- # "date[month]".
18
+ # the <tt>select_month</tt> method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead
19
+ # of "date[month]".
20
20
  module DateHelper
21
21
  # Reports the approximate distance in time between two Time or Date 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
22
+ # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs.
23
23
  # Distances are reported based on the following table:
24
24
  #
25
25
  # 0 <-> 29 secs # => less than a minute
@@ -94,9 +94,20 @@ module ActionView
94
94
  when 43200..86399 then locale.t :about_x_months, :count => 1
95
95
  when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
96
96
  else
97
- distance_in_years = distance_in_minutes / 525600
98
- minute_offset_for_leap_year = (distance_in_years / 4) * 1440
99
- remainder = ((distance_in_minutes - minute_offset_for_leap_year) % 525600)
97
+ fyear = from_time.year
98
+ fyear += 1 if from_time.month >= 3
99
+ tyear = to_time.year
100
+ tyear -= 1 if to_time.month < 3
101
+ leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
102
+ minute_offset_for_leap_year = leap_years * 1440
103
+ # Discount the leap year days when calculating year distance.
104
+ # e.g. if there are 20 leap year days between 2 dates having the same day
105
+ # and month then the based on 365 days calculation
106
+ # the distance in years will come out to over 80 years when in written
107
+ # english it would read better as about 80 years.
108
+ minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
109
+ remainder = (minutes_with_offset % 525600)
110
+ distance_in_years = (minutes_with_offset / 525600)
100
111
  if remainder < 131400
101
112
  locale.t(:about_x_years, :count => distance_in_years)
102
113
  elsif remainder < 394200
@@ -108,7 +119,7 @@ module ActionView
108
119
  end
109
120
  end
110
121
 
111
- # Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
122
+ # Like <tt>distance_of_time_in_words</tt>, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
112
123
  #
113
124
  # ==== Examples
114
125
  # time_ago_in_words(3.minutes.from_now) # => 3 minutes
@@ -165,7 +176,7 @@ module ActionView
165
176
  # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
166
177
  #
167
178
  # ==== Examples
168
- # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
179
+ # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute.
169
180
  # date_select("post", "written_on")
170
181
  #
171
182
  # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute,
@@ -186,7 +197,7 @@ module ActionView
186
197
  # # lacking a year field.
187
198
  # date_select("user", "birthday", :order => [:month, :day])
188
199
  #
189
- # # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute
200
+ # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
190
201
  # # which is initially set to the date 3 days from the current date
191
202
  # date_select("post", "written_on", :default => 3.days.from_now)
192
203
  #
@@ -194,7 +205,7 @@ module ActionView
194
205
  # # that will have a default day of 20.
195
206
  # date_select("credit_card", "bill_due", :default => { :day => 20 })
196
207
  #
197
- # # Generates a date select with custom prompts
208
+ # # Generates a date select with custom prompts.
198
209
  # date_select("post", "written_on", :prompt => { :day => 'Select day', :month => 'Select month', :year => 'Select year' })
199
210
  #
200
211
  # The selects are prepared for multi-parameter assignment to an Active Record object.
@@ -207,29 +218,34 @@ module ActionView
207
218
 
208
219
  # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a
209
220
  # specified time-based attribute (identified by +method+) on an object assigned to the template (identified by
210
- # +object+). You can include the seconds with <tt>:include_seconds</tt>.
221
+ # +object+). You can include the seconds with <tt>:include_seconds</tt>. You can get hours in the AM/PM format
222
+ # with <tt>:ampm</tt> option.
211
223
  #
212
224
  # This method will also generate 3 input hidden tags, for the actual year, month and day unless the option
213
- # <tt>:ignore_date</tt> is set to +true+.
225
+ # <tt>:ignore_date</tt> is set to +true+. If you set the <tt>:ignore_date</tt> to +true+, you must have a
226
+ # +date_select+ on the same method within the form otherwise an exception will be raised.
214
227
  #
215
228
  # If anything is passed in the html_options hash it will be applied to every select tag in the set.
216
229
  #
217
230
  # ==== Examples
218
- # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute
231
+ # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute.
219
232
  # time_select("post", "sunrise")
220
233
  #
221
234
  # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in
222
235
  # # the sunrise attribute.
223
236
  # time_select("post", "start_time", :include_seconds => true)
224
237
  #
225
- # # You can set the :minute_step to 15 which will give you: 00, 15, 30 and 45.
238
+ # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45.
226
239
  # time_select 'game', 'game_time', {:minute_step => 15}
227
240
  #
228
- # # Creates a time select tag with a custom prompt. Use :prompt => true for generic prompts.
241
+ # # Creates a time select tag with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
229
242
  # time_select("post", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'})
230
243
  # time_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours
231
244
  # time_select("post", "written_on", :prompt => true) # generic prompts for all
232
245
  #
246
+ # # You can set :ampm option to true which will show the hours as: 12 PM, 01 AM .. 11 PM.
247
+ # time_select 'game', 'game_time', {:ampm => true}
248
+ #
233
249
  # The selects are prepared for multi-parameter assignment to an Active Record object.
234
250
  #
235
251
  # 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
@@ -246,7 +262,7 @@ module ActionView
246
262
  #
247
263
  # ==== Examples
248
264
  # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on
249
- # # attribute
265
+ # # attribute.
250
266
  # datetime_select("post", "written_on")
251
267
  #
252
268
  # # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
@@ -257,11 +273,14 @@ module ActionView
257
273
  # # be stored in the trip variable in the departing attribute.
258
274
  # datetime_select("trip", "departing", :default => 3.days.from_now)
259
275
  #
276
+ # # Generate a datetime select with hours in the AM/PM format
277
+ # datetime_select("post", "written_on", :ampm => true)
278
+ #
260
279
  # # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable
261
280
  # # as the written_on attribute.
262
281
  # datetime_select("post", "written_on", :discard_type => true)
263
282
  #
264
- # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts.
283
+ # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
265
284
  # datetime_select("post", "written_on", :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
266
285
  # datetime_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours
267
286
  # datetime_select("post", "written_on", :prompt => true) # generic prompts for all
@@ -283,7 +302,7 @@ module ActionView
283
302
  # ==== Examples
284
303
  # my_date_time = Time.now + 4.days
285
304
  #
286
- # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
305
+ # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today).
287
306
  # select_datetime(my_date_time)
288
307
  #
289
308
  # # Generates a datetime select that defaults to today (no specified datetime)
@@ -306,11 +325,14 @@ module ActionView
306
325
  # # my_date_time (four days after today)
307
326
  # select_datetime(my_date_time, :discard_type => true)
308
327
  #
328
+ # # Generate a datetime field with hours in the AM/PM format
329
+ # select_datetime(my_date_time, :ampm => true)
330
+ #
309
331
  # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
310
332
  # # prefixed with 'payday' rather than 'date'
311
333
  # select_datetime(my_date_time, :prefix => 'payday')
312
334
  #
313
- # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts.
335
+ # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
314
336
  # select_datetime(my_date_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
315
337
  # select_datetime(my_date_time, :prompt => {:hour => true}) # generic prompt for hours
316
338
  # select_datetime(my_date_time, :prompt => true) # generic prompts for all
@@ -329,10 +351,10 @@ module ActionView
329
351
  # ==== Examples
330
352
  # my_date = Time.today + 6.days
331
353
  #
332
- # # Generates a date select that defaults to the date in my_date (six days after today)
354
+ # # Generates a date select that defaults to the date in my_date (six days afteri today).
333
355
  # select_date(my_date)
334
356
  #
335
- # # Generates a date select that defaults to today (no specified date)
357
+ # # Generates a date select that defaults to today (no specified date).
336
358
  # select_date()
337
359
  #
338
360
  # # Generates a date select that defaults to the date in my_date (six days after today)
@@ -340,18 +362,18 @@ module ActionView
340
362
  # select_date(my_date, :order => [:year, :month, :day])
341
363
  #
342
364
  # # Generates a date select that discards the type of the field and defaults to the date in
343
- # # my_date (six days after today)
365
+ # # my_date (six days after today).
344
366
  # select_date(my_date, :discard_type => true)
345
367
  #
346
368
  # # Generates a date select that defaults to the date in my_date,
347
- # # which has fields separated by '/'
369
+ # # which has fields separated by '/'.
348
370
  # select_date(my_date, :date_separator => '/')
349
371
  #
350
372
  # # Generates a date select that defaults to the datetime in my_date (six days after today)
351
- # # prefixed with 'payday' rather than 'date'
373
+ # # prefixed with 'payday' rather than 'date'.
352
374
  # select_date(my_date, :prefix => 'payday')
353
375
  #
354
- # # Generates a date select with a custom prompt. Use :prompt=>true for generic prompts.
376
+ # # Generates a date select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
355
377
  # select_date(my_date, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
356
378
  # select_date(my_date, :prompt => {:hour => true}) # generic prompt for hours
357
379
  # select_date(my_date, :prompt => true) # generic prompts for all
@@ -360,7 +382,7 @@ module ActionView
360
382
  DateTimeSelector.new(date, options, html_options).select_date
361
383
  end
362
384
 
363
- # Returns a set of html select-tags (one for hour and minute)
385
+ # Returns a set of html select-tags (one for hour and minute).
364
386
  # You can set <tt>:time_separator</tt> key to format the output, and
365
387
  # the <tt>:include_seconds</tt> option to include an input for seconds.
366
388
  #
@@ -369,25 +391,28 @@ module ActionView
369
391
  # ==== Examples
370
392
  # my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds
371
393
  #
372
- # # Generates a time select that defaults to the time in my_time
394
+ # # Generates a time select that defaults to the time in my_time.
373
395
  # select_time(my_time)
374
396
  #
375
- # # Generates a time select that defaults to the current time (no specified time)
397
+ # # Generates a time select that defaults to the current time (no specified time).
376
398
  # select_time()
377
399
  #
378
400
  # # Generates a time select that defaults to the time in my_time,
379
- # # which has fields separated by ':'
401
+ # # which has fields separated by ':'.
380
402
  # select_time(my_time, :time_separator => ':')
381
403
  #
382
404
  # # Generates a time select that defaults to the time in my_time,
383
- # # that also includes an input for seconds
405
+ # # that also includes an input for seconds.
384
406
  # select_time(my_time, :include_seconds => true)
385
407
  #
386
408
  # # Generates a time select that defaults to the time in my_time, that has fields
387
- # # separated by ':' and includes an input for seconds
409
+ # # separated by ':' and includes an input for seconds.
388
410
  # select_time(my_time, :time_separator => ':', :include_seconds => true)
389
411
  #
390
- # # Generates a time select with a custom prompt. Use :prompt=>true for generic prompts.
412
+ # # Generate a time select field with hours in the AM/PM format
413
+ # select_time(my_time, :ampm => true)
414
+ #
415
+ # # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
391
416
  # select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
392
417
  # select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours
393
418
  # select_time(my_time, :prompt => true) # generic prompts for all
@@ -403,17 +428,17 @@ module ActionView
403
428
  # ==== Examples
404
429
  # my_time = Time.now + 16.minutes
405
430
  #
406
- # # Generates a select field for seconds that defaults to the seconds for the time in my_time
431
+ # # Generates a select field for seconds that defaults to the seconds for the time in my_time.
407
432
  # select_second(my_time)
408
433
  #
409
- # # Generates a select field for seconds that defaults to the number given
434
+ # # Generates a select field for seconds that defaults to the number given.
410
435
  # select_second(33)
411
436
  #
412
437
  # # Generates a select field for seconds that defaults to the seconds for the time in my_time
413
- # # that is named 'interval' rather than 'second'
438
+ # # that is named 'interval' rather than 'second'.
414
439
  # select_second(my_time, :field_name => 'interval')
415
440
  #
416
- # # Generates a select field for seconds with a custom prompt. Use :prompt=>true for a
441
+ # # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a
417
442
  # # generic prompt.
418
443
  # select_minute(14, :prompt => 'Choose seconds')
419
444
  #
@@ -429,17 +454,17 @@ module ActionView
429
454
  # ==== Examples
430
455
  # my_time = Time.now + 6.hours
431
456
  #
432
- # # Generates a select field for minutes that defaults to the minutes for the time in my_time
457
+ # # Generates a select field for minutes that defaults to the minutes for the time in my_tiime.
433
458
  # select_minute(my_time)
434
459
  #
435
- # # Generates a select field for minutes that defaults to the number given
460
+ # # Generates a select field for minutes that defaults to the number given.
436
461
  # select_minute(14)
437
462
  #
438
463
  # # Generates a select field for minutes that defaults to the minutes for the time in my_time
439
- # # that is named 'stride' rather than 'second'
464
+ # # that is named 'stride' rather than 'second'.
440
465
  # select_minute(my_time, :field_name => 'stride')
441
466
  #
442
- # # Generates a select field for minutes with a custom prompt. Use :prompt=>true for a
467
+ # # Generates a select field for minutes with a custom prompt. Use <tt>:prompt => true</tt> for a
443
468
  # # generic prompt.
444
469
  # select_minute(14, :prompt => 'Choose minutes')
445
470
  #
@@ -454,20 +479,23 @@ module ActionView
454
479
  # ==== Examples
455
480
  # my_time = Time.now + 6.hours
456
481
  #
457
- # # Generates a select field for hours that defaults to the hour for the time in my_time
482
+ # # Generates a select field for hours that defaults to the hour for the time in my_time.
458
483
  # select_hour(my_time)
459
484
  #
460
- # # Generates a select field for hours that defaults to the number given
485
+ # # Generates a select field for hours that defaults to the number given.
461
486
  # select_hour(13)
462
487
  #
463
488
  # # Generates a select field for hours that defaults to the minutes for the time in my_time
464
- # # that is named 'stride' rather than 'second'
489
+ # # that is named 'stride' rather than 'second'.
465
490
  # select_hour(my_time, :field_name => 'stride')
466
491
  #
467
- # # Generates a select field for hours with a custom prompt. Use :prompt => true for a
492
+ # # Generates a select field for hours with a custom prompt. Use <tt>:prompt => true</tt> for a
468
493
  # # generic prompt.
469
494
  # select_hour(13, :prompt => 'Choose hour')
470
495
  #
496
+ # # Generate a select field for hours in the AM/PM format
497
+ # select_hour(my_time, :ampm => true)
498
+ #
471
499
  def select_hour(datetime, options = {}, html_options = {})
472
500
  DateTimeSelector.new(datetime, options, html_options).select_hour
473
501
  end
@@ -479,17 +507,17 @@ module ActionView
479
507
  # ==== Examples
480
508
  # my_date = Time.today + 2.days
481
509
  #
482
- # # Generates a select field for days that defaults to the day for the date in my_date
510
+ # # Generates a select field for days that defaults to the day for the date in my_date.
483
511
  # select_day(my_time)
484
512
  #
485
- # # Generates a select field for days that defaults to the number given
513
+ # # Generates a select field for days that defaults to the number given.
486
514
  # select_day(5)
487
515
  #
488
516
  # # Generates a select field for days that defaults to the day for the date in my_date
489
- # # that is named 'due' rather than 'day'
517
+ # # that is named 'due' rather than 'day'.
490
518
  # select_day(my_time, :field_name => 'due')
491
519
  #
492
- # # Generates a select field for days with a custom prompt. Use :prompt => true for a
520
+ # # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a
493
521
  # # generic prompt.
494
522
  # select_day(5, :prompt => 'Choose day')
495
523
  #
@@ -512,7 +540,7 @@ module ActionView
512
540
  # select_month(Date.today)
513
541
  #
514
542
  # # Generates a select field for months that defaults to the current month that
515
- # # is named "start" rather than "month"
543
+ # # is named "start" rather than "month".
516
544
  # select_month(Date.today, :field_name => 'start')
517
545
  #
518
546
  # # Generates a select field for months that defaults to the current month that
@@ -531,7 +559,7 @@ module ActionView
531
559
  # # will use keys like "Januar", "Marts."
532
560
  # select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
533
561
  #
534
- # # Generates a select field for months with a custom prompt. Use :prompt => true for a
562
+ # # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a
535
563
  # # generic prompt.
536
564
  # select_month(14, :prompt => 'Choose month')
537
565
  #
@@ -547,22 +575,22 @@ module ActionView
547
575
  #
548
576
  # ==== Examples
549
577
  # # Generates a select field for years that defaults to the current year that
550
- # # has ascending year values
578
+ # # has ascending year values.
551
579
  # select_year(Date.today, :start_year => 1992, :end_year => 2007)
552
580
  #
553
581
  # # Generates a select field for years that defaults to the current year that
554
- # # is named 'birth' rather than 'year'
582
+ # # is named 'birth' rather than 'year'.
555
583
  # select_year(Date.today, :field_name => 'birth')
556
584
  #
557
585
  # # Generates a select field for years that defaults to the current year that
558
- # # has descending year values
586
+ # # has descending year values.
559
587
  # select_year(Date.today, :start_year => 2005, :end_year => 1900)
560
588
  #
561
589
  # # Generates a select field for years that defaults to the year 2006 that
562
- # # has ascending year values
590
+ # # has ascending year values.
563
591
  # select_year(2006, :start_year => 2000, :end_year => 2010)
564
592
  #
565
- # # Generates a select field for years with a custom prompt. Use :prompt => true for a
593
+ # # Generates a select field for years with a custom prompt. Use <tt>:prompt => true</tt> for a
566
594
  # # generic prompt.
567
595
  # select_year(14, :prompt => 'Choose year')
568
596
  #
@@ -601,6 +629,15 @@ module ActionView
601
629
  :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6
602
630
  }.freeze
603
631
 
632
+ AMPM_TRANSLATION = Hash[
633
+ [[0, "12 AM"], [1, "01 AM"], [2, "02 AM"], [3, "03 AM"],
634
+ [4, "04 AM"], [5, "05 AM"], [6, "06 AM"], [7, "07 AM"],
635
+ [8, "08 AM"], [9, "09 AM"], [10, "10 AM"], [11, "11 AM"],
636
+ [12, "12 PM"], [13, "01 PM"], [14, "02 PM"], [15, "03 PM"],
637
+ [16, "04 PM"], [17, "05 PM"], [18, "06 PM"], [19, "07 PM"],
638
+ [20, "08 PM"], [21, "09 PM"], [22, "10 PM"], [23, "11 PM"]]
639
+ ].freeze
640
+
604
641
  def initialize(datetime, options = {}, html_options = {})
605
642
  @options = options.dup
606
643
  @html_options = html_options.dup
@@ -692,7 +729,7 @@ module ActionView
692
729
  if @options[:use_hidden] || @options[:discard_hour]
693
730
  build_hidden(:hour, hour)
694
731
  else
695
- build_options_and_select(:hour, hour, :end => 23)
732
+ build_options_and_select(:hour, hour, :end => 23, :ampm => @options[:ampm])
696
733
  end
697
734
  end
698
735
 
@@ -747,7 +784,7 @@ module ActionView
747
784
  end
748
785
 
749
786
  # Returns translated month names, but also ensures that a custom month
750
- # name array has a leading nil element
787
+ # name array has a leading nil element.
751
788
  def month_names
752
789
  month_names = @options[:use_month_names] || translated_month_names
753
790
  month_names.unshift(nil) if month_names.size < 13
@@ -755,13 +792,13 @@ module ActionView
755
792
  end
756
793
  memoize :month_names
757
794
 
758
- # Returns translated month names
795
+ # Returns translated month names.
759
796
  # => [nil, "January", "February", "March",
760
797
  # "April", "May", "June", "July",
761
798
  # "August", "September", "October",
762
799
  # "November", "December"]
763
800
  #
764
- # If :use_short_month option is set
801
+ # If <tt>:use_short_month</tt> option is set
765
802
  # => [nil, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
766
803
  # "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
767
804
  def translated_month_names
@@ -769,13 +806,13 @@ module ActionView
769
806
  I18n.translate(key, :locale => @options[:locale])
770
807
  end
771
808
 
772
- # Lookup month name for number
809
+ # Lookup month name for number.
773
810
  # month_name(1) => "January"
774
811
  #
775
- # If :use_month_numbers option is passed
812
+ # If <tt>:use_month_numbers</tt> option is passed
776
813
  # month_name(1) => 1
777
814
  #
778
- # If :add_month_numbers option is passed
815
+ # If <tt>:add_month_numbers</tt> option is passed
779
816
  # month_name(1) => "1 - January"
780
817
  def month_name(number)
781
818
  if @options[:use_month_numbers]
@@ -796,21 +833,27 @@ module ActionView
796
833
  I18n.translate(:'date.order', :locale => @options[:locale]) || []
797
834
  end
798
835
 
799
- # Build full select tag from date type and options
836
+ # Build full select tag from date type and options.
800
837
  def build_options_and_select(type, selected, options = {})
801
838
  build_select(type, build_options(selected, options))
802
839
  end
803
840
 
804
- # Build select option html from date value and options
841
+ # Build select option html from date value and options.
805
842
  # build_options(15, :start => 1, :end => 31)
806
843
  # => "<option value="1">1</option>
807
- # <option value=\"2\">2</option>
808
- # <option value=\"3\">3</option>..."
844
+ # <option value="2">2</option>
845
+ # <option value="3">3</option>..."
846
+ #
847
+ # If <tt>:step</tt> options is passed
848
+ # build_options(15, :start => 1, :end => 31, :step => 2)
849
+ # => "<option value="1">1</option>
850
+ # <option value="3">3</option>
851
+ # <option value="5">5</option>..."
809
852
  def build_options(selected, options = {})
810
853
  start = options.delete(:start) || 0
811
854
  stop = options.delete(:end) || 59
812
855
  step = options.delete(:step) || 1
813
- options.reverse_merge!({:leading_zeros => true})
856
+ options.reverse_merge!({:leading_zeros => true, :ampm => false})
814
857
  leading_zeros = options.delete(:leading_zeros)
815
858
 
816
859
  select_options = []
@@ -818,12 +861,13 @@ module ActionView
818
861
  value = leading_zeros ? sprintf("%02d", i) : i
819
862
  tag_options = { :value => value }
820
863
  tag_options[:selected] = "selected" if selected == i
821
- select_options << content_tag(:option, value, tag_options)
864
+ text = options[:ampm] ? AMPM_TRANSLATION[i] : value
865
+ select_options << content_tag(:option, text, tag_options)
822
866
  end
823
867
  (select_options.join("\n") + "\n").html_safe
824
868
  end
825
869
 
826
- # Builds select tag from date type and html select options
870
+ # Builds select tag from date type and html select options.
827
871
  # build_select(:month, "<option value="1">January</option>...")
828
872
  # => "<select id="post_written_on_2i" name="post[written_on(2i)]">
829
873
  # <option value="1">January</option>...
@@ -843,7 +887,7 @@ module ActionView
843
887
  (content_tag(:select, select_html.html_safe, select_options) + "\n").html_safe
844
888
  end
845
889
 
846
- # Builds a prompt option tag with supplied options or from default options
890
+ # Builds a prompt option tag with supplied options or from default options.
847
891
  # prompt_option_tag(:month, :prompt => 'Select month')
848
892
  # => "<option value="">Select month</option>"
849
893
  def prompt_option_tag(type, options)
@@ -860,7 +904,7 @@ module ActionView
860
904
  prompt ? content_tag(:option, prompt, :value => '') : ''
861
905
  end
862
906
 
863
- # Builds hidden input tag for date part and value
907
+ # Builds hidden input tag for date part and value.
864
908
  # build_hidden(:year, 2008)
865
909
  # => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />"
866
910
  def build_hidden(type, value)
@@ -872,7 +916,7 @@ module ActionView
872
916
  }.merge(@html_options.slice(:disabled))) + "\n").html_safe
873
917
  end
874
918
 
875
- # Returns the name attribute for the input tag
919
+ # Returns the name attribute for the input tag.
876
920
  # => post[written_on(1i)]
877
921
  def input_name_from_type(type)
878
922
  prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
@@ -886,7 +930,7 @@ module ActionView
886
930
  @options[:discard_type] ? prefix : "#{prefix}[#{field_name}]"
887
931
  end
888
932
 
889
- # Returns the id attribute for the input tag
933
+ # Returns the id attribute for the input tag.
890
934
  # => "post_written_on_1i"
891
935
  def input_id_from_type(type)
892
936
  input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
@@ -903,7 +947,7 @@ module ActionView
903
947
  select.html_safe
904
948
  end
905
949
 
906
- # Returns the separator for a given datetime component
950
+ # Returns the separator for a given datetime component.
907
951
  def separator(type)
908
952
  case type
909
953
  when :year