activesupport 6.0.6.1 → 7.1.3.2

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 (245) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +865 -438
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +30 -10
  8. data/lib/active_support/benchmarkable.rb +4 -3
  9. data/lib/active_support/broadcast_logger.rb +250 -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 +208 -63
  15. data/lib/active_support/cache/memory_store.rb +120 -38
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +201 -208
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +73 -66
  20. data/lib/active_support/cache.rb +539 -261
  21. data/lib/active_support/callbacks.rb +273 -142
  22. data/lib/active_support/code_generator.rb +65 -0
  23. data/lib/active_support/concern.rb +53 -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 +19 -6
  28. data/lib/active_support/configuration_file.rb +51 -0
  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/benchmark.rb +2 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  36. data/lib/active_support/core_ext/class/subclasses.rb +19 -29
  37. data/lib/active_support/core_ext/date/blank.rb +1 -1
  38. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  39. data/lib/active_support/core_ext/date/conversions.rb +18 -16
  40. data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
  41. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  42. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  43. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  44. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  45. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  46. data/lib/active_support/core_ext/enumerable.rb +146 -72
  47. data/lib/active_support/core_ext/erb/util.rb +196 -0
  48. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  49. data/lib/active_support/core_ext/hash/conversions.rb +3 -4
  50. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  51. data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
  52. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  53. data/lib/active_support/core_ext/hash/keys.rb +5 -5
  54. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  55. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  56. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  57. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  58. data/lib/active_support/core_ext/load_error.rb +1 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
  62. data/lib/active_support/core_ext/module/concerning.rb +14 -8
  63. data/lib/active_support/core_ext/module/delegation.rb +75 -42
  64. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  65. data/lib/active_support/core_ext/module/introspection.rb +1 -26
  66. data/lib/active_support/core_ext/name_error.rb +23 -2
  67. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  68. data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
  69. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  70. data/lib/active_support/core_ext/object/blank.rb +2 -2
  71. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  72. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  73. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  74. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  75. data/lib/active_support/core_ext/object/json.rb +52 -28
  76. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  77. data/lib/active_support/core_ext/object/try.rb +20 -20
  78. data/lib/active_support/core_ext/object/with.rb +44 -0
  79. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  80. data/lib/active_support/core_ext/object.rb +1 -0
  81. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  82. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  83. data/lib/active_support/core_ext/pathname.rb +4 -0
  84. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  85. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  86. data/lib/active_support/core_ext/range/each.rb +1 -1
  87. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  88. data/lib/active_support/core_ext/range.rb +1 -2
  89. data/lib/active_support/core_ext/regexp.rb +8 -1
  90. data/lib/active_support/core_ext/securerandom.rb +25 -13
  91. data/lib/active_support/core_ext/string/access.rb +5 -24
  92. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  93. data/lib/active_support/core_ext/string/filters.rb +21 -15
  94. data/lib/active_support/core_ext/string/indent.rb +1 -1
  95. data/lib/active_support/core_ext/string/inflections.rb +51 -10
  96. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  97. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  98. data/lib/active_support/core_ext/string/output_safety.rb +85 -194
  99. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  100. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  101. data/lib/active_support/core_ext/symbol.rb +3 -0
  102. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  103. data/lib/active_support/core_ext/time/calculations.rb +46 -8
  104. data/lib/active_support/core_ext/time/conversions.rb +16 -13
  105. data/lib/active_support/core_ext/time/zones.rb +12 -28
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  108. data/lib/active_support/current_attributes.rb +54 -22
  109. data/lib/active_support/deep_mergeable.rb +53 -0
  110. data/lib/active_support/dependencies/autoload.rb +17 -12
  111. data/lib/active_support/dependencies/interlock.rb +10 -18
  112. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  113. data/lib/active_support/dependencies.rb +58 -769
  114. data/lib/active_support/deprecation/behaviors.rb +77 -38
  115. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  116. data/lib/active_support/deprecation/deprecators.rb +104 -0
  117. data/lib/active_support/deprecation/disallowed.rb +54 -0
  118. data/lib/active_support/deprecation/instance_delegator.rb +31 -5
  119. data/lib/active_support/deprecation/method_wrappers.rb +12 -28
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
  121. data/lib/active_support/deprecation/reporting.rb +76 -16
  122. data/lib/active_support/deprecation.rb +36 -4
  123. data/lib/active_support/deprecator.rb +7 -0
  124. data/lib/active_support/descendants_tracker.rb +150 -68
  125. data/lib/active_support/digest.rb +5 -3
  126. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  127. data/lib/active_support/duration/iso8601_serializer.rb +24 -12
  128. data/lib/active_support/duration.rb +136 -56
  129. data/lib/active_support/encrypted_configuration.rb +72 -9
  130. data/lib/active_support/encrypted_file.rb +46 -13
  131. data/lib/active_support/environment_inquirer.rb +40 -0
  132. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  133. data/lib/active_support/error_reporter.rb +203 -0
  134. data/lib/active_support/evented_file_update_checker.rb +86 -137
  135. data/lib/active_support/execution_context/test_helper.rb +13 -0
  136. data/lib/active_support/execution_context.rb +53 -0
  137. data/lib/active_support/execution_wrapper.rb +31 -12
  138. data/lib/active_support/executor/test_helper.rb +7 -0
  139. data/lib/active_support/file_update_checker.rb +4 -2
  140. data/lib/active_support/fork_tracker.rb +79 -0
  141. data/lib/active_support/gem_version.rb +5 -5
  142. data/lib/active_support/gzip.rb +2 -0
  143. data/lib/active_support/hash_with_indifferent_access.rb +86 -42
  144. data/lib/active_support/html_safe_translation.rb +53 -0
  145. data/lib/active_support/i18n.rb +2 -1
  146. data/lib/active_support/i18n_railtie.rb +29 -27
  147. data/lib/active_support/inflector/inflections.rb +26 -9
  148. data/lib/active_support/inflector/methods.rb +54 -64
  149. data/lib/active_support/inflector/transliterate.rb +7 -5
  150. data/lib/active_support/isolated_execution_state.rb +76 -0
  151. data/lib/active_support/json/decoding.rb +6 -5
  152. data/lib/active_support/json/encoding.rb +31 -45
  153. data/lib/active_support/key_generator.rb +32 -7
  154. data/lib/active_support/lazy_load_hooks.rb +33 -7
  155. data/lib/active_support/locale/en.yml +10 -4
  156. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  157. data/lib/active_support/log_subscriber.rb +101 -32
  158. data/lib/active_support/logger.rb +9 -60
  159. data/lib/active_support/logger_silence.rb +2 -26
  160. data/lib/active_support/logger_thread_safe_level.rb +24 -25
  161. data/lib/active_support/message_encryptor.rb +205 -58
  162. data/lib/active_support/message_encryptors.rb +141 -0
  163. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  164. data/lib/active_support/message_pack/extensions.rb +292 -0
  165. data/lib/active_support/message_pack/serializer.rb +63 -0
  166. data/lib/active_support/message_pack.rb +50 -0
  167. data/lib/active_support/message_verifier.rb +237 -86
  168. data/lib/active_support/message_verifiers.rb +135 -0
  169. data/lib/active_support/messages/codec.rb +65 -0
  170. data/lib/active_support/messages/metadata.rb +112 -46
  171. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  172. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  173. data/lib/active_support/messages/rotator.rb +35 -32
  174. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  175. data/lib/active_support/multibyte/chars.rb +15 -52
  176. data/lib/active_support/multibyte/unicode.rb +8 -122
  177. data/lib/active_support/multibyte.rb +1 -1
  178. data/lib/active_support/notifications/fanout.rb +310 -105
  179. data/lib/active_support/notifications/instrumenter.rb +113 -48
  180. data/lib/active_support/notifications.rb +56 -29
  181. data/lib/active_support/number_helper/number_converter.rb +15 -8
  182. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  183. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  184. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  185. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
  186. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  187. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  188. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  189. data/lib/active_support/number_helper.rb +379 -304
  190. data/lib/active_support/option_merger.rb +11 -18
  191. data/lib/active_support/ordered_hash.rb +4 -4
  192. data/lib/active_support/ordered_options.rb +23 -3
  193. data/lib/active_support/parameter_filter.rb +104 -75
  194. data/lib/active_support/proxy_object.rb +2 -0
  195. data/lib/active_support/rails.rb +1 -4
  196. data/lib/active_support/railtie.rb +90 -6
  197. data/lib/active_support/reloader.rb +12 -4
  198. data/lib/active_support/rescuable.rb +18 -16
  199. data/lib/active_support/ruby_features.rb +7 -0
  200. data/lib/active_support/secure_compare_rotator.rb +58 -0
  201. data/lib/active_support/security_utils.rb +19 -12
  202. data/lib/active_support/string_inquirer.rb +5 -3
  203. data/lib/active_support/subscriber.rb +23 -47
  204. data/lib/active_support/syntax_error_proxy.rb +70 -0
  205. data/lib/active_support/tagged_logging.rb +84 -23
  206. data/lib/active_support/test_case.rb +166 -27
  207. data/lib/active_support/testing/assertions.rb +73 -20
  208. data/lib/active_support/testing/autorun.rb +0 -2
  209. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  210. data/lib/active_support/testing/deprecation.rb +53 -2
  211. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  212. data/lib/active_support/testing/isolation.rb +30 -29
  213. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  214. data/lib/active_support/testing/parallelization/server.rb +82 -0
  215. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  216. data/lib/active_support/testing/parallelization.rb +16 -95
  217. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  218. data/lib/active_support/testing/stream.rb +4 -6
  219. data/lib/active_support/testing/strict_warnings.rb +39 -0
  220. data/lib/active_support/testing/tagged_logging.rb +1 -1
  221. data/lib/active_support/testing/time_helpers.rb +89 -19
  222. data/lib/active_support/time_with_zone.rb +105 -70
  223. data/lib/active_support/values/time_zone.rb +59 -26
  224. data/lib/active_support/version.rb +1 -1
  225. data/lib/active_support/xml_mini/jdom.rb +4 -11
  226. data/lib/active_support/xml_mini/libxml.rb +5 -5
  227. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  228. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  229. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  230. data/lib/active_support/xml_mini/rexml.rb +9 -2
  231. data/lib/active_support/xml_mini.rb +7 -6
  232. data/lib/active_support.rb +40 -1
  233. metadata +127 -40
  234. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  235. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  236. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  237. data/lib/active_support/core_ext/marshal.rb +0 -24
  238. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  239. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  240. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  241. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
  242. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  243. data/lib/active_support/core_ext/uri.rb +0 -25
  244. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  245. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -2,6 +2,5 @@
