activesupport 4.2.11.3 → 5.2.8.1

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 (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +435 -403
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +4 -5
  5. data/lib/active_support/all.rb +5 -3
  6. data/lib/active_support/array_inquirer.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +7 -5
  8. data/lib/active_support/benchmarkable.rb +6 -4
  9. data/lib/active_support/builder.rb +3 -1
  10. data/lib/active_support/cache/file_store.rb +41 -35
  11. data/lib/active_support/cache/mem_cache_store.rb +91 -91
  12. data/lib/active_support/cache/memory_store.rb +27 -30
  13. data/lib/active_support/cache/null_store.rb +7 -8
  14. data/lib/active_support/cache/redis_cache_store.rb +466 -0
  15. data/lib/active_support/cache/strategy/local_cache.rb +67 -34
  16. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  17. data/lib/active_support/cache.rb +287 -196
  18. data/lib/active_support/callbacks.rb +640 -590
  19. data/lib/active_support/concern.rb +11 -5
  20. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  21. data/lib/active_support/concurrency/share_lock.rb +227 -0
  22. data/lib/active_support/configurable.rb +8 -5
  23. data/lib/active_support/core_ext/array/access.rb +29 -1
  24. data/lib/active_support/core_ext/array/conversions.rb +22 -18
  25. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  27. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  28. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -3
  29. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  30. data/lib/active_support/core_ext/array.rb +9 -6
  31. data/lib/active_support/core_ext/benchmark.rb +3 -1
  32. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  33. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  34. data/lib/active_support/core_ext/class/attribute.rb +41 -22
  35. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  36. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  37. data/lib/active_support/core_ext/class.rb +4 -3
  38. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  39. data/lib/active_support/core_ext/date/blank.rb +14 -0
  40. data/lib/active_support/core_ext/date/calculations.rb +11 -9
  41. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  42. data/lib/active_support/core_ext/date/zones.rb +4 -2
  43. data/lib/active_support/core_ext/date.rb +6 -4
  44. data/lib/active_support/core_ext/date_and_time/calculations.rb +170 -58
  45. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
  46. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
  47. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  48. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  49. data/lib/active_support/core_ext/date_time/calculations.rb +36 -18
  50. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  51. data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
  52. data/lib/active_support/core_ext/date_time.rb +7 -5
  53. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  54. data/lib/active_support/core_ext/digest.rb +3 -0
  55. data/lib/active_support/core_ext/enumerable.rb +101 -33
  56. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  57. data/lib/active_support/core_ext/file.rb +3 -1
  58. data/lib/active_support/core_ext/hash/compact.rb +14 -9
  59. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  60. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  61. data/lib/active_support/core_ext/hash/except.rb +11 -8
  62. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  63. data/lib/active_support/core_ext/hash/keys.rb +33 -27
  64. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  65. data/lib/active_support/core_ext/hash/slice.rb +8 -8
  66. data/lib/active_support/core_ext/hash/transform_values.rb +14 -5
  67. data/lib/active_support/core_ext/hash.rb +11 -9
  68. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  69. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  70. data/lib/active_support/core_ext/integer/time.rb +11 -18
  71. data/lib/active_support/core_ext/integer.rb +5 -3
  72. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +6 -5
  77. data/lib/active_support/core_ext/load_error.rb +3 -22
  78. data/lib/active_support/core_ext/marshal.rb +8 -8
  79. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  80. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  81. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +43 -40
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
  84. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  85. data/lib/active_support/core_ext/module/delegation.rb +98 -36
  86. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  87. data/lib/active_support/core_ext/module/introspection.rb +9 -9
  88. data/lib/active_support/core_ext/module/reachable.rb +5 -2
  89. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  90. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  91. data/lib/active_support/core_ext/module.rb +14 -11
  92. data/lib/active_support/core_ext/name_error.rb +22 -2
  93. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  94. data/lib/active_support/core_ext/numeric/conversions.rb +78 -81
  95. data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
  96. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  97. data/lib/active_support/core_ext/numeric.rb +6 -3
  98. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  99. data/lib/active_support/core_ext/object/blank.rb +27 -2
  100. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  101. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  102. data/lib/active_support/core_ext/object/duplicable.rb +41 -14
  103. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  104. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  105. data/lib/active_support/core_ext/object/json.rb +49 -19
  106. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  107. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  108. data/lib/active_support/core_ext/object/try.rb +69 -21
  109. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  110. data/lib/active_support/core_ext/object.rb +14 -13
  111. data/lib/active_support/core_ext/range/compare_range.rb +61 -0
  112. data/lib/active_support/core_ext/range/conversions.rb +27 -7
  113. data/lib/active_support/core_ext/range/each.rb +19 -17
  114. data/lib/active_support/core_ext/range/include_range.rb +2 -22
  115. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  116. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  117. data/lib/active_support/core_ext/range.rb +7 -4
  118. data/lib/active_support/core_ext/regexp.rb +6 -0
  119. data/lib/active_support/core_ext/securerandom.rb +25 -0
  120. data/lib/active_support/core_ext/string/access.rb +8 -6
  121. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  122. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  123. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  124. data/lib/active_support/core_ext/string/filters.rb +6 -5
  125. data/lib/active_support/core_ext/string/indent.rb +6 -4
  126. data/lib/active_support/core_ext/string/inflections.rb +61 -24
  127. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  128. data/lib/active_support/core_ext/string/multibyte.rb +15 -7
  129. data/lib/active_support/core_ext/string/output_safety.rb +62 -38
  130. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  131. data/lib/active_support/core_ext/string/strip.rb +4 -5
  132. data/lib/active_support/core_ext/string/zones.rb +4 -2
  133. data/lib/active_support/core_ext/string.rb +15 -13
  134. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  135. data/lib/active_support/core_ext/time/calculations.rb +85 -51
  136. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  137. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  138. data/lib/active_support/core_ext/time/zones.rb +41 -7
  139. data/lib/active_support/core_ext/time.rb +7 -6
  140. data/lib/active_support/core_ext/uri.rb +6 -8
  141. data/lib/active_support/core_ext.rb +3 -1
  142. data/lib/active_support/current_attributes.rb +195 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +57 -0
  145. data/lib/active_support/dependencies.rb +152 -161
  146. data/lib/active_support/deprecation/behaviors.rb +44 -11
  147. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  149. data/lib/active_support/deprecation/method_wrappers.rb +66 -20
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
  151. data/lib/active_support/deprecation/reporting.rb +32 -12
  152. data/lib/active_support/deprecation.rb +12 -9
  153. data/lib/active_support/descendants_tracker.rb +2 -0
  154. data/lib/active_support/digest.rb +20 -0
  155. data/lib/active_support/duration/iso8601_parser.rb +125 -0
  156. data/lib/active_support/duration/iso8601_serializer.rb +55 -0
  157. data/lib/active_support/duration.rb +314 -38
  158. data/lib/active_support/encrypted_configuration.rb +49 -0
  159. data/lib/active_support/encrypted_file.rb +99 -0
  160. data/lib/active_support/evented_file_update_checker.rb +205 -0
  161. data/lib/active_support/execution_wrapper.rb +131 -0
  162. data/lib/active_support/executor.rb +8 -0
  163. data/lib/active_support/file_update_checker.rb +63 -37
  164. data/lib/active_support/gem_version.rb +6 -4
  165. data/lib/active_support/gzip.rb +7 -5
  166. data/lib/active_support/hash_with_indifferent_access.rb +123 -28
  167. data/lib/active_support/i18n.rb +8 -6
  168. data/lib/active_support/i18n_railtie.rb +37 -13
  169. data/lib/active_support/inflections.rb +13 -11
  170. data/lib/active_support/inflector/inflections.rb +61 -12
  171. data/lib/active_support/inflector/methods.rb +163 -136
  172. data/lib/active_support/inflector/transliterate.rb +48 -27
  173. data/lib/active_support/inflector.rb +7 -5
  174. data/lib/active_support/json/decoding.rb +16 -13
  175. data/lib/active_support/json/encoding.rb +11 -58
  176. data/lib/active_support/json.rb +4 -2
  177. data/lib/active_support/key_generator.rb +25 -25
  178. data/lib/active_support/lazy_load_hooks.rb +50 -20
  179. data/lib/active_support/locale/en.yml +2 -0
  180. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  181. data/lib/active_support/log_subscriber.rb +13 -10
  182. data/lib/active_support/logger.rb +8 -7
  183. data/lib/active_support/logger_silence.rb +6 -4
  184. data/lib/active_support/logger_thread_safe_level.rb +7 -5
  185. data/lib/active_support/message_encryptor.rb +168 -53
  186. data/lib/active_support/message_verifier.rb +150 -17
  187. data/lib/active_support/messages/metadata.rb +71 -0
  188. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  189. data/lib/active_support/messages/rotator.rb +56 -0
  190. data/lib/active_support/multibyte/chars.rb +36 -23
  191. data/lib/active_support/multibyte/unicode.rb +100 -96
  192. data/lib/active_support/multibyte.rb +4 -2
  193. data/lib/active_support/notifications/fanout.rb +11 -9
  194. data/lib/active_support/notifications/instrumenter.rb +27 -7
  195. data/lib/active_support/notifications.rb +11 -7
  196. data/lib/active_support/number_helper/number_converter.rb +13 -11
  197. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
  198. data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
  199. data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
  200. data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
  201. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  202. data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
  203. data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
  204. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  205. data/lib/active_support/number_helper.rb +94 -68
  206. data/lib/active_support/option_merger.rb +3 -1
  207. data/lib/active_support/ordered_hash.rb +6 -4
  208. data/lib/active_support/ordered_options.rb +23 -5
  209. data/lib/active_support/per_thread_registry.rb +9 -4
  210. data/lib/active_support/proxy_object.rb +2 -0
  211. data/lib/active_support/rails.rb +16 -8
  212. data/lib/active_support/railtie.rb +43 -9
  213. data/lib/active_support/reloader.rb +131 -0
  214. data/lib/active_support/rescuable.rb +108 -53
  215. data/lib/active_support/security_utils.rb +15 -11
  216. data/lib/active_support/string_inquirer.rb +11 -3
  217. data/lib/active_support/subscriber.rb +21 -16
  218. data/lib/active_support/tagged_logging.rb +14 -11
  219. data/lib/active_support/test_case.rb +19 -47
  220. data/lib/active_support/testing/assertions.rb +137 -20
  221. data/lib/active_support/testing/autorun.rb +4 -2
  222. data/lib/active_support/testing/constant_lookup.rb +2 -1
  223. data/lib/active_support/testing/declarative.rb +3 -1
  224. data/lib/active_support/testing/deprecation.rb +14 -10
  225. data/lib/active_support/testing/file_fixtures.rb +36 -0
  226. data/lib/active_support/testing/isolation.rb +34 -25
  227. data/lib/active_support/testing/method_call_assertions.rb +43 -0
  228. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  229. data/lib/active_support/testing/stream.rb +44 -0
  230. data/lib/active_support/testing/tagged_logging.rb +3 -1
  231. data/lib/active_support/testing/time_helpers.rb +81 -15
  232. data/lib/active_support/time.rb +14 -12
  233. data/lib/active_support/time_with_zone.rb +169 -39
  234. data/lib/active_support/values/time_zone.rb +196 -61
  235. data/lib/active_support/values/unicode_tables.dat +0 -0
  236. data/lib/active_support/version.rb +3 -1
  237. data/lib/active_support/xml_mini/jdom.rb +116 -114
  238. data/lib/active_support/xml_mini/libxml.rb +16 -13
  239. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  240. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  241. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  242. data/lib/active_support/xml_mini/rexml.rb +11 -9
  243. data/lib/active_support/xml_mini.rb +37 -37
  244. data/lib/active_support.rb +12 -11
  245. metadata +57 -27
  246. data/lib/active_support/concurrency/latch.rb +0 -27
  247. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  248. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  249. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  250. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  251. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  252. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  253. data/lib/active_support/core_ext/object/itself.rb +0 -15
  254. data/lib/active_support/core_ext/struct.rb +0 -6
  255. data/lib/active_support/core_ext/thread.rb +0 -86
  256. data/lib/active_support/core_ext/time/marshal.rb +0 -30
@@ -1,5 +1,7 @@
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/compatibility'
4
- require 'active_support/core_ext/date_time/conversions'
5
- require 'active_support/core_ext/date_time/zones'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/date_time/acts_like"
4
+ require "active_support/core_ext/date_time/blank"
5
+ require "active_support/core_ext/date_time/calculations"
6
+ require "active_support/core_ext/date_time/compatibility"
7
+ require "active_support/core_ext/date_time/conversions"
@@ -1,4 +1,6 @@
1
- require 'securerandom'
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
2
4
 
3
5
  module Digest
4
6
  module UUID
@@ -12,7 +14,7 @@ module Digest
12
14
  # Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
13
15
  # uuid_from_hash always generates the same UUID for a given name and namespace combination.
14
16
  #
15
- # See RFC 4122 for details of UUID at: http://www.ietf.org/rfc/rfc4122.txt
17
+ # See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
16
18
  def self.uuid_from_hash(hash_class, uuid_namespace, name)
17
19
  if hash_class == Digest::MD5
18
20
  version = 3
@@ -26,7 +28,7 @@ module Digest
26
28
  hash.update(uuid_namespace)
27
29
  hash.update(name)
28
30
 
29
- ary = hash.digest.unpack('NnnnnN')
31
+ ary = hash.digest.unpack("NnnnnN")
30
32
  ary[2] = (ary[2] & 0x0FFF) | (version << 12)
31
33
  ary[3] = (ary[3] & 0x3FFF) | 0x8000
32
34
 
@@ -35,12 +37,12 @@ module Digest
35
37
 
36
38
  # Convenience method for uuid_from_hash using Digest::MD5.
37
39
  def self.uuid_v3(uuid_namespace, name)
38
- self.uuid_from_hash(Digest::MD5, uuid_namespace, name)
40
+ uuid_from_hash(Digest::MD5, uuid_namespace, name)
39
41
  end
40
42
 
41
43
  # Convenience method for uuid_from_hash using Digest::SHA1.
42
44
  def self.uuid_v5(uuid_namespace, name)
43
- self.uuid_from_hash(Digest::SHA1, uuid_namespace, name)
45
+ uuid_from_hash(Digest::SHA1, uuid_namespace, name)
44
46
  end
45
47
 
46
48
  # Convenience method for SecureRandom.uuid.
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/digest/uuid"
@@ -1,39 +1,71 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerable
2
- # Calculates a sum from the elements.
3
- #
4
- # payments.sum { |p| p.price * p.tax_rate }
5
- # payments.sum(&:price)
6
- #
7
- # The latter is a shortcut for:
8
- #
9
- # payments.inject(0) { |sum, p| sum + p.price }
10
- #
11
- # It can also calculate the sum without the use of a block.
4
+ # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
5
+ # when we omit an identity.
12
6
  #
13
- # [5, 15, 10].sum # => 30
14
- # ['foo', 'bar'].sum # => "foobar"
15
- # [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
16
- #
17
- # The default sum of an empty list is zero. You can override this default:
18
- #
19
- # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
20
- def sum(identity = 0, &block)
21
- if block_given?
22
- map(&block).sum(identity)
23
- else
24
- inject { |sum, element| sum + element } || identity
7
+ # We tried shimming it to attempt the fast native method, rescue TypeError,
8
+ # and fall back to the compatible implementation, but that's much slower than
9
+ # just calling the compat method in the first place.
10
+ if Enumerable.instance_methods(false).include?(:sum) && !((?a..?b).sum rescue false)
11
+ # :stopdoc:
12
+
13
+ # We can't use Refinements here because Refinements with Module which will be prepended
14
+ # doesn't work well https://bugs.ruby-lang.org/issues/13446
15
+ alias :_original_sum_with_required_identity :sum
16
+ private :_original_sum_with_required_identity
17
+
18
+ # :startdoc:
19
+
20
+ # Calculates a sum from the elements.
21
+ #
22
+ # payments.sum { |p| p.price * p.tax_rate }
23
+ # payments.sum(&:price)
24
+ #
25
+ # The latter is a shortcut for:
26
+ #
27
+ # payments.inject(0) { |sum, p| sum + p.price }
28
+ #
29
+ # It can also calculate the sum without the use of a block.
30
+ #
31
+ # [5, 15, 10].sum # => 30
32
+ # ['foo', 'bar'].sum # => "foobar"
33
+ # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
34
+ #
35
+ # The default sum of an empty list is zero. You can override this default:
36
+ #
37
+ # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
38
+ def sum(identity = nil, &block)
39
+ if identity
40
+ _original_sum_with_required_identity(identity, &block)
41
+ elsif block_given?
42
+ map(&block).sum(identity)
43
+ else
44
+ inject(:+) || 0
45
+ end
46
+ end
47
+ else
48
+ def sum(identity = nil, &block)
49
+ if block_given?
50
+ map(&block).sum(identity)
51
+ else
52
+ sum = identity ? inject(identity, :+) : inject(:+)
53
+ sum || identity || 0
54
+ end
25
55
  end
26
56
  end
27
57
 
28
58
  # Convert an enumerable to a hash.
29
59
  #
30
60
  # people.index_by(&:login)
31
- # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
61
+ # # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
32
62
  # people.index_by { |person| "#{person.first_name} #{person.last_name}" }
33
- # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
63
+ # # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
34
64
  def index_by
35
65
  if block_given?
36
- Hash[map { |elem| [yield(elem), elem] }]
66
+ result = {}
67
+ each { |elem| result[yield(elem)] = elem }
68
+ result
37
69
  else
38
70
  to_enum(:index_by) { size if respond_to?(:size) }
39
71
  end
@@ -60,20 +92,47 @@ module Enumerable
60
92
  def exclude?(object)
61
93
  !include?(object)
62
94
  end
95
+
96
+ # Returns a copy of the enumerable without the specified elements.
97
+ #
98
+ # ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd"
99
+ # # => ["David", "Rafael"]
100
+ #
101
+ # {foo: 1, bar: 2, baz: 3}.without :bar
102
+ # # => {foo: 1, baz: 3}
103
+ def without(*elements)
104
+ reject { |element| elements.include?(element) }
105
+ end
106
+
107
+ # Convert an enumerable to an array based on the given key.
108
+ #
109
+ # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
110
+ # # => ["David", "Rafael", "Aaron"]
111
+ #
112
+ # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
113
+ # # => [[1, "David"], [2, "Rafael"]]
114
+ def pluck(*keys)
115
+ if keys.many?
116
+ map { |element| keys.map { |key| element[key] } }
117
+ else
118
+ map { |element| element[keys.first] }
119
+ end
120
+ end
63
121
  end
64
122
 
65
123
  class Range #:nodoc:
66
124
  # Optimize range sum to use arithmetic progression if a block is not given and
67
125
  # we have a range of numeric values.
68
- def sum(identity = 0)
126
+ def sum(identity = nil)
69
127
  if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
70
128
  super
71
129
  else
72
130
  actual_last = exclude_end? ? (last - 1) : last
73
131
  if actual_last >= first
74
- (actual_last - first + 1) * (actual_last + first) / 2
132
+ sum = identity || 0
133
+ sum + (actual_last - first + 1) * (actual_last + first) / 2
75
134
  else
76
- identity
135
+ identity || 0
77
136
  end
78
137
  end
79
138
  end
@@ -85,12 +144,21 @@ end
85
144
  # and fall back to the compatible implementation, but that's much slower than
86
145
  # just calling the compat method in the first place.
87
146
  if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
88
- class Array
89
- remove_method :sum
147
+ # Using Refinements here in order not to expose our internal method
148
+ using Module.new {
149
+ refine Array do
150
+ alias :orig_sum :sum
151
+ end
152
+ }
90
153
 
91
- def sum(*args) #:nodoc:
92
- # Use Enumerable#sum instead.
93
- super
154
+ class Array
155
+ def sum(init = nil, &block) #:nodoc:
156
+ if init.is_a?(Numeric) || first.is_a?(Numeric)
157
+ init ||= 0
158
+ orig_sum(init, &block)
159
+ else
160
+ super
161
+ end
94
162
  end
95
163
  end
96
164
  end
@@ -1,4 +1,6 @@
1
- require 'fileutils'
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
2
4
 
3
5
  class File
4
6
  # Write to a file atomically. Useful for situations where you don't
@@ -8,51 +10,56 @@ class File
8
10
  # file.write('hello')
9
11
  # end
10
12
  #
11
- # If your temp directory is not on the same filesystem as the file you're
12
- # trying to write, you can provide a different temporary directory.
13
+ # This method needs to create a temporary file. By default it will create it
14
+ # in the same directory as the destination file. If you don't like this
15
+ # behavior you can provide a different directory but it must be on the
16
+ # same physical filesystem as the file you're trying to write.
13
17
  #
14
18
  # File.atomic_write('/data/something.important', '/data/tmp') do |file|
15
19
  # file.write('hello')
16
20
  # end
17
- def self.atomic_write(file_name, temp_dir = Dir.tmpdir)
18
- require 'tempfile' unless defined?(Tempfile)
19
- require 'fileutils' unless defined?(FileUtils)
20
-
21
- temp_file = Tempfile.new(basename(file_name), temp_dir)
22
- temp_file.binmode
23
- yield temp_file
24
- temp_file.close
25
-
26
- if File.exist?(file_name)
27
- # Get original file permissions
28
- old_stat = stat(file_name)
29
- else
30
- # If not possible, probe which are the default permissions in the
31
- # destination directory.
32
- old_stat = probe_stat_in(dirname(file_name))
33
- end
21
+ def self.atomic_write(file_name, temp_dir = dirname(file_name))
22
+ require "tempfile" unless defined?(Tempfile)
23
+
24
+ Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
25
+ temp_file.binmode
26
+ return_val = yield temp_file
27
+ temp_file.close
28
+
29
+ old_stat = if exist?(file_name)
30
+ # Get original file permissions
31
+ stat(file_name)
32
+ else
33
+ # If not possible, probe which are the default permissions in the
34
+ # destination directory.
35
+ probe_stat_in(dirname(file_name))
36
+ end
34
37
 
35
- # Overwrite original file with temp file
36
- FileUtils.mv(temp_file.path, file_name)
38
+ if old_stat
39
+ # Set correct permissions on new file
40
+ begin
41
+ chown(old_stat.uid, old_stat.gid, temp_file.path)
42
+ # This operation will affect filesystem ACL's
43
+ chmod(old_stat.mode, temp_file.path)
44
+ rescue Errno::EPERM, Errno::EACCES
45
+ # Changing file ownership failed, moving on.
46
+ end
47
+ end
37
48
 
38
- # Set correct permissions on new file
39
- begin
40
- chown(old_stat.uid, old_stat.gid, file_name)
41
- # This operation will affect filesystem ACL's
42
- chmod(old_stat.mode, file_name)
43
- rescue Errno::EPERM, Errno::EACCES
44
- # Changing file ownership failed, moving on.
49
+ # Overwrite original file with temp file
50
+ rename(temp_file.path, file_name)
51
+ return_val
45
52
  end
46
53
  end
47
54
 
48
55
  # Private utility method.
49
56
  def self.probe_stat_in(dir) #:nodoc:
50
57
  basename = [
51
- '.permissions_check',
58
+ ".permissions_check",
52
59
  Thread.current.object_id,
53
60
  Process.pid,
54
61
  rand(1000000)
55
- ].join('.')
62
+ ].join(".")
56
63
 
