activesupport 3.2.22.5 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +364 -135
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -4
  5. data/lib/active_support/backtrace_cleaner.rb +33 -25
  6. data/lib/active_support/basic_object.rb +7 -17
  7. data/lib/active_support/benchmarkable.rb +19 -15
  8. data/lib/active_support/buffered_logger.rb +9 -113
  9. data/lib/active_support/cache/file_store.rb +14 -14
  10. data/lib/active_support/cache/mem_cache_store.rb +24 -30
  11. data/lib/active_support/cache/memory_store.rb +2 -0
  12. data/lib/active_support/cache/strategy/local_cache.rb +48 -37
  13. data/lib/active_support/cache.rb +228 -183
  14. data/lib/active_support/callbacks.rb +201 -253
  15. data/lib/active_support/concern.rb +16 -23
  16. data/lib/active_support/concurrency/latch.rb +27 -0
  17. data/lib/active_support/configurable.rb +69 -12
  18. data/lib/active_support/core_ext/array/access.rb +17 -9
  19. data/lib/active_support/core_ext/array/conversions.rb +115 -55
  20. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  21. data/lib/active_support/core_ext/array/grouping.rb +21 -22
  22. data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
  23. data/lib/active_support/core_ext/array/wrap.rb +13 -16
  24. data/lib/active_support/core_ext/array.rb +0 -1
  25. data/lib/active_support/core_ext/benchmark.rb +7 -0
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -24
  27. data/lib/active_support/core_ext/class/attribute.rb +40 -32
  28. data/lib/active_support/core_ext/class/attribute_accessors.rb +14 -12
  29. data/lib/active_support/core_ext/class/delegating_attributes.rb +15 -19
  30. data/lib/active_support/core_ext/class/subclasses.rb +11 -5
  31. data/lib/active_support/core_ext/date/calculations.rb +44 -187
  32. data/lib/active_support/core_ext/date/conversions.rb +16 -38
  33. data/lib/active_support/core_ext/date/zones.rb +25 -2
  34. data/lib/active_support/core_ext/date.rb +5 -0
  35. data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
  36. data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
  37. data/lib/active_support/core_ext/date_time/calculations.rb +77 -62
  38. data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
  39. data/lib/active_support/core_ext/date_time/zones.rb +11 -8
  40. data/lib/active_support/core_ext/date_time.rb +4 -0
  41. data/lib/active_support/core_ext/enumerable.rb +26 -73
  42. data/lib/active_support/core_ext/file/atomic.rb +27 -11
  43. data/lib/active_support/core_ext/file.rb +0 -1
  44. data/lib/active_support/core_ext/hash/conversions.rb +145 -79
  45. data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
  46. data/lib/active_support/core_ext/hash/diff.rb +5 -4
  47. data/lib/active_support/core_ext/hash/except.rb +1 -9
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
  49. data/lib/active_support/core_ext/hash/keys.rb +108 -24
  50. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  51. data/lib/active_support/core_ext/hash/slice.rb +12 -12
  52. data/lib/active_support/core_ext/hash.rb +0 -1
  53. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  54. data/lib/active_support/core_ext/integer/time.rb +17 -12
  55. data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
  56. data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
  57. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  58. data/lib/active_support/core_ext/load_error.rb +7 -5
  59. data/lib/active_support/core_ext/logger.rb +7 -23
  60. data/lib/active_support/core_ext/marshal.rb +21 -0
  61. data/lib/active_support/core_ext/module/aliasing.rb +8 -9
  62. data/lib/active_support/core_ext/module/anonymous.rb +2 -7
  63. data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
  64. data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
  65. data/lib/active_support/core_ext/module/delegation.rb +92 -49
  66. data/lib/active_support/core_ext/module/deprecation.rb +19 -3
  67. data/lib/active_support/core_ext/module/introspection.rb +17 -27
  68. data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
  69. data/lib/active_support/core_ext/module/remove_method.rb +1 -5
  70. data/lib/active_support/core_ext/module.rb +1 -3
  71. data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
  72. data/lib/active_support/core_ext/numeric/time.rb +6 -6
  73. data/lib/active_support/core_ext/numeric.rb +1 -0
  74. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  75. data/lib/active_support/core_ext/object/blank.rb +7 -23
  76. data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
  77. data/lib/active_support/core_ext/object/duplicable.rb +1 -30
  78. data/lib/active_support/core_ext/object/inclusion.rb +8 -7
  79. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  80. data/lib/active_support/core_ext/object/to_json.rb +8 -0
  81. data/lib/active_support/core_ext/object/to_param.rb +5 -2
  82. data/lib/active_support/core_ext/object/try.rb +46 -25
  83. data/lib/active_support/core_ext/object/with_options.rb +7 -8
  84. data/lib/active_support/core_ext/object.rb +1 -0
  85. data/lib/active_support/core_ext/proc.rb +3 -0
  86. data/lib/active_support/core_ext/range/conversions.rb +0 -2
  87. data/lib/active_support/core_ext/range/include_range.rb +3 -1
  88. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  89. data/lib/active_support/core_ext/range.rb +0 -2
  90. data/lib/active_support/core_ext/string/access.rb +95 -90
  91. data/lib/active_support/core_ext/string/conversions.rb +27 -38
  92. data/lib/active_support/core_ext/string/encoding.rb +6 -9
  93. data/lib/active_support/core_ext/string/filters.rb +24 -18
  94. data/lib/active_support/core_ext/string/indent.rb +43 -0
  95. data/lib/active_support/core_ext/string/inflections.rb +70 -60
  96. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  97. data/lib/active_support/core_ext/string/multibyte.rb +41 -64
  98. data/lib/active_support/core_ext/string/output_safety.rb +59 -51
  99. data/lib/active_support/core_ext/string/zones.rb +13 -0
  100. data/lib/active_support/core_ext/string.rb +2 -3
  101. data/lib/active_support/core_ext/struct.rb +6 -0
  102. data/lib/active_support/core_ext/thread.rb +74 -0
  103. data/lib/active_support/core_ext/time/calculations.rb +108 -184
  104. data/lib/active_support/core_ext/time/conversions.rb +27 -51
  105. data/lib/active_support/core_ext/time/marshal.rb +0 -27
  106. data/lib/active_support/core_ext/time/zones.rb +27 -17
  107. data/lib/active_support/core_ext/time.rb +5 -0
  108. data/lib/active_support/core_ext/uri.rb +13 -17
  109. data/lib/active_support/core_ext.rb +3 -2
  110. data/lib/active_support/dependencies/autoload.rb +47 -20
  111. data/lib/active_support/dependencies.rb +160 -141
  112. data/lib/active_support/deprecation/behaviors.rb +44 -30
  113. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  114. data/lib/active_support/deprecation/method_wrappers.rb +33 -18
  115. data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
  116. data/lib/active_support/deprecation/reporting.rb +40 -11
  117. data/lib/active_support/deprecation.rb +39 -14
  118. data/lib/active_support/descendants_tracker.rb +34 -19
  119. data/lib/active_support/duration.rb +6 -8
  120. data/lib/active_support/file_update_checker.rb +63 -47
  121. data/lib/active_support/gzip.rb +11 -5
  122. data/lib/active_support/hash_with_indifferent_access.rb +127 -42
  123. data/lib/active_support/i18n.rb +4 -0
  124. data/lib/active_support/i18n_railtie.rb +5 -22
  125. data/lib/active_support/inflections.rb +14 -12
  126. data/lib/active_support/inflector/inflections.rb +108 -71
  127. data/lib/active_support/inflector/methods.rb +181 -160
  128. data/lib/active_support/inflector/transliterate.rb +16 -17
  129. data/lib/active_support/json/decoding.rb +18 -17
  130. data/lib/active_support/json/encoding.rb +93 -39
  131. data/lib/active_support/json/variable.rb +10 -1
  132. data/lib/active_support/key_generator.rb +75 -0
  133. data/lib/active_support/lazy_load_hooks.rb +21 -19
  134. data/lib/active_support/locale/en.yml +100 -3
  135. data/lib/active_support/log_subscriber/test_helper.rb +18 -15
  136. data/lib/active_support/log_subscriber.rb +35 -52
  137. data/lib/active_support/logger.rb +57 -0
  138. data/lib/active_support/logger_silence.rb +24 -0
  139. data/lib/active_support/message_encryptor.rb +38 -35
  140. data/lib/active_support/message_verifier.rb +9 -15
  141. data/lib/active_support/multibyte/chars.rb +80 -333
  142. data/lib/active_support/multibyte/unicode.rb +74 -64
  143. data/lib/active_support/multibyte.rb +5 -28
  144. data/lib/active_support/notifications/fanout.rb +112 -18
  145. data/lib/active_support/notifications/instrumenter.rb +33 -14
  146. data/lib/active_support/notifications.rb +79 -26
  147. data/lib/active_support/number_helper.rb +637 -0
  148. data/lib/active_support/ordered_hash.rb +8 -190
  149. data/lib/active_support/ordered_options.rb +21 -23
  150. data/lib/active_support/per_thread_registry.rb +52 -0
  151. data/lib/active_support/proxy_object.rb +13 -0
  152. data/lib/active_support/rails.rb +27 -0
  153. data/lib/active_support/railtie.rb +12 -32
  154. data/lib/active_support/rescuable.rb +9 -4
  155. data/lib/active_support/string_inquirer.rb +13 -8
  156. data/lib/active_support/subscriber.rb +93 -0
  157. data/lib/active_support/tagged_logging.rb +51 -73
  158. data/lib/active_support/test_case.rb +46 -17
  159. data/lib/active_support/testing/assertions.rb +56 -26
  160. data/lib/active_support/testing/autorun.rb +5 -0
  161. data/lib/active_support/testing/constant_lookup.rb +54 -0
  162. data/lib/active_support/testing/declarative.rb +1 -1
  163. data/lib/active_support/testing/deprecation.rb +0 -19
  164. data/lib/active_support/testing/isolation.rb +29 -58
  165. data/lib/active_support/testing/pending.rb +5 -43
  166. data/lib/active_support/testing/setup_and_teardown.rb +6 -92
  167. data/lib/active_support/testing/tagged_logging.rb +25 -0
  168. data/lib/active_support/time.rb +6 -21
  169. data/lib/active_support/time_with_zone.rb +80 -43
  170. data/lib/active_support/values/time_zone.rb +81 -60
  171. data/lib/active_support/values/unicode_tables.dat +0 -0
  172. data/lib/active_support/version.rb +7 -6
  173. data/lib/active_support/xml_mini/jdom.rb +9 -11
  174. data/lib/active_support/xml_mini/libxml.rb +1 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
  176. data/lib/active_support/xml_mini/nokogiri.rb +1 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
  178. data/lib/active_support/xml_mini/rexml.rb +6 -8
  179. data/lib/active_support/xml_mini.rb +35 -17
  180. data/lib/active_support.rb +8 -21
  181. metadata +104 -72
  182. data/lib/active_support/base64.rb +0 -54
  183. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  184. data/lib/active_support/core_ext/date/freeze.rb +0 -33
  185. data/lib/active_support/core_ext/exception.rb +0 -3
  186. data/lib/active_support/core_ext/file/path.rb +0 -5
  187. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  188. data/lib/active_support/core_ext/float.rb +0 -1
  189. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
  190. data/lib/active_support/core_ext/io.rb +0 -15
  191. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  192. data/lib/active_support/core_ext/module/synchronization.rb +0 -45
  193. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  194. data/lib/active_support/core_ext/process.rb +0 -1
  195. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  196. data/lib/active_support/core_ext/range/cover.rb +0 -3
  197. data/lib/active_support/core_ext/rexml.rb +0 -46
  198. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  199. data/lib/active_support/core_ext/string/xchar.rb +0 -18
  200. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
  201. data/lib/active_support/memoizable.rb +0 -116
  202. data/lib/active_support/multibyte/exceptions.rb +0 -8
  203. data/lib/active_support/multibyte/utils.rb +0 -60
  204. data/lib/active_support/ruby/shim.rb +0 -22
  205. data/lib/active_support/security_utils.rb +0 -27
  206. data/lib/active_support/testing/mochaing.rb +0 -7
  207. data/lib/active_support/testing/performance/jruby.rb +0 -115
  208. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  209. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  210. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  211. data/lib/active_support/testing/performance/ruby.rb +0 -152
  212. data/lib/active_support/testing/performance.rb +0 -317
  213. data/lib/active_support/time/autoload.rb +0 -5
  214. data/lib/active_support/whiny_nil.rb +0 -24
