activesupport 5.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (268) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +343 -590
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -4
  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 +11 -5
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +45 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +81 -79
  13. data/lib/active_support/cache/memory_store.rb +69 -41
  14. data/lib/active_support/cache/null_store.rb +11 -4
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +74 -37
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +332 -161
  19. data/lib/active_support/callbacks.rb +657 -586
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +59 -19
  23. data/lib/active_support/configurable.rb +15 -17
  24. data/lib/active_support/configuration_file.rb +46 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +20 -18
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +3 -1
  30. data/lib/active_support/core_ext/array/inquiry.rb +3 -1
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +9 -7
  33. data/lib/active_support/core_ext/benchmark.rb +5 -3
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -26
  39. data/lib/active_support/core_ext/class.rb +4 -2
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +3 -1
  42. data/lib/active_support/core_ext/date/calculations.rb +16 -13
  43. data/lib/active_support/core_ext/date/conversions.rb +23 -21
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +7 -5
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
  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 +3 -1
  51. data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
  53. data/lib/active_support/core_ext/date_time/conversions.rb +14 -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 +165 -29
  58. data/lib/active_support/core_ext/file/atomic.rb +7 -5
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/conversions.rb +40 -39
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -2
  65. data/lib/active_support/core_ext/hash/keys.rb +9 -36
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +10 -9
  69. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +11 -18
  72. data/lib/active_support/core_ext/integer.rb +5 -3
  73. data/lib/active_support/core_ext/kernel/concern.rb +3 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +5 -4
  77. data/lib/active_support/core_ext/load_error.rb +2 -23
  78. data/lib/active_support/core_ext/marshal.rb +6 -2
  79. data/lib/active_support/core_ext/module/aliasing.rb +5 -48
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
  84. data/lib/active_support/core_ext/module/concerning.rb +16 -11
  85. data/lib/active_support/core_ext/module/delegation.rb +159 -44
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +23 -26
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +13 -12
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +129 -134
  94. data/lib/active_support/core_ext/numeric/time.rb +18 -26
  95. data/lib/active_support/core_ext/numeric.rb +5 -4
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +14 -2
  98. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  99. data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
  100. data/lib/active_support/core_ext/object/duplicable.rb +13 -62
  101. data/lib/active_support/core_ext/object/inclusion.rb +3 -1
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +42 -15
  104. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  105. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  106. data/lib/active_support/core_ext/object/try.rb +20 -8
  107. data/lib/active_support/core_ext/object/with_options.rb +15 -2
  108. data/lib/active_support/core_ext/object.rb +14 -12
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +7 -4
  115. data/lib/active_support/core_ext/regexp.rb +10 -1
  116. data/lib/active_support/core_ext/securerandom.rb +28 -6
  117. data/lib/active_support/core_ext/string/access.rb +9 -18
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +47 -4
  122. data/lib/active_support/core_ext/string/indent.rb +6 -4
  123. data/lib/active_support/core_ext/string/inflections.rb +78 -29
  124. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  125. data/lib/active_support/core_ext/string/multibyte.rb +10 -5
  126. data/lib/active_support/core_ext/string/output_safety.rb +86 -31
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  129. data/lib/active_support/core_ext/string/zones.rb +4 -2
  130. data/lib/active_support/core_ext/string.rb +15 -13
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  134. data/lib/active_support/core_ext/time/calculations.rb +117 -45
  135. data/lib/active_support/core_ext/time/compatibility.rb +13 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +18 -12
  137. data/lib/active_support/core_ext/time/zones.rb +9 -7
  138. data/lib/active_support/core_ext/time.rb +7 -5
  139. data/lib/active_support/core_ext/uri.rb +12 -7
  140. data/lib/active_support/core_ext.rb +3 -2
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +208 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +7 -1
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  146. data/lib/active_support/dependencies.rb +172 -98
  147. data/lib/active_support/deprecation/behaviors.rb +45 -13
  148. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  151. data/lib/active_support/deprecation/method_wrappers.rb +32 -17
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
  153. data/lib/active_support/deprecation/reporting.rb +61 -16
  154. data/lib/active_support/deprecation.rb +17 -9
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +20 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +67 -66
  158. data/lib/active_support/duration/iso8601_serializer.rb +25 -17
  159. data/lib/active_support/duration.rb +349 -46
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +88 -112
  164. data/lib/active_support/execution_wrapper.rb +25 -13
  165. data/lib/active_support/executor.rb +3 -1
  166. data/lib/active_support/file_update_checker.rb +56 -51
  167. data/lib/active_support/fork_tracker.rb +62 -0
  168. data/lib/active_support/gem_version.rb +4 -2
  169. data/lib/active_support/gzip.rb +7 -5
  170. data/lib/active_support/hash_with_indifferent_access.rb +153 -49
  171. data/lib/active_support/i18n.rb +9 -6
  172. data/lib/active_support/i18n_railtie.rb +30 -20
  173. data/lib/active_support/inflections.rb +13 -11
  174. data/lib/active_support/inflector/inflections.rb +28 -15
  175. data/lib/active_support/inflector/methods.rb +120 -109
  176. data/lib/active_support/inflector/transliterate.rb +60 -25
  177. data/lib/active_support/inflector.rb +7 -5
  178. data/lib/active_support/json/decoding.rb +30 -29
  179. data/lib/active_support/json/encoding.rb +22 -11
  180. data/lib/active_support/json.rb +4 -2
  181. data/lib/active_support/key_generator.rb +6 -36
  182. data/lib/active_support/lazy_load_hooks.rb +53 -20
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +11 -9
  186. data/lib/active_support/log_subscriber.rb +51 -18
  187. data/lib/active_support/logger.rb +9 -22
  188. data/lib/active_support/logger_silence.rb +14 -21
  189. data/lib/active_support/logger_thread_safe_level.rb +55 -8
  190. data/lib/active_support/message_encryptor.rb +170 -53
  191. data/lib/active_support/message_verifier.rb +91 -20
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +24 -78
  196. data/lib/active_support/multibyte/unicode.rb +21 -352
  197. data/lib/active_support/multibyte.rb +4 -2
  198. data/lib/active_support/notifications/fanout.rb +121 -19
  199. data/lib/active_support/notifications/instrumenter.rb +78 -14
  200. data/lib/active_support/notifications.rb +80 -12
  201. data/lib/active_support/number_helper/number_converter.rb +17 -16
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -3
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -4
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +45 -16
  211. data/lib/active_support/option_merger.rb +25 -4
  212. data/lib/active_support/ordered_hash.rb +6 -4
  213. data/lib/active_support/ordered_options.rb +23 -9
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +7 -5
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +8 -9
  218. data/lib/active_support/railtie.rb +62 -11
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +20 -11
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +12 -3
  224. data/lib/active_support/subscriber.rb +77 -23
  225. data/lib/active_support/tagged_logging.rb +52 -17
  226. data/lib/active_support/test_case.rb +106 -29
  227. data/lib/active_support/testing/assertions.rb +144 -8
  228. data/lib/active_support/testing/autorun.rb +5 -10
  229. data/lib/active_support/testing/constant_lookup.rb +2 -1
  230. data/lib/active_support/testing/declarative.rb +3 -1
  231. data/lib/active_support/testing/deprecation.rb +4 -2
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +19 -24
  234. data/lib/active_support/testing/method_call_assertions.rb +31 -2
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  239. data/lib/active_support/testing/stream.rb +30 -29
  240. data/lib/active_support/testing/tagged_logging.rb +3 -1
  241. data/lib/active_support/testing/time_helpers.rb +125 -24
  242. data/lib/active_support/time.rb +14 -12
  243. data/lib/active_support/time_with_zone.rb +142 -55
  244. data/lib/active_support/values/time_zone.rb +160 -53
  245. data/lib/active_support/version.rb +3 -1
  246. data/lib/active_support/xml_mini/jdom.rb +115 -114
  247. data/lib/active_support/xml_mini/libxml.rb +15 -14
  248. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  249. data/lib/active_support/xml_mini/nokogiri.rb +13 -13
  250. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  251. data/lib/active_support/xml_mini/rexml.rb +18 -9
  252. data/lib/active_support/xml_mini.rb +44 -42
  253. data/lib/active_support.rb +19 -10
  254. metadata +79 -37
  255. data/lib/active_support/concurrency/latch.rb +0 -19
  256. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  257. data/lib/active_support/core_ext/hash/compact.rb +0 -20
  258. data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
  259. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  260. data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
  261. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
  262. data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
  263. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  264. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  265. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  266. data/lib/active_support/core_ext/struct.rb +0 -3
  267. data/lib/active_support/core_ext/time/marshal.rb +0 -3
  268. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  # If you pass a single integer, returns a substring of one character at that
