activesupport 4.2.11.3 → 5.0.7.2

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +678 -348
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +2 -3
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +1 -1
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +36 -22
  9. data/lib/active_support/cache/mem_cache_store.rb +63 -54
  10. data/lib/active_support/cache/memory_store.rb +16 -21
  11. data/lib/active_support/cache/null_store.rb +1 -4
  12. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  13. data/lib/active_support/cache/strategy/local_cache_middleware.rb +4 -4
  14. data/lib/active_support/cache.rb +71 -87
  15. data/lib/active_support/callbacks.rb +109 -113
  16. data/lib/active_support/concern.rb +1 -1
  17. data/lib/active_support/concurrency/latch.rb +11 -12
  18. data/lib/active_support/concurrency/share_lock.rb +226 -0
  19. data/lib/active_support/configurable.rb +1 -0
  20. data/lib/active_support/core_ext/array/access.rb +27 -1
  21. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  22. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  23. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  24. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  25. data/lib/active_support/core_ext/array.rb +1 -0
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  27. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  28. data/lib/active_support/core_ext/class/subclasses.rb +3 -2
  29. data/lib/active_support/core_ext/class.rb +0 -1
  30. data/lib/active_support/core_ext/date/blank.rb +12 -0
  31. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  32. data/lib/active_support/core_ext/date/conversions.rb +7 -6
  33. data/lib/active_support/core_ext/date.rb +1 -1
  34. data/lib/active_support/core_ext/date_and_time/calculations.rb +100 -27
  35. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -1
  36. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  37. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  38. data/lib/active_support/core_ext/date_time/calculations.rb +14 -8
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +1 -1
  41. data/lib/active_support/core_ext/enumerable.rb +75 -25
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +22 -2
  44. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  45. data/lib/active_support/core_ext/hash/except.rb +9 -8
  46. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  47. data/lib/active_support/core_ext/hash/keys.rb +25 -21
  48. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  49. data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
  50. data/lib/active_support/core_ext/integer/time.rb +2 -2
  51. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  53. data/lib/active_support/core_ext/kernel/reporting.rb +2 -84
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +5 -2
  56. data/lib/active_support/core_ext/marshal.rb +7 -9
  57. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  58. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  62. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  63. data/lib/active_support/core_ext/module/delegation.rb +11 -20
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +8 -2
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -13
  67. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  68. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  69. data/lib/active_support/core_ext/module.rb +1 -0
  70. data/lib/active_support/core_ext/name_error.rb +15 -2
  71. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  72. data/lib/active_support/core_ext/numeric/conversions.rb +78 -77
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +26 -6
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +15 -3
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +7 -12
  79. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  80. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  81. data/lib/active_support/core_ext/object/json.rb +15 -7
  82. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  83. data/lib/active_support/core_ext/object/try.rb +67 -21
  84. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  85. data/lib/active_support/core_ext/object.rb +0 -1
  86. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  87. data/lib/active_support/core_ext/range/each.rb +16 -18
  88. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  89. data/lib/active_support/core_ext/securerandom.rb +23 -0
  90. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  91. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  92. data/lib/active_support/core_ext/string/filters.rb +1 -2
  93. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  94. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  95. data/lib/active_support/core_ext/string/output_safety.rb +12 -14
  96. data/lib/active_support/core_ext/string/strip.rb +3 -6
  97. data/lib/active_support/core_ext/struct.rb +3 -6
  98. data/lib/active_support/core_ext/time/calculations.rb +18 -9
  99. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  100. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  101. data/lib/active_support/core_ext/time/zones.rb +36 -4
  102. data/lib/active_support/core_ext/time.rb +0 -1
  103. data/lib/active_support/core_ext/uri.rb +1 -3
  104. data/lib/active_support/core_ext.rb +2 -1
  105. data/lib/active_support/dependencies/interlock.rb +55 -0
  106. data/lib/active_support/dependencies.rb +88 -95
  107. data/lib/active_support/deprecation/behaviors.rb +15 -1
  108. data/lib/active_support/deprecation/instance_delegator.rb +13 -0
  109. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  110. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  111. data/lib/active_support/deprecation/reporting.rb +23 -5
  112. data/lib/active_support/deprecation.rb +1 -1
  113. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  114. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  115. data/lib/active_support/duration.rb +90 -15
  116. data/lib/active_support/evented_file_update_checker.rb +199 -0
  117. data/lib/active_support/execution_wrapper.rb +126 -0
  118. data/lib/active_support/executor.rb +6 -0
  119. data/lib/active_support/file_update_checker.rb +23 -3
  120. data/lib/active_support/gem_version.rb +5 -5
  121. data/lib/active_support/gzip.rb +1 -1
  122. data/lib/active_support/hash_with_indifferent_access.rb +40 -11
  123. data/lib/active_support/i18n_railtie.rb +25 -4
  124. data/lib/active_support/inflector/inflections.rb +36 -5
  125. data/lib/active_support/inflector/methods.rb +97 -90
  126. data/lib/active_support/inflector/transliterate.rb +36 -21
  127. data/lib/active_support/json/decoding.rb +11 -10
  128. data/lib/active_support/json/encoding.rb +1 -51
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/lazy_load_hooks.rb +46 -18
  131. data/lib/active_support/locale/en.yml +2 -0
  132. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  133. data/lib/active_support/log_subscriber.rb +1 -1
  134. data/lib/active_support/logger.rb +3 -4
  135. data/lib/active_support/logger_silence.rb +2 -1
  136. data/lib/active_support/logger_thread_safe_level.rb +2 -3
  137. data/lib/active_support/message_encryptor.rb +7 -7
  138. data/lib/active_support/message_verifier.rb +70 -8
  139. data/lib/active_support/multibyte/chars.rb +12 -3
  140. data/lib/active_support/multibyte/unicode.rb +44 -21
  141. data/lib/active_support/notifications/fanout.rb +5 -5
  142. data/lib/active_support/notifications/instrumenter.rb +20 -2
  143. data/lib/active_support/notifications.rb +2 -2
  144. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  145. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  146. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  147. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  148. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  149. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  150. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  151. data/lib/active_support/number_helper.rb +90 -67
  152. data/lib/active_support/ordered_hash.rb +1 -1
  153. data/lib/active_support/ordered_options.rb +15 -1
  154. data/lib/active_support/per_thread_registry.rb +3 -0
  155. data/lib/active_support/rails.rb +2 -2
  156. data/lib/active_support/railtie.rb +6 -1
  157. data/lib/active_support/reloader.rb +129 -0
  158. data/lib/active_support/rescuable.rb +101 -47
  159. data/lib/active_support/string_inquirer.rb +1 -1
  160. data/lib/active_support/subscriber.rb +5 -10
  161. data/lib/active_support/tagged_logging.rb +8 -7
  162. data/lib/active_support/test_case.rb +17 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/deprecation.rb +9 -8
  165. data/lib/active_support/testing/file_fixtures.rb +34 -0
  166. data/lib/active_support/testing/isolation.rb +22 -8
  167. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  168. data/lib/active_support/testing/stream.rb +42 -0
  169. data/lib/active_support/testing/time_helpers.rb +3 -1
  170. data/lib/active_support/time_with_zone.rb +123 -33
  171. data/lib/active_support/values/time_zone.rb +101 -47
  172. data/lib/active_support/values/unicode_tables.dat +0 -0
  173. data/lib/active_support/xml_mini/jdom.rb +1 -1
  174. data/lib/active_support/xml_mini/libxml.rb +2 -2
  175. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  176. data/lib/active_support.rb +11 -6
  177. metadata +36 -17
  178. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  179. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  180. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  181. data/lib/active_support/core_ext/object/itself.rb +0 -15
  182. data/lib/active_support/core_ext/thread.rb +0 -86
