activesupport 5.1.7 → 7.0.4.1

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 (279) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +259 -585
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +2 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  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 +2 -0
  11. data/lib/active_support/cache/file_store.rb +50 -43
  12. data/lib/active_support/cache/mem_cache_store.rb +194 -67
  13. data/lib/active_support/cache/memory_store.rb +70 -34
  14. data/lib/active_support/cache/null_store.rb +18 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +474 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +73 -50
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +556 -220
  19. data/lib/active_support/callbacks.rb +264 -159
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +81 -8
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
  23. data/lib/active_support/concurrency/share_lock.rb +4 -3
  24. data/lib/active_support/configurable.rb +17 -16
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +18 -8
  27. data/lib/active_support/core_ext/array/conversions.rb +20 -17
  28. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +8 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +4 -2
  33. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  34. data/lib/active_support/core_ext/array.rb +4 -1
  35. data/lib/active_support/core_ext/benchmark.rb +4 -2
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +3 -1
  37. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  38. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  40. data/lib/active_support/core_ext/class/subclasses.rb +10 -24
  41. data/lib/active_support/core_ext/class.rb +2 -0
  42. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  43. data/lib/active_support/core_ext/date/blank.rb +3 -1
  44. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  45. data/lib/active_support/core_ext/date/conversions.rb +24 -22
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +2 -0
  48. data/lib/active_support/core_ext/date.rb +3 -0
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +65 -41
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  54. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  56. data/lib/active_support/core_ext/date_time/conversions.rb +15 -14
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +3 -0
  59. data/lib/active_support/core_ext/digest/uuid.rb +42 -14
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +244 -72
  62. data/lib/active_support/core_ext/file/atomic.rb +6 -2
  63. data/lib/active_support/core_ext/file.rb +2 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +7 -6
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +4 -2
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +4 -31
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  72. data/lib/active_support/core_ext/hash.rb +3 -2
  73. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +7 -14
  76. data/lib/active_support/core_ext/integer.rb +2 -0
  77. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +6 -4
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +3 -1
  80. data/lib/active_support/core_ext/kernel.rb +2 -1
  81. data/lib/active_support/core_ext/load_error.rb +3 -8
  82. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  83. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  84. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -56
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +36 -27
  87. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  88. data/lib/active_support/core_ext/module/delegation.rb +97 -58
  89. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  90. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  93. data/lib/active_support/core_ext/module.rb +3 -1
  94. data/lib/active_support/core_ext/name_error.rb +30 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +134 -129
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  99. data/lib/active_support/core_ext/numeric.rb +3 -1
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +15 -5
  102. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  103. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  104. data/lib/active_support/core_ext/object/duplicable.rb +16 -110
  105. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  106. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  107. data/lib/active_support/core_ext/object/json.rb +51 -26
  108. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  109. data/lib/active_support/core_ext/object/to_query.rb +4 -2
  110. data/lib/active_support/core_ext/object/try.rb +26 -14
  111. data/lib/active_support/core_ext/object/with_options.rb +24 -3
  112. data/lib/active_support/core_ext/object.rb +2 -0
  113. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  114. data/lib/active_support/core_ext/pathname.rb +3 -0
  115. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +6 -3
  119. data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
  120. data/lib/active_support/core_ext/range/overlaps.rb +3 -1
  121. data/lib/active_support/core_ext/range.rb +4 -1
  122. data/lib/active_support/core_ext/regexp.rb +10 -5
  123. data/lib/active_support/core_ext/securerandom.rb +25 -3
  124. data/lib/active_support/core_ext/string/access.rb +7 -16
  125. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  126. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  127. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  128. data/lib/active_support/core_ext/string/filters.rb +44 -1
  129. data/lib/active_support/core_ext/string/indent.rb +2 -0
  130. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  133. data/lib/active_support/core_ext/string/output_safety.rb +135 -27
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +5 -1
  136. data/lib/active_support/core_ext/string/zones.rb +2 -0
  137. data/lib/active_support/core_ext/string.rb +2 -0
  138. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/symbol.rb +3 -0
  140. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  141. data/lib/active_support/core_ext/time/calculations.rb +81 -24
  142. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  143. data/lib/active_support/core_ext/time/conversions.rb +17 -12
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +12 -25
  146. data/lib/active_support/core_ext/time.rb +3 -0
  147. data/lib/active_support/core_ext/uri.rb +4 -23
  148. data/lib/active_support/core_ext.rb +4 -1
  149. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  150. data/lib/active_support/current_attributes.rb +226 -0
  151. data/lib/active_support/dependencies/autoload.rb +2 -0
  152. data/lib/active_support/dependencies/interlock.rb +12 -18
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +59 -715
  155. data/lib/active_support/deprecation/behaviors.rb +48 -13
  156. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  159. data/lib/active_support/deprecation/method_wrappers.rb +29 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -8
  161. data/lib/active_support/deprecation/reporting.rb +54 -9
  162. data/lib/active_support/deprecation.rb +10 -3
  163. data/lib/active_support/descendants_tracker.rb +192 -34
  164. data/lib/active_support/digest.rb +22 -0
  165. data/lib/active_support/duration/iso8601_parser.rb +9 -9
  166. data/lib/active_support/duration/iso8601_serializer.rb +29 -15
  167. data/lib/active_support/duration.rb +158 -72
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +129 -0
  170. data/lib/active_support/environment_inquirer.rb +20 -0
  171. data/lib/active_support/error_reporter.rb +117 -0
  172. data/lib/active_support/evented_file_update_checker.rb +87 -122
  173. data/lib/active_support/execution_context/test_helper.rb +13 -0
  174. data/lib/active_support/execution_context.rb +53 -0
  175. data/lib/active_support/execution_wrapper.rb +46 -21
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +2 -0
  178. data/lib/active_support/file_update_checker.rb +2 -1
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +7 -5
  181. data/lib/active_support/gzip.rb +2 -0
  182. data/lib/active_support/hash_with_indifferent_access.rb +126 -42
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +5 -1
  185. data/lib/active_support/i18n_railtie.rb +19 -14
  186. data/lib/active_support/inflections.rb +2 -0
  187. data/lib/active_support/inflector/inflections.rb +41 -14
  188. data/lib/active_support/inflector/methods.rb +73 -87
  189. data/lib/active_support/inflector/transliterate.rb +56 -18
  190. data/lib/active_support/inflector.rb +2 -0
  191. data/lib/active_support/isolated_execution_state.rb +72 -0
  192. data/lib/active_support/json/decoding.rb +27 -26
  193. data/lib/active_support/json/encoding.rb +16 -6
  194. data/lib/active_support/json.rb +2 -0
  195. data/lib/active_support/key_generator.rb +25 -38
  196. data/lib/active_support/lazy_load_hooks.rb +35 -6
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +8 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +4 -2
  200. data/lib/active_support/log_subscriber.rb +54 -13
  201. data/lib/active_support/logger.rb +4 -17
  202. data/lib/active_support/logger_silence.rb +13 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +48 -10
  204. data/lib/active_support/message_encryptor.rb +111 -37
  205. data/lib/active_support/message_verifier.rb +124 -21
  206. data/lib/active_support/messages/metadata.rb +80 -0
  207. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  208. data/lib/active_support/messages/rotator.rb +57 -0
  209. data/lib/active_support/multibyte/chars.rb +19 -76
  210. data/lib/active_support/multibyte/unicode.rb +9 -331
  211. data/lib/active_support/multibyte.rb +3 -1
  212. data/lib/active_support/notifications/fanout.rb +165 -37
  213. data/lib/active_support/notifications/instrumenter.rb +92 -11
  214. data/lib/active_support/notifications.rb +96 -30
  215. data/lib/active_support/number_helper/number_converter.rb +8 -9
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -12
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +6 -3
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +7 -4
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +6 -3
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
  223. data/lib/active_support/number_helper/rounding_helper.rb +16 -34
  224. data/lib/active_support/number_helper.rb +38 -12
  225. data/lib/active_support/option_merger.rb +19 -6
  226. data/lib/active_support/ordered_hash.rb +4 -2
  227. data/lib/active_support/ordered_options.rb +18 -6
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +8 -1
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +3 -10
  232. data/lib/active_support/railtie.rb +112 -11
  233. data/lib/active_support/reloader.rb +12 -11
  234. data/lib/active_support/rescuable.rb +19 -18
  235. data/lib/active_support/ruby_features.rb +7 -0
  236. data/lib/active_support/secure_compare_rotator.rb +51 -0
  237. data/lib/active_support/security_utils.rb +26 -15
  238. data/lib/active_support/string_inquirer.rb +4 -3
  239. data/lib/active_support/subscriber.rb +81 -42
  240. data/lib/active_support/tagged_logging.rb +45 -9
  241. data/lib/active_support/test_case.rb +86 -2
  242. data/lib/active_support/testing/assertions.rb +89 -21
  243. data/lib/active_support/testing/autorun.rb +2 -0
  244. data/lib/active_support/testing/constant_lookup.rb +2 -0
  245. data/lib/active_support/testing/declarative.rb +2 -0
  246. data/lib/active_support/testing/deprecation.rb +54 -2
  247. data/lib/active_support/testing/file_fixtures.rb +4 -0
  248. data/lib/active_support/testing/isolation.rb +6 -4
  249. data/lib/active_support/testing/method_call_assertions.rb +34 -5
  250. data/lib/active_support/testing/parallelization/server.rb +82 -0
  251. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  252. data/lib/active_support/testing/parallelization.rb +55 -0
  253. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  254. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  255. data/lib/active_support/testing/stream.rb +6 -7
  256. data/lib/active_support/testing/tagged_logging.rb +3 -1
  257. data/lib/active_support/testing/time_helpers.rb +91 -15
  258. data/lib/active_support/time.rb +2 -0
  259. data/lib/active_support/time_with_zone.rb +168 -56
  260. data/lib/active_support/values/time_zone.rb +85 -37
  261. data/lib/active_support/version.rb +3 -1
  262. data/lib/active_support/xml_mini/jdom.rb +6 -5
  263. data/lib/active_support/xml_mini/libxml.rb +9 -7
  264. data/lib/active_support/xml_mini/libxmlsax.rb +7 -5
  265. data/lib/active_support/xml_mini/nokogiri.rb +8 -6
  266. data/lib/active_support/xml_mini/nokogirisax.rb +6 -4
  267. data/lib/active_support/xml_mini/rexml.rb +13 -4
  268. data/lib/active_support/xml_mini.rb +10 -15
  269. data/lib/active_support.rb +30 -9
  270. metadata +76 -35
  271. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  272. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  273. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  274. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  275. data/lib/active_support/core_ext/marshal.rb +0 -22
  276. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  277. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  278. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  279. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/big_decimal/conversions"
