activesupport 6.1.0 → 7.1.5.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.
Files changed (225) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1075 -325
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +32 -7
  8. data/lib/active_support/benchmarkable.rb +3 -2
  9. data/lib/active_support/broadcast_logger.rb +251 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +53 -20
  14. data/lib/active_support/cache/mem_cache_store.rb +201 -62
  15. data/lib/active_support/cache/memory_store.rb +86 -24
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +186 -193
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +63 -71
  20. data/lib/active_support/cache.rb +487 -249
  21. data/lib/active_support/callbacks.rb +227 -105
  22. data/lib/active_support/code_generator.rb +70 -0
  23. data/lib/active_support/concern.rb +9 -7
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/concurrency/share_lock.rb +2 -2
  27. data/lib/active_support/configurable.rb +18 -5
  28. data/lib/active_support/configuration_file.rb +7 -2
  29. data/lib/active_support/core_ext/array/access.rb +1 -5
  30. data/lib/active_support/core_ext/array/conversions.rb +15 -13
  31. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  33. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  34. data/lib/active_support/core_ext/class/subclasses.rb +37 -26
  35. data/lib/active_support/core_ext/date/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  37. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  38. data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
  39. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  40. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  41. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  42. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  43. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  44. data/lib/active_support/core_ext/enumerable.rb +85 -83
  45. data/lib/active_support/core_ext/erb/util.rb +196 -0
  46. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  47. data/lib/active_support/core_ext/hash/conversions.rb +1 -2
  48. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  49. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  50. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  51. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  52. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  53. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  54. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  55. data/lib/active_support/core_ext/module/attribute_accessors.rb +8 -0
  56. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
  57. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  58. data/lib/active_support/core_ext/module/delegation.rb +81 -43
  59. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  60. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  61. data/lib/active_support/core_ext/name_error.rb +2 -8
  62. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  63. data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
  64. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  65. data/lib/active_support/core_ext/object/blank.rb +2 -2
  66. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  67. data/lib/active_support/core_ext/object/duplicable.rb +31 -11
  68. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  69. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  70. data/lib/active_support/core_ext/object/json.rb +49 -27
  71. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  72. data/lib/active_support/core_ext/object/try.rb +20 -20
  73. data/lib/active_support/core_ext/object/with.rb +44 -0
  74. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  75. data/lib/active_support/core_ext/object.rb +1 -0
  76. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  77. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  78. data/lib/active_support/core_ext/pathname.rb +4 -0
  79. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  80. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  81. data/lib/active_support/core_ext/range/each.rb +1 -1
  82. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  83. data/lib/active_support/core_ext/range.rb +1 -2
  84. data/lib/active_support/core_ext/securerandom.rb +25 -13
  85. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  86. data/lib/active_support/core_ext/string/filters.rb +21 -15
  87. data/lib/active_support/core_ext/string/indent.rb +1 -1
  88. data/lib/active_support/core_ext/string/inflections.rb +17 -10
  89. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  90. data/lib/active_support/core_ext/string/output_safety.rb +85 -165
  91. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  92. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  93. data/lib/active_support/core_ext/time/calculations.rb +30 -8
  94. data/lib/active_support/core_ext/time/conversions.rb +15 -13
  95. data/lib/active_support/core_ext/time/zones.rb +12 -28
  96. data/lib/active_support/core_ext.rb +2 -1
  97. data/lib/active_support/current_attributes.rb +47 -20
  98. data/lib/active_support/deep_mergeable.rb +53 -0
  99. data/lib/active_support/dependencies/autoload.rb +17 -12
  100. data/lib/active_support/dependencies/interlock.rb +10 -18
  101. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  102. data/lib/active_support/dependencies.rb +58 -788
  103. data/lib/active_support/deprecation/behaviors.rb +66 -40
  104. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  105. data/lib/active_support/deprecation/deprecators.rb +104 -0
  106. data/lib/active_support/deprecation/disallowed.rb +6 -8
  107. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  108. data/lib/active_support/deprecation/method_wrappers.rb +9 -26
  109. data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
  110. data/lib/active_support/deprecation/reporting.rb +43 -26
  111. data/lib/active_support/deprecation.rb +32 -5
  112. data/lib/active_support/deprecator.rb +7 -0
  113. data/lib/active_support/descendants_tracker.rb +150 -72
  114. data/lib/active_support/digest.rb +5 -3
  115. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  116. data/lib/active_support/duration/iso8601_serializer.rb +9 -3
  117. data/lib/active_support/duration.rb +83 -52
  118. data/lib/active_support/encrypted_configuration.rb +72 -9
  119. data/lib/active_support/encrypted_file.rb +29 -13
  120. data/lib/active_support/environment_inquirer.rb +23 -3
  121. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  122. data/lib/active_support/error_reporter.rb +203 -0
  123. data/lib/active_support/evented_file_update_checker.rb +20 -7
  124. data/lib/active_support/execution_context/test_helper.rb +13 -0
  125. data/lib/active_support/execution_context.rb +53 -0
  126. data/lib/active_support/execution_wrapper.rb +44 -22
  127. data/lib/active_support/executor/test_helper.rb +7 -0
  128. data/lib/active_support/file_update_checker.rb +4 -2
  129. data/lib/active_support/fork_tracker.rb +28 -11
  130. data/lib/active_support/gem_version.rb +4 -4
  131. data/lib/active_support/gzip.rb +2 -0
  132. data/lib/active_support/hash_with_indifferent_access.rb +44 -19
  133. data/lib/active_support/html_safe_translation.rb +53 -0
  134. data/lib/active_support/i18n.rb +2 -1
  135. data/lib/active_support/i18n_railtie.rb +21 -14
  136. data/lib/active_support/inflector/inflections.rb +25 -7
  137. data/lib/active_support/inflector/methods.rb +50 -64
  138. data/lib/active_support/inflector/transliterate.rb +4 -2
  139. data/lib/active_support/isolated_execution_state.rb +76 -0
  140. data/lib/active_support/json/decoding.rb +2 -1
  141. data/lib/active_support/json/encoding.rb +27 -45
  142. data/lib/active_support/key_generator.rb +31 -6
  143. data/lib/active_support/lazy_load_hooks.rb +33 -7
  144. data/lib/active_support/locale/en.yml +4 -2
  145. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  146. data/lib/active_support/log_subscriber.rb +97 -35
  147. data/lib/active_support/logger.rb +9 -60
  148. data/lib/active_support/logger_thread_safe_level.rb +11 -34
  149. data/lib/active_support/message_encryptor.rb +206 -56
  150. data/lib/active_support/message_encryptors.rb +141 -0
  151. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  152. data/lib/active_support/message_pack/extensions.rb +292 -0
  153. data/lib/active_support/message_pack/serializer.rb +63 -0
  154. data/lib/active_support/message_pack.rb +50 -0
  155. data/lib/active_support/message_verifier.rb +235 -84
  156. data/lib/active_support/message_verifiers.rb +135 -0
  157. data/lib/active_support/messages/codec.rb +65 -0
  158. data/lib/active_support/messages/metadata.rb +112 -46
  159. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  160. data/lib/active_support/messages/rotator.rb +34 -32
  161. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  162. data/lib/active_support/multibyte/chars.rb +12 -11
  163. data/lib/active_support/multibyte/unicode.rb +9 -49
  164. data/lib/active_support/multibyte.rb +1 -1
  165. data/lib/active_support/notifications/fanout.rb +304 -114
  166. data/lib/active_support/notifications/instrumenter.rb +117 -35
  167. data/lib/active_support/notifications.rb +25 -25
  168. data/lib/active_support/number_helper/number_converter.rb +14 -7
  169. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  170. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  171. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -4
  172. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  173. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  174. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  175. data/lib/active_support/number_helper.rb +379 -319
  176. data/lib/active_support/option_merger.rb +10 -18
  177. data/lib/active_support/ordered_hash.rb +4 -4
  178. data/lib/active_support/ordered_options.rb +15 -1
  179. data/lib/active_support/parameter_filter.rb +105 -81
  180. data/lib/active_support/proxy_object.rb +2 -0
  181. data/lib/active_support/railtie.rb +83 -21
  182. data/lib/active_support/reloader.rb +13 -5
  183. data/lib/active_support/rescuable.rb +18 -16
  184. data/lib/active_support/ruby_features.rb +7 -0
  185. data/lib/active_support/secure_compare_rotator.rb +18 -11
  186. data/lib/active_support/security_utils.rb +1 -1
  187. data/lib/active_support/string_inquirer.rb +3 -3
  188. data/lib/active_support/subscriber.rb +11 -40
  189. data/lib/active_support/syntax_error_proxy.rb +60 -0
  190. data/lib/active_support/tagged_logging.rb +65 -25
  191. data/lib/active_support/test_case.rb +166 -27
  192. data/lib/active_support/testing/assertions.rb +61 -15
  193. data/lib/active_support/testing/autorun.rb +0 -2
  194. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  195. data/lib/active_support/testing/deprecation.rb +53 -2
  196. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  197. data/lib/active_support/testing/isolation.rb +30 -29
  198. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  199. data/lib/active_support/testing/parallelization/server.rb +4 -0
  200. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  201. data/lib/active_support/testing/parallelization.rb +4 -0
  202. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  203. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  204. data/lib/active_support/testing/stream.rb +4 -6
  205. data/lib/active_support/testing/strict_warnings.rb +39 -0
  206. data/lib/active_support/testing/tagged_logging.rb +1 -1
  207. data/lib/active_support/testing/time_helpers.rb +49 -16
  208. data/lib/active_support/time_with_zone.rb +39 -28
  209. data/lib/active_support/values/time_zone.rb +50 -18
  210. data/lib/active_support/version.rb +1 -1
  211. data/lib/active_support/xml_mini/jdom.rb +4 -11
  212. data/lib/active_support/xml_mini/libxml.rb +5 -5
  213. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  214. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  215. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  216. data/lib/active_support/xml_mini/rexml.rb +2 -2
  217. data/lib/active_support/xml_mini.rb +7 -6
  218. data/lib/active_support.rb +28 -1
  219. metadata +150 -18
  220. data/lib/active_support/core_ext/marshal.rb +0 -26
  221. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
  222. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  223. data/lib/active_support/core_ext/uri.rb +0 -29
  224. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  225. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -9,21 +9,21 @@ require "active_support/values/time_zone"