57
64
  file_name = join(dir, basename)
58
65
  FileUtils.touch(file_name)
@@ -1 +1,3 @@
1
- require 'active_support/core_ext/file/atomic'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/file/atomic"
@@ -1,24 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Hash
2
4
  unless Hash.instance_methods(false).include?(:compact)
3
5
  # Returns a hash with non +nil+ values.
4
6
  #
5
- # hash = { a: true, b: false, c: nil}
6
- # hash.compact # => { a: true, b: false}
7
- # hash # => { a: true, b: false, c: nil}
8
- # { c: nil }.compact # => {}
7
+ # hash = { a: true, b: false, c: nil }
8
+ # hash.compact # => { a: true, b: false }
9
+ # hash # => { a: true, b: false, c: nil }
10
+ # { c: nil }.compact # => {}
11
+ # { c: true }.compact # => { c: true }
9
12
  def compact
10
- self.select { |_, value| !value.nil? }
13
+ select { |_, value| !value.nil? }
11
14
  end
12
15
  end
13
16
 
14
17
  unless Hash.instance_methods(false).include?(:compact!)
15
18
  # Replaces current hash with non +nil+ values.
19
+ # Returns +nil+ if no changes were made, otherwise returns the hash.
16
20
  #
17
- # hash = { a: true, b: false, c: nil}
18
- # hash.compact! # => { a: true, b: false}
19
- # hash # => { a: true, b: false}
21
+ # hash = { a: true, b: false, c: nil }
22
+ # hash.compact! # => { a: true, b: false }
23
+ # hash # => { a: true, b: false }
24
+ # { c: true }.compact! # => nil
20
25
  def compact!