@@ -3,29 +3,35 @@ require 'active_support/duration'
3
3
  require 'active_support/core_ext/object/acts_like'
4
4
  require 'active_support/core_ext/date/zones'
5
5
  require 'active_support/core_ext/time/zones'
6
+ require 'active_support/core_ext/date_and_time/calculations'
6
7
 
7
8
  class Date
8
- DAYS_INTO_WEEK = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6 }
9
+ include DateAndTime::Calculations
9
10
 
10
- if RUBY_VERSION < '1.9'
11
- undef :>>
11
+ class << self
12
+ attr_accessor :beginning_of_week_default
12
13
 
13
- # Backported from 1.9. The one in 1.8 leads to incorrect next_month and
14
- # friends for dates where the calendar reform is involved. It additionally
15
- # prevents an infinite loop fixed in r27013.
16
- def >>(n)
17
- y, m = (year * 12 + (mon - 1) + n).divmod(12)
18
- m, = (m + 1) .divmod(1)
19
- d = mday
20
- until jd2 = self.class.valid_civil?(y, m, d, start)
21
- d -= 1
22
- raise ArgumentError, 'invalid date' unless d > 0
23
- end
24
- self + (jd2 - jd)
14
+ # Returns the week start (e.g. :monday) for the current request, if this has been set (via Date.beginning_of_week=).
15
+ # If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
16
+ # If no config.beginning_of_week was specified, returns :monday.
17
+ def beginning_of_week
18
+ Thread.current[:beginning_of_week] || beginning_of_week_default || :monday
19
+ end
20
+
21
+ # Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. :monday) for current request/thread.
22
+ #
23
+ # This method accepts any of the following day symbols:
24
+ # :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
25
+ def beginning_of_week=(week_start)
26
+ Thread.current[:beginning_of_week] = find_beginning_of_week!(week_start)
27
+ end
28
+
29
+ # Returns week start day symbol (e.g. :monday), or raises an ArgumentError for invalid day symbol.
30
+ def find_beginning_of_week!(week_start)
31
+ raise ArgumentError, "Invalid beginning of week: #{week_start}" unless ::Date::DAYS_INTO_WEEK.key?(week_start)
32
+ week_start
25
33
  end
