activesupport 4.2.11.1 → 6.0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (263) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +399 -411
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +48 -0
  8. data/lib/active_support/backtrace_cleaner.rb +34 -6
  9. data/lib/active_support/benchmarkable.rb +6 -4
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +58 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +95 -91
  13. data/lib/active_support/cache/memory_store.rb +39 -36
  14. data/lib/active_support/cache/null_store.rb +11 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +75 -42
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +331 -217
  19. data/lib/active_support/callbacks.rb +650 -592
  20. data/lib/active_support/concern.rb +35 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +226 -0
  23. data/lib/active_support/configurable.rb +13 -14
  24. data/lib/active_support/core_ext/array/access.rb +41 -1
  25. data/lib/active_support/core_ext/array/conversions.rb +24 -20
  26. data/lib/active_support/core_ext/array/extract.rb +21 -0
  27. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  28. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  29. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  30. data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
  31. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  32. data/lib/active_support/core_ext/array.rb +9 -6
  33. data/lib/active_support/core_ext/benchmark.rb +3 -1
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +45 -31
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  39. data/lib/active_support/core_ext/class.rb +4 -3
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +14 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  43. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +6 -4
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +154 -65
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  53. data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +114 -22
  58. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/compact.rb +4 -23
  61. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  62. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  63. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  64. data/lib/active_support/core_ext/hash/except.rb +12 -9
  65. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  66. data/lib/active_support/core_ext/hash/keys.rb +19 -42
  67. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  68. data/lib/active_support/core_ext/hash/slice.rb +5 -27
  69. data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
  70. data/lib/active_support/core_ext/hash.rb +10 -9
  71. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  72. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  73. data/lib/active_support/core_ext/integer/time.rb +11 -18
  74. data/lib/active_support/core_ext/integer.rb +5 -3
  75. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  76. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  78. data/lib/active_support/core_ext/kernel.rb +5 -5
  79. data/lib/active_support/core_ext/load_error.rb +3 -22
  80. data/lib/active_support/core_ext/marshal.rb +8 -8
  81. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  82. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  83. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  84. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -46
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  87. data/lib/active_support/core_ext/module/delegation.rb +133 -30
  88. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  89. data/lib/active_support/core_ext/module/introspection.rb +44 -19
  90. data/lib/active_support/core_ext/module/reachable.rb +5 -7
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -11
  94. data/lib/active_support/core_ext/name_error.rb +22 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
  97. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  99. data/lib/active_support/core_ext/numeric.rb +5 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  101. data/lib/active_support/core_ext/object/blank.rb +27 -3
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  104. data/lib/active_support/core_ext/object/duplicable.rb +13 -93
  105. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +51 -20
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  110. data/lib/active_support/core_ext/object/try.rb +81 -23
  111. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  112. data/lib/active_support/core_ext/object.rb +14 -13
  113. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  114. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  115. data/lib/active_support/core_ext/range/each.rb +18 -17
  116. data/lib/active_support/core_ext/range/include_range.rb +7 -21
  117. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  118. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  119. data/lib/active_support/core_ext/range.rb +7 -4
  120. data/lib/active_support/core_ext/regexp.rb +2 -0
  121. data/lib/active_support/core_ext/securerandom.rb +45 -0
  122. data/lib/active_support/core_ext/string/access.rb +16 -6
  123. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  124. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  125. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  126. data/lib/active_support/core_ext/string/filters.rb +48 -6
  127. data/lib/active_support/core_ext/string/indent.rb +6 -4
  128. data/lib/active_support/core_ext/string/inflections.rb +66 -24
  129. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  130. data/lib/active_support/core_ext/string/multibyte.rb +16 -7
  131. data/lib/active_support/core_ext/string/output_safety.rb +93 -40
  132. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  133. data/lib/active_support/core_ext/string/strip.rb +6 -5
  134. data/lib/active_support/core_ext/string/zones.rb +4 -2
  135. data/lib/active_support/core_ext/string.rb +15 -13
  136. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  137. data/lib/active_support/core_ext/time/calculations.rb +115 -52
  138. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  139. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  140. data/lib/active_support/core_ext/time/zones.rb +41 -7
  141. data/lib/active_support/core_ext/time.rb +7 -6
  142. data/lib/active_support/core_ext/uri.rb +6 -7
  143. data/lib/active_support/core_ext.rb +3 -1
  144. data/lib/active_support/current_attributes.rb +203 -0
  145. data/lib/active_support/dependencies/autoload.rb +2 -0
  146. data/lib/active_support/dependencies/interlock.rb +57 -0
  147. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  148. data/lib/active_support/dependencies.rb +208 -166
  149. data/lib/active_support/deprecation/behaviors.rb +44 -11
  150. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  151. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  152. data/lib/active_support/deprecation/method_wrappers.rb +61 -21
  153. data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
  154. data/lib/active_support/deprecation/reporting.rb +32 -12
  155. data/lib/active_support/deprecation.rb +12 -9
  156. data/lib/active_support/descendants_tracker.rb +57 -9
  157. data/lib/active_support/digest.rb +20 -0
  158. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  159. data/lib/active_support/duration/iso8601_serializer.rb +53 -0
  160. data/lib/active_support/duration.rb +315 -40
  161. data/lib/active_support/encrypted_configuration.rb +45 -0
  162. data/lib/active_support/encrypted_file.rb +100 -0
  163. data/lib/active_support/evented_file_update_checker.rb +234 -0
  164. data/lib/active_support/execution_wrapper.rb +129 -0
  165. data/lib/active_support/executor.rb +8 -0
  166. data/lib/active_support/file_update_checker.rb +62 -37
  167. data/lib/active_support/gem_version.rb +6 -4
  168. data/lib/active_support/gzip.rb +7 -5
  169. data/lib/active_support/hash_with_indifferent_access.rb +129 -30
  170. data/lib/active_support/i18n.rb +9 -6
  171. data/lib/active_support/i18n_railtie.rb +50 -14
  172. data/lib/active_support/inflections.rb +13 -11
  173. data/lib/active_support/inflector/inflections.rb +58 -13
  174. data/lib/active_support/inflector/methods.rb +159 -145
  175. data/lib/active_support/inflector/transliterate.rb +84 -34
  176. data/lib/active_support/inflector.rb +7 -5
  177. data/lib/active_support/json/decoding.rb +32 -30
  178. data/lib/active_support/json/encoding.rb +17 -60
  179. data/lib/active_support/json.rb +4 -2
  180. data/lib/active_support/key_generator.rb +11 -43
  181. data/lib/active_support/lazy_load_hooks.rb +53 -20
  182. data/lib/active_support/locale/en.rb +33 -0
  183. data/lib/active_support/locale/en.yml +2 -0
  184. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  185. data/lib/active_support/log_subscriber.rb +44 -19
  186. data/lib/active_support/logger.rb +9 -23
  187. data/lib/active_support/logger_silence.rb +32 -14
  188. data/lib/active_support/logger_thread_safe_level.rb +32 -8
  189. data/lib/active_support/message_encryptor.rb +166 -53
  190. data/lib/active_support/message_verifier.rb +149 -16
  191. data/lib/active_support/messages/metadata.rb +72 -0
  192. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  193. data/lib/active_support/messages/rotator.rb +56 -0
  194. data/lib/active_support/multibyte/chars.rb +56 -63
  195. data/lib/active_support/multibyte/unicode.rb +56 -290
  196. data/lib/active_support/multibyte.rb +4 -2
  197. data/lib/active_support/notifications/fanout.rb +109 -22
  198. data/lib/active_support/notifications/instrumenter.rb +107 -16
  199. data/lib/active_support/notifications.rb +51 -10
  200. data/lib/active_support/number_helper/number_converter.rb +16 -15
  201. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
  202. data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
  203. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
  204. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
  205. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  206. data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
  207. data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
  208. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  209. data/lib/active_support/number_helper.rb +105 -68
  210. data/lib/active_support/option_merger.rb +24 -4
  211. data/lib/active_support/ordered_hash.rb +7 -5
  212. data/lib/active_support/ordered_options.rb +27 -5
  213. data/lib/active_support/parameter_filter.rb +128 -0
  214. data/lib/active_support/per_thread_registry.rb +9 -4
  215. data/lib/active_support/proxy_object.rb +2 -0
  216. data/lib/active_support/rails.rb +10 -8
  217. data/lib/active_support/railtie.rb +43 -9
  218. data/lib/active_support/reloader.rb +130 -0
  219. data/lib/active_support/rescuable.rb +108 -53
  220. data/lib/active_support/security_utils.rb +15 -11
  221. data/lib/active_support/string_inquirer.rb +11 -4
  222. data/lib/active_support/subscriber.rb +74 -30
  223. data/lib/active_support/tagged_logging.rb +25 -13
  224. data/lib/active_support/test_case.rb +107 -44
  225. data/lib/active_support/testing/assertions.rb +151 -20
  226. data/lib/active_support/testing/autorun.rb +4 -2
  227. data/lib/active_support/testing/constant_lookup.rb +2 -1
  228. data/lib/active_support/testing/declarative.rb +3 -1
  229. data/lib/active_support/testing/deprecation.rb +13 -10
  230. data/lib/active_support/testing/file_fixtures.rb +38 -0
  231. data/lib/active_support/testing/isolation.rb +35 -26
  232. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  233. data/lib/active_support/testing/parallelization.rb +134 -0
  234. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  235. data/lib/active_support/testing/stream.rb +43 -0
  236. data/lib/active_support/testing/tagged_logging.rb +3 -1
  237. data/lib/active_support/testing/time_helpers.rb +84 -20
  238. data/lib/active_support/time.rb +14 -12
  239. data/lib/active_support/time_with_zone.rb +179 -39
  240. data/lib/active_support/values/time_zone.rb +203 -63
  241. data/lib/active_support/version.rb +3 -1
  242. data/lib/active_support/xml_mini/jdom.rb +116 -115
  243. data/lib/active_support/xml_mini/libxml.rb +16 -13
  244. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  245. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  246. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  247. data/lib/active_support/xml_mini/rexml.rb +11 -9
  248. data/lib/active_support/xml_mini.rb +38 -46
  249. data/lib/active_support.rb +13 -11
  250. metadata +84 -26
  251. data/lib/active_support/concurrency/latch.rb +0 -27
  252. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  253. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  254. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  255. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  256. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  257. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  258. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  259. data/lib/active_support/core_ext/object/itself.rb +0 -15
  260. data/lib/active_support/core_ext/struct.rb +0 -6
  261. data/lib/active_support/core_ext/thread.rb +0 -86
  262. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  263. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -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,4 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerable
4
+ INDEX_WITH_DEFAULT = Object.new
5
+ private_constant :INDEX_WITH_DEFAULT
6
+
7
+ # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
8
+ # when we omit an identity.
9
+
10
+ # :stopdoc:
11
+
12
+ # We can't use Refinements here because Refinements with Module which will be prepended
13
+ # doesn't work well https://bugs.ruby-lang.org/issues/13446
14
+ alias :_original_sum_with_required_identity :sum
15
+ private :_original_sum_with_required_identity
16
+
17
+ # :startdoc:
18
+
2
19
  # Calculates a sum from the elements.
3
20
  #
4
21
  # payments.sum { |p| p.price * p.tax_rate }
@@ -12,33 +29,58 @@ module Enumerable
12
29
  #
13
30
  # [5, 15, 10].sum # => 30
14
31
  # ['foo', 'bar'].sum # => "foobar"
15
- # [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
32
+ # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
16
33
  #
17
34
  # The default sum of an empty list is zero. You can override this default:
18
35
  #
19
36
  # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
20
- def sum(identity = 0, &block)
21
- if block_given?
37
+ def sum(identity = nil, &block)
38
+ if identity
39
+ _original_sum_with_required_identity(identity, &block)
40
+ elsif block_given?
22
41
  map(&block).sum(identity)