2
4
  require "active_support/core_ext/object/blank"
3
5
  require "active_support/core_ext/hash/keys"
@@ -28,7 +30,7 @@ module ActiveSupport
28
30
  # If set to true, precision will mean the number of significant digits instead
29
31
  # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
30
32
  significant: false,
31
- # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
33
+ # If set, the zeros after the decimal separator will always be stripped (e.g.: 1.200 will be 1.2)
32
34
  strip_insignificant_zeros: false
33
35
  },
34
36
 
@@ -134,7 +136,6 @@ module ActiveSupport
134
136
  end
135
137
 
136
138
  private
137
-
138
139
  def options
139
140
  @options ||= format_options.merge(opts)
140
141
  end
@@ -160,12 +161,12 @@ module ActiveSupport
160
161
  options
161
162
  end
162
163
 
163
- def translate_number_value_with_default(key, i18n_options = {})
164
- I18n.translate(key, { default: default_value(key), scope: :number }.merge!(i18n_options))
164
+ def translate_number_value_with_default(key, **i18n_options)
165
+ I18n.translate(key, **{ default: default_value(key), scope: :number }.merge!(i18n_options))
165
166
  end
166
167
 
167
- def translate_in_locale(key, i18n_options = {})
168
- translate_number_value_with_default(key, { locale: options[:locale] }.merge(i18n_options))
168
+ def translate_in_locale(key, **i18n_options)
169
+ translate_number_value_with_default(key, **{ locale: options[:locale] }.merge(i18n_options))
169
170
  end