3
5
  # position. The first character of the string is at position 0, the next at
4
6
  # position 1, and so on. If a range is supplied, a substring containing
5
7
  # characters at offsets given by the range is returned. In both cases, if an
6
- # offset is negative, it is counted from the end of the string. Returns nil
8
+ # offset is negative, it is counted from the end of the string. Returns +nil+
7
9
  # if the initial offset falls outside the string. Returns an empty string if
8
10
  # the beginning of the range is greater than the end of the string.
9
11
  #
@@ -17,7 +19,7 @@ class String
17
19
  #
18
20
  # If a Regexp is given, the matching portion of the string is returned.
19
21
  # If a String is given, that given string is returned if it occurs in
20
- # the string. In both cases, nil is returned if there is no match.
22
+ # the string. In both cases, +nil+ is returned if there is no match.
21
23
  #
22
24
  # str = "hello"
23
25
  # str.at(/lo/) # => "lo"
@@ -42,7 +44,7 @@ class String
42
44
  # str.from(0).to(-1) # => "hello"
43
45
  # str.from(1).to(-2) # => "ell"
44
46
  def from(position)
45
- self[position..-1]
47
+ self[position, length]
46
48
  end
47
49
 
48
50
  # Returns a substring from the beginning of the string to the given position.
@@ -59,7 +61,8 @@ class String
59
61
  # str.from(0).to(-1) # => "hello"
