activesupport 4.2.0 → 5.0.0

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +630 -220
  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.rb +73 -89
  14. data/lib/active_support/callbacks.rb +195 -155
  15. data/lib/active_support/concern.rb +2 -2
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +186 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext/array/access.rb +27 -1
  20. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  21. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  22. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  23. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  24. data/lib/active_support/core_ext/array.rb +1 -0
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  27. data/lib/active_support/core_ext/class/subclasses.rb +3 -4
  28. data/lib/active_support/core_ext/class.rb +0 -1
  29. data/lib/active_support/core_ext/date/blank.rb +12 -0
  30. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date/conversions.rb +13 -6
  32. data/lib/active_support/core_ext/date.rb +1 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
  38. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +2 -1
  41. data/lib/active_support/core_ext/enumerable.rb +49 -5
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +23 -4
  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 +23 -19
  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 +1 -16
  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 -83
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +4 -2
  56. data/lib/active_support/core_ext/marshal.rb +12 -11
  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 +35 -25
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +4 -0
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
  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 +74 -64
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +24 -19
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +17 -5
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +8 -13
  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 +68 -22
  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/access.rb +1 -1
  91. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  92. data/lib/active_support/core_ext/string/conversions.rb +4 -3
  93. data/lib/active_support/core_ext/string/filters.rb +5 -5
  94. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  95. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  96. data/lib/active_support/core_ext/string/output_safety.rb +18 -16
  97. data/lib/active_support/core_ext/string/strip.rb +3 -6
  98. data/lib/active_support/core_ext/struct.rb +3 -6
  99. data/lib/active_support/core_ext/time/calculations.rb +36 -11
  100. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  101. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  102. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  103. data/lib/active_support/core_ext/time/zones.rb +36 -4
  104. data/lib/active_support/core_ext/time.rb +1 -1
  105. data/lib/active_support/core_ext/uri.rb +1 -3
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/dependencies/interlock.rb +51 -0
  108. data/lib/active_support/dependencies.rb +87 -95
  109. data/lib/active_support/deprecation/behaviors.rb +16 -2
  110. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  111. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  112. data/lib/active_support/deprecation/reporting.rb +23 -5
  113. data/lib/active_support/deprecation.rb +1 -1
  114. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  115. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  116. data/lib/active_support/duration.rb +55 -10
  117. data/lib/active_support/evented_file_update_checker.rb +194 -0
  118. data/lib/active_support/execution_wrapper.rb +117 -0
  119. data/lib/active_support/executor.rb +6 -0
  120. data/lib/active_support/file_update_checker.rb +23 -3
  121. data/lib/active_support/gem_version.rb +3 -3
  122. data/lib/active_support/hash_with_indifferent_access.rb +46 -13
  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 +4 -49
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/locale/en.yml +2 -0
  131. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  132. data/lib/active_support/log_subscriber.rb +1 -1
  133. data/lib/active_support/logger.rb +50 -1
  134. data/lib/active_support/logger_silence.rb +8 -4
  135. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  136. data/lib/active_support/message_encryptor.rb +4 -4
  137. data/lib/active_support/message_verifier.rb +70 -8
  138. data/lib/active_support/multibyte/chars.rb +13 -4
  139. data/lib/active_support/multibyte/unicode.rb +44 -21
  140. data/lib/active_support/notifications/fanout.rb +6 -6
  141. data/lib/active_support/notifications/instrumenter.rb +20 -2
  142. data/lib/active_support/notifications.rb +2 -2
  143. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  144. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  145. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  147. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  148. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  149. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  150. data/lib/active_support/number_helper.rb +90 -67
  151. data/lib/active_support/ordered_hash.rb +1 -1
  152. data/lib/active_support/ordered_options.rb +15 -1
  153. data/lib/active_support/per_thread_registry.rb +8 -3
  154. data/lib/active_support/rails.rb +2 -2
  155. data/lib/active_support/railtie.rb +6 -1
  156. data/lib/active_support/reloader.rb +129 -0
  157. data/lib/active_support/rescuable.rb +93 -47
  158. data/lib/active_support/security_utils.rb +7 -0
  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 +3 -1
  162. data/lib/active_support/test_case.rb +15 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/autorun.rb +8 -1
  165. data/lib/active_support/testing/deprecation.rb +9 -8
  166. data/lib/active_support/testing/file_fixtures.rb +34 -0
  167. data/lib/active_support/testing/isolation.rb +22 -8
  168. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  169. data/lib/active_support/testing/stream.rb +42 -0
  170. data/lib/active_support/testing/time_helpers.rb +13 -10
  171. data/lib/active_support/time_with_zone.rb +135 -46
  172. data/lib/active_support/values/time_zone.rb +95 -47
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/xml_mini/jdom.rb +7 -6
  175. data/lib/active_support/xml_mini/libxml.rb +2 -2
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/rexml.rb +7 -8
  178. data/lib/active_support/xml_mini.rb +22 -14
  179. data/lib/active_support.rb +20 -6
  180. metadata +32 -35
  181. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
  182. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  183. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  184. data/lib/active_support/core_ext/object/itself.rb +0 -15
  185. data/lib/active_support/core_ext/thread.rb +0 -86
