activesupport 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 activesupport might be problematic. Click here for more details.

Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +325 -136
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -2
  5. data/lib/active_support.rb +8 -21
  6. data/lib/active_support/backtrace_cleaner.rb +33 -25
  7. data/lib/active_support/basic_object.rb +7 -17
  8. data/lib/active_support/benchmarkable.rb +19 -15
  9. data/lib/active_support/buffered_logger.rb +9 -113
  10. data/lib/active_support/cache.rb +203 -171
  11. data/lib/active_support/cache/file_store.rb +12 -12
  12. data/lib/active_support/cache/mem_cache_store.rb +24 -30
  13. data/lib/active_support/cache/memory_store.rb +2 -0
  14. data/lib/active_support/callbacks.rb +195 -247
  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.rb +1 -0
  19. data/lib/active_support/core_ext/array.rb +0 -1
  20. data/lib/active_support/core_ext/array/access.rb +17 -9
  21. data/lib/active_support/core_ext/array/conversions.rb +113 -55
  22. data/lib/active_support/core_ext/array/extract_options.rb +2 -2
  23. data/lib/active_support/core_ext/array/grouping.rb +21 -22
  24. data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
  25. data/lib/active_support/core_ext/array/wrap.rb +11 -14
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +7 -24
  27. data/lib/active_support/core_ext/class/attribute.rb +12 -8
  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.rb +6 -0
  32. data/lib/active_support/core_ext/date/calculations.rb +34 -188
  33. data/lib/active_support/core_ext/date/conversions.rb +16 -38
  34. data/lib/active_support/core_ext/date/infinite_comparable.rb +5 -0
  35. data/lib/active_support/core_ext/date/zones.rb +25 -2
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
  37. data/lib/active_support/core_ext/date_time.rb +5 -0
  38. data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
  39. data/lib/active_support/core_ext/date_time/calculations.rb +73 -65
  40. data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
  41. data/lib/active_support/core_ext/date_time/infinite_comparable.rb +5 -0
  42. data/lib/active_support/core_ext/date_time/zones.rb +11 -8
  43. data/lib/active_support/core_ext/enumerable.rb +26 -73
  44. data/lib/active_support/core_ext/file.rb +0 -1
  45. data/lib/active_support/core_ext/file/atomic.rb +27 -11
  46. data/lib/active_support/core_ext/hash.rb +0 -1
  47. data/lib/active_support/core_ext/hash/conversions.rb +145 -79
  48. data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
  49. data/lib/active_support/core_ext/hash/diff.rb +5 -4
  50. data/lib/active_support/core_ext/hash/except.rb +1 -9
  51. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
  52. data/lib/active_support/core_ext/hash/keys.rb +108 -24
  53. data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
  54. data/lib/active_support/core_ext/hash/slice.rb +12 -12
  55. data/lib/active_support/core_ext/infinite_comparable.rb +35 -0
  56. data/lib/active_support/core_ext/integer/inflections.rb +13 -1
  57. data/lib/active_support/core_ext/integer/time.rb +17 -12
  58. data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
  59. data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
  60. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
  61. data/lib/active_support/core_ext/load_error.rb +7 -5
  62. data/lib/active_support/core_ext/logger.rb +7 -23
  63. data/lib/active_support/core_ext/marshal.rb +19 -0
  64. data/lib/active_support/core_ext/module.rb +1 -3
  65. data/lib/active_support/core_ext/module/aliasing.rb +8 -9
  66. data/lib/active_support/core_ext/module/anonymous.rb +2 -7
  67. data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
  68. data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
  69. data/lib/active_support/core_ext/module/delegation.rb +57 -40
  70. data/lib/active_support/core_ext/module/deprecation.rb +19 -3
  71. data/lib/active_support/core_ext/module/introspection.rb +17 -27
  72. data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
  73. data/lib/active_support/core_ext/module/remove_method.rb +1 -5
  74. data/lib/active_support/core_ext/numeric.rb +2 -0
  75. data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
  76. data/lib/active_support/core_ext/numeric/infinite_comparable.rb +9 -0
  77. data/lib/active_support/core_ext/numeric/time.rb +6 -6
  78. data/lib/active_support/core_ext/object.rb +1 -0
  79. data/lib/active_support/core_ext/object/acts_like.rb +4 -4
  80. data/lib/active_support/core_ext/object/blank.rb +7 -23
  81. data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
  82. data/lib/active_support/core_ext/object/duplicable.rb +1 -30
  83. data/lib/active_support/core_ext/object/inclusion.rb +6 -6
  84. data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
  85. data/lib/active_support/core_ext/object/to_json.rb +8 -0
  86. data/lib/active_support/core_ext/object/to_param.rb +5 -2
  87. data/lib/active_support/core_ext/object/try.rb +46 -25
  88. data/lib/active_support/core_ext/object/with_options.rb +7 -8
  89. data/lib/active_support/core_ext/proc.rb +3 -0
  90. data/lib/active_support/core_ext/range.rb +0 -2
  91. data/lib/active_support/core_ext/range/conversions.rb +0 -2
  92. data/lib/active_support/core_ext/range/include_range.rb +1 -1
  93. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  94. data/lib/active_support/core_ext/string.rb +2 -2
  95. data/lib/active_support/core_ext/string/access.rb +95 -90
  96. data/lib/active_support/core_ext/string/conversions.rb +29 -38
  97. data/lib/active_support/core_ext/string/encoding.rb +6 -9
  98. data/lib/active_support/core_ext/string/filters.rb +24 -18
  99. data/lib/active_support/core_ext/string/indent.rb +43 -0
  100. data/lib/active_support/core_ext/string/inflections.rb +70 -60
  101. data/lib/active_support/core_ext/string/inquiry.rb +2 -2
  102. data/lib/active_support/core_ext/string/multibyte.rb +41 -64
  103. data/lib/active_support/core_ext/string/output_safety.rb +59 -51
  104. data/lib/active_support/core_ext/string/zones.rb +13 -0
  105. data/lib/active_support/core_ext/struct.rb +6 -0
  106. data/lib/active_support/core_ext/thread.rb +74 -0
  107. data/lib/active_support/core_ext/time.rb +6 -0
  108. data/lib/active_support/core_ext/time/calculations.rb +105 -193
  109. data/lib/active_support/core_ext/time/conversions.rb +27 -51
  110. data/lib/active_support/core_ext/time/infinite_comparable.rb +5 -0
  111. data/lib/active_support/core_ext/time/marshal.rb +0 -27
  112. data/lib/active_support/core_ext/time/zones.rb +27 -17
  113. data/lib/active_support/core_ext/uri.rb +13 -17
  114. data/lib/active_support/dependencies.rb +160 -141
  115. data/lib/active_support/dependencies/autoload.rb +47 -20
  116. data/lib/active_support/deprecation.rb +39 -14
  117. data/lib/active_support/deprecation/behaviors.rb +44 -30
  118. data/lib/active_support/deprecation/instance_delegator.rb +24 -0
  119. data/lib/active_support/deprecation/method_wrappers.rb +33 -18
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
  121. data/lib/active_support/deprecation/reporting.rb +40 -11
  122. data/lib/active_support/descendants_tracker.rb +34 -19
  123. data/lib/active_support/duration.rb +6 -8
  124. data/lib/active_support/file_update_checker.rb +63 -47
  125. data/lib/active_support/gzip.rb +11 -5
  126. data/lib/active_support/hash_with_indifferent_access.rb +112 -37
  127. data/lib/active_support/i18n.rb +4 -0
  128. data/lib/active_support/i18n_railtie.rb +5 -22
  129. data/lib/active_support/inflections.rb +14 -12
  130. data/lib/active_support/inflector/inflections.rb +108 -71
  131. data/lib/active_support/inflector/methods.rb +181 -160
  132. data/lib/active_support/inflector/transliterate.rb +16 -17
  133. data/lib/active_support/json/decoding.rb +18 -17
  134. data/lib/active_support/json/encoding.rb +93 -39
  135. data/lib/active_support/json/variable.rb +10 -1
  136. data/lib/active_support/key_generator.rb +75 -0
  137. data/lib/active_support/lazy_load_hooks.rb +21 -19
  138. data/lib/active_support/locale/en.yml +100 -3
  139. data/lib/active_support/log_subscriber.rb +56 -36
  140. data/lib/active_support/log_subscriber/test_helper.rb +18 -15
  141. data/lib/active_support/logger.rb +57 -0
  142. data/lib/active_support/logger_silence.rb +24 -0
  143. data/lib/active_support/message_encryptor.rb +32 -29
  144. data/lib/active_support/message_verifier.rb +8 -14
  145. data/lib/active_support/multibyte.rb +5 -28
  146. data/lib/active_support/multibyte/chars.rb +80 -333
  147. data/lib/active_support/multibyte/unicode.rb +74 -64
  148. data/lib/active_support/notifications.rb +57 -25
  149. data/lib/active_support/notifications/fanout.rb +105 -18
  150. data/lib/active_support/notifications/instrumenter.rb +32 -13
  151. data/lib/active_support/number_helper.rb +636 -0
  152. data/lib/active_support/ordered_hash.rb +8 -190
  153. data/lib/active_support/ordered_options.rb +21 -23
  154. data/lib/active_support/proxy_object.rb +13 -0
  155. data/lib/active_support/rails.rb +27 -0
  156. data/lib/active_support/railtie.rb +12 -32
  157. data/lib/active_support/rescuable.rb +9 -4
  158. data/lib/active_support/string_inquirer.rb +13 -8
  159. data/lib/active_support/tagged_logging.rb +51 -73
  160. data/lib/active_support/test_case.rb +46 -17
  161. data/lib/active_support/testing/assertions.rb +56 -26
  162. data/lib/active_support/testing/autorun.rb +5 -0
  163. data/lib/active_support/testing/constant_lookup.rb +52 -0
  164. data/lib/active_support/testing/declarative.rb +1 -1
  165. data/lib/active_support/testing/deprecation.rb +0 -19
  166. data/lib/active_support/testing/isolation.rb +25 -58
  167. data/lib/active_support/testing/pending.rb +5 -43
  168. data/lib/active_support/testing/setup_and_teardown.rb +6 -92
  169. data/lib/active_support/testing/tagged_logging.rb +25 -0
  170. data/lib/active_support/time.rb +6 -21
  171. data/lib/active_support/time_with_zone.rb +78 -43
  172. data/lib/active_support/values/time_zone.rb +77 -58
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/version.rb +4 -4
  175. data/lib/active_support/xml_mini.rb +35 -17
  176. data/lib/active_support/xml_mini/jdom.rb +9 -17
  177. data/lib/active_support/xml_mini/libxml.rb +1 -2
  178. data/lib/active_support/xml_mini/libxmlsax.rb +1 -2
  179. data/lib/active_support/xml_mini/nokogiri.rb +1 -2
  180. data/lib/active_support/xml_mini/nokogirisax.rb +1 -2
  181. data/lib/active_support/xml_mini/rexml.rb +6 -8
  182. metadata +107 -77
  183. data/lib/active_support/base64.rb +0 -54
  184. data/lib/active_support/core_ext/array/random_access.rb +0 -30
  185. data/lib/active_support/core_ext/date/freeze.rb +0 -33
  186. data/lib/active_support/core_ext/exception.rb +0 -3
  187. data/lib/active_support/core_ext/file/path.rb +0 -5
  188. data/lib/active_support/core_ext/float.rb +0 -1
  189. data/lib/active_support/core_ext/float/rounding.rb +0 -19
  190. data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
  191. data/lib/active_support/core_ext/io.rb +0 -15
  192. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  193. data/lib/active_support/core_ext/module/synchronization.rb +0 -45
  194. data/lib/active_support/core_ext/process.rb +0 -1
  195. data/lib/active_support/core_ext/process/daemon.rb +0 -23
  196. data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
  197. data/lib/active_support/core_ext/range/cover.rb +0 -3
  198. data/lib/active_support/core_ext/rexml.rb +0 -46
  199. data/lib/active_support/core_ext/string/interpolation.rb +0 -2
  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.rb +0 -317
  208. data/lib/active_support/testing/performance/jruby.rb +0 -115
  209. data/lib/active_support/testing/performance/rubinius.rb +0 -113
  210. data/lib/active_support/testing/performance/ruby.rb +0 -152
  211. data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
  212. data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
  213. data/lib/active_support/time/autoload.rb +0 -5
  214. data/lib/active_support/whiny_nil.rb +0 -24