2
2
 
3
3
  require "active_support/core_ext/range/conversions"
4
4
  require "active_support/core_ext/range/compare_range"
5
- require "active_support/core_ext/range/include_time_with_zone"
6
- require "active_support/core_ext/range/overlaps"
5
+ require "active_support/core_ext/range/overlap"
7
6
  require "active_support/core_ext/range/each"
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Regexp #:nodoc:
3
+ class Regexp
4
+ # Returns +true+ if the regexp has the multiline flag set.
5
+ #
6
+ # (/./).multiline? # => false
7
+ # (/./m).multiline? # => true
8
+ #
9
+ # Regexp.new(".").multiline? # => false
10
+ # Regexp.new(".", Regexp::MULTILINE).multiline? # => true
4
11
  def multiline?
5
12
  options & MULTILINE == MULTILINE
6
13
  end
@@ -12,16 +12,22 @@ module SecureRandom
12
12
  #
13
13
  # If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
14
14
  #
15
- # The result may contain alphanumeric characters except 0, O, I and l.
15
+ # The result may contain alphanumeric characters except 0, O, I, and l.
16
16
  #
17
17
  # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
18
18
  # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
19
- def self.base58(n = 16)
20
- SecureRandom.random_bytes(n).unpack("C*").map do |byte|
21
- idx = byte % 64
22
- idx = SecureRandom.random_number(58) if idx >= 58
23
- BASE58_ALPHABET[idx]
24
- end.join
19
+ if RUBY_VERSION >= "3.3"
20
+ def self.base58(n = 16)
21
+ SecureRandom.alphanumeric(n, chars: BASE58_ALPHABET)
22
+ end
23
+ else
24
+ def self.base58(n = 16)
25
+ SecureRandom.random_bytes(n).unpack("C*").map do |byte|
26
+ idx = byte % 64
27
+ idx = SecureRandom.random_number(58) if idx >= 58
28
+ BASE58_ALPHABET[idx]
29
+ end.join
30
+ end
25
31
  end