60
62
  # str.from(1).to(-2) # => "ell"
61
63
  def to(position)
62
- self[0..position]
64
+ position += size if position < 0
65
+ self[0, position + 1] || +""
63
66
  end
64
67
 
65
68
  # Returns the first character. If a limit is supplied, returns a substring
@@ -73,13 +76,7 @@ class String
73
76
  # str.first(0) # => ""
74
77
  # str.first(6) # => "hello"
75
78
  def first(limit = 1)
76
- if limit == 0
77
- ''
78
- elsif limit >= size
79
- self.dup
80
- else
81
- to(limit - 1)
82
- end
79
+ self[0, limit] || raise(ArgumentError, "negative limit")
83
80
  end
84
81
 
85
82
  # Returns the last character of the string. If a limit is supplied, returns a substring
@@ -93,12 +90,6 @@ class String
93
90
  # str.last(0) # => ""
94
91
  # str.last(6) # => "hello"
95
92
  def last(limit = 1)
96
- if limit == 0
97
- ''
98
- elsif limit >= size
99
- self.dup
100
- else
101
- from(-limit)
102
- end
93
+ self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
103
94
  end
104
95
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  # Enables more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
3
5
  def acts_like_string?
@@ -1,5 +1,7 @@
1
- require 'date'
2
- require 'active_support/core_ext/time/calculations'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/core_ext/time/calculations"
3
5
 
4
6
  class String
5
7
  # Converts a string to a Time value.
@@ -16,6 +18,7 @@ class String
16
18
  # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
17
19
  # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
18
20
  # "12/13/2012".to_time # => ArgumentError: argument out of range
21
+ # "1604326192".to_time # => ArgumentError: argument out of range
19
22
  def to_time(form = :local)
20
23
  parts = Date._parse(self, false)
21
24
  used_keys = %i(year mon mday hour min sec sec_fraction offset)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  # The inverse of <tt>String#include?</tt>. Returns true if the string
3
5
  # does not include the other string.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  # Returns the string, first removing all whitespace on both ends of