@@ -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
@@ -0,0 +1,5 @@
1
+ require 'active_support/core_ext/infinite_comparable'
2
+
3
+ class Date
4
+ include InfiniteComparable
5
+ 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,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
+ # Week is assumed to start on +start_day+, default is
113
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
114
+ # DateTime objects have their time set to 0:00.
115
+ def next_week(start_day = Date.beginning_of_week)
116
+ first_hour{ weeks_since(1).beginning_of_week.days_since(days_span(start_day)) }
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
@@ -0,0 +1,5 @@
1
+ require 'active_support/core_ext/date_time/acts_like'
2
+ require 'active_support/core_ext/date_time/calculations'
3
+ require 'active_support/core_ext/date_time/conversions'
4
+ require 'active_support/core_ext/date_time/zones'
5
+ require 'active_support/core_ext/date_time/infinite_comparable'
@@ -1,4 +1,3 @@
1
- require 'date'
2
1
  require 'active_support/core_ext/object/acts_like'
3
2
 
4
3
  class DateTime
@@ -1,46 +1,67 @@
1
- require 'rational' unless RUBY_VERSION >= '1.9.2'
1
+ require 'active_support/deprecation'
2
2
 
3
3
  class DateTime
4
4
  class << self
5
- # DateTimes aren't aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone
5
+ # *DEPRECATED*: Use +DateTime.civil_from_format+ directly.
6
6
  def local_offset