26
- end
27
34
 
28
- class << self
29
35
  # Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
30
36
  def yesterday
31
37
  ::Date.current.yesterday
@@ -42,37 +48,22 @@ class Date
42
48
  end
43
49
  end
44
50
 
45
- # Returns true if the Date object's date lies in the past. Otherwise returns false.
46
- def past?
47
- self < ::Date.current
48
- end
49
-
50
- # Returns true if the Date object's date is today.
51
- def today?
52
- self.to_date == ::Date.current # we need the to_date because of DateTime
53
- end
54
-
55
- # Returns true if the Date object's date lies in the future.
56
- def future?
57
- self > ::Date.current
58
- end
59
-
60
51
  # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
61
52
  # and then subtracts the specified number of seconds.
62
53
  def ago(seconds)
63
- to_time_in_current_zone.since(-seconds)
54
+ in_time_zone.since(-seconds)
64
55
  end
65
56
 
66
57
  # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
67
58
  # and then adds the specified number of seconds
68
59
  def since(seconds)
69
- to_time_in_current_zone.since(seconds)
60
+ in_time_zone.since(seconds)
70
61
  end
71
62
  alias :in :since
72
63
 
73
64
  # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
74
65
  def beginning_of_day
75
- to_time_in_current_zone
66
+ in_time_zone
76
67
  end
