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
@@ -5,9 +5,13 @@ require "active_support/number_helper"
5
5
 
6
6
  module ActiveSupport
7
7
  module NumericWithFormat
8
+ # \Numeric With Format
9
+ #
8
10
  # Provides options for converting numbers into formatted strings.
9
11
  # Options are provided for phone numbers, currency, percentage,
10
- # precision, positional notation, file size and pretty printing.
12
+ # precision, positional notation, file size, and pretty printing.
13
+ #
14
+ # This method is aliased to <tt>to_formatted_s</tt>.
11
15
  #
12
16
  # ==== Options
13
17
  #
@@ -16,102 +20,102 @@ module ActiveSupport
16
20
  # ==== Examples
17
21
  #
18
22
  # Phone Numbers:
19
- # 5551234.to_s(:phone) # => "555-1234"
20
- # 1235551234.to_s(:phone) # => "123-555-1234"
21
- # 1235551234.to_s(:phone, area_code: true) # => "(123) 555-1234"
22
- # 1235551234.to_s(:phone, delimiter: ' ') # => "123 555 1234"
23
- # 1235551234.to_s(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555"
24
- # 1235551234.to_s(:phone, country_code: 1) # => "+1-123-555-1234"
25
- # 1235551234.to_s(:phone, country_code: 1, extension: 1343, delimiter: '.')
23
+ # 5551234.to_fs(:phone) # => "555-1234"
24
+ # 1235551234.to_fs(:phone) # => "123-555-1234"
25
+ # 1235551234.to_fs(:phone, area_code: true) # => "(123) 555-1234"
26
+ # 1235551234.to_fs(:phone, delimiter: ' ') # => "123 555 1234"
27
+ # 1235551234.to_fs(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555"
28
+ # 1235551234.to_fs(:phone, country_code: 1) # => "+1-123-555-1234"
29
+ # 1235551234.to_fs(:phone, country_code: 1, extension: 1343, delimiter: '.')
26
30
  # # => "+1.123.555.1234 x 1343"
27
31
  #
28
32
  # Currency:
29
- # 1234567890.50.to_s(:currency) # => "$1,234,567,890.50"
30
- # 1234567890.506.to_s(:currency) # => "$1,234,567,890.51"
31
- # 1234567890.506.to_s(:currency, precision: 3) # => "$1,234,567,890.506"
32
- # 1234567890.506.to_s(:currency, round_mode: :down) # => "$1,234,567,890.50"
33
- # 1234567890.506.to_s(:currency, locale: :fr) # => "1 234 567 890,51 €"
34
- # -1234567890.50.to_s(:currency, negative_format: '(%u%n)')
33
+ # 1234567890.50.to_fs(:currency) # => "$1,234,567,890.50"
34
+ # 1234567890.506.to_fs(:currency) # => "$1,234,567,890.51"
35
+ # 1234567890.506.to_fs(:currency, precision: 3) # => "$1,234,567,890.506"
36
+ # 1234567890.506.to_fs(:currency, round_mode: :down) # => "$1,234,567,890.50"
37
+ # 1234567890.506.to_fs(:currency, locale: :fr) # => "1 234 567 890,51 €"
38
+ # -1234567890.50.to_fs(:currency, negative_format: '(%u%n)')
35
39
  # # => "($1,234,567,890.50)"
36
- # 1234567890.50.to_s(:currency, unit: '&pound;', separator: ',', delimiter: '')
40
+ # 1234567890.50.to_fs(:currency, unit: '&pound;', separator: ',', delimiter: '')
37
41
  # # => "&pound;1234567890,50"
38
- # 1234567890.50.to_s(:currency, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
42
+ # 1234567890.50.to_fs(:currency, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
39
43
  # # => "1234567890,50 &pound;"
40
44
  #
41
45
  # Percentage:
42
- # 100.to_s(:percentage) # => "100.000%"
43
- # 100.to_s(:percentage, precision: 0) # => "100%"
44
- # 1000.to_s(:percentage, delimiter: '.', separator: ',') # => "1.000,000%"
45
- # 302.24398923423.to_s(:percentage, precision: 5) # => "302.24399%"
46
- # 302.24398923423.to_s(:percentage, round_mode: :down) # => "302.243%"
47
- # 1000.to_s(:percentage, locale: :fr) # => "1 000,000%"
48
- # 100.to_s(:percentage, format: '%n %') # => "100.000 %"
46
+ # 100.to_fs(:percentage) # => "100.000%"
47
+ # 100.to_fs(:percentage, precision: 0) # => "100%"
48
+ # 1000.to_fs(:percentage, delimiter: '.', separator: ',') # => "1.000,000%"
49
+ # 302.24398923423.to_fs(:percentage, precision: 5) # => "302.24399%"
50
+ # 302.24398923423.to_fs(:percentage, round_mode: :down) # => "302.243%"
51
+ # 1000.to_fs(:percentage, locale: :fr) # => "1 000,000%"
52
+ # 100.to_fs(:percentage, format: '%n %') # => "100.000 %"
49
53
  #
50
54
  # Delimited:
51
- # 12345678.to_s(:delimited) # => "12,345,678"
52
- # 12345678.05.to_s(:delimited) # => "12,345,678.05"
53
- # 12345678.to_s(:delimited, delimiter: '.') # => "12.345.678"
54
- # 12345678.to_s(:delimited, delimiter: ',') # => "12,345,678"
55
- # 12345678.05.to_s(:delimited, separator: ' ') # => "12,345,678 05"
56
- # 12345678.05.to_s(:delimited, locale: :fr) # => "12 345 678,05"
57
- # 98765432.98.to_s(:delimited, delimiter: ' ', separator: ',')
55
+ # 12345678.to_fs(:delimited) # => "12,345,678"
56
+ # 12345678.05.to_fs(:delimited) # => "12,345,678.05"
57
+ # 12345678.to_fs(:delimited, delimiter: '.') # => "12.345.678"
58
+ # 12345678.to_fs(:delimited, delimiter: ',') # => "12,345,678"
59
+ # 12345678.05.to_fs(:delimited, separator: ' ') # => "12,345,678 05"
60
+ # 12345678.05.to_fs(:delimited, locale: :fr) # => "12 345 678,05"
61
+ # 98765432.98.to_fs(:delimited, delimiter: ' ', separator: ',')
58
62
  # # => "98 765 432,98"
59
63
  #
60
64
  # Rounded:
61
- # 111.2345.to_s(:rounded) # => "111.235"
62
- # 111.2345.to_s(:rounded, precision: 2) # => "111.23"
63
- # 111.2345.to_s(:rounded, precision: 2, round_mode: :up) # => "111.24"
64
- # 13.to_s(:rounded, precision: 5) # => "13.00000"
65
- # 389.32314.to_s(:rounded, precision: 0) # => "389"
66
- # 111.2345.to_s(:rounded, significant: true) # => "111"
67
- # 111.2345.to_s(:rounded, precision: 1, significant: true) # => "100"
68
- # 13.to_s(:rounded, precision: 5, significant: true) # => "13.000"
69
- # 111.234.to_s(:rounded, locale: :fr) # => "111,234"
70
- # 13.to_s(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true)
65
+ # 111.2345.to_fs(:rounded) # => "111.235"
66
+ # 111.2345.to_fs(:rounded, precision: 2) # => "111.23"
67
+ # 111.2345.to_fs(:rounded, precision: 2, round_mode: :up) # => "111.24"
68
+ # 13.to_fs(:rounded, precision: 5) # => "13.00000"
69
+ # 389.32314.to_fs(:rounded, precision: 0) # => "389"
70
+ # 111.2345.to_fs(:rounded, significant: true) # => "111"
71
+ # 111.2345.to_fs(:rounded, precision: 1, significant: true) # => "100"
72
+ # 13.to_fs(:rounded, precision: 5, significant: true) # => "13.000"
73
+ # 111.234.to_fs(:rounded, locale: :fr) # => "111,234"
74
+ # 13.to_fs(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true)
71
75
  # # => "13"
72
- # 389.32314.to_s(:rounded, precision: 4, significant: true) # => "389.3"
73
- # 1111.2345.to_s(:rounded, precision: 2, separator: ',', delimiter: '.')
76
+ # 389.32314.to_fs(:rounded, precision: 4, significant: true) # => "389.3"
77
+ # 1111.2345.to_fs(:rounded, precision: 2, separator: ',', delimiter: '.')
74
78
  # # => "1.111,23"