170
171
 
171
172
  def default_value(key)
@@ -173,9 +174,7 @@ module ActiveSupport
173
174
  end
174
175
 
175
176
  def valid_float?
176
- Float(number)
177
- rescue ArgumentError, TypeError
178
- false
177
+ Float(number, exception: false)
179
178
  end
180
179
  end
181
180
  end
@@ -1,4 +1,6 @@
1
- require "active_support/core_ext/numeric/inquiry"
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
2
4
 
3
5
  module ActiveSupport
4
6
  module NumberHelper
@@ -6,24 +8,24 @@ module ActiveSupport
6
8
  self.namespace = :currency
7
9
 
8
10
  def convert
9
- number = self.number.to_s.strip
10
11
  format = options[:format]
11
12
 
12
- if number.to_f.negative?
13
- format = options[:negative_format]
14
- number = absolute_value(number)
13
+ number_f = valid_float?
14
+ if number_f
15
+ if number_f.negative?
16
+ number_f = number_f.abs
17
+ format = options[:negative_format] if (number_f * 10**options[:precision]) >= 0.5
18
+ end
19
+ number_s = NumberToRoundedConverter.convert(number_f, options)
20
+ else
21
+ number_s = number.to_s.strip
22
+ format = options[:negative_format] if number_s.sub!(/^-/, "")
15
23
  end