3
5
  # the string, and then changing remaining consecutive whitespace
@@ -17,7 +19,7 @@ class String
17
19
  # str.squish! # => "foo bar boo"
18
20
  # str # => "foo bar boo"
19
21
  def squish!
20
- gsub!(/[[:space:]]+/, ' ')
22
+ gsub!(/[[:space:]]+/, " ")
21
23
  strip!
22
24
  self
23
25
  end
@@ -64,7 +66,7 @@ class String
64
66
  def truncate(truncate_at, options = {})
65
67
  return dup unless length > truncate_at
66
68
 
67
- omission = options[:omission] || '...'
69
+ omission = options[:omission] || "..."
68
70
  length_with_room_for_omission = truncate_at - omission.length
69
71
  stop = \
70
72
  if options[:separator]
@@ -73,7 +75,48 @@ class String
73
75
  length_with_room_for_omission
74
76
  end
75
77
 
76
- "#{self[0, stop]}#{omission}"
78
+ +"#{self[0, stop]}#{omission}"
79
+ end
80
+
81
+ # Truncates +text+ to at most <tt>bytesize</tt> bytes in length without
82
+ # breaking string encoding by splitting multibyte characters or breaking
83
+ # grapheme clusters ("perceptual characters") by truncating at combining
84
+ # characters.
85
+ #
86
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".size
87
+ # => 20
88
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".bytesize
89
+ # => 80
90
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".truncate_bytes(20)
91
+ # => "🔪🔪🔪🔪…"
92
+ #
93
+ # 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: "…")
96
+ omission ||= ""
97
+
98
+ case
99
+ when bytesize <= truncate_at
100
+ 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
104
+ omission.dup
105
+ else
106
+ self.class.new.tap do |cut|
107
+ cut_at = truncate_at - omission.bytesize
108
+
109
+ scan(/\X/) do |grapheme|
110
+ if cut.bytesize + grapheme.bytesize <= cut_at
111
+ cut << grapheme
112
+ else
113
+ break
114
+ end
115
+ end
116
+
117
+ cut << omission
118
+ end
119
+ end
77
120
  end
78
121
 
79
122
  # Truncates a given +text+ after a given number of words (<tt>words_count</tt>):
@@ -94,7 +137,7 @@ class String
94
137
  sep = options[:separator] || /\s+/
95
138
  sep = Regexp.escape(sep.to_s) unless Regexp === sep
96
139
  if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
97
- $1 + (options[:omission] || '...')
140
+ $1 + (options[:omission] || "...")
98
141
  else
99
142
  dup
100
143
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  # Same as +indent+, except it indents the receiver in-place.
3
5
  #
4
6
  # Returns the indented string, or +nil+ if there was nothing to indent.
5
- def indent!(amount, indent_string=nil, indent_empty_lines=false)
6
- indent_string = indent_string || self[/^[ \t]/] || ' '
7
+ def indent!(amount, indent_string = nil, indent_empty_lines = false)
8
+ indent_string = indent_string || self[/^[ \t]/] || " "
7
9
  re = indent_empty_lines ? /^/ : /^(?!$)/
8
10
  gsub!(re, indent_string * amount)
9
11
  end
@@ -37,7 +39,7 @@ class String
37
39
  # "foo\n\nbar".indent(2) # => " foo\n\n bar"
38
40
  # "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar"
39
41
  #
40
- def indent(amount, indent_string=nil, indent_empty_lines=false)
41
- dup.tap {|_| _.indent!(amount, indent_string, indent_empty_lines)}
42
+ def indent(amount, indent_string = nil, indent_empty_lines = false)
43
+ dup.tap { |_| _.indent!(amount, indent_string, indent_empty_lines) }
42
44
  end
43
45
  end
@@ -1,5 +1,7 @@
1
- require 'active_support/inflector/methods'
2
- require 'active_support/inflector/transliterate'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/inflector/methods"
4
+ require "active_support/inflector/transliterate"
3
5
 
4
6
  # String inflections define new methods on the String class to transform names for different purposes.
5
7
  # For instance, you can figure out the name of a table from the name of a class.