9
9
  class DateTime
10
10
  # Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
11
11
  #
12
- # This method is aliased to <tt>to_s</tt>.
12
+ # This method is aliased to <tt>to_formatted_s</tt>.
13
13
  #
14
14
  # === Examples
15
15
  # datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
16
16
  #
17
- # datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
18
- # datetime.to_s(:db) # => "2007-12-04 00:00:00"
19
- # datetime.to_s(:number) # => "20071204000000"
20
- # datetime.to_formatted_s(:short) # => "04 Dec 00:00"
21
- # datetime.to_formatted_s(:long) # => "December 04, 2007 00:00"
22
- # datetime.to_formatted_s(:long_ordinal) # => "December 4th, 2007 00:00"
23
- # datetime.to_formatted_s(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
24
- # datetime.to_formatted_s(:iso8601) # => "2007-12-04T00:00:00+00:00"
17
+ # datetime.to_fs(:db) # => "2007-12-04 00:00:00"
18
+ # datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
19
+ # datetime.to_fs(:number) # => "20071204000000"
20
+ # datetime.to_fs(:short) # => "04 Dec 00:00"
21
+ # datetime.to_fs(:long) # => "December 04, 2007 00:00"
22
+ # datetime.to_fs(:long_ordinal) # => "December 4th, 2007 00:00"
23
+ # datetime.to_fs(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
24
+ # datetime.to_fs(:iso8601) # => "2007-12-04T00:00:00+00:00"
25
25
  #