23
42
  else
24
- inject { |sum, element| sum + element } || identity
43
+ inject(:+) || 0
25
44
  end
26
45
  end
27
46
 
28
- # Convert an enumerable to a hash.
47
+ # Convert an enumerable to a hash keying it by the block return value.
29
48
  #
30
49
  # people.index_by(&:login)
31
- # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
50
+ # # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
51
+ #
32
52
  # people.index_by { |person| "#{person.first_name} #{person.last_name}" }
33
- # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
53
+ # # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
34
54
  def index_by
35
55
  if block_given?
36
- Hash[map { |elem| [yield(elem), elem] }]
56
+ result = {}
57
+ each { |elem| result[yield(elem)] = elem }
58
+ result
37
59
  else
38
60
  to_enum(:index_by) { size if respond_to?(:size) }
39
61
  end
40
62
  end
41
63
 
64
+ # Convert an enumerable to a hash keying it with the enumerable items and with the values returned in the block.
65
+ #
66
+ # post = Post.new(title: "hey there", body: "what's up?")
67
+ #
68
+ # %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
69
+ # # => { title: "hey there", body: "what's up?" }
70
+ def index_with(default = INDEX_WITH_DEFAULT)
71
+ if block_given?
72
+ result = {}
73
+ each { |elem| result[elem] = yield(elem) }
74
+ result
75
+ elsif default != INDEX_WITH_DEFAULT
76
+ result = {}
77
+ each { |elem| result[elem] = default }
78
+ result
79
+ else
80
+ to_enum(:index_with) { size if respond_to?(:size) }
81
+ end
82
+ end
83
+
42
84
  # Returns +true+ if the enumerable has more than 1 element. Functionally