@@ -0,0 +1,186 @@
1
+ require 'thread'
2
+ require 'monitor'
3
+
4
+ module ActiveSupport
5
+ module Concurrency
6
+ # A share/exclusive lock, otherwise known as a read/write lock.
7
+ #
8
+ # https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
9
+ class ShareLock
10
+ include MonitorMixin
11
+
12
+ # We track Thread objects, instead of just using counters, because
13
+ # we need exclusive locks to be reentrant, and we need to be able
14
+ # to upgrade share locks to exclusive.
15
+
16
+
17
+ def initialize
18
+ super()
19
+
20
+ @cv = new_cond
21
+
22
+ @sharing = Hash.new(0)
23
+ @waiting = {}
24
+ @exclusive_thread = nil
25
+ @exclusive_depth = 0
26
+ end
27
+
28
+ # Returns false if +no_wait+ is set and the lock is not
29
+ # immediately available. Otherwise, returns true after the lock
30
+ # has been acquired.
31
+ #
32
+ # +purpose+ and +compatible+ work together; while this thread is
33
+ # waiting for the exclusive lock, it will yield its share (if any)
34
+ # to any other attempt whose +purpose+ appears in this attempt's
35
+ # +compatible+ list. This allows a "loose" upgrade, which, being
36
+ # less strict, prevents some classes of deadlocks.
37
+ #
38
+ # For many resources, loose upgrades are sufficient: if a thread
39
+ # is awaiting a lock, it is not running any other code. With
40
+ # +purpose+ matching, it is possible to yield only to other
41
+ # threads whose activity will not interfere.
42
+ def start_exclusive(purpose: nil, compatible: [], no_wait: false)
43
+ synchronize do
44
+ unless @exclusive_thread == Thread.current
45
+ if busy_for_exclusive?(purpose)
46
+ return false if no_wait
47
+
48
+ yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
49
+ @cv.wait_while { busy_for_exclusive?(purpose) }
50
+ end
51
+ end
52
+ @exclusive_thread = Thread.current
53
+ end
54
+ @exclusive_depth += 1
55
+
56
+ true
57
+ end
58
+ end
59
+
60
+ # Relinquish the exclusive lock. Must only be called by the thread
61
+ # that called start_exclusive (and currently holds the lock).
62
+ def stop_exclusive(compatible: [])
63
+ synchronize do
64
+ raise "invalid unlock" if @exclusive_thread != Thread.current
65
+
66
+ @exclusive_depth -= 1
67
+ if @exclusive_depth == 0
68
+ @exclusive_thread = nil
69
+
70
+ if eligible_waiters?(compatible)
71
+ yield_shares(compatible: compatible, block_share: true) do
72
+ @cv.wait_while { @exclusive_thread || eligible_waiters?(compatible) }
73
+ end
74
+ end
75
+ @cv.broadcast
76
+ end
77
+ end
78
+ end
79
+
80
+ def start_sharing
81
+ synchronize do
82
+ if @sharing[Thread.current] > 0 || @exclusive_thread == Thread.current
83
+ # We already hold a lock; nothing to wait for
84
+ elsif @waiting[Thread.current]
85
+ # We're nested inside a +yield_shares+ call: we'll resume as
86
+ # soon as there isn't an exclusive lock in our way
87
+ @cv.wait_while { @exclusive_thread }
88
+ else
89
+ # This is an initial / outermost share call: any outstanding
90
+ # requests for an exclusive lock get to go first
91
+ @cv.wait_while { busy_for_sharing?(false) }
92
+ end
93
+ @sharing[Thread.current] += 1
94
+ end
95
+ end
96
+
97
+ def stop_sharing
98
+ synchronize do
99
+ if @sharing[Thread.current] > 1
100
+ @sharing[Thread.current] -= 1
101
+ else
102
+ @sharing.delete Thread.current
103
+ @cv.broadcast
104
+ end
105
+ end
106
+ end
107
+
108
+ # Execute the supplied block while holding the Exclusive lock. If
109
+ # +no_wait+ is set and the lock is not immediately available,
110
+ # returns +nil+ without yielding. Otherwise, returns the result of
111
+ # the block.
112
+ #
113
+ # See +start_exclusive+ for other options.
114
+ def exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false)
115
+ if start_exclusive(purpose: purpose, compatible: compatible, no_wait: no_wait)
116
+ begin
117
+ yield
118
+ ensure
119
+ stop_exclusive(compatible: after_compatible)
120
+ end
121
+ end
122
+ end
123
+
124
+ # Execute the supplied block while holding the Share lock.
125
+ def sharing
126
+ start_sharing
127
+ begin
128
+ yield
129
+ ensure
130
+ stop_sharing
131
+ end
132
+ end
133
+
134
+ # Temporarily give up all held Share locks while executing the
135
+ # supplied block, allowing any +compatible+ exclusive lock request
136
+ # to proceed.
137
+ def yield_shares(purpose: nil, compatible: [], block_share: false)
138
+ loose_shares = previous_wait = nil
139
+ synchronize do
140
+ if loose_shares = @sharing.delete(Thread.current)
141
+ if previous_wait = @waiting[Thread.current]
142
+ purpose = nil unless purpose == previous_wait[0]
143
+ compatible &= previous_wait[1]
144
+ end
145
+ compatible |= [false] unless block_share
146
+ @waiting[Thread.current] = [purpose, compatible]
147
+ end
148
+
149
+ @cv.broadcast
150
+ end
151
+
152
+ begin
153
+ yield
154
+ ensure
155
+ synchronize do
156
+ @cv.wait_while { @exclusive_thread && @exclusive_thread != Thread.current }
157
+
158
+ if previous_wait
159
+ @waiting[Thread.current] = previous_wait
160
+ else
161
+ @waiting.delete Thread.current
162
+ end
163
+ @sharing[Thread.current] = loose_shares if loose_shares
164
+ end
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ # Must be called within synchronize
171
+ def busy_for_exclusive?(purpose)
172
+ busy_for_sharing?(purpose) ||
173
+ @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0)
174
+ end
175
+
176
+ def busy_for_sharing?(purpose)
177
+ (@exclusive_thread && @exclusive_thread != Thread.current) ||
178
+ @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) }
179
+ end
180
+
181
+ def eligible_waiters?(compatible)
182
+ @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
183
+ end
184
+ end
185
+ end
186
+ end
@@ -122,6 +122,7 @@ module ActiveSupport
122
122
  send("#{name}=", yield) if block_given?