75
79
  #
76
80
  # Human-friendly size in Bytes:
77
- # 123.to_s(:human_size) # => "123 Bytes"
78
- # 1234.to_s(:human_size) # => "1.21 KB"
79
- # 12345.to_s(:human_size) # => "12.1 KB"
80
- # 1234567.to_s(:human_size) # => "1.18 MB"
81
- # 1234567890.to_s(:human_size) # => "1.15 GB"
82
- # 1234567890123.to_s(:human_size) # => "1.12 TB"
83
- # 1234567890123456.to_s(:human_size) # => "1.1 PB"
84
- # 1234567890123456789.to_s(:human_size) # => "1.07 EB"
85
- # 1234567.to_s(:human_size, precision: 2) # => "1.2 MB"
86
- # 1234567.to_s(:human_size, precision: 2, round_mode: :up) # => "1.3 MB"
87
- # 483989.to_s(:human_size, precision: 2) # => "470 KB"
88
- # 1234567.to_s(:human_size, precision: 2, separator: ',') # => "1,2 MB"
89
- # 1234567890123.to_s(:human_size, precision: 5) # => "1.1228 TB"
90
- # 524288000.to_s(:human_size, precision: 5) # => "500 MB"
81
+ # 123.to_fs(:human_size) # => "123 Bytes"
82
+ # 1234.to_fs(:human_size) # => "1.21 KB"
83
+ # 12345.to_fs(:human_size) # => "12.1 KB"
84
+ # 1234567.to_fs(:human_size) # => "1.18 MB"
85
+ # 1234567890.to_fs(:human_size) # => "1.15 GB"
86
+ # 1234567890123.to_fs(:human_size) # => "1.12 TB"
87
+ # 1234567890123456.to_fs(:human_size) # => "1.1 PB"
88
+ # 1234567890123456789.to_fs(:human_size) # => "1.07 EB"
89
+ # 1234567.to_fs(:human_size, precision: 2) # => "1.2 MB"
90
+ # 1234567.to_fs(:human_size, precision: 2, round_mode: :up) # => "1.3 MB"
91
+ # 483989.to_fs(:human_size, precision: 2) # => "470 KB"
92
+ # 1234567.to_fs(:human_size, precision: 2, separator: ',') # => "1,2 MB"
93
+ # 1234567890123.to_fs(:human_size, precision: 5) # => "1.1228 TB"
94
+ # 524288000.to_fs(:human_size, precision: 5) # => "500 MB"
91
95
  #
92
96
  # Human-friendly format:
93
- # 123.to_s(:human) # => "123"
94
- # 1234.to_s(:human) # => "1.23 Thousand"
95
- # 12345.to_s(:human) # => "12.3 Thousand"
96
- # 1234567.to_s(:human) # => "1.23 Million"
97
- # 1234567890.to_s(:human) # => "1.23 Billion"
98
- # 1234567890123.to_s(:human) # => "1.23 Trillion"
99
- # 1234567890123456.to_s(:human) # => "1.23 Quadrillion"
100
- # 1234567890123456789.to_s(:human) # => "1230 Quadrillion"
101
- # 489939.to_s(:human, precision: 2) # => "490 Thousand"
102
- # 489939.to_s(:human, precision: 2, round_mode: :down) # => "480 Thousand"
103
- # 489939.to_s(:human, precision: 4) # => "489.9 Thousand"
104
- # 1234567.to_s(:human, precision: 4,
105
- # significant: false) # => "1.2346 Million"
106
- # 1234567.to_s(:human, precision: 1,
97
+ # 123.to_fs(:human) # => "123"
98
+ # 1234.to_fs(:human) # => "1.23 Thousand"
99
+ # 12345.to_fs(:human) # => "12.3 Thousand"
100
+ # 1234567.to_fs(:human) # => "1.23 Million"
101
+ # 1234567890.to_fs(:human) # => "1.23 Billion"
102
+ # 1234567890123.to_fs(:human) # => "1.23 Trillion"
103
+ # 1234567890123456.to_fs(:human) # => "1.23 Quadrillion"
104
+ # 1234567890123456789.to_fs(:human) # => "1230 Quadrillion"
105
+ # 489939.to_fs(:human, precision: 2) # => "490 Thousand"
106
+ # 489939.to_fs(:human, precision: 2, round_mode: :down) # => "480 Thousand"
107
+ # 489939.to_fs(:human, precision: 4) # => "489.9 Thousand"
108
+ # 1234567.to_fs(:human, precision: 4,
109
+ # significant: false) # => "1.2346 Million"
110
+ # 1234567.to_fs(:human, precision: 1,
107
111
  # separator: ',',