@@ -21,12 +21,24 @@ class Array
21
21
  # %w( a b c ).to(-10) # => []
22
22
  def to(position)
23
23
  if position >= 0
24
- first position + 1
24
+ take position + 1
25
25
  else
26
26
  self[0..position]
27
27
  end
28
28
  end
29
29
 
30
+ # Returns a copy of the Array without the specified elements.
31
+ #
32
+ # people = ["David", "Rafael", "Aaron", "Todd"]
33
+ # people.without "Aaron", "Todd"
34
+ # => ["David", "Rafael"]
35
+ #
36
+ # Note: This is an optimization of `Enumerable#without` that uses `Array#-`
37
+ # instead of `Array#reject` for performance reasons.
38
+ def without(*elements)
39
+ self - elements
40
+ end
41
+
30
42
  # Equal to <tt>self[1]</tt>.
31
43
  #
32
44
  # %w( a b c d e ).second # => "b"
@@ -61,4 +73,18 @@ class Array
61
73
  def forty_two
62
74
  self[41]
63
75
  end
76
+
77
+ # Equal to <tt>self[-3]</tt>.
78
+ #
79
+ # %w( a b c d e ).third_to_last # => "c"
80
+ def third_to_last
81
+ self[-3]
82
+ end
83
+
84
+ # Equal to <tt>self[-2]</tt>.
85
+ #
86
+ # %w( a b c d e ).second_to_last # => "d"
87
+ def second_to_last
88
+ self[-2]
89
+ end
64
90
  end