@@ -28,10 +30,12 @@ class String
28
30
  # 'apple'.pluralize(2) # => "apples"
29
31
  # 'ley'.pluralize(:es) # => "leyes"
30
32
  # 'ley'.pluralize(1, :es) # => "ley"
33
+ #
34
+ # See ActiveSupport::Inflector.pluralize.
31
35
  def pluralize(count = nil, locale = :en)
32
36
  locale = count if count.is_a?(Symbol)
33
37
  if count == 1
34
- self.dup
38
+ dup
35
39
  else
36
40
  ActiveSupport::Inflector.pluralize(self, locale)
37
41
  end
@@ -51,28 +55,34 @@ class String
51
55
  # 'the blue mailmen'.singularize # => "the blue mailman"
52
56
  # 'CamelOctopi'.singularize # => "CamelOctopus"
53
57
  # 'leyes'.singularize(:es) # => "ley"
58
+ #
59
+ # See ActiveSupport::Inflector.singularize.
54
60
  def singularize(locale = :en)
55
61
  ActiveSupport::Inflector.singularize(self, locale)
56
62
  end
57
63
 
58
64
  # +constantize+ tries to find a declared constant with the name specified
59
65
  # in the string. It raises a NameError when the name is not in CamelCase
60
- # or is not initialized. See ActiveSupport::Inflector.constantize
66
+ # or is not initialized.
61
67
  #
62
68
  # 'Module'.constantize # => Module
63
69
  # 'Class'.constantize # => Class
64
70
  # 'blargle'.constantize # => NameError: wrong constant name blargle
71
+ #
72
+ # See ActiveSupport::Inflector.constantize.
65
73
  def constantize
66
74
  ActiveSupport::Inflector.constantize(self)
67
75
  end
68
76
 
69
77
  # +safe_constantize+ tries to find a declared constant with the name specified
70
- # in the string. It returns nil when the name is not in CamelCase
71
- # or is not initialized. See ActiveSupport::Inflector.safe_constantize
78
+ # in the string. It returns +nil+ when the name is not in CamelCase
79
+ # or is not initialized.
72
80
  #
73
81
  # 'Module'.safe_constantize # => Module
74
82
  # 'Class'.safe_constantize # => Class
75
83
  # 'blargle'.safe_constantize # => nil
84
+ #
85
+ # See ActiveSupport::Inflector.safe_constantize.
76
86
  def safe_constantize
77
87
  ActiveSupport::Inflector.safe_constantize(self)
78
88
  end
@@ -86,12 +96,18 @@ class String
86
96
  # 'active_record'.camelize(:lower) # => "activeRecord"
87
97
  # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
88
98
  # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
99
+ #
100
+ # +camelize+ is also aliased as +camelcase+.
101
+ #
102
+ # See ActiveSupport::Inflector.camelize.
89
103
  def camelize(first_letter = :upper)
90
104
  case first_letter
91
105
  when :upper
92
106
  ActiveSupport::Inflector.camelize(self, true)
93
107
  when :lower
94
108
  ActiveSupport::Inflector.camelize(self, false)
109
+ else
110
+ raise ArgumentError, "Invalid option, use either :upper or :lower."
95
111
  end
96
112
  end
97
113
  alias_method :camelcase, :camelize
@@ -100,12 +116,19 @@ class String
100
116
  # a nicer looking title. +titleize+ is meant for creating pretty output. It is not
101
117
  # used in the Rails internals.
102
118
  #
119
+ # The trailing '_id','Id'.. can be kept and capitalized by setting the
120
+ # optional parameter +keep_id_suffix+ to true.
121
+ # By default, this parameter is false.
122
+ #
123
+ # 'man from the boondocks'.titleize # => "Man From The Boondocks"
124
+ # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
125
+ # 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
126
+ #
103
127
  # +titleize+ is also aliased as +titlecase+.
104
128
  #
105
- # 'man from the boondocks'.titleize # => "Man From The Boondocks"
106
- # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
107
- def titleize
108
- ActiveSupport::Inflector.titleize(self)
129
+ # See ActiveSupport::Inflector.titleize.
130
+ def titleize(keep_id_suffix: false)
131
+ ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
109
132
  end