7
+ ActiveSupport::Deprecation.warn 'DateTime.local_offset is deprecated. Use DateTime.civil_from_format directly.'
8
+
7
9
  ::Time.local(2012).utc_offset.to_r / 86400
8
10
  end
9
11
 
10
- # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise returns <tt>Time.now.to_datetime</tt>.
12
+ # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or
13
+ # <tt>config.time_zone</tt> are set, otherwise returns
14
+ # <tt>Time.now.to_datetime</tt>.
11
15
  def current
12
16
  ::Time.zone ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
13
17
  end
14
18
  end
15
19
 
16
- # Tells whether the DateTime object's datetime lies in the past
20
+ # Tells whether the DateTime object's datetime lies in the past.
17
21
  def past?
18
22
  self < ::DateTime.current
19
23
  end
20
24
 
21
- # Tells whether the DateTime object's datetime lies in the future
25
+ # Tells whether the DateTime object's datetime lies in the future.
22
26
  def future?
23
27
  self > ::DateTime.current
24
28
  end
25
29
 
26
- # Seconds since midnight: DateTime.now.seconds_since_midnight
30
+ # Seconds since midnight: DateTime.now.seconds_since_midnight.
27
31
  def seconds_since_midnight
28
32
  sec + (min * 60) + (hour * 3600)