21
- self.reject! { |_, value| value.nil? }
26
+ reject! { |_, value| value.nil? }
22
27
  end
23
28
  end
24
29
  end
@@ -1,11 +1,13 @@
1
- require 'active_support/xml_mini'
2
- require 'active_support/time'
3
- require 'active_support/core_ext/object/blank'
4
- require 'active_support/core_ext/object/to_param'
5
- require 'active_support/core_ext/object/to_query'
6
- require 'active_support/core_ext/array/wrap'
7
- require 'active_support/core_ext/hash/reverse_merge'
8
- require 'active_support/core_ext/string/inflections'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/xml_mini"
4
+ require "active_support/time"
5
+ require "active_support/core_ext/object/blank"
6
+ require "active_support/core_ext/object/to_param"
7
+ require "active_support/core_ext/object/to_query"
8
+ require "active_support/core_ext/array/wrap"
9
+ require "active_support/core_ext/hash/reverse_merge"
10
+ require "active_support/core_ext/string/inflections"
9
11
 
10
12
  class Hash
11
13
  # Returns a string containing an XML representation of its receiver:
@@ -31,7 +33,7 @@ class Hash
31
33
  # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
32
34
  # callable can add nodes by using <tt>options[:builder]</tt>.
33
35
  #
34
- # 'foo'.to_xml(lambda { |options, key| options[:builder].b(key) })
36
+ # {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
35
37
  # # => "<b>foo</b>"