26
32
 
27
33
  # SecureRandom.base36 generates a random base36 string in lowercase.
@@ -35,11 +41,17 @@ module SecureRandom
35
41
  #
36
42
  # p SecureRandom.base36 # => "4kugl2pdqmscqtje"
37
43
  # p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
38
- def self.base36(n = 16)
39
- SecureRandom.random_bytes(n).unpack("C*").map do |byte|
40
- idx = byte % 64
41
- idx = SecureRandom.random_number(36) if idx >= 36
42
- BASE36_ALPHABET[idx]
43
- end.join
44
+ if RUBY_VERSION >= "3.3"
45
+ def self.base36(n = 16)
46
+ SecureRandom.alphanumeric(n, chars: BASE36_ALPHABET)
47
+ end
48
+ else
49
+ def self.base36(n = 16)
50
+ SecureRandom.random_bytes(n).unpack("C*").map do |byte|
51
+ idx = byte % 64
52
+ idx = SecureRandom.random_number(36) if idx >= 36
53
+ BASE36_ALPHABET[idx]
54
+ end.join
55
+ end
44
56
  end
45
57
  end
@@ -44,7 +44,7 @@ class String
44
44
  # str.from(0).to(-1) # => "hello"
45
45
  # str.from(1).to(-2) # => "ell"