108
- # significant: false) # => "1,2 Million"
109
- def to_s(format = nil, options = nil)
112
+ # significant: false) # => "1,2 Million"
113
+ def to_fs(format = nil, options = nil)
114
+ return to_s if format.nil?
115
+
110
116
  case format
111
- when nil
112
- super()
113
117
  when Integer, String
114
- super(format)
118
+ to_s(format)
115
119
  when :phone
116
120
  ActiveSupport::NumberHelper.number_to_phone(self, options || {})
117
121
  when :currency
@@ -127,11 +131,12 @@ module ActiveSupport
127
131
  when :human_size
128
132
  ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
129
133
  when Symbol
130
- super()
134
+ to_s
131
135
  else
132
- super(format)
136
+ to_s(format)
133
137
  end
134
138
  end
139
+ alias_method :to_formatted_s, :to_fs
135
140
  end
136
141
  end
137
142
 
@@ -1,11 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Object
4
- # A duck-type assistant method. For example, Active Support extends Date
5
- # to define an <tt>acts_like_date?</tt> method, and extends Time to define
6
- # <tt>acts_like_time?</tt>. As a result, we can do <tt>x.acts_like?(:time)</tt> and
7
- # <tt>x.acts_like?(:date)</tt> to do duck-type-safe comparisons, since classes that
8
- # we want to act like Time simply need to define an <tt>acts_like_time?</tt> method.
4
+ # Provides a way to check whether some class acts like some other class based on the existence of
5
+ # an appropriately-named marker method.
6
+ #
7
+ # A class that provides the same interface as <tt>SomeClass</tt> may define a marker method named
8
+ # <tt>acts_like_some_class?</tt> to signal its compatibility to callers of
9
+ # <tt>acts_like?(:some_class)</tt>.
10
+ #
11
+ # For example, Active Support extends <tt>Date</tt> to define an <tt>acts_like_date?</tt> method,
12
+ # and extends <tt>Time</tt> to define <tt>acts_like_time?</tt>. As a result, developers can call
13
+ # <tt>x.acts_like?(:time)</tt> and <tt>x.acts_like?(:date)</tt> to test duck-type compatibility,
14
+ # and classes that are able to act like <tt>Time</tt> can also define an <tt>acts_like_time?</tt>
15
+ # method to interoperate.
16
+ #
17
+ # Note that the marker method is only expected to exist. It isn't called, so its body or return
18
+ # value are irrelevant.
19
+ #
20
+ # ==== Example: A class that provides the same interface as <tt>String</tt>
21
+ #
22
+ # This class may define:
23
+ #
24
+ # class Stringish
25
+ # def acts_like_string?
26
+ # end
27
+ # end
28
+ #
29
+ # Then client code can query for duck-type-safeness this way:
30
+ #
31
+ # Stringish.new.acts_like?(:string) # => true
32
+ #
9
33
  def acts_like?(duck)
10
34
  case duck
11
35
  when :time
@@ -131,7 +131,7 @@ class String
131
131
  end
132
132
  end
133
133
 
134
- class Numeric #:nodoc:
134
+ class Numeric # :nodoc:
135
135
  # No number is blank:
136
136
  #
137
137
  # 1.blank? # => false
@@ -143,7 +143,7 @@ class Numeric #:nodoc:
143
143
  end
144
144
  end
145
145
 
146
- class Time #:nodoc:
146
+ class Time # :nodoc:
147
147
  # No Time is blank:
148
148
  #
149
149
  # Time.now.blank? # => false
@@ -43,7 +43,7 @@ class Hash
43
43
  def deep_dup
44
44
  hash = dup
45
45
  each_pair do |key, value|
46
- if (::String === key && key.frozen?) || ::Symbol === key
46
+ if ::String === key || ::Symbol === key
47
47
  hash[key] = value.deep_dup
48
48
  else