77
68
  alias :midnight :beginning_of_day
78
69
  alias :at_midnight :beginning_of_day
@@ -80,8 +71,9 @@ class Date
80
71
 
81
72
  # Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59)
82
73
  def end_of_day
83
- to_time_in_current_zone.end_of_day
74
+ in_time_zone.end_of_day
84
75
  end
76
+ alias :at_end_of_day :end_of_day
85
77
 
86
78
  def plus_with_duration(other) #:nodoc:
87
79
  if ActiveSupport::Duration === other
@@ -116,161 +108,26 @@ class Date
116
108
  end
117
109
 
118
110
  # Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
111
+ # The +options+ parameter is a hash with a combination of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>.
119
112
  #
120
- # Examples:
121
- #
122
- # Date.new(2007, 5, 12).change(:day => 1) # => Date.new(2007, 5, 1)
123
- # Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12)
113
+ # Date.new(2007, 5, 12).change(day: 1) # => Date.new(2007, 5, 1)
114
+ # Date.new(2007, 5, 12).change(year: 2005, month: 1) # => Date.new(2005, 1, 12)
124
115
  def change(options)
125
116
  ::Date.new(
126
- options[:year] || self.year,
127
- options[:month] || self.month,
128
- options[:day] || self.day
117
+ options.fetch(:year, year),
118
+ options.fetch(:month, month),
119
+ options.fetch(:day, day)
129
120
  )
130
121
  end