36
38
  #
37
39
  # * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
@@ -71,11 +73,11 @@ class Hash
71
73
  # configure your own builder with the <tt>:builder</tt> option. The method also accepts
72
74
  # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
73
75
  def to_xml(options = {})
74
- require 'active_support/builder' unless defined?(Builder)
76
+ require "active_support/builder" unless defined?(Builder)
75
77
 
76
78
  options = options.dup
77
79
  options[:indent] ||= 2
78
- options[:root] ||= 'hash'
80
+ options[:root] ||= "hash"
79
81
  options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
80
82
 
81
83
  builder = options[:builder]
@@ -105,7 +107,25 @@ class Hash
105
107
  # # => {"hash"=>{"foo"=>1, "bar"=>2}}
106
108
  #
107
109
  # +DisallowedType+ is raised if the XML contains attributes with <tt>type="yaml"</tt> or
108
- # <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to parse this XML.
110
+ # <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
111
+ # parse this XML.
112
+ #
113
+ # Custom +disallowed_types+ can also be passed in the form of an
114
+ # array.
115
+ #
116
+ # xml = <<-XML
117
+ # <?xml version="1.0" encoding="UTF-8"?>
118
+ # <hash>
119
+ # <foo type="integer">1</foo>
120
+ # <bar type="string">"David"</bar>
121
+ # </hash>
122
+ # XML
123
+ #
124
+ # hash = Hash.from_xml(xml, ['integer'])
125
+ # # => ActiveSupport::XMLConverter::DisallowedType: Disallowed type attribute: "integer"
126
+ #
127
+ # Note that passing custom disallowed types will override the default types,
128
+ # which are Symbol and YAML.
109
129
  def from_xml(xml, disallowed_types = nil)