26
- # == Adding your own datetime formats to to_formatted_s
26
+ # == Adding your own datetime formats to to_fs
27
27
  # DateTime formats are shared with Time. You can add your own to the
28
28
  # Time::DATE_FORMATS hash. Use the format name as the hash key and
29
29
  # either a strftime string or Proc instance that takes a time or
@@ -32,15 +32,19 @@ class DateTime
32
32
  # # config/initializers/time_formats.rb
33
33
  # Time::DATE_FORMATS[:month_and_year] = '%B %Y'
34
34
  # Time::DATE_FORMATS[:short_ordinal] = lambda { |time| time.strftime("%B #{time.day.ordinalize}") }
35
- def to_formatted_s(format = :default)
35
+ def to_fs(format = :default)
36
36
  if formatter = ::Time::DATE_FORMATS[format]
37
37
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
38
38
  else
39
- to_default_s
39
+ to_s
40
40
  end
41
41
  end
42
- alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
43
- alias_method :to_s, :to_formatted_s
42
+ alias_method :to_formatted_s, :to_fs
43
+ if instance_methods(false).include?(:to_s)
44
+ alias_method :to_default_s, :to_s
45
+ deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
46
+ end
47
+
44
48
 
45
49
  # Returns a formatted string of the offset from UTC, or an alternative
46
50
  # string if the time zone is already UTC.
@@ -54,7 +58,7 @@ class DateTime
54
58
 
55
59
  # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000".
56
60
  def readable_inspect
57
- to_s(:rfc822)
61
+ to_fs(:rfc822)
58
62
  end
59
63
  alias_method :default_inspect, :inspect
60
64
  alias_method :inspect, :readable_inspect
@@ -1,29 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "securerandom"
4
+ require "openssl"
4
5
 
5
6
  module Digest
6
7
  module UUID