131
-
132
- # Returns a new Date/DateTime representing the time a number of specified weeks ago.
133
- def weeks_ago(weeks)
134
- advance(:weeks => -weeks)
135
- end
136
-
137
- # Returns a new Date/DateTime representing the time a number of specified months ago.
138
- def months_ago(months)
139
- advance(:months => -months)
140
- end
141
-
142
- # Returns a new Date/DateTime representing the time a number of specified months in the future.
143
- def months_since(months)
144
- advance(:months => months)
145
- end
146
-
147
- # Returns a new Date/DateTime representing the time a number of specified years ago.
148
- def years_ago(years)
149
- advance(:years => -years)
150
- end
151
-
152
- # Returns a new Date/DateTime representing the time a number of specified years in the future.
153
- def years_since(years)
154
- advance(:years => years)
155
- end
156
-
157
- # Shorthand for years_ago(1)
158
- def prev_year
159
- years_ago(1)
160
- end unless method_defined?(:prev_year)
161
-
162
- # Shorthand for years_since(1)
163
- def next_year
164
- years_since(1)
165
- end unless method_defined?(:next_year)
166
-
167
- # Shorthand for months_ago(1)
168
- def prev_month
169
- months_ago(1)
170
- end unless method_defined?(:prev_month)
171
-
172
- # Shorthand for months_since(1)
173
- def next_month
174
- months_since(1)
175
- end unless method_defined?(:next_month)
176
-
177
- # Returns number of days to start of this week. Week is assumed to start on
178
- # +start_day+, default is +:monday+.
179
- def days_to_week_start(start_day = :monday)
180
- start_day_number = DAYS_INTO_WEEK[start_day]
181
- current_day_number = wday != 0 ? wday - 1 : 6
182
- (current_day_number - start_day_number) % 7
183
- end
184
-
185
- # Returns a new +Date+/+DateTime+ representing the start of this week. Week is
186
- # assumed to start on +start_day+, default is +:monday+. +DateTime+ objects
187
- # have their time set to 0:00.
188
- def beginning_of_week(start_day = :monday)
189
- days_to_start = days_to_week_start(start_day)
190
- result = self - days_to_start
191
- acts_like?(:time) ? result.midnight : result
192
- end
193
- alias :at_beginning_of_week :beginning_of_week
194
-
195
- # Returns a new +Date+/+DateTime+ representing the start of this week. Week is
196
- # assumed to start on a Monday. +DateTime+ objects have their time set to 0:00.
197
- def monday
198
- beginning_of_week
199
- end
200
-
201
- # Returns a new +Date+/+DateTime+ representing the end of this week. Week is
202
- # assumed to start on +start_day+, default is +:monday+. +DateTime+ objects
203
- # have their time set to 23:59:59.
204
- def end_of_week(start_day = :monday)
205
- days_to_end = 6 - days_to_week_start(start_day)
206
- result = self + days_to_end.days
207
- self.acts_like?(:time) ? result.end_of_day : result
208
- end
209
- alias :at_end_of_week :end_of_week
210
-
211
- # Returns a new +Date+/+DateTime+ representing the end of this week. Week is
212
- # assumed to start on a Monday. +DateTime+ objects have their time set to 23:59:59.
213
- def sunday
214
- end_of_week
215
- end
216
-
217
- # Returns a new +Date+/+DateTime+ representing the given +day+ in the previous
218
- # week. Default is +:monday+. +DateTime+ objects have their time set to 0:00.
219
- def prev_week(day = :monday)
220
- result = (self - 7).beginning_of_week + DAYS_INTO_WEEK[day]
221
- self.acts_like?(:time) ? result.change(:hour => 0) : result
222
- end
223
-
224
- # Returns a new Date/DateTime representing the start of the given day in next week (default is :monday).
225
- def next_week(day = :monday)
226
- result = (self + 7).beginning_of_week + DAYS_INTO_WEEK[day]
227
- self.acts_like?(:time) ? result.change(:hour => 0) : result
228
- end
229
-
230
- # Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00)
231
- def beginning_of_month
232
- self.acts_like?(:time) ? change(:day => 1, :hour => 0) : change(:day => 1)
233
- end
234
- alias :at_beginning_of_month :beginning_of_month
235
-
236
- # Returns a new Date/DateTime representing the end of the month (last day of the month; DateTime objects will have time set to 0:00)
237
- def end_of_month
238
- last_day = ::Time.days_in_month( self.month, self.year )
239
- self.acts_like?(:time) ? change(:day => last_day, :hour => 23, :min => 59, :sec => 59) : change(:day => last_day)
240
- end
241
- alias :at_end_of_month :end_of_month
242
-
243
- # Returns a new Date/DateTime representing the start of the quarter (1st of january, april, july, october; DateTime objects will have time set to 0:00)
244
- def beginning_of_quarter
245
- beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
246
- end
247
- alias :at_beginning_of_quarter :beginning_of_quarter
248
-
249
- # Returns a new Date/DateTime representing the end of the quarter (last day of march, june, september, december; DateTime objects will have time set to 23:59:59)
250
- def end_of_quarter
251
- beginning_of_month.change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month
252
- end
253
- alias :at_end_of_quarter :end_of_quarter
254
-
255
- # Returns a new Date/DateTime representing the start of the year (1st of january; DateTime objects will have time set to 0:00)
256
- def beginning_of_year
257
- self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0) : change(:month => 1, :day => 1)
258
- end
259
- alias :at_beginning_of_year :beginning_of_year
260
-
261
- # Returns a new Time representing the end of the year (31st of december; DateTime objects will have time set to 23:59:59)
262
- def end_of_year
263
- self.acts_like?(:time) ? change(:month => 12, :day => 31, :hour => 23, :min => 59, :sec => 59) : change(:month => 12, :day => 31)
264
- end
265
- alias :at_end_of_year :end_of_year
266
-
267
- # Convenience method which returns a new Date/DateTime representing the time 1 day ago
268
- def yesterday
269
- self - 1
270
- end
271
-
272
- # Convenience method which returns a new Date/DateTime representing the time 1 day since the instance time
273
- def tomorrow
274
- self + 1
122
+
123
+ # Allow Date to be compared with Time by converting to DateTime and relying on the <=> from there.
124
+ def compare_with_coercion(other)
125
+ if other.is_a?(Time)
126
+ self.to_datetime <=> other
127
+ else
128
+ compare_without_coercion(other)
129
+ end
275
130
  end
131
+ alias_method :compare_without_coercion, :<=>
132
+ alias_method :<=>, :compare_with_coercion
276
133
  end
@@ -5,25 +5,27 @@ require 'active_support/core_ext/module/remove_method'
5
5
 