110
130
  ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
111
131
  end
@@ -119,6 +139,8 @@ end
119
139
 
120
140
  module ActiveSupport
121
141
  class XMLConverter # :nodoc:
142
+ # Raised if the XML contains attributes with type="yaml" or
143
+ # type="symbol". Read Hash#from_xml for more details.
122
144
  class DisallowedType < StandardError
123
145
  def initialize(type)
124
146
  super "Disallowed type attribute: #{type.inspect}"
@@ -139,36 +161,36 @@ module ActiveSupport
139
161
  private
140
162
  def normalize_keys(params)
141
163
  case params
142
- when Hash
143
- Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ]
144
- when Array
145
- params.map { |v| normalize_keys(v) }
146
- else
147
- params
164
+ when Hash
165
+ Hash[params.map { |k, v| [k.to_s.tr("-", "_"), normalize_keys(v)] } ]
166
+ when Array
167
+ params.map { |v| normalize_keys(v) }
168
+ else
169
+ params
148
170
  end
149
171
  end
150
172
 
151
173
  def deep_to_h(value)
152
174
  case value
153
- when Hash
154
- process_hash(value)
155
- when Array
156
- process_array(value)
157
- when String
158
- value
159
- else
160
- raise "can't typecast #{value.class.name} - #{value.inspect}"
175
+ when Hash
176
+ process_hash(value)
177
+ when Array
178
+ process_array(value)
179
+ when String
180
+ value
181
+ else
182
+ raise "can't typecast #{value.class.name} - #{value.inspect}"
161
183
  end