16
24
 
17
- rounded_number = NumberToRoundedConverter.convert(number, options)
18
- format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, options[:unit])
25
+ format.gsub("%n", number_s).gsub("%u", options[:unit])
19
26
  end
20
27
 
21
28
  private
22
-
23
- def absolute_value(number)
24
- number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "")
25
- end
26
-
27
29
  def options
28
30
  @options ||= begin
29
31
  defaults = default_format_options.merge(i18n_opts)
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
1
5
  module ActiveSupport
2
6
  module NumberHelper
3
- class NumberToDelimitedConverter < NumberConverter #:nodoc:
7
+ class NumberToDelimitedConverter < NumberConverter # :nodoc:
4
8
  self.validate_float = true
5
9
 
6
10
  DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
@@ -10,9 +14,8 @@ module ActiveSupport
10
14
  end
11
15
 
12
16
  private
13
-
14
17
  def parts
15
- left, right = number.to_s.split(".".freeze)
18
+ left, right = number.to_s.split(".")
16
19
  left.gsub!(delimiter_pattern) do |digit_to_delimit|
17
20
  "#{digit_to_delimit}#{options[:delimiter]}"
18
21
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
1
5
  module ActiveSupport
2
6
  module NumberHelper
3
7
  class NumberToHumanConverter < NumberConverter # :nodoc:
@@ -12,7 +16,7 @@ module ActiveSupport
12
16
  @number = RoundingHelper.new(options).round(number)
13
17
  @number = Float(number)
14
18
 
15
- # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
19
+ # For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
16
20
  unless options.key?(:strip_insignificant_zeros)
17
21
  options[:strip_insignificant_zeros] = true
18
22
  end
@@ -23,11 +27,10 @@ module ActiveSupport
23
27
 
24
28
  rounded_number = NumberToRoundedConverter.convert(number, options)
25
29
  unit = determine_unit(units, exponent)
26
- format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, unit).strip
30
+ format.gsub("%n", rounded_number).gsub("%u", unit).strip
27
31
  end
28
32
 
29
33
  private
30
-
31
34
  def format
32
35
  options[:format] || translate_in_locale("human.decimal_units.format")
33
36
  end
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
1
5
  module ActiveSupport
2
6
  module NumberHelper
3
- class NumberToHumanSizeConverter < NumberConverter #:nodoc:
7
+ class NumberToHumanSizeConverter < NumberConverter # :nodoc:
4
8
  STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
5
9
 
6
10
  self.namespace = :human
@@ -9,7 +13,7 @@ module ActiveSupport
9
13
  def convert
10
14
  @number = Float(number)
11
15
 
12
- # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
16
+ # For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
13
17
  unless options.key?(:strip_insignificant_zeros)
14
18
  options[:strip_insignificant_zeros] = true
15
19
  end
@@ -20,11 +24,10 @@ module ActiveSupport
20
24
  human_size = number / (base**exponent)
21
25
  number_to_format = NumberToRoundedConverter.convert(human_size, options)
22
26
  end
23
- conversion_format.gsub("%n".freeze, number_to_format).gsub("%u".freeze, unit)
27
+ conversion_format.gsub("%n", number_to_format).gsub("%u", unit)
24
28
  end
25
29
 
26
30
  private
27
-
28
31
  def conversion_format
29
32
  translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true)
30
33
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
1
5
  module ActiveSupport
2
6
  module NumberHelper
3
7
  class NumberToPercentageConverter < NumberConverter # :nodoc:
@@ -5,7 +9,7 @@ module ActiveSupport
5
9
 
6
10
  def convert
7
11
  rounded_number = NumberToRoundedConverter.convert(number, options)
8
- options[:format].gsub("%n".freeze, rounded_number)
12
+ options[:format].gsub("%n", rounded_number)
9
13
  end
10
14
  end
11
15
  end
@@ -1,14 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
1
5
  module ActiveSupport
2
6
  module NumberHelper
3
- class NumberToPhoneConverter < NumberConverter #:nodoc:
7
+ class NumberToPhoneConverter < NumberConverter # :nodoc:
4
8
  def convert