@@ -32,7 +32,7 @@ class Array
32
32
  # ['one', 'two', 'three'].to_sentence # => "one, two, and three"
33
33
  #
34
34
  # ['one', 'two'].to_sentence(passing: 'invalid option')
35
- # # => ArgumentError: Unknown key :passing
35
+ # # => ArgumentError: Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale
36
36
  #
37
37
  # ['one', 'two'].to_sentence(two_words_connector: '-')
38
38
  # # => "one-two"
@@ -74,7 +74,7 @@ class Array
74
74
  when 0
75
75
  ''
76
76
  when 1
77
- self[0].to_s.dup
77
+ "#{self[0]}"
78
78
  when 2
79
79
  "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
80
80
  else
@@ -85,14 +85,16 @@ class Array
85
85
  # Extends <tt>Array#to_s</tt> to convert a collection of elements into a
86
86
  # comma separated id list if <tt>:db</tt> argument is given as the format.
87
87
  #
88
- # Blog.all.to_formatted_s(:db) # => "1,2,3"
88
+ # Blog.all.to_formatted_s(:db) # => "1,2,3"
89
+ # Blog.none.to_formatted_s(:db) # => "null"
90
+ # [1,2].to_formatted_s # => "[1, 2]"
89
91
  def to_formatted_s(format = :default)
90
92
  case format
91
93
  when :db
92
94
  if empty?
93
95
  'null'
94
96
  else
95
- collect { |element| element.id }.join(',')
97
+ collect(&:id).join(',')
96
98
  end
97
99
  else
98
100
  to_default_s
@@ -89,28 +89,19 @@ class Array
89
89
  # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
90
90
  # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
91
91
  def split(value = nil)
92
+ arr = self.dup
93
+ result = []
92
94
  if block_given?
93
- inject([[]]) do |results, element|
94
- if yield(element)
95
- results << []
96
- else
97
- results.last << element
98
- end
99
-
100
- results
95
+ while (idx = arr.index { |i| yield i })
96
+ result << arr.shift(idx)
97
+ arr.shift
101
98
  end
102
99
  else