162
184
  end
163
185
 
164
186
  def process_hash(value)
165
- if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type'])
166
- raise DisallowedType, value['type']
187
+ if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"])
188
+ raise DisallowedType, value["type"]
167
189
  end
168
190
 
169
191
  if become_array?(value)
170
- _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
171
- if entries.nil? || value['__content__'].try(:empty?)
192
+ _, entries = Array.wrap(value.detect { |k, v| not v.is_a?(String) })
193
+ if entries.nil? || value["__content__"].try(:empty?)
172
194
  []
173
195
  else
174
196
  case entries
@@ -184,28 +206,28 @@ module ActiveSupport
184
206
  process_content(value)
185
207
 
186
208
  elsif become_empty_string?(value)
187
- ''
209
+ ""
188
210
  elsif become_hash?(value)
189
- xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }]
211
+ xml_value = Hash[value.map { |k, v| [k, deep_to_h(v)] }]
190
212
 
191
213
  # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
192
214
  # how multipart uploaded files from HTML appear
193
- xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
215
+ xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
194
216
  end
195
217
  end
196
218
 
197
219
  def become_content?(value)
198
- value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?))
220
+ value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
199
221
  end
200
222
 
201
223
  def become_array?(value)
202
- value['type'] == 'array'
224
+ value["type"] == "array"
203
225
  end