46
46
  def from(position)
47
- self[position..-1]
47
+ self[position, length]
48
48
  end
49
49
 
50
50
  # Returns a substring from the beginning of the string to the given position.
@@ -61,7 +61,8 @@ class String
61
61
  # str.from(0).to(-1) # => "hello"
62
62
  # str.from(1).to(-2) # => "ell"
63
63
  def to(position)
64
- self[0..position]
64
+ position += size if position < 0
65
+ self[0, position + 1] || +""
65
66
  end
66
67
 
67
68
  # Returns the first character. If a limit is supplied, returns a substring
@@ -75,17 +76,7 @@ class String
75
76
  # str.first(0) # => ""
76
77
  # str.first(6) # => "hello"
77
78
  def first(limit = 1)
78
- ActiveSupport::Deprecation.warn(
79
- "Calling String#first with a negative integer limit " \
80
- "will raise an ArgumentError in Rails 6.1."
81
- ) if limit < 0
82
- if limit == 0
83
- ""
84
- elsif limit >= size
85
- dup
86
- else
87
- to(limit - 1)
88
- end
79
+ self[0, limit] || raise(ArgumentError, "negative limit")
89
80
  end
90
81
 
91
82
  # Returns the last character of the string. If a limit is supplied, returns a substring
@@ -99,16 +90,6 @@ class String
99
90
  # str.last(0) # => ""
100
91
  # str.last(6) # => "hello"
101
92
  def last(limit = 1)
102
- ActiveSupport::Deprecation.warn(
103
- "Calling String#last with a negative integer limit " \
104
- "will raise an ArgumentError in Rails 6.1."
105
- ) if limit < 0
106
- if limit == 0
107
- ""
108
- elsif limit >= size
109
- dup
110
- else
111
- from(-limit)
112
- end
93
+ self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
113
94
  end
114
95
  end
@@ -5,10 +5,10 @@ require "active_support/core_ext/time/calculations"
5
5
 
6
6
  class String
7
7
  # Converts a string to a Time value.
8
- # The +form+ can be either :utc or :local (default :local).
8
+ # The +form+ can be either +:utc+ or +:local+ (default +:local+).
9
9
  #
10
10
  # The time is parsed using Time.parse method.
11
- # If +form+ is :local, then the time is in the system timezone.
11
+ # If +form+ is +:local+, then the time is in the system timezone.
12
12
  # If the date part is missing then the current date is used and if
13
13
  # the time part is missing then it is assumed to be 00:00:00.
14
14
  #
@@ -18,6 +18,7 @@ class String
18
18
  # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
19
19
  # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
20
20
  # "12/13/2012".to_time # => ArgumentError: argument out of range
21
+ # "1604326192".to_time # => ArgumentError: argument out of range
21
22
  def to_time(form = :local)
22
23
  parts = Date._parse(self, false)
23
24
  used_keys = %i(year mon mday hour min sec sec_fraction offset)
@@ -45,7 +45,7 @@ class String
45
45
  self
46
46
  end
47
47
 
48
- # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
48
+ # Truncates a given +text+ to length <tt>truncate_to</tt> if +text+ is longer than <tt>truncate_to</tt>:
49
49
  #
50
50
  # 'Once upon a time in a world far far away'.truncate(27)
51
51
  # # => "Once upon a time in a wo..."
@@ -58,16 +58,20 @@ class String
58
58
  # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
59
59
  # # => "Once upon a time in a..."
60
60
  #