5
- str = country_code(opts[:country_code])
9
+ str = country_code(opts[:country_code]).dup
6
10
  str << convert_to_phone_number(number.to_s.strip)
7
11
  str << phone_ext(opts[:extension])
8
12
  end
9
13
 
10
14
  private
11
-
12
15
  def convert_to_phone_number(number)
13
16
  if opts[:area_code]
14
17
  convert_with_area_code(number)
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
1
5
  module ActiveSupport
2
6
  module NumberHelper
3
7
  class NumberToRoundedConverter < NumberConverter # :nodoc:
@@ -16,14 +20,18 @@ module ActiveSupport
16
20
  end
17
21
 
18
22
  formatted_string =
19
- if BigDecimal === rounded_number && rounded_number.finite?
23
+ if rounded_number.finite?
20
24
  s = rounded_number.to_s("F")
21
- s << "0".freeze * precision
22
- a, b = s.split(".".freeze, 2)
23
- a << ".".freeze
24
- a << b[0, precision]
25
+ a, b = s.split(".", 2)
26
+ if precision != 0
27
+ b << "0" * precision
28
+ a << "."
29
+ a << b[0, precision]
30
+ end
31
+ a
25
32
  else
26
- "%00.#{precision}f" % rounded_number
33
+ # Infinity/NaN
34
+ "%f" % rounded_number
27
35
  end
28
36
  else
29
37
  formatted_string = rounded_number
@@ -34,27 +42,6 @@ module ActiveSupport
34
42
  end
35
43
 
36
44
  private