103
- results, arr = [[]], self.dup
104
- until arr.empty?
105
- if (idx = arr.index(value))
106
- results.last.concat(arr.shift(idx))
107
- arr.shift
108
- results << []
109
- else
110
- results.last.concat(arr.shift(arr.size))
111
- end
100
+ while (idx = arr.index(value))
101
+ result << arr.shift(idx)
102
+ arr.shift
112
103
  end
113
- results
114
104
  end
105
+ result << arr
115
106
  end
116
107
  end
@@ -0,0 +1,17 @@
1
+ require 'active_support/array_inquirer'
2
+
3
+ class Array
4
+ # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way
5
+ # to check its string-like contents.
6
+ #
7
+ # pets = [:cat, :dog].inquiry
8
+ #
9
+ # pets.cat? # => true
10
+ # pets.ferret? # => false
11
+ #
12
+ # pets.any?(:cat, :ferret) # => true
13
+ # pets.any?(:ferret, :alligator) # => false
14
+ def inquiry
15
+ ActiveSupport::ArrayInquirer.new(self)
16
+ end
17
+ end
@@ -3,7 +3,7 @@ class Array
3
3
  #
4
4
  # Specifically:
5
5
  #
6
- # * If the argument is +nil+ an empty list is returned.
6
+ # * If the argument is +nil+ an empty array is returned.
7
7
  # * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
8
8
  # * Otherwise, returns an array with the argument as its single element.
9
9
  #
@@ -15,12 +15,13 @@ class Array
15
15
  #
16
16
  # * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
17
17
  # moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns
18
- # +nil+ right away.
18
+ # an array with the argument as its single element right away.
19
19
  # * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt>
20
20
  # raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
21
- # * It does not call +to_a+ on the argument, but returns an empty array if argument is +nil+.
21
+ # * It does not call +to_a+ on the argument, if the argument does not respond to +to_ary+
22
+ # it returns an array with the argument as its single element.
22
23
  #
23
- # The second point is easily explained with some enumerables:
24
+ # The last point is easily explained with some enumerables:
24
25
  #
25
26
  # Array(foo: :bar) # => [[:foo, :bar]]
26
27
  # Array.wrap(foo: :bar) # => [{:foo=>:bar}]
@@ -4,3 +4,4 @@ require 'active_support/core_ext/array/conversions'
4
4
  require 'active_support/core_ext/array/extract_options'
5
5
  require 'active_support/core_ext/array/grouping'
6
6
  require 'active_support/core_ext/array/prepend_and_append'
7
+ require 'active_support/core_ext/array/inquiry'
@@ -1,16 +1,14 @@
1
1
  require 'bigdecimal'
2
2
  require 'bigdecimal/util'
3
3
 
4
- class BigDecimal
5
- DEFAULT_STRING_FORMAT = 'F'
6
- def to_formatted_s(*args)
7
- if args[0].is_a?(Symbol)
8
- super
9
- else
10
- format = args[0] || DEFAULT_STRING_FORMAT
11
- _original_to_s(format)
4
+ module ActiveSupport
5
+ module BigDecimalWithDefaultFormat #:nodoc:
6
+ DEFAULT_STRING_FORMAT = 'F'
7
+
8
+ def to_s(format = nil)
9
+ super(format || DEFAULT_STRING_FORMAT)
12
10
  end
13
11
  end
14
- alias_method :_original_to_s, :to_s
15
- alias_method :to_s, :to_formatted_s
16
12
  end
13
+
14
+ BigDecimal.prepend(ActiveSupport::BigDecimalWithDefaultFormat)
@@ -75,11 +75,15 @@ class Class
75
75
  instance_predicate = options.fetch(:instance_predicate, true)
76
76
 
77
77
  attrs.each do |name|
78
+ remove_possible_singleton_method(name)
78
79
  define_singleton_method(name) { nil }
80
+
81
+ remove_possible_singleton_method("#{name}?")
79
82
  define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
80
83
 
81
84
  ivar = "@#{name}"
82
85
 