29
33
  end
30
34
 
31
- # Returns a new DateTime where one or more of the elements have been changed according to the +options+ parameter. The time options
32
- # (hour, minute, sec) reset cascadingly, so if only the hour is passed, then minute and sec is set to 0. If the hour and
33
- # minute is passed, then sec is set to 0.
35
+ # Returns the number of seconds until 23:59:59.
36
+ #
37
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399
38
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103
39
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_until_end_of_day # => 0
40
+ def seconds_until_end_of_day
41
+ end_of_day.to_i - to_i
42
+ end
43
+
44
+ # Returns a new DateTime where one or more of the elements have been changed
45
+ # according to the +options+ parameter. The time options (<tt>:hour</tt>,
46
+ # <tt>:min</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is
47
+ # passed, then minute and sec is set to 0. If the hour and minute is passed,
48
+ # then sec is set to 0. The +options+ parameter takes a hash with any of these
49
+ # keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>,
50
+ # <tt>:min</tt>, <tt>:sec</tt>, <tt>:offset</tt>, <tt>:start</tt>.
51
+ #
52
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => DateTime.new(2012, 8, 1, 22, 35, 0)
53
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => DateTime.new(1981, 8, 1, 22, 35, 0)
54
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
34
55
  def change(options)
35
56
  ::DateTime.civil(
36
- options[:year] || year,
37
- options[:month] || month,
38
- options[:day] || day,
39
- options[:hour] || hour,
40
- options[:min] || (options[:hour] ? 0 : min),
41
- options[:sec] || ((options[:hour] || options[:min]) ? 0 : sec),
42
- options[:offset] || offset,
43
- options[:start] || start
57
+ options.fetch(:year, year),
58
+ options.fetch(:month, month),
59
+ options.fetch(:day, day),
60
+ options.fetch(:hour, hour),
61
+ options.fetch(:min, options[:hour] ? 0 : min),
62
+ options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec + sec_fraction),
63
+ options.fetch(:offset, offset),
64
+ options.fetch(:start, start)
44
65
  )
45
66
  end
46
67
 
@@ -51,24 +72,33 @@ class DateTime
51
72
  def advance(options)
52
73
  d = to_date.advance(options)
53
74
  datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
54
- seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
55
- seconds_to_advance == 0 ? datetime_advanced_by_date : datetime_advanced_by_date.since(seconds_to_advance)
75
+ seconds_to_advance = \
76
+ options.fetch(:seconds, 0) +
77
+ options.fetch(:minutes, 0) * 60 +
78
+ options.fetch(:hours, 0) * 3600
79
+
80
+ if seconds_to_advance.zero?
81
+ datetime_advanced_by_date
82
+ else
83
+ datetime_advanced_by_date.since seconds_to_advance
84
+ end
56
85
  end
57
86
 