37
-
38
- def digits_and_rounded_number(precision)
39
- if zero?
40
- [1, 0]
41
- else
42
- digits = digit_count(number)
43
- multiplier = 10**(digits - precision)
44
- rounded_number = calculate_rounded_number(multiplier)
45
- digits = digit_count(rounded_number) # After rounding, the number of digits may have changed
46
- [digits, rounded_number]
47
- end
48
- end
49
-
50
- def calculate_rounded_number(multiplier)
51
- (number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier
52
- end
53
-
54
- def digit_count(number)
55
- number.zero? ? 1 : (Math.log10(absolute_number(number)) + 1).floor
56
- end
57
-
58
45
  def strip_insignificant_zeros
59
46
  options[:strip_insignificant_zeros]
60
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  module NumberHelper
3
5
  class RoundingHelper # :nodoc:
@@ -8,56 +10,36 @@ module ActiveSupport
8
10
  end
9
11
 
10
12
  def round(number)
13
+ precision = absolute_precision(number)
11
14
  return number unless precision
12
- number = convert_to_decimal(number)
13
- if significant && precision > 0
14
- round_significant(number)
15
- else
16
- round_without_significant(number)
17
- end
15
+
16
+ rounded_number = convert_to_decimal(number).round(precision, options.fetch(:round_mode, :default).to_sym)
17
+ rounded_number.zero? ? rounded_number.abs : rounded_number # prevent showing negative zeros
18
18
  end
19
19
 
20
20
  def digit_count(number)
21
21
  return 1 if number.zero?
22
- (Math.log10(absolute_number(number)) + 1).floor
22
+ (Math.log10(number.abs) + 1).floor
23
23
  end
24
24
 
25
25
  private
26
- def round_without_significant(number)
27
- number = number.round(precision)
28
- number = number.to_i if precision == 0 && number.finite?
29
- number = number.abs if number.zero? # prevent showing negative zeros
30
- number
31
- end
32
-
33
- def round_significant(number)
34
- return 0 if number.zero?
35
- digits = digit_count(number)
36
- multiplier = 10**(digits - precision)
37
- (number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier
38
- end
39
-
40
26
  def convert_to_decimal(number)
41
27
  case number
42
28
  when Float, String
43
- number = BigDecimal(number.to_s)
29
+ BigDecimal(number.to_s)
44
30
  when Rational
45
- number = BigDecimal(number, digit_count(number.to_i) + precision)
31
+ BigDecimal(number, digit_count(number.to_i) + options[:precision])
46
32
  else
47
- number = number.to_d
33
+ number.to_d
48
34
  end
49
35
  end
50
36
 
51
- def precision
52
- options[:precision]
53
- end
54
-
55
- def significant
56
- options[:significant]
57
- end
58
-
59
- def absolute_number(number)
60
- number.respond_to?(:abs) ? number.abs : number.to_d.abs
37
+ def absolute_precision(number)
38
+ if options[:significant] && options[:precision] > 0
39
+ options[:precision] - digit_count(convert_to_decimal(number))
40
+ else
41
+ options[:precision]
42
+ end
61
43
  end
62
44
  end
63
45
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  module NumberHelper
3
5
  extend ActiveSupport::Autoload
@@ -69,6 +71,8 @@ module ActiveSupport
69
71
  # (defaults to current locale).
70
72
  # * <tt>:precision</tt> - Sets the level of precision (defaults
71
73
  # to 2).
74
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
75
+ # (defaults to :default. See BigDecimal::mode)
72
76
  # * <tt>:unit</tt> - Sets the denomination of the currency
73
77
  # (defaults to "$").
74
78
  # * <tt>:separator</tt> - Sets the separator between the units
@@ -83,6 +87,9 @@ module ActiveSupport
83
87
  # number given by <tt>:format</tt>). Accepts the same fields
84
88
  # than <tt>:format</tt>, except <tt>%n</tt> is here the
85
89
  # absolute value of the number.
90
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
91
+ # insignificant zeros after the decimal separator (defaults to
92
+ # +false+).
86
93
  #
87
94
  # ==== Examples
88
95
  #
@@ -92,12 +99,18 @@ module ActiveSupport
92
99
  # number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
93
100
  # number_to_currency('123a456') # => "$123a456"
94
101
  #
102
+ # number_to_currency(-0.456789, precision: 0)
103
+ # # => "$0"
95
104
  # number_to_currency(-1234567890.50, negative_format: '(%u%n)')
96
105
  # # => "($1,234,567,890.50)"
97
106
  # number_to_currency(1234567890.50, unit: '&pound;', separator: ',', delimiter: '')
98
107
  # # => "&pound;1234567890,50"
99
108
  # number_to_currency(1234567890.50, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
100
109
  # # => "1234567890,50 &pound;"
110
+ # number_to_currency(1234567890.50, strip_insignificant_zeros: true)
111
+ # # => "$1,234,567,890.5"
112
+ # number_to_currency(1234567890.50, precision: 0, round_mode: :up)
113
+ # # => "$1,234,567,891"
101
114
  def number_to_currency(number, options = {})
102
115
  NumberToCurrencyConverter.convert(number, options)
103
116
  end
@@ -111,6 +124,8 @@ module ActiveSupport
111
124
  # (defaults to current locale).
112
125
  # * <tt>:precision</tt> - Sets the precision of the number
113
126
  # (defaults to 3). Keeps the number's precision if +nil+.
127
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
128
+ # (defaults to :default. See BigDecimal::mode)
114
129
  # * <tt>:significant</tt> - If +true+, precision will be the number
115
130
  # of significant_digits. If +false+, the number of fractional
116
131
  # digits (defaults to +false+).
@@ -126,15 +141,16 @@ module ActiveSupport
126
141
  #
127
142
  # ==== Examples
128
143
  #
129
- # number_to_percentage(100) # => "100.000%"
130
- # number_to_percentage('98') # => "98.000%"
131
- # number_to_percentage(100, precision: 0) # => "100%"
132
- # number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
133
- # number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
134
- # number_to_percentage(1000, locale: :fr) # => "1000,000%"
135
- # number_to_percentage(1000, precision: nil) # => "1000%"
136
- # number_to_percentage('98a') # => "98a%"
137
- # number_to_percentage(100, format: '%n %') # => "100.000 %"
144
+ # number_to_percentage(100) # => "100.000%"
145
+ # number_to_percentage('98') # => "98.000%"
146
+ # number_to_percentage(100, precision: 0) # => "100%"
147
+ # number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
148
+ # number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
149
+ # number_to_percentage(1000, locale: :fr) # => "1000,000%"
150
+ # number_to_percentage(1000, precision: nil) # => "1000%"
151
+ # number_to_percentage('98a') # => "98a%"
152
+ # number_to_percentage(100, format: '%n %') # => "100.000 %"
153
+ # number_to_percentage(302.24398923423, precision: 5, round_mode: :down) # => "302.24398%"
138
154
  def number_to_percentage(number, options = {})
139
155
  NumberToPercentageConverter.convert(number, options)
140
156
  end
@@ -185,6 +201,8 @@ module ActiveSupport
185
201
  # (defaults to current locale).
186
202
  # * <tt>:precision</tt> - Sets the precision of the number
187
203
  # (defaults to 3). Keeps the number's precision if +nil+.
204
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
205
+ # (defaults to :default. See BigDecimal::mode)
188
206
  # * <tt>:significant</tt> - If +true+, precision will be the number
189
207
  # of significant_digits. If +false+, the number of fractional
190
208
  # digits (defaults to +false+).
@@ -206,6 +224,7 @@ module ActiveSupport
206
224
  # number_to_rounded(111.2345, precision: 1, significant: true) # => "100"
207
225
  # number_to_rounded(13, precision: 5, significant: true) # => "13.000"
208
226
  # number_to_rounded(13, precision: nil) # => "13"
227
+ # number_to_rounded(389.32314, precision: 0, round_mode: :up) # => "390"
209
228
  # number_to_rounded(111.234, locale: :fr) # => "111,234"
210
229
  #
211
230
  # number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true)
@@ -219,7 +238,7 @@ module ActiveSupport
219
238
  end
220
239
 
221
240
  # Formats the bytes in +number+ into a more understandable
222
- # representation (e.g., giving it 1500 yields 1.5 KB). This
241
+ # representation (e.g., giving it 1500 yields 1.46 KB). This
223
242
  # method is useful for reporting file sizes to users. You can
224
243
  # customize the format in the +options+ hash.
225
244
  #
@@ -232,6 +251,8 @@ module ActiveSupport
232
251
  # (defaults to current locale).
233
252
  # * <tt>:precision</tt> - Sets the precision of the number
234
253
  # (defaults to 3).
254
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
255
+ # (defaults to :default. See BigDecimal::mode)
235
256
  # * <tt>:significant</tt> - If +true+, precision will be the number
236
257
  # of significant_digits. If +false+, the number of fractional
237
258
  # digits (defaults to +true+)
@@ -255,6 +276,7 @@ module ActiveSupport
255
276
  # number_to_human_size(1234567890123456789) # => "1.07 EB"
256
277
  # number_to_human_size(1234567, precision: 2) # => "1.2 MB"
257
278
  # number_to_human_size(483989, precision: 2) # => "470 KB"
279
+ # number_to_human_size(483989, precision: 2, round_mode: :up) # => "480 KB"
258
280
  # number_to_human_size(1234567, precision: 2, separator: ',') # => "1,2 MB"
259
281
  # number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
260
282
  # number_to_human_size(524288000, precision: 5) # => "500 MB"
@@ -263,7 +285,7 @@ module ActiveSupport
263
285
  end
264
286
 
265
287
  # Pretty prints (formats and approximates) a number in a way it
266
- # is more readable by humans (eg.: 1200000000 becomes "1.2
288
+ # is more readable by humans (e.g.: 1200000000 becomes "1.2
267
289
  # Billion"). This is useful for numbers that can get very large
268
290
  # (and too hard to read).
269
291
  #
@@ -271,7 +293,7 @@ module ActiveSupport
271
293
  # size.
272
294
  #
273
295
  # You can also define your own unit-quantifier names if you want
274
- # to use other decimal units (eg.: 1500 becomes "1.5
296
+ # to use other decimal units (e.g.: 1500 becomes "1.5
275
297
  # kilometers", 0.150 becomes "150 milliliters", etc). You may
276
298
  # define a wide range of unit quantifiers, even fractional ones
277
299
  # (centi, deci, mili, etc).
@@ -282,6 +304,8 @@ module ActiveSupport
282
304
  # (defaults to current locale).
283
305
  # * <tt>:precision</tt> - Sets the precision of the number
284
306
  # (defaults to 3).
307
+ # * <tt>:round_mode</tt> - Determine how rounding is performed
308
+ # (defaults to :default. See BigDecimal::mode)
285
309
  # * <tt>:significant</tt> - If +true+, precision will be the number
286
310
  # of significant_digits. If +false+, the number of fractional
287
311
  # digits (defaults to +true+)
@@ -319,6 +343,8 @@ module ActiveSupport
319
343
  # number_to_human(1234567890123456789) # => "1230 Quadrillion"
320
344
  # number_to_human(489939, precision: 2) # => "490 Thousand"
321
345
  # number_to_human(489939, precision: 4) # => "489.9 Thousand"
346
+ # number_to_human(489939, precision: 2
347
+ # , round_mode: :down) # => "480 Thousand"
322
348
  # number_to_human(1234567, precision: 4,
323
349
  # significant: false) # => "1.2346 Million"
324
350
  # number_to_human(1234567, precision: 1,
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash/deep_merge"
2
4
 
3
5
  module ActiveSupport
4
- class OptionMerger #:nodoc:
6
+ class OptionMerger # :nodoc:
5
7
  instance_methods.each do |method|
6
- undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
8
+ undef_method(method) unless method.start_with?("__", "instance_eval", "class", "object_id")
7
9
  end
8
10
 
9
11
  def initialize(context, options)
@@ -12,14 +14,25 @@ module ActiveSupport
12
14
 
13
15
  private
14
16
  def method_missing(method, *arguments, &block)
15
- if arguments.first.is_a?(Proc)
16
- proc = arguments.pop
17
+ options = nil
18
+ if arguments.size == 1 && arguments.first.is_a?(Proc)
19
+ proc = arguments.shift
17
20
  arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
21
+ elsif arguments.last.respond_to?(:to_hash)
22
+ options = @options.deep_merge(arguments.pop)
18
23
  else
19
- arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
24
+ options = @options
20
25
  end
21
26
 
22
- @context.__send__(method, *arguments, &block)
27
+ if options
28
+ @context.__send__(method, *arguments, **options, &block)
29
+ else
30
+ @context.__send__(method, *arguments, &block)
31
+ end
32
+ end
33
+
34
+ def respond_to_missing?(*arguments)
35
+ @context.respond_to?(*arguments)
23
36
  end
24
37
  end
25
38
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
2
4
 
3
5
  YAML.add_builtin_type("omap") do |type, val|
@@ -14,12 +16,12 @@ module ActiveSupport
14
16
  # oh.keys # => [:a, :b], this order is guaranteed
15
17
  #
16
18
  # Also, maps the +omap+ feature for YAML files
17
- # (See http://yaml.org/type/omap.html) to support ordered items
19
+ # (See https://yaml.org/type/omap.html) to support ordered items
18
20
  # when loading from yaml.
19
21
  #
20
22
  # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
21
23
  # with other implementations.
22
- class OrderedHash < ::Hash
24
+ class OrderedHash < ::Hash # :nodoc:
23
25
  def to_yaml_type
24
26
  "!tag:yaml.org,2002:omap"
25
27
  end
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/object/blank"
2
4
 
3
5
  module ActiveSupport
4
- # Usually key value pairs are handled something like this:
6
+ # +OrderedOptions+ inherits from +Hash+ and provides dynamic accessor methods.
7
+ #
8
+ # With a +Hash+, key-value pairs are typically managed like this:
5
9
  #
6
10
  # h = {}
7
11
  # h[:boy] = 'John'
@@ -10,7 +14,7 @@ module ActiveSupport
10
14
  # h[:girl] # => 'Mary'
11
15
  # h[:dog] # => nil
12
16
  #
13
- # Using +OrderedOptions+, the above code could be reduced to:
17
+ # Using +OrderedOptions+, the above code can be written as:
14
18
  #
15
19
  # h = ActiveSupport::OrderedOptions.new
16
20
  # h.boy = 'John'
@@ -22,7 +26,7 @@ module ActiveSupport
22
26
  # To raise an exception when the value is blank, append a
23
27
  # bang to the key name, like:
24
28
  #
25
- # h.dog! # => raises KeyError: key not found: :dog
29
+ # h.dog! # => raises KeyError: :dog is blank
26
30
  #
27
31
  class OrderedOptions < Hash
28
32
  alias_method :_get, :[] # preserve the original #[] method
@@ -37,14 +41,14 @@ module ActiveSupport
37
41
  end
38
42
 
39
43
  def method_missing(name, *args)
40
- name_string = name.to_s
44
+ name_string = +name.to_s
41
45
  if name_string.chomp!("=")
42
46
  self[name_string] = args.first
43
47
  else
44
48
  bangs = name_string.chomp!("!")
45
49
 
46
50
  if bangs
47
- fetch(name_string.to_sym).presence || raise(KeyError.new("#{name_string} is blank."))
51
+ self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
48
52
  else
49
53
  self[name_string]
50
54
  end
@@ -54,9 +58,17 @@ module ActiveSupport
54
58
  def respond_to_missing?(name, include_private)
55
59
  true
56
60
  end
61
+
62
+ def extractable_options?
63
+ true
64
+ end
65
+
66
+ def inspect
67
+ "#<#{self.class.name} #{super}>"
68
+ end
57
69
  end
58
70
 
59
- # +InheritableOptions+ provides a constructor to build an +OrderedOptions+
71
+ # +InheritableOptions+ provides a constructor to build an OrderedOptions
60
72
  # hash inherited from another hash.
61
73
  #
62
74
  # Use this if you already have some hash and you want to create a new one based on it.