86
+ remove_possible_singleton_method("#{name}=")
83
87
  define_singleton_method("#{name}=") do |val|
84
88
  singleton_class.class_eval do
85
89
  remove_possible_method(name)
@@ -110,18 +114,15 @@ class Class
110
114
  self.class.public_send name
111
115
  end
112
116
  end
117
+
118
+ remove_possible_method "#{name}?"
113
119
  define_method("#{name}?") { !!public_send(name) } if instance_predicate
114
120
  end
115
121
 
116
- attr_writer name if instance_writer
117
- end
118
- end
119
-
120
- private
121
-
122
- unless respond_to?(:singleton_class?)
123
- def singleton_class?
124
- ancestors.first != self
122
+ if instance_writer
123
+ remove_possible_method "#{name}="
124
+ attr_writer name
125
125
  end
126
126
  end
127
+ end
127
128
  end
@@ -3,7 +3,8 @@ require 'active_support/core_ext/module/reachable'
3
3
 
4
4
  class Class
5
5
  begin
6
- ObjectSpace.each_object(Class.new) {}
6
+ # Test if this Ruby supports each_object against singleton_class
7
+ ObjectSpace.each_object(Numeric.singleton_class) {}
7
8
 
8
9
  def descendants # :nodoc:
9
10
  descendants = []
@@ -12,7 +13,7 @@ class Class
12
13
  end
13
14
  descendants
14
15
  end
15
- rescue StandardError # JRuby
16
+ rescue StandardError # JRuby 9.0.4.0 and earlier
16
17
  def descendants # :nodoc:
17
18
  descendants = []
18
19
  ObjectSpace.each_object(Class) do |k|
@@ -1,3 +1,2 @@
1
1
  require 'active_support/core_ext/class/attribute'
2
- require 'active_support/core_ext/class/delegating_attributes'
3
2
  require 'active_support/core_ext/class/subclasses'
@@ -0,0 +1,12 @@
1
+ require 'date'
2
+
3
+ class Date #:nodoc:
4
+ # No Date is blank:
5
+ #
6
+ # Date.today.blank? # => false
7
+ #
8
+ # @return [false]
9
+ def blank?
10
+ false
11
+ end
12
+ end
@@ -26,7 +26,7 @@ class Date
26
26
  Thread.current[:beginning_of_week] = find_beginning_of_week!(week_start)
27
27
  end
28
28
 
29
- # Returns week start day symbol (e.g. :monday), or raises an ArgumentError for invalid day symbol.
29
+ # Returns week start day symbol (e.g. :monday), or raises an +ArgumentError+ for invalid day symbol.
30
30
  def find_beginning_of_week!(week_start)
31
31
  raise ArgumentError, "Invalid beginning of week: #{week_start}" unless ::Date::DAYS_INTO_WEEK.key?(week_start)
32
32
  week_start
@@ -5,15 +5,15 @@ 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',
8
+ :short => '%d %b',
9
+ :long => '%B %d, %Y',
10
10
  :db => '%Y-%m-%d',
11
11
  :number => '%Y%m%d',
12
12
  :long_ordinal => lambda { |date|
13
13
  day_format = ActiveSupport::Inflector.ordinalize(date.day)
14
14
  date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007"
15
15
  },
16
- :rfc822 => '%e %b %Y',
16
+ :rfc822 => '%d %b %Y',
17
17
  :iso8601 => lambda { |date| date.iso8601 }
18
18
  }
19
19
 
@@ -75,11 +75,12 @@ class Date
75
75
  #
76
76
  # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
77
77
  #
78
- # date.to_time # => Sat Nov 10 00:00:00 0800 2007
79
- # date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007
78
+ # date.to_time # => 2007-11-10 00:00:00 0800
79
+ # date.to_time(:local) # => 2007-11-10 00:00:00 0800
80
80
  #
81
- # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
81
+ # date.to_time(:utc) # => 2007-11-10 00:00:00 UTC
82
82
  def to_time(form = :local)