204
226
 
205
227
  def become_empty_string?(value)
206
228
  # { "string" => true }
207
229
  # No tests fail when the second term is removed.
208
- value['type'] == 'string' && value['nil'] != 'true'
230
+ value["type"] == "string" && value["nil"] != "true"
209
231
  end
210
232
 
211
233
  def become_hash?(value)
@@ -214,19 +236,19 @@ module ActiveSupport
214
236
 
215
237
  def nothing?(value)
216
238
  # blank or nil parsed values are represented by nil
217
- value.blank? || value['nil'] == 'true'
239
+ value.blank? || value["nil"] == "true"
218
240
  end
219
241
 
220
242
  def garbage?(value)
221
243
  # If the type is the only element which makes it then
222
244
  # this still makes the value nil, except if type is
223
245
  # an XML node(where type['value'] is a Hash)
224
- value['type'] && !value['type'].is_a?(::Hash) && value.size == 1
246
+ value["type"] && !value["type"].is_a?(::Hash) && value.size == 1
225
247
  end
226
248
 
227
249
  def process_content(value)
228
- content = value['__content__']
229
- if parser = ActiveSupport::XmlMini::PARSING[value['type']]
250
+ content = value["__content__"]
251
+ if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
230
252
  parser.arity == 1 ? parser.call(content) : parser.call(content, value)