58
- # Returns a new DateTime representing the time a number of seconds ago
87
+ # Returns a new DateTime representing the time a number of seconds ago.
59
88
  # Do not use this method in combination with x.months, use months_ago instead!
60
89
  def ago(seconds)
61
90
  since(-seconds)
62
91
  end
63
92
 
64
- # Returns a new DateTime representing the time a number of seconds since the instance time
65
- # Do not use this method in combination with x.months, use months_since instead!
93
+ # Returns a new DateTime representing the time a number of seconds since the
94
+ # instance time. Do not use this method in combination with x.months, use
95
+ # months_since instead!
66
96
  def since(seconds)
67
97
  self + Rational(seconds.round, 86400)
68
98
  end
69
99
  alias :in :since
70
100
 
71
- # Returns a new DateTime representing the start of the day (0:00)
101
+ # Returns a new DateTime representing the start of the day (0:00).
72
102
  def beginning_of_day
73
103
  change(:hour => 0)
74
104
  end
@@ -76,74 +106,52 @@ class DateTime
76
106
  alias :at_midnight :beginning_of_day
77
107
  alias :at_beginning_of_day :beginning_of_day
78
108
 
79
- # Returns a new DateTime representing the end of the day (23:59:59)
109
+ # Returns a new DateTime representing the end of the day (23:59:59).
80
110
  def end_of_day
81
111
  change(:hour => 23, :min => 59, :sec => 59)
82
112
  end
113
+ alias :at_end_of_day :end_of_day
83
114
 
84
- # Returns a new DateTime representing the start of the hour (hh:00:00)
115
+ # Returns a new DateTime representing the start of the hour (hh:00:00).
85
116
  def beginning_of_hour
86
117
  change(:min => 0)
87
118
  end
88
119
  alias :at_beginning_of_hour :beginning_of_hour
89
120
 
90
- # Returns a new DateTime representing the end of the hour (hh:59:59)
121
+ # Returns a new DateTime representing the end of the hour (hh:59:59).
91
122
  def end_of_hour
92
123
  change(:min => 59, :sec => 59)
93
124
  end
125
+ alias :at_end_of_hour :end_of_hour
94
126
 
95
- # 1.9.3 defines + and - on DateTime, < 1.9.3 do not.
96
- if DateTime.public_instance_methods(false).include?(:+)
97
- def plus_with_duration(other) #:nodoc:
98
- if ActiveSupport::Duration === other
99
- other.since(self)
100
- else
101
- plus_without_duration(other)
102
- end
103
- end
104
- alias_method :plus_without_duration, :+
105
- alias_method :+, :plus_with_duration
106
-
107
- def minus_with_duration(other) #:nodoc:
108
- if ActiveSupport::Duration === other
109
- plus_with_duration(-other)
110
- else
111
- minus_without_duration(other)
112
- end
113
- end
114
- alias_method :minus_without_duration, :-
115
- alias_method :-, :minus_with_duration
127
+ # Returns a new DateTime representing the start of the minute (hh:mm:00).
128
+ def beginning_of_minute
129
+ change(:sec => 0)
116
130
  end
131
+ alias :at_beginning_of_minute :beginning_of_minute
117
132
 
118
- # Adjusts DateTime to UTC by adding its offset value; offset is set to 0
119
- #
120
- # Example:
133
+ # Returns a new DateTime representing the end of the minute (hh:mm:59).
134
+ def end_of_minute
135
+ change(:sec => 59)
136
+ end
137
+ alias :at_end_of_minute :end_of_minute
138
+
139
+ # Adjusts DateTime to UTC by adding its offset value; offset is set to 0.
121
140
  #
122
- # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
123
- # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
141
+ # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
142
+ # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
124
143
  def utc
125
144
  new_offset(0)
126
145
  end
127
146
  alias_method :getutc, :utc
128
147
 
129
- # Returns true if offset == 0
148
+ # Returns +true+ if <tt>offset == 0</tt>.
130
149
  def utc?
131
150
  offset == 0
132
151
  end
133
152
 
134
- # Returns the offset value in seconds
153
+ # Returns the offset value in seconds.
135
154
  def utc_offset
136
155
  (offset * 86400).to_i
137
156
  end
138
-
139
- # Layers additional behavior on DateTime#<=> so that Time and ActiveSupport::TimeWithZone instances can be compared with a DateTime
140
- def <=>(other)
141
- if other.kind_of?(Infinity)
142
- super
143
- elsif other.respond_to? :to_datetime
144
- super other.to_datetime
145
- else
146
- nil
147
- end
148
- end
149
157
  end