83
+ raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form)
83
84
  ::Time.send(form, year, month, day)
84
85
  end
85
86
 
@@ -1,5 +1,5 @@
1
1
  require 'active_support/core_ext/date/acts_like'
2
+ require 'active_support/core_ext/date/blank'
2
3
  require 'active_support/core_ext/date/calculations'
3
4
  require 'active_support/core_ext/date/conversions'
4
5
  require 'active_support/core_ext/date/zones'
5
-
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/object/try'
2
+
1
3
  module DateAndTime
2
4
  module Calculations
3
5
  DAYS_INTO_WEEK = {
@@ -9,15 +11,26 @@ module DateAndTime
9
11
  :saturday => 5,
10
12
  :sunday => 6
11
13
  }
14
+ WEEKEND_DAYS = [ 6, 0 ]
12
15
 
13
16
  # Returns a new date/time representing yesterday.
14
17
  def yesterday
15
- advance(:days => -1)
18
+ advance(days: -1)
19
+ end
20
+
21
+ # Returns a new date/time representing the previous day.
22
+ def prev_day
23
+ advance(days: -1)
16
24
  end
17
25
 
18
26
  # Returns a new date/time representing tomorrow.
19
27
  def tomorrow
20
- advance(:days => 1)
28
+ advance(days: 1)
29
+ end
30
+
31
+ # Returns a new date/time representing the next day.
32
+ def next_day
33
+ advance(days: 1)
21
34
  end
22
35
 
23
36
  # Returns true if the date/time is today.
@@ -35,6 +48,16 @@ module DateAndTime
35
48
  self > self.class.current
36
49
  end
37
50
 
51
+ # Returns true if the date/time falls on a Saturday or Sunday.
52
+ def on_weekend?
53
+ WEEKEND_DAYS.include?(wday)
54
+ end
55
+
56
+ # Returns true if the date/time does not fall on a Saturday or Sunday.
57
+ def on_weekday?
58
+ !WEEKEND_DAYS.include?(wday)
59
+ end
60
+
38
61
  # Returns a new date/time the specified number of days ago.
39
62
  def days_ago(days)
40
63
  advance(:days => -days)
@@ -76,15 +99,28 @@ module DateAndTime
76
99
  end
77
100
 
78
101
  # Returns a new date/time at the start of the month.
79
- # DateTime objects will have a time set to 0:00.
102
+ #
103
+ # today = Date.today # => Thu, 18 Jun 2015
104
+ # today.beginning_of_month # => Mon, 01 Jun 2015
105
+ #
106
+ # +DateTime+ objects will have a time set to 0:00.
107
+ #
108
+ # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000
109
+ # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000
80
110
  def beginning_of_month
81
111
  first_hour(change(:day => 1))
82
112
  end
83
113
  alias :at_beginning_of_month :beginning_of_month
84
114
 
85
115
  # 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.
116
+ #
117
+ # today = Date.today # => Fri, 10 Jul 2015
118
+ # today.beginning_of_quarter # => Wed, 01 Jul 2015
119
+ #
120
+ # +DateTime+ objects will have a time set to 0:00.
121
+ #
122
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
123
+ # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
88
124
  def beginning_of_quarter
89
125
  first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
90
126
  beginning_of_month.change(:month => first_quarter_month)
@@ -92,17 +128,29 @@ module DateAndTime
92
128
  alias :at_beginning_of_quarter :beginning_of_quarter
93
129
 
94
130
  # 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.
131
+ #
132
+ # today = Date.today # => Fri, 10 Jul 2015
133
+ # today.end_of_quarter # => Wed, 30 Sep 2015
134
+ #
135
+ # +DateTime+ objects will have a time set to 23:59:59.
136
+ #
137
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
138
+ # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
97
139
  def end_of_quarter
98
140
  last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
99
141
  beginning_of_month.change(:month => last_quarter_month).end_of_month