7
- DNS_NAMESPACE = "k\xA7\xB8\x10\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
8
- URL_NAMESPACE = "k\xA7\xB8\x11\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
9
- OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
10
- X500_NAMESPACE = "k\xA7\xB8\x14\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
8
+ DNS_NAMESPACE = "k\xA7\xB8\x10\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
9
+ URL_NAMESPACE = "k\xA7\xB8\x11\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
10
+ OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
11
+ X500_NAMESPACE = "k\xA7\xB8\x14\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
11
12
 
12
13
  # Generates a v5 non-random UUID (Universally Unique IDentifier).
13
14
  #
14
- # Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
15
+ # Using OpenSSL::Digest::MD5 generates version 3 UUIDs; OpenSSL::Digest::SHA1 generates version 5 UUIDs.
15
16
  # uuid_from_hash always generates the same UUID for a given name and namespace combination.
16
17
  #
17
18
  # See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
18
- def self.uuid_from_hash(hash_class, uuid_namespace, name)
19
- if hash_class == Digest::MD5
19
+ def self.uuid_from_hash(hash_class, namespace, name)
20
+ if hash_class == Digest::MD5 || hash_class == OpenSSL::Digest::MD5
20
21
  version = 3
21
- elsif hash_class == Digest::SHA1
22
+ elsif hash_class == Digest::SHA1 || hash_class == OpenSSL::Digest::SHA1
22
23
  version = 5
23
24
  else
24
- raise ArgumentError, "Expected Digest::SHA1 or Digest::MD5, got #{hash_class.name}."
25
+ raise ArgumentError, "Expected OpenSSL::Digest::SHA1 or OpenSSL::Digest::MD5, got #{hash_class.name}."
25
26
  end
26
27
 
28
+ uuid_namespace = pack_uuid_namespace(namespace)
29
+
27
30
  hash = hash_class.new
28
31
  hash.update(uuid_namespace)
29
32
  hash.update(name)
@@ -35,19 +38,33 @@ module Digest
35
38
  "%08x-%04x-%04x-%04x-%04x%08x" % ary
36
39
  end
37
40
 
38
- # Convenience method for uuid_from_hash using Digest::MD5.
41
+ # Convenience method for uuid_from_hash using OpenSSL::Digest::MD5.
39
42
  def self.uuid_v3(uuid_namespace, name)
40
- uuid_from_hash(Digest::MD5, uuid_namespace, name)
43
+ uuid_from_hash(OpenSSL::Digest::MD5, uuid_namespace, name)
41
44
  end
42
45
 
43
- # Convenience method for uuid_from_hash using Digest::SHA1.
46
+ # Convenience method for uuid_from_hash using OpenSSL::Digest::SHA1.
44
47
  def self.uuid_v5(uuid_namespace, name)
45
- uuid_from_hash(Digest::SHA1, uuid_namespace, name)
48
+ uuid_from_hash(OpenSSL::Digest::SHA1, uuid_namespace, name)
46
49
  end
47
50
 
48
51
  # Convenience method for SecureRandom.uuid.
49
52
  def self.uuid_v4
50
53
  SecureRandom.uuid
51
54
  end
55
+
56
+ def self.pack_uuid_namespace(namespace)
57
+ if [DNS_NAMESPACE, OID_NAMESPACE, URL_NAMESPACE, X500_NAMESPACE].include?(namespace)
58
+ namespace
59
+ else
60
+ match_data = namespace.match(/\A(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{4})(\h{8})\z/)
61
+
62
+ raise ArgumentError, "Only UUIDs are valid namespace identifiers" unless match_data.present?
63
+
64
+ match_data.captures.map { |s| s.to_i(16) }.pack("NnnnnN")
65
+ end
66
+ end
67
+
68
+ private_class_method :pack_uuid_namespace
52
69
  end
53
70
  end
@@ -1,47 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
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:
3
+ module ActiveSupport
4
+ module EnumerableCoreExt # :nodoc:
5
+ module Constants
6
+ private
7
+ def const_missing(name)
8
+ if name == :SoleItemExpectedError
9
+ ::ActiveSupport::EnumerableCoreExt::SoleItemExpectedError
10
+ else
11
+ super
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
11
17
 
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
18
+ module Enumerable
19
+ # Error generated by +sole+ when called on an enumerable that doesn't have
20
+ # exactly one item.
21
+ class SoleItemExpectedError < StandardError; end
16
22
 
17
- # :startdoc:
23
+ # HACK: For performance reasons, Enumerable shouldn't have any constants of its own.
24
+ # So we move SoleItemExpectedError into ActiveSupport::EnumerableCoreExt.
25
+ ActiveSupport::EnumerableCoreExt::SoleItemExpectedError = remove_const(:SoleItemExpectedError)
26
+ singleton_class.prepend(ActiveSupport::EnumerableCoreExt::Constants)
18
27
 