6
6
  class Date
7
7
  DATE_FORMATS = {
8
- :short => "%e %b",
9
- :long => "%B %e, %Y",
10
- :db => "%Y-%m-%d",
11
- :number => "%Y%m%d",
12
- :long_ordinal => lambda { |date| date.strftime("%B #{ActiveSupport::Inflector.ordinalize(date.day)}, %Y") }, # => "April 25th, 2007"
13
- :rfc822 => "%e %b %Y"
8
+ :short => '%e %b',
9
+ :long => '%B %e, %Y',
10
+ :db => '%Y-%m-%d',
11
+ :number => '%Y%m%d',
12
+ :long_ordinal => lambda { |date|
13
+ day_format = ActiveSupport::Inflector.ordinalize(date.day)
14
+ date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007"
15
+ },
16
+ :rfc822 => '%e %b %Y'
14
17
  }
15
18
 
16
19
  # Ruby 1.9 has Date#to_time which converts to localtime only.
17
- remove_possible_method :to_time
20
+ remove_method :to_time
18
21
 
19
22
  # Ruby 1.9 has Date#xmlschema which converts to a string without the time component.
20
- remove_possible_method :xmlschema
23
+ remove_method :xmlschema
21
24
 
22
25
  # Convert to a formatted string. See DATE_FORMATS for predefined formats.
23
26
  #
24
27
  # This method is aliased to <tt>to_s</tt>.
25
28
  #
26
- # ==== Examples
27
29
  # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
28
30
  #
29
31
  # date.to_formatted_s(:db) # => "2007-11-10"
@@ -40,8 +42,8 @@ class Date
40
42
  # or Proc instance that takes a date argument as the value.
41
43
  #
42
44
  # # config/initializers/time_formats.rb
43
- # Date::DATE_FORMATS[:month_and_year] = "%B %Y"
44
- # Date::DATE_FORMATS[:short_ordinal] = lambda { |date| date.strftime("%B #{date.day.ordinalize}") }
45
+ # Date::DATE_FORMATS[:month_and_year] = '%B %Y'
46
+ # Date::DATE_FORMATS[:short_ordinal] = ->(date) { date.strftime("%B #{date.day.ordinalize}") }
45
47
  def to_formatted_s(format = :default)
46
48
  if formatter = DATE_FORMATS[format]
47
49
  if formatter.respond_to?(:call)
@@ -58,21 +60,14 @@ class Date
58
60
 
59
61
  # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
60
62
  def readable_inspect
61
- strftime("%a, %d %b %Y")
63
+ strftime('%a, %d %b %Y')
62
64
  end
63
65
  alias_method :default_inspect, :inspect
64
66
  alias_method :inspect, :readable_inspect
65
67
 
66
- # A method to keep Time, Date and DateTime instances interchangeable on conversions.
67
- # In this case, it simply returns +self+.
68
- def to_date
69
- self
70
- end if RUBY_VERSION < '1.9'
71
-
72
68
  # Converts a Date instance to a Time, where the time is set to the beginning of the day.
73
69
  # The timezone can be either :local or :utc (default :local).
74
70
  #
75
- # ==== Examples
76
71
  # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
77
72
  #
78
73
  # date.to_time # => Sat Nov 10 00:00:00 0800 2007
@@ -80,27 +75,10 @@ class Date
80
75
  #
81
76
  # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
82
77
  def to_time(form = :local)
83
- ::Time.send("#{form}_time", year, month, day)
78
+ ::Time.send(form, year, month, day)
84
79
  end
85
80
 
86
- # Converts a Date instance to a DateTime, where the time is set to the beginning of the day
87
- # and UTC offset is set to 0.
88
- #
89
- # ==== Examples
90
- # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
91
- #
92
- # date.to_datetime # => Sat, 10 Nov 2007 00:00:00 0000
93
- def to_datetime
94
- ::DateTime.civil(year, month, day, 0, 0, 0, 0)
95
- end if RUBY_VERSION < '1.9'
96
-
97
- def iso8601
98
- strftime('%F')
99
- end if RUBY_VERSION < '1.9'
100
-
101
- alias_method :rfc3339, :iso8601 if RUBY_VERSION < '1.9'
102
-
103
81
  def xmlschema
104
- to_time_in_current_zone.xmlschema
82
+ in_time_zone.xmlschema
105
83
  end
106
84
  end
@@ -2,13 +2,36 @@ require 'date'
2
2
  require 'active_support/core_ext/time/zones'
3
3
 
4
4
  class Date
5
- # Converts Date to a TimeWithZone in the current zone if Time.zone or Time.zone_default
6
- # is set, otherwise converts Date to a Time via Date#to_time
5
+ # *DEPRECATED*: Use +Date#in_time_zone+ instead.
6
+ #
7
+ # Converts Date to a TimeWithZone in the current zone if <tt>Time.zone</tt> or
8
+ # <tt>Time.zone_default</tt> is set, otherwise converts Date to a Time via
9
+ # Date#to_time.
7
10
  def to_time_in_current_zone