49
49
  hash.delete(key)
@@ -53,3 +53,19 @@ class Hash
53
53
  hash
54
54
  end
55
55
  end
56
+
57
+ class Module
58
+ # Returns a copy of module or class if it's anonymous. If it's
59
+ # named, returns +self+.
60
+ #
61
+ # Object.deep_dup == Object # => true
62
+ # klass = Class.new
63
+ # klass.deep_dup == klass # => false
64
+ def deep_dup
65
+ if name.nil?
66
+ super
67
+ else
68
+ self
69
+ end
70
+ end
71
+ end
@@ -28,21 +28,41 @@ class Object
28
28
  end
29
29
  end
30
30
 
31
- class Method
32
- # Methods are not duplicable:
33
- #
34
- # method(:puts).duplicable? # => false
35
- # method(:puts).dup # => TypeError: allocator undefined for Method
36
- def duplicable?
37
- false
31
+ methods_are_duplicable = begin
32
+ Object.instance_method(:duplicable?).dup
33
+ true
34
+ rescue TypeError
35
+ false
36
+ end
37
+
38
+ unless methods_are_duplicable
39
+ class Method
40
+ # Methods are not duplicable:
41
+ #
42
+ # method(:puts).duplicable? # => false
43
+ # method(:puts).dup # => TypeError: allocator undefined for Method
44
+ def duplicable?
45
+ false
46
+ end
47
+ end
48
+
49
+ class UnboundMethod
50
+ # Unbound methods are not duplicable:
51
+ #
52
+ # method(:puts).unbind.duplicable? # => false
53
+ # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
54
+ def duplicable?
55
+ false
56
+ end
38
57
  end
39
58
  end
40
59
 
41
- class UnboundMethod
42
- # Unbound methods are not duplicable:
60
+ require "singleton"
61
+
62
+ module Singleton
63
+ # Singleton instances are not duplicable:
43
64
  #
44
- # method(:puts).unbind.duplicable? # => false
45
- # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
65
+ # Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton
46
66
  def duplicable?
47
67
  false
48
68
  end
@@ -1,16 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Object
4
- # Returns true if this object is included in the argument. Argument must be
5
- # any object which responds to +#include?+. Usage:
4
+ # Returns true if this object is included in the argument.
5
+ #
6
+ # When argument is a +Range+, +#cover?+ is used to properly handle inclusion
7
+ # check within open ranges. Otherwise, argument must be any object which responds
8
+ # to +#include?+. Usage:
6
9
  #
7
10
  # characters = ["Konata", "Kagami", "Tsukasa"]
8
11
  # "Konata".in?(characters) # => true
9
12
  #
10
- # This will throw an +ArgumentError+ if the argument doesn't respond
11
- # to +#include?+.
13
+ # For non +Range+ arguments, this will throw an +ArgumentError+ if the argument
14
+ # doesn't respond to +#include?+.
12
15
  def in?(another_object)
13
- another_object.include?(self)
16
+ case another_object
17
+ when Range
18
+ another_object.cover?(self)
19
+ else
20
+ another_object.include?(self)
21
+ end
14
22
  rescue NoMethodError
15
23
  raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
16
24
  end
@@ -12,19 +12,29 @@ class Object
12
12
  #
13
13
  # C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
14
14
  def instance_values
15
- Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
15
+ instance_variables.to_h do |ivar|
16
+ [ivar[1..-1].freeze, instance_variable_get(ivar)]
17
+ end
16
18
  end
17
19
 
18
- # Returns an array of instance variable names as strings including "@".
19
- #
20
- # class C
21
- # def initialize(x, y)
22
- # @x, @y = x, y
23
- # end
24
- # end
25
- #
26
- # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
27
- def instance_variable_names
28
- instance_variables.map(&:to_s)
20
+ if Symbol.method_defined?(:name) # RUBY_VERSION >= "3.0"
21
+ # Returns an array of instance variable names as strings including "@".
22
+ #
23
+ # class C
24
+ # def initialize(x, y)
25
+ # @x, @y = x, y
26
+ # end
27
+ # end
28
+ #
29
+ # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
30
+ def instance_variable_names
31
+ instance_variables.map(&:name)
32
+ end
33
+ else
34
+ def instance_variable_names
35
+ variables = instance_variables
36
+ variables.map! { |s| s.to_s.freeze }
37
+ variables
38
+ end
29
39
  end