19
- # Calculates a sum from the elements.
20
- #
21
- # payments.sum { |p| p.price * p.tax_rate }
22
- # payments.sum(&:price)
23
- #
24
- # The latter is a shortcut for:
25
- #
26
- # payments.inject(0) { |sum, p| sum + p.price }
28
+ # Calculates the minimum from the extracted elements.
27
29
  #
28
- # It can also calculate the sum without the use of a block.
29
- #
30
- # [5, 15, 10].sum # => 30
31
- # ['foo', 'bar'].sum # => "foobar"
32
- # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
33
- #
34
- # The default sum of an empty list is zero. You can override this default:
30
+ # payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
31
+ # payments.minimum(:price) # => 5
32
+ def minimum(key)
33
+ map(&key).min
34
+ end
35
+
36
+ # Calculates the maximum from the extracted elements.
35
37
  #
36
- # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
37
- def sum(identity = nil, &block)
38
- if identity
39
- _original_sum_with_required_identity(identity, &block)
40
- elsif block_given?
41
- map(&block).sum(identity)
42
- else
43
- inject(:+) || 0
44
- end
38
+ # payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
39
+ # payments.maximum(:price) # => 15
40
+ def maximum(key)
41
+ map(&key).max
45
42
  end
46
43
 
47
44
  # Convert an enumerable to a hash, using the block result as the key and the
@@ -75,17 +72,17 @@ module Enumerable
75
72
  #
76
73
  # %i( created_at updated_at ).index_with(Time.now)
77
74
  # # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
78
- def index_with(default = INDEX_WITH_DEFAULT)
75
+ def index_with(default = (no_default = true))
79
76
  if block_given?
80
77
  result = {}
81
78
  each { |elem| result[elem] = yield(elem) }
82
79
  result
83
- elsif default != INDEX_WITH_DEFAULT
80
+ elsif no_default
81
+ to_enum(:index_with) { size if respond_to?(:size) }
82
+ else
84
83
  result = {}
85
84
  each { |elem| result[elem] = default }
86
85
  result
87
- else
88
- to_enum(:index_with) { size if respond_to?(:size) }
89
86
  end
90
87
  end
91
88
 
@@ -96,8 +93,8 @@ module Enumerable
96
93
  def many?
97
94
  cnt = 0
98
95
  if block_given?
99
- any? do |element|
100
- cnt += 1 if yield element
96
+ any? do |*args|
97
+ cnt += 1 if yield(*args)
101
98
  cnt > 1
102
99
  end
103
100
  else
@@ -136,11 +133,7 @@ module Enumerable
136
133
  elements.flatten!(1)
137
134
  reject { |element| elements.include?(element) }
138
135
  end
139
-
140
- # Alias for #excluding.
141
- def without(*elements)
142
- excluding(*elements)
143
- end
136
+ alias :without :excluding
144
137
 
145
138
  # Extract the given key from each element in the enumerable.
146
139
  #
@@ -178,81 +171,90 @@ module Enumerable
178
171
  # Returns a new +Array+ without the blank items.
179
172
  # Uses Object#blank? for determining if an item is blank.
180
173
  #
181
- # [1, "", nil, 2, " ", [], {}, false, true].compact_blank
182
- # # => [1, 2, true]
174
+ # [1, "", nil, 2, " ", [], {}, false, true].compact_blank
175
+ # # => [1, 2, true]
183
176
  #
184
- # Set.new([nil, "", 1, 2])
185
- # # => [2, 1] (or [1, 2])
177
+ # Set.new([nil, "", 1, false]).compact_blank
178
+ # # => [1]
186
179
  #
187
180
  # When called on a +Hash+, returns a new +Hash+ without the blank values.
188
181
  #
189
- # { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
190
- # #=> { b: 1, f: true }
182
+ # { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
183
+ # # => { b: 1, f: true }
191
184
  def compact_blank
192
185
  reject(&:blank?)
193
186
  end
187
+
188
+ # Returns a new +Array+ where the order has been set to that provided in the +series+, based on the +key+ of the
189
+ # objects in the original enumerable.
190
+ #
191
+ # [ Person.find(5), Person.find(3), Person.find(1) ].in_order_of(:id, [ 1, 5, 3 ])
192
+ # # => [ Person.find(1), Person.find(5), Person.find(3) ]
193
+ #
194
+ # If the +series+ include keys that have no corresponding element in the Enumerable, these are ignored.
195
+ # If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result.
196
+ def in_order_of(key, series)
197
+ group_by(&key).values_at(*series).flatten(1).compact
198
+ end
199
+
200
+ # Returns the sole item in the enumerable. If there are no items, or more
201
+ # than one item, raises +Enumerable::SoleItemExpectedError+.
202
+ #
203
+ # ["x"].sole # => "x"
204
+ # Set.new.sole # => Enumerable::SoleItemExpectedError: no item found
205
+ # { a: 1, b: 2 }.sole # => Enumerable::SoleItemExpectedError: multiple items found
206
+ def sole
207
+ case count
208
+ when 1 then return first # rubocop:disable Style/RedundantReturn
209
+ when 0 then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "no item found"
210
+ when 2.. then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "multiple items found"
211
+ end
212
+ end
194
213
  end