100
142
  end
101
143
  alias :at_end_of_quarter :end_of_quarter
102
144
 
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.
145
+ # Returns a new date/time at the beginning of the year.
146
+ #
147
+ # today = Date.today # => Fri, 10 Jul 2015
148
+ # today.beginning_of_year # => Thu, 01 Jan 2015
149
+ #
150
+ # +DateTime+ objects will have a time set to 0:00.
151
+ #
152
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
153
+ # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000
106
154
  def beginning_of_year
107
155
  change(:month => 1).beginning_of_month
108
156
  end
@@ -115,16 +163,27 @@ module DateAndTime
115
163
  #
116
164
  # The +given_day_in_next_week+ defaults to the beginning of the week
117
165
  # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
166
+ # when set.
118
167
  #
119
168
  # today = Date.today # => Thu, 07 May 2015
120
169
  # today.next_week(:friday) # => Fri, 15 May 2015
121
170
  #
122
- # when set. +DateTime+ objects have their time set to 0:00.
171
+ # +DateTime+ objects have their time set to 0:00 unless +same_time+ is true.
123
172
  #
124
- # now = Time.current # => Thu, 07 May 2015 13:31:16 UTC +00:00
125
- # now.next_week # => Mon, 11 May 2015 00:00:00 UTC +00:00
126
- def next_week(given_day_in_next_week = Date.beginning_of_week)
127
- first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
173
+ # now = DateTime.current # => Thu, 07 May 2015 13:31:16 +0000
174
+ # now.next_week # => Mon, 11 May 2015 00:00:00 +0000
175
+ def next_week(given_day_in_next_week = Date.beginning_of_week, same_time: false)
176
+ result = first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
177
+ same_time ? copy_time_to(result) : result
178
+ end
179
+
180
+ # Returns a new date/time representing the next weekday.
181
+ def next_weekday
182
+ if next_day.on_weekend?
183
+ next_week(:monday, same_time: true)
184
+ else
185
+ next_day
186
+ end
128
187
  end
129
188
 
130
189
  # Short-hand for months_since(1).
@@ -145,12 +204,23 @@ module DateAndTime
145
204
  # Returns a new date/time representing the given day in the previous week.
146
205
  # Week is assumed to start on +start_day+, default is
147
206
  # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
148
- # DateTime objects have their time set to 0:00.
149
- def prev_week(start_day = Date.beginning_of_week)
150
- first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
207
+ # DateTime objects have their time set to 0:00 unless +same_time+ is true.
208
+ def prev_week(start_day = Date.beginning_of_week, same_time: false)
209
+ result = first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
210
+ same_time ? copy_time_to(result) : result
151
211
  end
152
212
  alias_method :last_week, :prev_week
153
213
 
214
+ # Returns a new date/time representing the previous weekday.
215
+ def prev_weekday
216
+ if prev_day.on_weekend?
217
+ copy_time_to(beginning_of_week(:friday))
218
+ else
219
+ prev_day
220
+ end
221
+ end
222
+ alias_method :last_weekday, :prev_weekday
223
+
154
224
  # Short-hand for months_ago(1).
155
225
  def prev_month
156
226
  months_ago(1)
@@ -246,17 +316,20 @@ module DateAndTime
246
316
  end
247
317
 
248
318
  private
319
+ def first_hour(date_or_time)
320
+ date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time
321
+ end
249
322
 
250
- def first_hour(date_or_time)
251
- date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time
252
- end
323
+ def last_hour(date_or_time)
324
+ date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time
325
+ end
253
326
 