231
253
  else
232
254
  content
@@ -237,6 +259,5 @@ module ActiveSupport
237
259
  value.map! { |i| deep_to_h(i) }
238
260
  value.length > 1 ? value : value.first
239
261
  end
240
-
241
262
  end
242
263
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Hash
2
4
  # Returns a new hash with +self+ and +other_hash+ merged recursively.
3
5
  #
4
6
  # h1 = { a: true, b: { c: [1, 2, 3] } }
5
7
  # h2 = { a: false, b: { x: [3, 4, 5] } }
6
8
  #
7
- # h1.deep_merge(h2) #=> { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
9
+ # h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
8
10
  #
9
11
  # Like with Hash#merge in the standard library, a block can be provided
10
12
  # to merge values:
@@ -19,20 +21,14 @@ class Hash
19
21
 
20
22
  # Same as +deep_merge+, but modifies +self+.
21
23
  def deep_merge!(other_hash, &block)
22
- other_hash.each_pair do |current_key, other_value|
23
- this_value = self[current_key]
24
-
25
- self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
26
- this_value.deep_merge(other_value, &block)
24
+ merge!(other_hash) do |key, this_val, other_val|
25
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
26
+ this_val.deep_merge(other_val, &block)
27
+ elsif block_given?
28
+ block.call(key, this_val, other_val)
27
29
  else
28
- if block_given? && key?(current_key)
29
- block.call(current_key, this_value, other_value)
30
- else
31
- other_value
32
- end
30
+ other_val
33
31
  end
34
32
  end
35
-
36
- self
37
33
  end
38
34
  end
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Hash
2
- # Returns a hash that includes everything but the given keys.
3
- # hash = { a: true, b: false, c: nil}
4
- # hash.except(:c) # => { a: true, b: false}
5
- # hash # => { a: true, b: false, c: nil}
4
+ # Returns a hash that includes everything except given keys.
5
+ # hash = { a: true, b: false, c: nil }
6
+ # hash.except(:c) # => { a: true, b: false }
7
+ # hash.except(:a, :b) # => { c: nil }
8
+ # hash # => { a: true, b: false, c: nil }
6
9
  #
7
10
  # This is useful for limiting a set of parameters to everything but a few known toggles:
8
11
  # @person.update(params[:person].except(:admin))
@@ -10,10 +13,10 @@ class Hash
10
13
  dup.except!(*keys)
11
14
  end
12
15
 
13
- # Replaces the hash without the given keys.
14
- # hash = { a: true, b: false, c: nil}
15
- # hash.except!(:c) # => { a: true, b: false}
16
- # hash # => { a: true, b: false }
16
+ # Removes the given keys from hash and returns it.
17
+ # hash = { a: true, b: false, c: nil }
18
+ # hash.except!(:c) # => { a: true, b: false }
19
+ # hash # => { a: true, b: false }
17
20
  def except!(*keys)
18
21
  keys.each { |key| delete(key) }
19
22
  self
@@ -1,12 +1,13 @@
1
- require 'active_support/hash_with_indifferent_access'
1
+ # frozen_string_literal: true
2
2
 
3
- class Hash
3
+ require "active_support/hash_with_indifferent_access"
4
4
 
5
+ class Hash
5
6
  # Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
6
7
  #
7
8
  # { a: 1 }.with_indifferent_access['a'] # => 1
8
9
  def with_indifferent_access
9
- ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
10
+ ActiveSupport::HashWithIndifferentAccess.new(self)
10
11
  end
11
12
 
12
13
  # Called when object is nested under an object that receives