110
133
  alias_method :titlecase, :titleize
111
134
 
@@ -115,6 +138,8 @@ class String
115
138
  #
116
139
  # 'ActiveModel'.underscore # => "active_model"
117
140
  # 'ActiveModel::Errors'.underscore # => "active_model/errors"
141
+ #
142
+ # See ActiveSupport::Inflector.underscore.
118
143
  def underscore
119
144
  ActiveSupport::Inflector.underscore(self)
120
145
  end
@@ -122,16 +147,20 @@ class String
122
147
  # Replaces underscores with dashes in the string.
123
148
  #
124
149
  # 'puni_puni'.dasherize # => "puni-puni"
150
+ #
151
+ # See ActiveSupport::Inflector.dasherize.
125
152
  def dasherize
126
153
  ActiveSupport::Inflector.dasherize(self)
127
154
  end
128
155
 
129
156
  # Removes the module part from the constant expression in the string.
130
157
  #
131
- # 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
132
- # 'Inflections'.demodulize # => "Inflections"
133
- # '::Inflections'.demodulize # => "Inflections"
134
- # ''.demodulize # => ''
158
+ # 'ActiveSupport::Inflector::Inflections'.demodulize # => "Inflections"
159
+ # 'Inflections'.demodulize # => "Inflections"
160
+ # '::Inflections'.demodulize # => "Inflections"
161
+ # ''.demodulize # => ''
162
+ #
163
+ # See ActiveSupport::Inflector.demodulize.
135
164
  #
136
165
  # See also +deconstantize+.
137
166
  def demodulize
@@ -146,6 +175,8 @@ class String
146
175
  # '::String'.deconstantize # => ""
147
176
  # ''.deconstantize # => ""
148
177
  #
178
+ # See ActiveSupport::Inflector.deconstantize.
179
+ #
149
180
  # See also +demodulize+.
150
181
  def deconstantize
151
182
  ActiveSupport::Inflector.deconstantize(self)
@@ -153,6 +184,11 @@ class String
153
184
 
154
185
  # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
155
186
  #
187
+ # If the optional parameter +locale+ is specified,
188
+ # the word will be parameterized as a word of that language.
189
+ # By default, this parameter is set to <tt>nil</tt> and it will use
190
+ # the configured <tt>I18n.locale</tt>.
191
+ #
156
192
  # class Person
157
193
  # def to_param
158
194
  # "#{id}-#{name.parameterize}"
@@ -164,8 +200,8 @@ class String
164
200
  #
165
201
  # <%= link_to(@person.name, person_path) %>
166
202
  # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
167
- #
168
- # To preserve the case of the characters in a string, use the `preserve_case` argument.
203
+ #
204
+ # To preserve the case of the characters in a string, use the +preserve_case+ argument.
169
205
  #
170
206
  # class Person
171
207
  # def to_param
@@ -178,12 +214,10 @@ class String
178
214
  #
179
215
  # <%= link_to(@person.name, person_path) %>
180
216
  # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
181
- def parameterize(sep = :unused, separator: '-', preserve_case: false)
182
- unless sep == :unused
183
- ActiveSupport::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.")
184
- separator = sep
185
- end
186
- ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case)
217
+ #
218
+ # See ActiveSupport::Inflector.parameterize.
219
+ def parameterize(separator: "-", preserve_case: false, locale: nil)
220
+ ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
187
221
  end
188
222
 
189
223
  # Creates the name of a table like Rails does for models to table names. This method
@@ -192,6 +226,8 @@ class String
192
226
  # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
193
227
  # 'ham_and_egg'.tableize # => "ham_and_eggs"
194
228
  # 'fancyCategory'.tableize # => "fancy_categories"
229
+ #
230
+ # See ActiveSupport::Inflector.tableize.
195
231
  def tableize
196
232
  ActiveSupport::Inflector.tableize(self)
197
233
  end
@@ -202,11 +238,13 @@ class String
202
238
  #
203
239
  # 'ham_and_eggs'.classify # => "HamAndEgg"