123
123
  end
124
124
  end
125
+ private :config_accessor
125
126
  end
126
127
 
127
128
  # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
@@ -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|
@@ -25,8 +26,6 @@ class Class
25
26
 
26
27
  # Returns an array with the direct children of +self+.
27
28
  #
28
- # Integer.subclasses # => [Fixnum, Bignum]
29
- #
30
29
  # class Foo; end
31
30
  # class Bar < Foo; end
32
31
  # class Baz < Bar; end
@@ -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
 
@@ -35,6 +35,7 @@ class Date
35
35
  # date.to_s(:db) # => "2007-11-10"
36
36
  #
37
37
  # date.to_formatted_s(:short) # => "10 Nov"
38
+ # date.to_formatted_s(:number) # => "20071110"
38
39
  # date.to_formatted_s(:long) # => "November 10, 2007"
39
40
  # date.to_formatted_s(:long_ordinal) # => "November 10th, 2007"
40
41
  # date.to_formatted_s(:rfc822) # => "10 Nov 2007"
@@ -74,14 +75,20 @@ class Date
74
75
  #
75
76
  # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
76
77
  #
77
- # date.to_time # => Sat Nov 10 00:00:00 0800 2007
78
- # 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
79
80
  #
80
- # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
81
+ # date.to_time(:utc) # => 2007-11-10 00:00:00 UTC
81
82
  def to_time(form = :local)
83
+ raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form)
82
84
  ::Time.send(form, year, month, day)
83
85
  end
84
86
 
87
+ # Returns a string which represents the time in used time zone as DateTime
88
+ # defined by XML Schema:
89
+ #
90
+ # date = Date.new(2015, 05, 23) # => Sat, 23 May 2015
91
+ # date.xmlschema # => "2015-05-23T00:00:00+04:00"
85
92
  def xmlschema
86
93
  in_time_zone.xmlschema
87
94
  end
@@ -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
-