30
40
  end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Hack to load json gem first so we can overwrite its to_json.
3
+ # Hack to load JSON gem first so we can override its to_json.
4
4
  require "json"
5
5
  require "bigdecimal"
6
+ require "ipaddr"
6
7
  require "uri/generic"
7
8
  require "pathname"
8
9
  require "active_support/core_ext/big_decimal/conversions" # for #to_s
@@ -18,8 +19,7 @@ require "active_support/core_ext/date/conversions"
18
19
  # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
19
20
  # their default behavior. That said, we need to define the basic to_json method in all of them,
20
21
  # otherwise they will always use to_json gem implementation, which is backwards incompatible in
21
- # several cases (for instance, the JSON implementation for Hash does not work) with inheritance
22
- # and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
22
+ # several cases (for instance, the JSON implementation for Hash does not work) with inheritance.
23
23
  #
24
24
  # On the other hand, we should avoid conflict with ::JSON.{generate,dump}(obj). Unfortunately, the
25
25
  # JSON gem's encoder relies on its own to_json implementation to encode objects. Since it always
@@ -29,7 +29,7 @@ require "active_support/core_ext/date/conversions"
29
29
  # It should be noted that when using ::JSON.{generate,dump} directly, ActiveSupport's encoder is
30
30
  # bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
31
31
  # ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
32
- # should give exactly the same results with or without active support.
32
+ # should give exactly the same results with or without Active Support.
33
33
 
34
34
  module ActiveSupport
35
35
  module ToJsonWithActiveSupportEncoder # :nodoc:
@@ -49,8 +49,14 @@ end
49
49
  klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
50
50
  end
51
51
 
52
+ class Module
53
+ def as_json(options = nil) # :nodoc:
54
+ name
55
+ end
56
+ end
57
+
52
58
  class Object
53
- def as_json(options = nil) #:nodoc:
59
+ def as_json(options = nil) # :nodoc:
54
60
  if respond_to?(:to_hash)
55
61
  to_hash.as_json(options)
56
62
  else
@@ -59,44 +65,52 @@ class Object
59
65
  end
60
66
  end
61
67
 
62
- class Struct #:nodoc:
68
+ if RUBY_VERSION >= "3.2"
69
+ class Data # :nodoc:
70
+ def as_json(options = nil)
71
+ to_h.as_json(options)
72
+ end
73
+ end
74
+ end
75
+
76
+ class Struct # :nodoc:
63
77
  def as_json(options = nil)
64
- Hash[members.zip(values)].as_json(options)
78
+ to_h.as_json(options)
65
79
  end
66
80
  end
67
81
 
68
82
  class TrueClass
69
- def as_json(options = nil) #:nodoc:
83
+ def as_json(options = nil) # :nodoc:
70
84
  self
71
85
  end
72
86
  end
73
87
 
74
88
  class FalseClass
75
- def as_json(options = nil) #:nodoc:
89
+ def as_json(options = nil) # :nodoc:
76
90
  self
77
91
  end
78
92
  end
79
93
 
80
94
  class NilClass
81
- def as_json(options = nil) #:nodoc:
95
+ def as_json(options = nil) # :nodoc:
82
96
  self
83
97
  end
84
98
  end
85
99
 
86
100
  class String
87
- def as_json(options = nil) #:nodoc:
101
+ def as_json(options = nil) # :nodoc:
88
102
  self
89
103
  end
90
104
  end
91
105
 
92
106
  class Symbol
93
- def as_json(options = nil) #:nodoc:
107
+ def as_json(options = nil) # :nodoc:
94
108
  to_s
95
109
  end
96
110
  end
97
111
 
98
112
  class Numeric
99
- def as_json(options = nil) #:nodoc:
113
+ def as_json(options = nil) # :nodoc:
100
114
  self
101
115
  end
102
116
  end
@@ -104,7 +118,7 @@ end
104
118
  class Float
105
119
  # Encoding Infinity or NaN to JSON should return "null". The default returns
106
120
  # "Infinity" or "NaN" which are not valid JSON.
107
- def as_json(options = nil) #:nodoc:
121
+ def as_json(options = nil) # :nodoc:
108
122
  finite? ? self : nil
