activesupport 6.0.0

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 (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/big_decimal/conversions"
4
+ require "active_support/core_ext/object/blank"
5
+ require "active_support/core_ext/hash/keys"
6
+ require "active_support/i18n"
7
+ require "active_support/core_ext/class/attribute"
8
+
9
+ module ActiveSupport
10
+ module NumberHelper
11
+ class NumberConverter # :nodoc:
12
+ # Default and i18n option namespace per class
13
+ class_attribute :namespace
14
+
15
+ # Does the object need a number that is a valid float?
16
+ class_attribute :validate_float
17
+
18
+ attr_reader :number, :opts
19
+
20
+ DEFAULTS = {
21
+ # Used in number_to_delimited
22
+ # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
23
+ format: {
24
+ # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
25
+ separator: ".",
26
+ # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three)
27
+ delimiter: ",",
28
+ # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
29
+ precision: 3,
30
+ # If set to true, precision will mean the number of significant digits instead
31
+ # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
32
+ significant: false,
33
+ # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
34
+ strip_insignificant_zeros: false
35
+ },
36
+
37
+ # Used in number_to_currency
38
+ currency: {
39
+ format: {
40
+ format: "%u%n",
41
+ negative_format: "-%u%n",
42
+ unit: "$",
43
+ # These five are to override number.format and are optional
44
+ separator: ".",
45
+ delimiter: ",",
46
+ precision: 2,
47
+ significant: false,
48
+ strip_insignificant_zeros: false
49
+ }
50
+ },
51
+
52
+ # Used in number_to_percentage
53
+ percentage: {
54
+ format: {
55
+ delimiter: "",
56
+ format: "%n%"
57
+ }
58
+ },
59
+
60
+ # Used in number_to_rounded
61
+ precision: {
62
+ format: {
63
+ delimiter: ""
64
+ }
65
+ },
66
+
67
+ # Used in number_to_human_size and number_to_human
68
+ human: {
69
+ format: {
70
+ # These five are to override number.format and are optional
71
+ delimiter: "",
72
+ precision: 3,
73
+ significant: true,
74
+ strip_insignificant_zeros: true
75
+ },
76
+ # Used in number_to_human_size
77
+ storage_units: {
78
+ # Storage units output formatting.
79
+ # %u is the storage unit, %n is the number (default: 2 MB)
80
+ format: "%n %u",
81
+ units: {
82
+ byte: "Bytes",
83
+ kb: "KB",
84
+ mb: "MB",
85
+ gb: "GB",
86
+ tb: "TB"
87
+ }
88
+ },
89
+ # Used in number_to_human
90
+ decimal_units: {
91
+ format: "%n %u",
92
+ # Decimal units output formatting
93
+ # By default we will only quantify some of the exponents
94
+ # but the commented ones might be defined or overridden
95
+ # by the user.
96
+ units: {
97
+ # femto: Quadrillionth
98
+ # pico: Trillionth
99
+ # nano: Billionth
100
+ # micro: Millionth
101
+ # mili: Thousandth
102
+ # centi: Hundredth
103
+ # deci: Tenth
104
+ unit: "",
105
+ # ten:
106
+ # one: Ten
107
+ # other: Tens
108
+ # hundred: Hundred
109
+ thousand: "Thousand",
110
+ million: "Million",
111
+ billion: "Billion",
112
+ trillion: "Trillion",
113
+ quadrillion: "Quadrillion"
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ def self.convert(number, options)
120
+ new(number, options).execute
121
+ end
122
+
123
+ def initialize(number, options)
124
+ @number = number
125
+ @opts = options.symbolize_keys
126
+ end
127
+
128
+ def execute
129
+ if !number
130
+ nil
131
+ elsif validate_float? && !valid_float?
132
+ number
133
+ else
134
+ convert
135
+ end
136
+ end
137
+
138
+ private
139
+
140
+ def options
141
+ @options ||= format_options.merge(opts)
142
+ end
143
+
144
+ def format_options
145
+ default_format_options.merge!(i18n_format_options)
146
+ end
147
+
148
+ def default_format_options
149
+ options = DEFAULTS[:format].dup
150
+ options.merge!(DEFAULTS[namespace][:format]) if namespace
151
+ options
152
+ end
153
+
154
+ def i18n_format_options
155
+ locale = opts[:locale]
156
+ options = I18n.translate(:'number.format', locale: locale, default: {}).dup
157
+
158
+ if namespace
159
+ options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {}))
160
+ end
161
+
162
+ options
163
+ end
164
+
165
+ def translate_number_value_with_default(key, i18n_options = {})
166
+ I18n.translate(key, { default: default_value(key), scope: :number }.merge!(i18n_options))
167
+ end
168
+
169
+ def translate_in_locale(key, i18n_options = {})
170
+ translate_number_value_with_default(key, { locale: options[:locale] }.merge(i18n_options))
171
+ end
172
+
173
+ def default_value(key)
174
+ key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
175
+ end
176
+
177
+ def valid_float?
178
+ Float(number)
179
+ rescue ArgumentError, TypeError
180
+ false
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
5
+ module ActiveSupport
6
+ module NumberHelper
7
+ class NumberToCurrencyConverter < NumberConverter # :nodoc:
8
+ self.namespace = :currency
9
+
10
+ def convert
11
+ number = self.number.to_s.strip
12
+ format = options[:format]
13
+
14
+ if number.to_f.negative?
15
+ format = options[:negative_format]
16
+ number = absolute_value(number)
17
+ end
18
+
19
+ rounded_number = NumberToRoundedConverter.convert(number, options)
20
+ format.gsub("%n", rounded_number).gsub("%u", options[:unit])
21
+ end
22
+
23
+ private
24
+
25
+ def absolute_value(number)
26
+ number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "")
27
+ end
28
+
29
+ def options
30
+ @options ||= begin
31
+ defaults = default_format_options.merge(i18n_opts)
32
+ # Override negative format if format options are given
33
+ defaults[:negative_format] = "-#{opts[:format]}" if opts[:format]
34
+ defaults.merge!(opts)
35
+ end
36
+ end
37
+
38
+ def i18n_opts
39
+ # Set International negative format if it does not exist
40
+ i18n = i18n_format_options
41
+ i18n[:negative_format] ||= "-#{i18n[:format]}" if i18n[:format]
42
+ i18n
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
5
+ module ActiveSupport
6
+ module NumberHelper
7
+ class NumberToDelimitedConverter < NumberConverter #:nodoc:
8
+ self.validate_float = true
9
+
10
+ DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
11
+
12
+ def convert
13
+ parts.join(options[:separator])
14
+ end
15
+
16
+ private
17
+
18
+ def parts
19
+ left, right = number.to_s.split(".")
20
+ left.gsub!(delimiter_pattern) do |digit_to_delimit|
21
+ "#{digit_to_delimit}#{options[:delimiter]}"
22
+ end
23
+ [left, right].compact
24
+ end
25
+
26
+ def delimiter_pattern
27
+ options.fetch(:delimiter_pattern, DEFAULT_DELIMITER_REGEX)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
5
+ module ActiveSupport
6
+ module NumberHelper
7
+ class NumberToHumanConverter < NumberConverter # :nodoc:
8
+ DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
9
+ -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto }
10
+ INVERTED_DECIMAL_UNITS = DECIMAL_UNITS.invert
11
+
12
+ self.namespace = :human
13
+ self.validate_float = true
14
+
15
+ def convert # :nodoc:
16
+ @number = RoundingHelper.new(options).round(number)
17
+ @number = Float(number)
18
+
19
+ # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
20
+ unless options.key?(:strip_insignificant_zeros)
21
+ options[:strip_insignificant_zeros] = true
22
+ end
23
+
24
+ units = opts[:units]
25
+ exponent = calculate_exponent(units)
26
+ @number = number / (10**exponent)
27
+
28
+ rounded_number = NumberToRoundedConverter.convert(number, options)
29
+ unit = determine_unit(units, exponent)
30
+ format.gsub("%n", rounded_number).gsub("%u", unit).strip
31
+ end
32
+
33
+ private
34
+
35
+ def format
36
+ options[:format] || translate_in_locale("human.decimal_units.format")
37
+ end
38
+
39
+ def determine_unit(units, exponent)
40
+ exp = DECIMAL_UNITS[exponent]
41
+ case units
42
+ when Hash
43
+ units[exp] || ""
44
+ when String, Symbol
45
+ I18n.translate("#{units}.#{exp}", locale: options[:locale], count: number.to_i)
46
+ else
47
+ translate_in_locale("human.decimal_units.units.#{exp}", count: number.to_i)
48
+ end
49
+ end
50
+
51
+ def calculate_exponent(units)
52
+ exponent = number != 0 ? Math.log10(number.abs).floor : 0
53
+ unit_exponents(units).find { |e| exponent >= e } || 0
54
+ end
55
+
56
+ def unit_exponents(units)
57
+ case units
58
+ when Hash
59
+ units
60
+ when String, Symbol
61
+ I18n.translate(units.to_s, locale: options[:locale], raise: true)
62
+ when nil
63
+ translate_in_locale("human.decimal_units.units", raise: true)
64
+ else
65
+ raise ArgumentError, ":units must be a Hash or String translation scope."
66
+ end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by(&:-@)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
5
+ module ActiveSupport
6
+ module NumberHelper
7
+ class NumberToHumanSizeConverter < NumberConverter #:nodoc:
8
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
9
+
10
+ self.namespace = :human
11
+ self.validate_float = true
12
+
13
+ def convert
14
+ @number = Float(number)
15
+
16
+ # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
17
+ unless options.key?(:strip_insignificant_zeros)
18
+ options[:strip_insignificant_zeros] = true
19
+ end
20
+
21
+ if smaller_than_base?
22
+ number_to_format = number.to_i.to_s
23
+ else
24
+ human_size = number / (base**exponent)
25
+ number_to_format = NumberToRoundedConverter.convert(human_size, options)
26
+ end
27
+ conversion_format.gsub("%n", number_to_format).gsub("%u", unit)
28
+ end
29
+
30
+ private
31
+
32
+ def conversion_format
33
+ translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true)
34
+ end
35
+
36
+ def unit
37
+ translate_number_value_with_default(storage_unit_key, locale: options[:locale], count: number.to_i, raise: true)
38
+ end
39
+
40
+ def storage_unit_key
41
+ key_end = smaller_than_base? ? "byte" : STORAGE_UNITS[exponent]
42
+ "human.storage_units.units.#{key_end}"
43
+ end
44
+
45
+ def exponent
46
+ max = STORAGE_UNITS.size - 1
47
+ exp = (Math.log(number) / Math.log(base)).to_i
48
+ exp = max if exp > max # avoid overflow for the highest unit
49
+ exp
50
+ end
51
+
52
+ def smaller_than_base?
53
+ number.to_i < base
54
+ end
55
+
56
+ def base
57
+ 1024
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
5
+ module ActiveSupport
6
+ module NumberHelper
7
+ class NumberToPercentageConverter < NumberConverter # :nodoc:
8
+ self.namespace = :percentage
9
+
10
+ def convert
11
+ rounded_number = NumberToRoundedConverter.convert(number, options)
12
+ options[:format].gsub("%n", rounded_number)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/number_helper/number_converter"
4
+
5
+ module ActiveSupport
6
+ module NumberHelper
7
+ class NumberToPhoneConverter < NumberConverter #:nodoc:
8
+ def convert
9
+ str = country_code(opts[:country_code]).dup
10
+ str << convert_to_phone_number(number.to_s.strip)
11
+ str << phone_ext(opts[:extension])
12
+ end
13
+
14
+ private
15
+
16
+ def convert_to_phone_number(number)
17
+ if opts[:area_code]
18
+ convert_with_area_code(number)
19
+ else
20
+ convert_without_area_code(number)
21
+ end
22
+ end
23
+
24
+ def convert_with_area_code(number)
25
+ default_pattern = /(\d{1,3})(\d{3})(\d{4}$)/
26
+ number.gsub!(regexp_pattern(default_pattern),
27
+ "(\\1) \\2#{delimiter}\\3")
28
+ number
29
+ end
30
+
31
+ def convert_without_area_code(number)
32
+ default_pattern = /(\d{0,3})(\d{3})(\d{4})$/
33
+ number.gsub!(regexp_pattern(default_pattern),
34
+ "\\1#{delimiter}\\2#{delimiter}\\3")
35
+ number.slice!(0, 1) if start_with_delimiter?(number)
36
+ number
37
+ end
38
+
39
+ def start_with_delimiter?(number)
40
+ delimiter.present? && number.start_with?(delimiter)
41
+ end
42
+
43
+ def delimiter
44
+ opts[:delimiter] || "-"
45
+ end
46
+
47
+ def country_code(code)
48
+ code.blank? ? "" : "+#{code}#{delimiter}"
49
+ end
50
+
51
+ def phone_ext(ext)
52
+ ext.blank? ? "" : " x #{ext}"
53
+ end
54
+
55
+ def regexp_pattern(default_pattern)
56
+ opts.fetch :pattern, default_pattern
57
+ end
58
+ end
59
+ end
60
+ end