204
240
  # 'posts'.classify # => "Post"
241
+ #
242
+ # See ActiveSupport::Inflector.classify.
205
243
  def classify
206
244
  ActiveSupport::Inflector.classify(self)
207
245
  end
208
246
 
209
- # Capitalizes the first word, turns underscores into spaces, and strips a
247
+ # Capitalizes the first word, turns underscores into spaces, and (by default)strips a
210
248
  # trailing '_id' if present.
211
249
  # Like +titleize+, this is meant for creating pretty output.
212
250
  #
@@ -214,12 +252,19 @@ class String
214
252
  # optional parameter +capitalize+ to false.
215
253
  # By default, this parameter is true.
216
254
  #
217
- # 'employee_salary'.humanize # => "Employee salary"
218
- # 'author_id'.humanize # => "Author"
219
- # 'author_id'.humanize(capitalize: false) # => "author"
220
- # '_id'.humanize # => "Id"
221
- def humanize(options = {})
222
- ActiveSupport::Inflector.humanize(self, options)
255
+ # The trailing '_id' can be kept and capitalized by setting the
256
+ # optional parameter +keep_id_suffix+ to true.
257
+ # By default, this parameter is false.
258
+ #
259
+ # 'employee_salary'.humanize # => "Employee salary"
260
+ # 'author_id'.humanize # => "Author"
261
+ # 'author_id'.humanize(capitalize: false) # => "author"
262
+ # '_id'.humanize # => "Id"
263
+ # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
264
+ #
265
+ # See ActiveSupport::Inflector.humanize.
266
+ def humanize(capitalize: true, keep_id_suffix: false)
267
+ ActiveSupport::Inflector.humanize(self, capitalize: capitalize, keep_id_suffix: keep_id_suffix)
223
268
  end
224
269
 
225
270
  # Converts just the first character to uppercase.
@@ -227,6 +272,8 @@ class String
227
272
  # 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
228
273
  # 'w'.upcase_first # => "W"
229
274
  # ''.upcase_first # => ""
275
+ #
276
+ # See ActiveSupport::Inflector.upcase_first.
230
277
  def upcase_first
231
278
  ActiveSupport::Inflector.upcase_first(self)
232
279
  end
@@ -238,6 +285,8 @@ class String
238
285
  # 'Message'.foreign_key # => "message_id"
239
286
  # 'Message'.foreign_key(false) # => "messageid"
240
287
  # 'Admin::Post'.foreign_key # => "post_id"
288
+ #
289
+ # See ActiveSupport::Inflector.foreign_key.
241
290
  def foreign_key(separate_class_name_and_id_with_underscore = true)
242
291
  ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
243
292
  end
@@ -1,4 +1,7 @@
1
- require 'active_support/string_inquirer'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/string_inquirer"
4
+ require "active_support/environment_inquirer"
2
5
 
3
6
  class String
4
7
  # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
@@ -1,4 +1,6 @@
1
- require 'active_support/multibyte'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/multibyte"
2
4
 
3
5
  class String
4
6
  # == Multibyte proxy
@@ -9,11 +11,14 @@ class String
9
11
  # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
10
12
  # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
11
13
  #
12
- # >> "lj".upcase
13
- # => "lj"
14
14
  # >> "lj".mb_chars.upcase.to_s
15
15
  # => "LJ"
16
16
  #
17
+ # NOTE: Ruby 2.4 and later support native Unicode case mappings:
18
+ #
19
+ # >> "lj".upcase
20
+ # => "LJ"
21
+ #
17
22
  # == Method chaining
18
23
  #
19
24
  # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
@@ -42,9 +47,9 @@ class String
42
47
  # iso_str.is_utf8? # => false
43
48
  def is_utf8?
44
49
  case encoding
45
- when Encoding::UTF_8
50
+ when Encoding::UTF_8, Encoding::US_ASCII
46
51
  valid_encoding?
47
- when Encoding::ASCII_8BIT, Encoding::US_ASCII
52
+ when Encoding::ASCII_8BIT
48
53
  dup.force_encoding(Encoding::UTF_8).valid_encoding?
49
54
  else
50
55
  false