254
- def last_hour(date_or_time)
255
- date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time
256
- end
327
+ def days_span(day)
328
+ (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
329
+ end
257
330
 
258
- def days_span(day)
259
- (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
260
- end
331
+ def copy_time_to(other)
332
+ other.change(hour: hour, min: min, sec: sec, nsec: try(:nsec))
333
+ end
261
334
  end
262
335
  end
@@ -1,5 +1,4 @@
1
1
  require 'active_support/core_ext/module/attribute_accessors'
2
- require 'active_support/core_ext/module/remove_method'
3
2
 
4
3
  module DateAndTime
5
4
  module Compatibility
@@ -4,8 +4,8 @@ module DateAndTime
4
4
  # if Time.zone_default is set. Otherwise, it returns the current time.
5
5
  #
6
6
  # Time.zone = 'Hawaii' # => 'Hawaii'
7
- # DateTime.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
8
- # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
7
+ # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
8
+ # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
9
9
  #
10
10
  # This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
11
11
  # instead of the operating system's time zone.
@@ -14,8 +14,7 @@ module DateAndTime
14
14
  # and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
15
15
  #
16
16
  # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
17
- # DateTime.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
18
- # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
17
+ # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
19
18
  def in_time_zone(zone = ::Time.zone)
20
19
  time_zone = ::Time.find_zone! zone
21
20
  time = acts_like?(:time) ? self : nil
@@ -0,0 +1,12 @@
1
+ require 'date'
2
+
3
+ class DateTime #:nodoc:
4
+ # No DateTime is ever blank:
5
+ #
6
+ # DateTime.now.blank? # => false
7
+ #
8
+ # @return [false]
9
+ def blank?
10
+ false
11
+ end
12
+ end
@@ -10,7 +10,11 @@ class DateTime
10
10
  end
11
11
  end
12
12
 
13
- # Seconds since midnight: DateTime.now.seconds_since_midnight.
13
+ # Returns the number of seconds since 00:00:00.
14
+ #
15
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
16
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
17
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
14
18
  def seconds_since_midnight
15
19
  sec + (min * 60) + (hour * 3600)
16
20
  end
@@ -157,12 +161,17 @@ class DateTime
157
161
  end
158
162
  alias_method :getlocal, :localtime
159
163
 
160
- # Returns a <tt>DateTime</tt> instance of the simultaneous time in the UTC timezone.
164
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
161
165
  #
162
166
  # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
163
167
  # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC
164
168
  def utc
165
- new_offset(0)
169
+ utc = new_offset(0)
170
+
171
+ Time.utc(
172
+ utc.year, utc.month, utc.day,
173
+ utc.hour, utc.min, utc.sec + utc.sec_fraction
174
+ )
166
175
  end
167
176
  alias_method :getgm, :utc
168
177
  alias_method :getutc, :utc
@@ -181,13 +190,10 @@ class DateTime
181
190
  # Layers additional behavior on DateTime#<=> so that Time and
182
191
  # ActiveSupport::TimeWithZone instances can be compared with a DateTime.
183
192
  def <=>(other)
184
- if other.kind_of?(Infinity)
185
- super
186
- elsif other.respond_to? :to_datetime
193
+ if other.respond_to? :to_datetime
187
194
  super other.to_datetime rescue nil
188
195
  else
189
- nil
196
+ super
190
197
  end
191
198
  end
192
-
193
199
  end
@@ -40,6 +40,8 @@ class DateTime
40
40
  alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
41
41
  alias_method :to_s, :to_formatted_s
42
42
 
43
+ # Returns a formatted string of the offset from UTC, or an alternative
44
+ # string if the time zone is already UTC.
43
45
  #
44
46
  # datetime = DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-6, 24))
45
47
  # datetime.formatted_offset # => "-06:00"
@@ -1,5 +1,5 @@
1
1
  require 'active_support/core_ext/date_time/acts_like'
2
+ require 'active_support/core_ext/date_time/blank'
2
3
  require 'active_support/core_ext/date_time/calculations'
3
4
  require 'active_support/core_ext/date_time/compatibility'
4
5
  require 'active_support/core_ext/date_time/conversions'
5
- require 'active_support/core_ext/date_time/zones'