195
214
 
196
215
  class Hash
197
216
  # Hash#reject has its own definition, so this needs one too.
198
- def compact_blank #:nodoc:
217
+ def compact_blank # :nodoc:
199
218
  reject { |_k, v| v.blank? }
200
219
  end
201
220
 
202
221
  # Removes all blank values from the +Hash+ in place and returns self.
203
222
  # Uses Object#blank? for determining if a value is blank.
204
223
  #
205
- # h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
206
- # h.compact_blank!
207
- # # => { b: 1, f: true }
224
+ # h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
225
+ # h.compact_blank!
226
+ # # => { b: 1, f: true }
208
227
  def compact_blank!
209
228
  # use delete_if rather than reject! because it always returns self even if nothing changed
210
229
  delete_if { |_k, v| v.blank? }
211
230
  end
212
231
  end
213
232
 
214
- class Range #:nodoc:
233
+ class Range # :nodoc:
215
234
  # Optimize range sum to use arithmetic progression if a block is not given and
216
235
  # we have a range of numeric values.
217
- def sum(identity = nil)
236
+ def sum(initial_value = 0)
218
237
  if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
219
238
  super
220
239
  else
221
240
  actual_last = exclude_end? ? (last - 1) : last
222
241
  if actual_last >= first
223
- sum = identity || 0
242
+ sum = initial_value || 0
224
243
  sum + (actual_last - first + 1) * (actual_last + first) / 2
225
244
  else
226
- identity || 0
245
+ initial_value || 0
227
246
  end
228
247
  end
229
248
  end
230
249
  end
231
250
 
232
- # Using Refinements here in order not to expose our internal method
233
- using Module.new {
234
- refine Array do
235
- alias :orig_sum :sum
236
- end
237
- }
238
-
239
- class Array #:nodoc:
240
- # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
241
- def sum(init = nil, &block)
242
- if init.is_a?(Numeric) || first.is_a?(Numeric)
243
- init ||= 0
244
- orig_sum(init, &block)
245
- else
246
- super
247
- end
248
- end
249
-
251
+ class Array # :nodoc:
250
252
  # Removes all blank elements from the +Array+ in place and returns self.
251
253
  # Uses Object#blank? for determining if an item is blank.
252
254
  #
253
- # a = [1, "", nil, 2, " ", [], {}, false, true]
254
- # a.compact_blank!
255
- # # => [1, 2, true]
255
+ # a = [1, "", nil, 2, " ", [], {}, false, true]
256
+ # a.compact_blank!
257
+ # # => [1, 2, true]
256
258
  def compact_blank!
257
259
  # use delete_if rather than reject! because it always returns self even if nothing changed