11
+ ActiveSupport::Deprecation.warn 'Date#to_time_in_current_zone is deprecated. Use Date#in_time_zone instead', caller
12
+
8
13
  if ::Time.zone
9
14
  ::Time.zone.local(year, month, day)
10
15
  else
11
16
  to_time
12
17
  end
13
18
  end
19
+
20
+ # Converts Date to a TimeWithZone in the current zone if Time.zone or Time.zone_default
21
+ # is set, otherwise converts Date to a Time via Date#to_time
22
+ #
23
+ # Time.zone = 'Hawaii' # => 'Hawaii'
24
+ # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
25
+ #
26
+ # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
27
+ # and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
28
+ #
29
+ # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
30
+ def in_time_zone(zone = ::Time.zone)
31
+ if zone
32
+ ::Time.find_zone!(zone).local(year, month, day)
33
+ else
34
+ to_time
35
+ end
36
+ end
14
37
  end
@@ -0,0 +1,5 @@
1
+ require 'active_support/core_ext/date/acts_like'
2
+ require 'active_support/core_ext/date/calculations'
3
+ require 'active_support/core_ext/date/conversions'
4
+ require 'active_support/core_ext/date/zones'
5
+
@@ -0,0 +1,232 @@
1
+ module DateAndTime
2
+ module Calculations
3
+ DAYS_INTO_WEEK = {
4
+ :monday => 0,
5
+ :tuesday => 1,
6
+ :wednesday => 2,
7
+ :thursday => 3,
8
+ :friday => 4,
9
+ :saturday => 5,
10
+ :sunday => 6
11
+ }
12
+
13
+ # Returns a new date/time representing yesterday.
14
+ def yesterday
15
+ advance(:days => -1)
16
+ end
17
+
18
+ # Returns a new date/time representing tomorrow.
19
+ def tomorrow
20
+ advance(:days => 1)
21
+ end
22
+
23
+ # Returns true if the date/time is today.
24
+ def today?
25
+ to_date == ::Date.current
26
+ end
27
+
28
+ # Returns true if the date/time is in the past.
29
+ def past?
30
+ self < self.class.current
31
+ end
32
+
33
+ # Returns true if the date/time is in the future.
34
+ def future?
35
+ self > self.class.current
36
+ end
37
+
38
+ # Returns a new date/time the specified number of days ago.
39
+ def days_ago(days)
40
+ advance(:days => -days)
41
+ end
42
+
43
+ # Returns a new date/time the specified number of days in the future.
44
+ def days_since(days)
45
+ advance(:days => days)
46
+ end
47
+
48
+ # Returns a new date/time the specified number of weeks ago.
49
+ def weeks_ago(weeks)
50
+ advance(:weeks => -weeks)
51
+ end
52
+
53
+ # Returns a new date/time the specified number of weeks in the future.
54
+ def weeks_since(weeks)
55
+ advance(:weeks => weeks)
56
+ end
57
+
58
+ # Returns a new date/time the specified number of months ago.
59
+ def months_ago(months)
60
+ advance(:months => -months)
61
+ end
62
+
63
+ # Returns a new date/time the specified number of months in the future.
64
+ def months_since(months)
65
+ advance(:months => months)
66
+ end
67
+
68
+ # Returns a new date/time the specified number of years ago.
69
+ def years_ago(years)
70
+ advance(:years => -years)
71
+ end
72
+
73
+ # Returns a new date/time the specified number of years in the future.
74
+ def years_since(years)
75
+ advance(:years => years)
76
+ end
77
+
78
+ # Returns a new date/time at the start of the month.
79
+ # DateTime objects will have a time set to 0:00.
80
+ def beginning_of_month
81
+ first_hour{ change(:day => 1) }
82
+ end
83
+ alias :at_beginning_of_month :beginning_of_month
84
+
85
+ # Returns a new date/time at the start of the quarter.
86
+ # Example: 1st January, 1st July, 1st October.
87
+ # DateTime objects will have a time set to 0:00.
88
+ def beginning_of_quarter
89
+ first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
90
+ beginning_of_month.change(:month => first_quarter_month)
91
+ end
92
+ alias :at_beginning_of_quarter :beginning_of_quarter
93
+
94
+ # Returns a new date/time at the end of the quarter.
95
+ # Example: 31st March, 30th June, 30th September.
96
+ # DateTime objects will have a time set to 23:59:59.
97
+ def end_of_quarter
98
+ last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
99
+ beginning_of_month.change(:month => last_quarter_month).end_of_month
100
+ end
101
+ alias :at_end_of_quarter :end_of_quarter
102
+
103
+ # Return a new date/time at the beginning of the year.
104
+ # Example: 1st January.
105
+ # DateTime objects will have a time set to 0:00.
106
+ def beginning_of_year
107
+ change(:month => 1).beginning_of_month
108
+ end
109
+ alias :at_beginning_of_year :beginning_of_year
110
+
111
+ # Returns a new date/time representing the given day in the next week.
112
+ # The +given_day_in_next_week+ defaults to the beginning of the week
113
+ # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
114
+ # when set. +DateTime+ objects have their time set to 0:00.
115
+ def next_week(given_day_in_next_week = Date.beginning_of_week)
116
+ first_hour{ weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)) }
117
+ end
118
+
119
+ # Short-hand for months_since(1).
120
+ def next_month
121
+ months_since(1)
122
+ end
123
+
124
+ # Short-hand for months_since(3)
125
+ def next_quarter
126
+ months_since(3)
127
+ end
128
+
129
+ # Short-hand for years_since(1).
130
+ def next_year
131
+ years_since(1)
132
+ end
133
+
134
+ # Returns a new date/time representing the given day in the previous week.
135
+ # Week is assumed to start on +start_day+, default is
136
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
137
+ # DateTime objects have their time set to 0:00.
138
+ def prev_week(start_day = Date.beginning_of_week)
139
+ first_hour{ weeks_ago(1).beginning_of_week.days_since(days_span(start_day)) }
140
+ end
141
+ alias_method :last_week, :prev_week
142
+
143
+ # Short-hand for months_ago(1).
144
+ def prev_month
145
+ months_ago(1)
146
+ end
147
+ alias_method :last_month, :prev_month
148
+
149
+ # Short-hand for months_ago(3).
150
+ def prev_quarter
151
+ months_ago(3)
152
+ end
153
+ alias_method :last_quarter, :prev_quarter
154
+
155
+ # Short-hand for years_ago(1).
156
+ def prev_year
157
+ years_ago(1)
158
+ end
159
+ alias_method :last_year, :prev_year
160
+
161
+ # Returns the number of days to the start of the week on the given day.
162
+ # Week is assumed to start on +start_day+, default is
163
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
164
+ def days_to_week_start(start_day = Date.beginning_of_week)
165
+ start_day_number = DAYS_INTO_WEEK[start_day]
166
+ current_day_number = wday != 0 ? wday - 1 : 6
167
+ (current_day_number - start_day_number) % 7
168
+ end
169
+
170
+ # Returns a new date/time representing the start of this week on the given day.
171
+ # Week is assumed to start on +start_day+, default is
172
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
173
+ # +DateTime+ objects have their time set to 0:00.
174
+ def beginning_of_week(start_day = Date.beginning_of_week)
175
+ result = days_ago(days_to_week_start(start_day))
176
+ acts_like?(:time) ? result.midnight : result
177
+ end
178
+ alias :at_beginning_of_week :beginning_of_week
179
+
180
+ # Returns Monday of this week assuming that week starts on Monday.
181
+ # +DateTime+ objects have their time set to 0:00.
182
+ def monday
183
+ beginning_of_week(:monday)
184
+ end
185
+
186
+ # Returns a new date/time representing the end of this week on the given day.
187
+ # Week is assumed to start on +start_day+, default is
188
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
189
+ # DateTime objects have their time set to 23:59:59.
190
+ def end_of_week(start_day = Date.beginning_of_week)
191
+ last_hour{ days_since(6 - days_to_week_start(start_day)) }
192
+ end
193
+ alias :at_end_of_week :end_of_week
194
+
195
+ # Returns Sunday of this week assuming that week starts on Monday.
196
+ # +DateTime+ objects have their time set to 23:59:59.
197
+ def sunday
198
+ end_of_week(:monday)
199
+ end
200
+
201
+ # Returns a new date/time representing the end of the month.
202
+ # DateTime objects will have a time set to 23:59:59.
203
+ def end_of_month
204
+ last_day = ::Time.days_in_month(month, year)
205
+ last_hour{ days_since(last_day - day) }
206
+ end
207
+ alias :at_end_of_month :end_of_month
208
+
209
+ # Returns a new date/time representing the end of the year.
210
+ # DateTime objects will have a time set to 23:59:59.
211
+ def end_of_year
212
+ change(:month => 12).end_of_month
213
+ end
214
+ alias :at_end_of_year :end_of_year
215
+
216
+ private
217
+
218
+ def first_hour
219
+ result = yield
220
+ acts_like?(:time) ? result.change(:hour => 0) : result
221
+ end
222
+
223
+ def last_hour
224
+ result = yield
225
+ acts_like?(:time) ? result.end_of_day : result
226
+ end
227
+
228
+ def days_span(day)
229
+ (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
230
+ end
231
+ end
232
+ end
@@ -1,4 +1,3 @@
1
- require 'date'
2
1
  require 'active_support/core_ext/object/acts_like'
3
2
 
4
3
  class DateTime