109
123
  end
110
124
  end
@@ -119,43 +133,43 @@ class BigDecimal
119
133
  # if the other end knows by contract that the data is supposed to be a
120
134
  # BigDecimal, it still has the chance to post-process the string and get the
121
135
  # real value.
122
- def as_json(options = nil) #:nodoc:
136
+ def as_json(options = nil) # :nodoc:
123
137
  finite? ? to_s : nil
124
138
  end
125
139
  end
126
140
 
127
141
  class Regexp
128
- def as_json(options = nil) #:nodoc:
142
+ def as_json(options = nil) # :nodoc:
129
143
  to_s
130
144
  end
131
145
  end
132
146
 
133
147
  module Enumerable
134
- def as_json(options = nil) #:nodoc:
148
+ def as_json(options = nil) # :nodoc:
135
149
  to_a.as_json(options)
136
150
  end
137
151
  end
138
152
 
139
153
  class IO
140
- def as_json(options = nil) #:nodoc:
154
+ def as_json(options = nil) # :nodoc:
141
155
  to_s
142
156
  end
143
157
  end
144
158
 
145
159
  class Range
146
- def as_json(options = nil) #:nodoc:
160
+ def as_json(options = nil) # :nodoc:
147
161
  to_s
148
162
  end
149
163
  end
150
164
 
151
165
  class Array
152
- def as_json(options = nil) #:nodoc:
166
+ def as_json(options = nil) # :nodoc:
153
167
  map { |v| options ? v.as_json(options.dup) : v.as_json }
154
168
  end
155
169
  end
156
170
 
157
171
  class Hash
158
- def as_json(options = nil) #:nodoc:
172
+ def as_json(options = nil) # :nodoc:
159
173
  # create a subset of the hash by applying :only or :except
160
174
  subset = if options
161
175
  if attrs = options[:only]
@@ -178,7 +192,7 @@ class Hash
178
192
  end
179
193
 
180
194
  class Time
181
- def as_json(options = nil) #:nodoc:
195
+ def as_json(options = nil) # :nodoc:
182
196
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
183
197
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
184
198
  else
@@ -188,7 +202,7 @@ class Time
188
202
  end
189
203
 
190
204
  class Date
191
- def as_json(options = nil) #:nodoc:
205
+ def as_json(options = nil) # :nodoc:
192
206
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
193
207
  strftime("%Y-%m-%d")
194
208
  else
@@ -198,7 +212,7 @@ class Date
198
212
  end
199
213
 
200
214
  class DateTime
201
- def as_json(options = nil) #:nodoc:
215
+ def as_json(options = nil) # :nodoc:
202
216
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
203
217
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
204
218
  else
@@ -207,19 +221,27 @@ class DateTime
207
221
  end
208
222
  end
209
223
 
210
- class URI::Generic #:nodoc:
224
+ class URI::Generic # :nodoc:
211
225
  def as_json(options = nil)
212
226
  to_s
213
227
  end
214
228
  end
215
229
 
216
- class Pathname #:nodoc:
230
+ class Pathname # :nodoc:
217
231
  def as_json(options = nil)
218
232
  to_s
219
233
  end
220
234
  end
221
235
 
222
- class Process::Status #:nodoc:
236
+ unless IPAddr.method_defined?(:as_json, false)
237
+ class IPAddr # :nodoc:
238
+ def as_json(options = nil)
239
+ to_s
240
+ end
241
+ end
242
+ end
243
+
244
+ class Process::Status # :nodoc:
223
245
  def as_json(options = nil)
224
246
  { exitstatus: exitstatus, pid: pid }
225
247
  end
@@ -72,14 +72,12 @@ class Hash
72
72
  #
73
73
  # The string pairs "key=value" that conform the query string
74
74
  # are sorted lexicographically in ascending order.
75
- #
76
- # This method is also aliased as +to_param+.
77
75
  def to_query(namespace = nil)
78
- query = collect do |key, value|
76
+ query = filter_map do |key, value|
79
77
  unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
80
78
  value.to_query(namespace ? "#{namespace}[#{key}]" : key)
81
79
  end
82
- end.compact
80
+ end
83
81
 
84
82
  query.sort! unless namespace.to_s.include?("[]")
85
83
  query.join("&")