258
260
  delete_if(&:blank?)
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module ActiveSupport
6
+ module CoreExt
7
+ module ERBUtil
8
+ # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
9
+ # This method is not for public consumption! Seriously!
10
+ def html_escape(s) # :nodoc:
11
+ s = s.to_s
12
+ if s.html_safe?
13
+ s
14
+ else
15
+ super(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
16
+ end
17
+ end
18
+ alias :unwrapped_html_escape :html_escape # :nodoc:
19
+
20
+ # A utility method for escaping HTML tag characters.
21
+ # This method is also aliased as <tt>h</tt>.
22
+ #
23
+ # puts html_escape('is a > 0 & a < 10?')
24
+ # # => is a &gt; 0 &amp; a &lt; 10?
25
+ def html_escape(s) # rubocop:disable Lint/DuplicateMethods
26
+ unwrapped_html_escape(s).html_safe
27
+ end
28
+ alias h html_escape
29
+ end
30
+
31
+ module ERBUtilPrivate
32
+ include ERBUtil
33
+ private :unwrapped_html_escape, :html_escape, :h
34
+ end
35
+ end
36
+ end
37
+
38
+ class ERB
39
+ module Util
40
+ HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
41
+ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
42
+
43
+ # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
44
+ TAG_NAME_START_CODEPOINTS = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
45
+ "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
46
+ "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
47
+ INVALID_TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_CODEPOINTS}]/
48
+ TAG_NAME_FOLLOWING_CODEPOINTS = "#{TAG_NAME_START_CODEPOINTS}\\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}"
49
+ INVALID_TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_FOLLOWING_CODEPOINTS}]/
50
+ SAFE_XML_TAG_NAME_REGEXP = /\A[#{TAG_NAME_START_CODEPOINTS}][#{TAG_NAME_FOLLOWING_CODEPOINTS}]*\z/
51
+ TAG_NAME_REPLACEMENT_CHAR = "_"
52
+
53
+ prepend ActiveSupport::CoreExt::ERBUtilPrivate
54
+ singleton_class.prepend ActiveSupport::CoreExt::ERBUtil
55
+
56
+ # A utility method for escaping HTML without affecting existing escaped entities.
57
+ #
58
+ # html_escape_once('1 < 2 &amp; 3')
59
+ # # => "1 &lt; 2 &amp; 3"
60
+ #
61
+ # html_escape_once('&lt;&lt; Accept & Checkout')
62
+ # # => "&lt;&lt; Accept &amp; Checkout"
63
+ def html_escape_once(s)
64
+ ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE).html_safe
65
+ end
66
+
67
+ module_function :html_escape_once
68
+
69
+ # A utility method for escaping HTML entities in JSON strings. Specifically, the
70
+ # &, > and < characters are replaced with their equivalent unicode escaped form -
71
+ # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
72
+ # escaped as they are treated as newline characters in some JavaScript engines.
73
+ # These sequences have identical meaning as the original characters inside the
74
+ # context of a JSON string, so assuming the input is a valid and well-formed
75
+ # JSON value, the output will have equivalent meaning when parsed:
76
+ #
77
+ # json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
78
+ # # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
79
+ #
80
+ # json_escape(json)
81
+ # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
82
+ #
83
+ # JSON.parse(json) == JSON.parse(json_escape(json))
84
+ # # => true
85
+ #
86
+ # The intended use case for this method is to escape JSON strings before including
87
+ # them inside a script tag to avoid XSS vulnerability:
88
+ #
89
+ # <script>
90
+ # var currentUser = <%= raw json_escape(current_user.to_json) %>;
91
+ # </script>
92
+ #
93
+ # It is necessary to +raw+ the result of +json_escape+, so that quotation marks
94
+ # don't get converted to <tt>&quot;</tt> entities. +json_escape+ doesn't
95
+ # automatically flag the result as HTML safe, since the raw value is unsafe to
96
+ # use inside HTML attributes.
97
+ #
98
+ # If your JSON is being used downstream for insertion into the DOM, be aware of
99
+ # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
100
+ # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
101
+ # content returned by your JSON.
102
+ #
103
+ # If you need to output JSON elsewhere in your HTML, you can just do something
104
+ # like this, as any unsafe characters (including quotation marks) will be
105
+ # automatically escaped for you:
106
+ #
107
+ # <div data-user-info="<%= current_user.to_json %>">...</div>
108
+ #
109
+ # WARNING: this helper only works with valid JSON. Using this on non-JSON values
110
+ # will open up serious XSS vulnerabilities. For example, if you replace the
111
+ # +current_user.to_json+ in the example above with user input instead, the browser
112
+ # will happily <tt>eval()</tt> that string as JavaScript.
113
+ #
114
+ # The escaping performed in this method is identical to those performed in the
115
+ # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
116
+ # set to true. Because this transformation is idempotent, this helper can be
117
+ # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
118
+ #
119
+ # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
120
+ # is enabled, or if you are unsure where your JSON string originated from, it
121
+ # is recommended that you always apply this helper (other libraries, such as the
122
+ # JSON gem, do not provide this kind of protection by default; also some gems
123
+ # might override +to_json+ to bypass Active Support's encoder).
124
+ def json_escape(s)
125
+ result = s.to_s.dup
126
+ result.gsub!(">", '\u003e')
127
+ result.gsub!("<", '\u003c')
128
+ result.gsub!("&", '\u0026')
129
+ result.gsub!("\u2028", '\u2028')
130
+ result.gsub!("\u2029", '\u2029')
131
+ s.html_safe? ? result.html_safe : result
132
+ end
133
+
134
+ module_function :json_escape
135
+
136
+ # A utility method for escaping XML names of tags and names of attributes.
137
+ #
138
+ # xml_name_escape('1 < 2 & 3')
139
+ # # => "1___2___3"
140
+ #
141
+ # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
142
+ def xml_name_escape(name)
143
+ name = name.to_s
144
+ return "" if name.blank?
145
+ return name if name.match?(SAFE_XML_TAG_NAME_REGEXP)
146
+
147
+ starting_char = name[0]
148
+ starting_char.gsub!(INVALID_TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
149
+
150
+ return starting_char if name.size == 1
151
+
152
+ following_chars = name[1..-1]
153
+ following_chars.gsub!(INVALID_TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
154
+
155
+ starting_char << following_chars
156
+ end
157
+ module_function :xml_name_escape
158
+
159
+ # Tokenizes a line of ERB. This is really just for error reporting and
160
+ # nobody should use it.
161
+ def self.tokenize(source) # :nodoc:
162
+ require "strscan"
163
+ source = StringScanner.new(source.chomp)
164
+ tokens = []
165
+
166
+ start_re = /<%(?:={1,2}|-|\#|%)?/m
167
+ finish_re = /(?:[-=])?%>/m
168
+
169
+ while !source.eos?
170
+ pos = source.pos
171
+ source.scan_until(/(?:#{start_re}|#{finish_re})/)
172
+ raise NotImplementedError if source.matched.nil?
173
+ len = source.pos - source.matched.bytesize - pos
174
+
175
+ case source.matched
176
+ when start_re
177
+ tokens << [:TEXT, source.string[pos, len]] if len > 0
178
+ tokens << [:OPEN, source.matched]
179
+ if source.scan(/(.*?)(?=#{finish_re}|\z)/m)
180
+ tokens << [:CODE, source.matched] unless source.matched.empty?
181
+ tokens << [:CLOSE, source.scan(finish_re)] unless source.eos?
182
+ else
183
+ raise NotImplementedError
184
+ end
185
+ when finish_re
186
+ tokens << [:CODE, source.string[pos, len]] if len > 0
187
+ tokens << [:CLOSE, source.matched]
188
+ else
189
+ raise NotImplementedError, source.matched
190
+ end
191
+ end
192
+
193
+ tokens
194
+ end
195
+ end
196
+ end
@@ -53,7 +53,7 @@ class File
53
53
  end
54
54
 
55
55
  # Private utility method.
56
- def self.probe_stat_in(dir) #:nodoc:
56
+ def self.probe_stat_in(dir) # :nodoc:
57
57
  basename = [
58
58
  ".permissions_check",
59
59
  Thread.current.object_id,
@@ -64,6 +64,8 @@ class File
64
64
  file_name = join(dir, basename)
65
65
  FileUtils.touch(file_name)
66
66
  stat(file_name)
67
+ rescue Errno::ENOENT
68
+ file_name = nil
67
69
  ensure
68
70
  FileUtils.rm_f(file_name) if file_name
69
71
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/xml_mini"
4
3
  require "active_support/core_ext/object/blank"
5
4
  require "active_support/core_ext/object/to_param"
6
5
  require "active_support/core_ext/object/to_query"
@@ -69,7 +68,7 @@ class Hash
69
68
  #
70
69
  # By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
71
70
  #
72
- # The default XML builder is a fresh instance of <tt>Builder::XmlMarkup</tt>. You can
71
+ # The default XML builder is a fresh instance of +Builder::XmlMarkup+. You can
73
72
  # configure your own builder with the <tt>:builder</tt> option. The method also accepts
74
73
  # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
75
74
  def to_xml(options = {})
@@ -1,6 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deep_mergeable"
4
+
3
5
  class Hash
6
+ include ActiveSupport::DeepMergeable
7
+
8
+ ##
9
+ # :method: deep_merge
10
+ # :call-seq: deep_merge(other_hash, &block)
11
+ #
4
12
  # Returns a new hash with +self+ and +other_hash+ merged recursively.
5
13
  #
6
14
  # h1 = { a: true, b: { c: [1, 2, 3] } }
@@ -15,20 +23,20 @@ class Hash
15
23
  # h2 = { b: 250, c: { c1: 200 } }
16
24
  # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
17
25
  # # => { a: 100, b: 450, c: { c1: 300 } }
18
- def deep_merge(other_hash, &block)
19
- dup.deep_merge!(other_hash, &block)
20
- end
26
+ #
27
+ #--
28
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge.
29
+
30
+ ##
31
+ # :method: deep_merge!
32
+ # :call-seq: deep_merge!(other_hash, &block)
33
+ #
34
+ # Same as #deep_merge, but modifies +self+.
35
+ #
36
+ #--
37
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge!.
21
38
 
22
- # Same as +deep_merge+, but modifies +self+.
23
- def deep_merge!(other_hash, &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)
29
- else
30
- other_val
31
- end
32
- end
39
+ def deep_merge?(other) # :nodoc:
40
+ other.is_a?(Hash)
33
41
  end
34
42
  end