61
- # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
62
- # for a total length not exceeding <tt>length</tt>:
61
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...").
62
+ # The total length will not exceed <tt>truncate_to</tt> unless both +text+ and <tt>:omission</tt>
63
+ # are longer than <tt>truncate_to</tt>:
63
64
  #
64
65
  # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
65
66
  # # => "And they f... (continued)"
66
- def truncate(truncate_at, options = {})
67
- return dup unless length > truncate_at
67
+ #
68
+ # 'And they found that many people were sleeping better.'.truncate(4, omission: '... (continued)')
69
+ # # => "... (continued)"
70
+ def truncate(truncate_to, options = {})
71
+ return dup unless length > truncate_to
68
72
 
69
73
  omission = options[:omission] || "..."
70
- length_with_room_for_omission = truncate_at - omission.length
74
+ length_with_room_for_omission = truncate_to - omission.length
71
75
  stop = \
72
76
  if options[:separator]
73
77
  rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
@@ -78,7 +82,7 @@ class String
78
82
  +"#{self[0, stop]}#{omission}"
79
83
  end
80
84
 
81
- # Truncates +text+ to at most <tt>bytesize</tt> bytes in length without
85
+ # Truncates +text+ to at most <tt>truncate_to</tt> bytes in length without
82
86
  # breaking string encoding by splitting multibyte characters or breaking
83
87
  # grapheme clusters ("perceptual characters") by truncating at combining
84
88
  # characters.
@@ -91,22 +95,24 @@ class String
91
95
  # => "🔪🔪🔪🔪…"
92
96
  #
93
97
  # The truncated text ends with the <tt>:omission</tt> string, defaulting
94
- # to "…", for a total length not exceeding <tt>bytesize</tt>.
95
- def truncate_bytes(truncate_at, omission: "…")
98
+ # to "…", for a total length not exceeding <tt>truncate_to</tt>.
99
+ #
100
+ # Raises +ArgumentError+ when the bytesize of <tt>:omission</tt> exceeds <tt>truncate_to</tt>.
101
+ def truncate_bytes(truncate_to, omission: "…")
96
102
  omission ||= ""
97
103
 
98
104
  case
99
- when bytesize <= truncate_at
105
+ when bytesize <= truncate_to
100
106
  dup
101
- when omission.bytesize > truncate_at
102
- raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{truncate_at} bytes"
103
- when omission.bytesize == truncate_at
107
+ when omission.bytesize > truncate_to
108
+ raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{truncate_to} bytes"
109
+ when omission.bytesize == truncate_to
104
110
  omission.dup
105
111
  else
106
112
  self.class.new.tap do |cut|
107
- cut_at = truncate_at - omission.bytesize
113
+ cut_at = truncate_to - omission.bytesize
108
114
 
109
- scan(/\X/) do |grapheme|
115
+ each_grapheme_cluster do |grapheme|
110
116
  if cut.bytesize + grapheme.bytesize <= cut_at
111
117
  cut << grapheme
112
118
  else
@@ -24,7 +24,7 @@ class String
24
24
  #
25
25
  # The second argument, +indent_string+, specifies which indent string to
26
26
  # use. The default is +nil+, which tells the method to make a guess by
27
- # peeking at the first indented line, and fallback to a space if there is
27
+ # peeking at the first indented line, and fall back to a space if there is
28
28
  # none.
29
29
  #
30
30
  # " foo".indent(2) # => " foo"
@@ -30,6 +30,8 @@ class String
30
30
  # 'apple'.pluralize(2) # => "apples"
31
31
  # 'ley'.pluralize(:es) # => "leyes"
32
32
  # 'ley'.pluralize(1, :es) # => "ley"
33
+ #
34
+ # See ActiveSupport::Inflector.pluralize.
33
35
  def pluralize(count = nil, locale = :en)
34
36
  locale = count if count.is_a?(Symbol)
35
37
  if count == 1
@@ -53,28 +55,34 @@ class String
53
55
  # 'the blue mailmen'.singularize # => "the blue mailman"
54
56
  # 'CamelOctopi'.singularize # => "CamelOctopus"
55
57
  # 'leyes'.singularize(:es) # => "ley"
58
+ #
59
+ # See ActiveSupport::Inflector.singularize.
56
60
  def singularize(locale = :en)
57
61
  ActiveSupport::Inflector.singularize(self, locale)
58
62
  end
59
63
 
60
64
  # +constantize+ tries to find a declared constant with the name specified
61
65
  # in the string. It raises a NameError when the name is not in CamelCase