43
85
  # equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
44
86
  # much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
@@ -55,41 +97,91 @@ module Enumerable
55
97
  end
56
98
  end
57
99
 
100
+ # Returns a new array that includes the passed elements.
101
+ #
102
+ # [ 1, 2, 3 ].including(4, 5)
103
+ # # => [ 1, 2, 3, 4, 5 ]
104
+ #
105
+ # ["David", "Rafael"].including %w[ Aaron Todd ]
106
+ # # => ["David", "Rafael", "Aaron", "Todd"]
107
+ def including(*elements)
108
+ to_a.including(*elements)
109
+ end
110
+
58
111
  # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
59
112
  # collection does not include the object.
60
113
  def exclude?(object)
61
114
  !include?(object)
62
115
  end
116
+
117
+ # Returns a copy of the enumerable excluding the specified elements.
118
+ #
119
+ # ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
120
+ # # => ["David", "Rafael"]
121
+ #
122
+ # ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
123
+ # # => ["David", "Rafael"]
124
+ #
125
+ # {foo: 1, bar: 2, baz: 3}.excluding :bar
126
+ # # => {foo: 1, baz: 3}
127
+ def excluding(*elements)
128
+ elements.flatten!(1)
129
+ reject { |element| elements.include?(element) }
130
+ end
131
+
132
+ # Alias for #excluding.
133
+ def without(*elements)
134
+ excluding(*elements)
135
+ end
136
+
137
+ # Convert an enumerable to an array based on the given key.
138
+ #
139
+ # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
140
+ # # => ["David", "Rafael", "Aaron"]
141
+ #
142
+ # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
143
+ # # => [[1, "David"], [2, "Rafael"]]
144
+ def pluck(*keys)
145
+ if keys.many?
146
+ map { |element| keys.map { |key| element[key] } }
147
+ else
148
+ map { |element| element[keys.first] }
149
+ end
150
+ end
63
151
  end
64
152
 
65
153
  class Range #:nodoc:
66
154
  # Optimize range sum to use arithmetic progression if a block is not given and
67
155
  # we have a range of numeric values.
68
- def sum(identity = 0)
156
+ def sum(identity = nil)
69
157
  if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
70
158
  super
71
159
  else
72
160
  actual_last = exclude_end? ? (last - 1) : last
73
161
  if actual_last >= first
74
- (actual_last - first + 1) * (actual_last + first) / 2
162
+ sum = identity || 0
163
+ sum + (actual_last - first + 1) * (actual_last + first) / 2
75
164
  else
76
- identity
165
+ identity || 0
77
166
  end
78
167
  end
79
168
  end
80
169
  end
81
170
 
82
- # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
83
- #
84
- # We tried shimming it to attempt the fast native method, rescue TypeError,
85
- # and fall back to the compatible implementation, but that's much slower than
86
- # just calling the compat method in the first place.
87
- if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
88
- class Array
89
- remove_method :sum
90
-
91
- def sum(*args) #:nodoc:
92
- # Use Enumerable#sum instead.
171
+ # Using Refinements here in order not to expose our internal method
172
+ using Module.new {
173
+ refine Array do
174
+ alias :orig_sum :sum
175
+ end
176
+ }
177
+
178
+ class Array #:nodoc:
179
+ # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
180
+ def sum(init = nil, &block)
181
+ if init.is_a?(Numeric) || first.is_a?(Numeric)
182
+ init ||= 0
183
+ orig_sum(init, &block)
184
+ else
93
185
  super
94
186
  end
95
187
  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,5 @@
1
- class Hash
2
- unless Hash.instance_methods(false).include?(:compact)
3
- # Returns a hash with non +nil+ values.
4
- #
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 # => {}
9
- def compact
10
- self.select { |_, value| !value.nil? }
11
- end
12
- end
1
+ # frozen_string_literal: true
13
2
 
14
- unless Hash.instance_methods(false).include?(:compact!)
15
- # Replaces current hash with non +nil+ values.
16
- #
17
- # hash = { a: true, b: false, c: nil}
18
- # hash.compact! # => { a: true, b: false}
19
- # hash # => { a: true, b: false}
20
- def compact!
21
- self.reject! { |_, value| value.nil? }
22
- end
23
- end
24
- end
3
+ require "active_support/deprecation"
4
+
5
+ ActiveSupport::Deprecation.warn "Ruby 2.5+ (required by Rails 6) provides Hash#compact and Hash#compact! natively, so requiring active_support/core_ext/hash/compact is no longer necessary. Requiring it will raise LoadError in Rails 6.1."
@@ -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::XmlMarkup)
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