62
- # or is not initialized. See ActiveSupport::Inflector.constantize
66
+ # or is not initialized.
63
67
  #
64
68
  # 'Module'.constantize # => Module
65
69
  # 'Class'.constantize # => Class
66
70
  # 'blargle'.constantize # => NameError: wrong constant name blargle
71
+ #
72
+ # See ActiveSupport::Inflector.constantize.
67
73
  def constantize
68
74
  ActiveSupport::Inflector.constantize(self)
69
75
  end
70
76
 
71
77
  # +safe_constantize+ tries to find a declared constant with the name specified
72
78
  # in the string. It returns +nil+ when the name is not in CamelCase
73
- # or is not initialized. See ActiveSupport::Inflector.safe_constantize
79
+ # or is not initialized.
74
80
  #
75
81
  # 'Module'.safe_constantize # => Module
76
82
  # 'Class'.safe_constantize # => Class
77
83
  # 'blargle'.safe_constantize # => nil
84
+ #
85
+ # See ActiveSupport::Inflector.safe_constantize.
78
86
  def safe_constantize
79
87
  ActiveSupport::Inflector.safe_constantize(self)
80
88
  end
@@ -88,6 +96,8 @@ class String
88
96
  # 'active_record'.camelize(:lower) # => "activeRecord"
89
97
  # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
90
98
  # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
99
+ #
100
+ # See ActiveSupport::Inflector.camelize.
91
101
  def camelize(first_letter = :upper)
92
102
  case first_letter
93
103
  when :upper
@@ -102,17 +112,17 @@ class String
102
112
 
103
113
  # Capitalizes all the words and replaces some characters in the string to create
104
114
  # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
105
- # used in the Rails internals.
115
+ # used in the \Rails internals.
106
116
  #
107
117
  # The trailing '_id','Id'.. can be kept and capitalized by setting the
108
118
  # optional parameter +keep_id_suffix+ to true.
109
119
  # By default, this parameter is false.
110
120
  #
111
- # +titleize+ is also aliased as +titlecase+.
112
- #
113
121
  # 'man from the boondocks'.titleize # => "Man From The Boondocks"
114
122
  # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
115
123
  # 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
124
+ #
125
+ # See ActiveSupport::Inflector.titleize.
116
126
  def titleize(keep_id_suffix: false)
117
127
  ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
118
128
  end
@@ -124,6 +134,8 @@ class String
124
134
  #
125
135
  # 'ActiveModel'.underscore # => "active_model"
126
136
  # 'ActiveModel::Errors'.underscore # => "active_model/errors"
137
+ #
138
+ # See ActiveSupport::Inflector.underscore.
127
139
  def underscore
128
140
  ActiveSupport::Inflector.underscore(self)
129
141
  end
@@ -131,6 +143,8 @@ class String
131
143
  # Replaces underscores with dashes in the string.
132
144
  #
133
145
  # 'puni_puni'.dasherize # => "puni-puni"
146
+ #
147
+ # See ActiveSupport::Inflector.dasherize.
134
148
  def dasherize
135
149
  ActiveSupport::Inflector.dasherize(self)
136
150
  end
@@ -142,6 +156,8 @@ class String
142
156
  # '::Inflections'.demodulize # => "Inflections"
143
157
  # ''.demodulize # => ''
144
158
  #
159
+ # See ActiveSupport::Inflector.demodulize.
160
+ #
145
161
  # See also +deconstantize+.
146
162
  def demodulize
147
163
  ActiveSupport::Inflector.demodulize(self)
@@ -155,6 +171,8 @@ class String
155
171
  # '::String'.deconstantize # => ""
156
172
  # ''.deconstantize # => ""
157
173
  #
174
+ # See ActiveSupport::Inflector.deconstantize.
175
+ #
158
176
  # See also +demodulize+.
159
177
  def deconstantize
160
178
  ActiveSupport::Inflector.deconstantize(self)
@@ -192,31 +210,37 @@ class String
192
210
  #
193
211
  # <%= link_to(@person.name, person_path) %>
194
212
  # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
213
+ #
214
+ # See ActiveSupport::Inflector.parameterize.
195
215
  def parameterize(separator: "-", preserve_case: false, locale: nil)
196
216
  ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
197
217
  end
198
218
 
199
- # Creates the name of a table like Rails does for models to table names. This method
219
+ # Creates the name of a table like \Rails does for models to table names. This method
200
220
  # uses the +pluralize+ method on the last word in the string.
201
221
  #
202
222
  # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
203
223
  # 'ham_and_egg'.tableize # => "ham_and_eggs"
204
224
  # 'fancyCategory'.tableize # => "fancy_categories"
225
+ #
226
+ # See ActiveSupport::Inflector.tableize.
205
227
  def tableize
206
228
  ActiveSupport::Inflector.tableize(self)
207
229
  end
208
230
 
209
- # Creates a class name from a plural table name like Rails does for table names to models.
231
+ # Creates a class name from a plural table name like \Rails does for table names to models.
210
232
  # Note that this returns a string and not a class. (To convert to an actual class
211
233
  # follow +classify+ with +constantize+.)
212
234
  #
213
235
  # 'ham_and_eggs'.classify # => "HamAndEgg"
214
236
  # 'posts'.classify # => "Post"
237
+ #
238
+ # See ActiveSupport::Inflector.classify.
215
239
  def classify
216
240
  ActiveSupport::Inflector.classify(self)
217
241
  end
218
242
 
219
- # Capitalizes the first word, turns underscores into spaces, and (by default)strips a
243
+ # Capitalizes the first word, turns underscores into spaces, and (by default) strips a
220
244
  # trailing '_id' if present.
221
245
  # Like +titleize+, this is meant for creating pretty output.
222
246
  #
@@ -232,20 +256,35 @@ class String
232
256
  # 'author_id'.humanize # => "Author"
233
257
  # 'author_id'.humanize(capitalize: false) # => "author"
234
258
  # '_id'.humanize # => "Id"
235
- # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
259
+ # 'author_id'.humanize(keep_id_suffix: true) # => "Author id"
260
+ #
261
+ # See ActiveSupport::Inflector.humanize.
236
262
  def humanize(capitalize: true, keep_id_suffix: false)
237
263
  ActiveSupport::Inflector.humanize(self, capitalize: capitalize, keep_id_suffix: keep_id_suffix)
238
264
  end
239
265
 
240
- # Converts just the first character to uppercase.
266
+ # Converts the first character to uppercase.
241
267
  #
242
268
  # 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
243
269
  # 'w'.upcase_first # => "W"
244
270
  # ''.upcase_first # => ""
271
+ #
272
+ # See ActiveSupport::Inflector.upcase_first.
245
273
  def upcase_first
246
274
  ActiveSupport::Inflector.upcase_first(self)
247
275
  end
248
276
 
277
+ # Converts the first character to lowercase.
278
+ #
279
+ # 'If they enjoyed The Matrix'.downcase_first # => "if they enjoyed The Matrix"
280
+ # 'I'.downcase_first # => "i"
281
+ # ''.downcase_first # => ""
282
+ #
283
+ # See ActiveSupport::Inflector.downcase_first.
284
+ def downcase_first
285
+ ActiveSupport::Inflector.downcase_first(self)
286
+ end
287
+
249
288
  # Creates a foreign key name from a class name.
250
289
  # +separate_class_name_and_id_with_underscore+ sets whether
251
290
  # the method should put '_' between the name and 'id'.
@@ -253,6 +292,8 @@ class String
253
292
  # 'Message'.foreign_key # => "message_id"
254
293
  # 'Message'.foreign_key(false) # => "messageid"
255
294
  # 'Admin::Post'.foreign_key # => "post_id"
295
+ #
296
+ # See ActiveSupport::Inflector.foreign_key.
256
297
  def foreign_key(separate_class_name_and_id_with_underscore = true)
257
298
  ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
258
299
  end
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/string_inquirer"
4
+ require "active_support/environment_inquirer"
4
5
 
5
6
  class String
6
- # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
7
+ # Wraps the current string in the ActiveSupport::StringInquirer class,
7
8
  # which gives you a prettier way to test for equality.
8
9
  #
9
10
  # env = 'production'.inquiry
@@ -47,9 +47,9 @@ class String
47
47
  # iso_str.is_utf8? # => false
48
48
  def is_utf8?
49
49
  case encoding
50
- when Encoding::UTF_8
50
+ when Encoding::UTF_8, Encoding::US_ASCII
51
51
  valid_encoding?
52
- when Encoding::ASCII_8BIT, Encoding::US_ASCII
52
+ when Encoding::ASCII_8BIT
53
53
  dup.force_encoding(Encoding::UTF_8).valid_encoding?
54
54
  else
55
55
  false