activesupport 4.0.12 → 7.0.2.4

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 (295) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +249 -501
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +48 -0
  8. data/lib/active_support/backtrace_cleaner.rb +41 -13
  9. data/lib/active_support/benchmarkable.rb +7 -15
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +96 -74
  12. data/lib/active_support/cache/mem_cache_store.rb +211 -103
  13. data/lib/active_support/cache/memory_store.rb +90 -58
  14. data/lib/active_support/cache/null_store.rb +19 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +468 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +86 -83
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  18. data/lib/active_support/cache.rb +580 -241
  19. data/lib/active_support/callbacks.rb +812 -425
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +103 -14
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
  23. data/lib/active_support/concurrency/share_lock.rb +226 -0
  24. data/lib/active_support/configurable.rb +21 -19
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +47 -1
  27. data/lib/active_support/core_ext/array/conversions.rb +35 -44
  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 +26 -16
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  34. data/lib/active_support/core_ext/array.rb +10 -7
  35. data/lib/active_support/core_ext/benchmark.rb +5 -3
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
  37. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  38. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
  40. data/lib/active_support/core_ext/class/subclasses.rb +25 -26
  41. data/lib/active_support/core_ext/class.rb +4 -4
  42. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  43. data/lib/active_support/core_ext/date/blank.rb +14 -0
  44. data/lib/active_support/core_ext/date/calculations.rb +31 -18
  45. data/lib/active_support/core_ext/date/conversions.rb +43 -32
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +5 -34
  48. data/lib/active_support/core_ext/date.rb +7 -4
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -0
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +79 -38
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +8 -4
  59. data/lib/active_support/core_ext/digest/uuid.rb +79 -0
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +249 -17
  62. data/lib/active_support/core_ext/file/atomic.rb +41 -32
  63. data/lib/active_support/core_ext/file.rb +3 -1
  64. data/lib/active_support/core_ext/hash/conversions.rb +71 -49
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +14 -5
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +39 -56
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -23
  72. data/lib/active_support/core_ext/hash.rb +10 -8
  73. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +11 -33
  76. data/lib/active_support/core_ext/integer.rb +5 -3
  77. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  80. data/lib/active_support/core_ext/kernel.rb +5 -4
  81. data/lib/active_support/core_ext/load_error.rb +5 -21
  82. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  83. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  84. data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +186 -44
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
  87. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  88. data/lib/active_support/core_ext/module/delegation.rb +172 -45
  89. data/lib/active_support/core_ext/module/deprecation.rb +3 -3
  90. data/lib/active_support/core_ext/module/introspection.rb +23 -38
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -10
  94. data/lib/active_support/core_ext/name_error.rb +45 -4
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +37 -50
  99. data/lib/active_support/core_ext/numeric.rb +6 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +70 -20
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
  104. data/lib/active_support/core_ext/object/duplicable.rb +17 -47
  105. data/lib/active_support/core_ext/object/inclusion.rb +18 -15
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +244 -0
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +21 -8
  110. data/lib/active_support/core_ext/object/try.rb +106 -26
  111. data/lib/active_support/core_ext/object/with_options.rb +64 -5
  112. data/lib/active_support/core_ext/object.rb +14 -12
  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 +37 -15
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +18 -17
  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 +2 -0
  121. data/lib/active_support/core_ext/range.rb +7 -4
  122. data/lib/active_support/core_ext/regexp.rb +10 -1
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string/access.rb +42 -51
  125. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  126. data/lib/active_support/core_ext/string/conversions.rb +18 -13
  127. data/lib/active_support/core_ext/string/exclude.rb +5 -3
  128. data/lib/active_support/core_ext/string/filters.rb +97 -7
  129. data/lib/active_support/core_ext/string/indent.rb +6 -4
  130. data/lib/active_support/core_ext/string/inflections.rb +106 -25
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +18 -9
  133. data/lib/active_support/core_ext/string/output_safety.rb +227 -54
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +6 -5
  136. data/lib/active_support/core_ext/string/zones.rb +4 -1
  137. data/lib/active_support/core_ext/string.rb +15 -13
  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 +3 -1
  141. data/lib/active_support/core_ext/time/calculations.rb +178 -116
  142. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  143. data/lib/active_support/core_ext/time/conversions.rb +37 -25
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +44 -42
  146. data/lib/active_support/core_ext/time.rb +8 -5
  147. data/lib/active_support/core_ext/uri.rb +4 -25
  148. data/lib/active_support/core_ext.rb +4 -2
  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 +3 -1
  152. data/lib/active_support/dependencies/interlock.rb +49 -0
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +71 -696
  155. data/lib/active_support/deprecation/behaviors.rb +65 -16
  156. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  159. data/lib/active_support/deprecation/method_wrappers.rb +62 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
  161. data/lib/active_support/deprecation/reporting.rb +81 -18
  162. data/lib/active_support/deprecation.rb +19 -11
  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 +123 -0
  166. data/lib/active_support/duration/iso8601_serializer.rb +67 -0
  167. data/lib/active_support/duration.rb +437 -39
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +117 -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 +170 -0
  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 +151 -0
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +8 -0
  178. data/lib/active_support/file_update_checker.rb +62 -37
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +17 -0
  181. data/lib/active_support/gzip.rb +7 -5
  182. data/lib/active_support/hash_with_indifferent_access.rb +207 -54
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +10 -6
  185. data/lib/active_support/i18n_railtie.rb +48 -19
  186. data/lib/active_support/inflections.rb +19 -12
  187. data/lib/active_support/inflector/inflections.rb +97 -37
  188. data/lib/active_support/inflector/methods.rb +192 -157
  189. data/lib/active_support/inflector/transliterate.rb +83 -33
  190. data/lib/active_support/inflector.rb +7 -5
  191. data/lib/active_support/isolated_execution_state.rb +64 -0
  192. data/lib/active_support/json/decoding.rb +37 -42
  193. data/lib/active_support/json/encoding.rb +93 -293
  194. data/lib/active_support/json.rb +4 -2
  195. data/lib/active_support/key_generator.rb +30 -47
  196. data/lib/active_support/lazy_load_hooks.rb +54 -21
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +10 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  200. data/lib/active_support/log_subscriber.rb +61 -18
  201. data/lib/active_support/logger.rb +40 -4
  202. data/lib/active_support/logger_silence.rb +17 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +69 -0
  204. data/lib/active_support/message_encryptor.rb +178 -55
  205. data/lib/active_support/message_verifier.rb +195 -26
  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 +45 -92
  210. data/lib/active_support/multibyte/unicode.rb +44 -377
  211. data/lib/active_support/multibyte.rb +5 -3
  212. data/lib/active_support/notifications/fanout.rb +177 -44
  213. data/lib/active_support/notifications/instrumenter.rb +117 -17
  214. data/lib/active_support/notifications.rb +106 -39
  215. data/lib/active_support/number_helper/number_converter.rb +181 -0
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +59 -0
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  223. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  224. data/lib/active_support/number_helper.rb +152 -394
  225. data/lib/active_support/option_merger.rb +18 -5
  226. data/lib/active_support/ordered_hash.rb +8 -6
  227. data/lib/active_support/ordered_options.rb +43 -7
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +24 -11
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +10 -11
  232. data/lib/active_support/railtie.rb +118 -12
  233. data/lib/active_support/reloader.rb +130 -0
  234. data/lib/active_support/rescuable.rb +112 -57
  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 +38 -0
  238. data/lib/active_support/string_inquirer.rb +11 -4
  239. data/lib/active_support/subscriber.rb +109 -39
  240. data/lib/active_support/tagged_logging.rb +54 -17
  241. data/lib/active_support/test_case.rb +121 -37
  242. data/lib/active_support/testing/assertions.rb +177 -39
  243. data/lib/active_support/testing/autorun.rb +5 -3
  244. data/lib/active_support/testing/constant_lookup.rb +3 -6
  245. data/lib/active_support/testing/declarative.rb +10 -22
  246. data/lib/active_support/testing/deprecation.rb +65 -11
  247. data/lib/active_support/testing/file_fixtures.rb +38 -0
  248. data/lib/active_support/testing/isolation.rb +56 -87
  249. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  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 +30 -10
  255. data/lib/active_support/testing/stream.rb +41 -0
  256. data/lib/active_support/testing/tagged_logging.rb +6 -4
  257. data/lib/active_support/testing/time_helpers.rb +246 -0
  258. data/lib/active_support/time.rb +13 -13
  259. data/lib/active_support/time_with_zone.rb +315 -90
  260. data/lib/active_support/values/time_zone.rb +306 -135
  261. data/lib/active_support/version.rb +6 -7
  262. data/lib/active_support/xml_mini/jdom.rb +117 -115
  263. data/lib/active_support/xml_mini/libxml.rb +22 -21
  264. data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
  265. data/lib/active_support/xml_mini/nokogiri.rb +19 -19
  266. data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
  267. data/lib/active_support/xml_mini/rexml.rb +25 -17
  268. data/lib/active_support/xml_mini.rb +67 -56
  269. data/lib/active_support.rb +58 -3
  270. metadata +125 -66
  271. data/lib/active_support/basic_object.rb +0 -11
  272. data/lib/active_support/buffered_logger.rb +0 -21
  273. data/lib/active_support/concurrency/latch.rb +0 -27
  274. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  275. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  276. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
  277. data/lib/active_support/core_ext/date_time/zones.rb +0 -24
  278. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  279. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  280. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  281. data/lib/active_support/core_ext/logger.rb +0 -67
  282. data/lib/active_support/core_ext/marshal.rb +0 -21
  283. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  284. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  285. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  286. data/lib/active_support/core_ext/proc.rb +0 -17
  287. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  288. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  289. data/lib/active_support/core_ext/struct.rb +0 -6
  290. data/lib/active_support/core_ext/thread.rb +0 -79
  291. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  292. data/lib/active_support/file_watcher.rb +0 -36
  293. data/lib/active_support/json/variable.rb +0 -18
  294. data/lib/active_support/testing/pending.rb +0 -14
  295. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,6 +1,7 @@
1
- require 'active_support/notifications/instrumenter'
2
- require 'active_support/notifications/fanout'
3
- require 'active_support/per_thread_registry'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/notifications/instrumenter"
4
+ require "active_support/notifications/fanout"
4
5
 
5
6
  module ActiveSupport
6
7
  # = Notifications
@@ -13,10 +14,10 @@ module ActiveSupport
13
14
  # To instrument an event you just need to do:
14
15
  #
15
16
  # ActiveSupport::Notifications.instrument('render', extra: :information) do
16
- # render text: 'Foo'
17
+ # render plain: 'Foo'
17
18
  # end
18
19
  #
19
- # That executes the block first and notifies all subscribers once done.
20
+ # That first executes the block and then notifies all subscribers once done.
20
21
  #
21
22
  # In the example above +render+ is the name of the event, and the rest is called
22
23
  # the _payload_. The payload is a mechanism that allows instrumenters to pass
@@ -32,10 +33,23 @@ module ActiveSupport
32
33
  # name # => String, name of the event (such as 'render' from above)
33
34
  # start # => Time, when the instrumented block started execution
34
35
  # finish # => Time, when the instrumented block ended execution
35
- # id # => String, unique ID for this notification
36
+ # id # => String, unique ID for the instrumenter that fired the event
36
37
  # payload # => Hash, the payload
37
38
  # end
38
39
  #
40
+ # Here, the +start+ and +finish+ values represent wall-clock time. If you are
41
+ # concerned about accuracy, you can register a monotonic subscriber.
42
+ #
43
+ # ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
44
+ # name # => String, name of the event (such as 'render' from above)
45
+ # start # => Monotonic time, when the instrumented block started execution
46
+ # finish # => Monotonic time, when the instrumented block ended execution
47
+ # id # => String, unique ID for the instrumenter that fired the event
48
+ # payload # => Hash, the payload
49
+ # end
50
+ #
51
+ # The +start+ and +finish+ values above represent monotonic time.
52
+ #
39
53
  # For instance, let's store all "render" events in an array:
40
54
  #
41
55
  # events = []
@@ -48,7 +62,7 @@ module ActiveSupport
48
62
  # The block is saved and will be called whenever someone instruments "render":
49
63
  #
50
64
  # ActiveSupport::Notifications.instrument('render', extra: :information) do
51
- # render text: 'Foo'
65
+ # render plain: 'Foo'
52
66
  # end
53
67
  #
54
68
  # event = events.first
@@ -57,20 +71,25 @@ module ActiveSupport
57
71
  # event.payload # => { extra: :information }
58
72
  #
59
73
  # The block in the <tt>subscribe</tt> call gets the name of the event, start
60
- # timestamp, end timestamp, a string with a unique identifier for that event
74
+ # timestamp, end timestamp, a string with a unique identifier for that event's instrumenter
61
75
  # (something like "535801666f04d0298cd6"), and a hash with the payload, in
62
76
  # that order.
63
77
  #
64
78
  # If an exception happens during that particular instrumentation the payload will
65
79
  # have a key <tt>:exception</tt> with an array of two elements as value: a string with
66
80
  # the name of the exception class, and the exception message.
81
+ # The <tt>:exception_object</tt> key of the payload will have the exception
82
+ # itself as the value:
67
83
  #
68
- # As the previous example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
84
+ # event.payload[:exception] # => ["ArgumentError", "Invalid value"]
85
+ # event.payload[:exception_object] # => #<ArgumentError: Invalid value>
86
+ #
87
+ # As the earlier example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
69
88
  # is able to take the arguments as they come and provide an object-oriented
70
89
  # interface to that data.
71
90
  #
72
- # It is also possible to pass an object as the second parameter passed to the
73
- # <tt>subscribe</tt> method instead of a block:
91
+ # It is also possible to pass an object which responds to <tt>call</tt> method
92
+ # as the second parameter to the <tt>subscribe</tt> method instead of a block:
74
93
  #
75
94
  # module ActionController
76
95
  # class PageRequest
@@ -128,6 +147,16 @@ module ActiveSupport
128
147
  # during the execution of the block. The callback is unsubscribed automatically
129
148
  # after that.
130
149
  #
150
+ # To record +started+ and +finished+ values with monotonic time,
151
+ # specify the optional <tt>:monotonic</tt> option to the
152
+ # <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
153
+ # to +false+ by default.
154
+ #
155
+ # callback = lambda {|name, started, finished, unique_id, payload| ... }
156
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
157
+ # ...
158
+ # end
159
+ #
131
160
  # === Manual Unsubscription
132
161
  #
133
162
  # The +subscribe+ method returns a subscriber object:
@@ -141,10 +170,24 @@ module ActiveSupport
141
170
  #
142
171
  # ActiveSupport::Notifications.unsubscribe(subscriber)
143
172
  #
173
+ # You can also unsubscribe by passing the name of the subscriber object. Note
174
+ # that this will unsubscribe all subscriptions with the given name:
175
+ #
176
+ # ActiveSupport::Notifications.unsubscribe("render")
177
+ #
178
+ # Subscribers using a regexp or other pattern-matching object will remain subscribed
179
+ # to all events that match their original pattern, unless those events match a string
180
+ # passed to +unsubscribe+:
181
+ #
182
+ # subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
183
+ # ActiveSupport::Notifications.unsubscribe('render_template.action_view')
184
+ # subscriber.matches?('render_template.action_view') # => false
185
+ # subscriber.matches?('render_partial.action_view') # => true
186
+ #
144
187
  # == Default Queue
145
188
  #
146
- # Notifications ships with a queue implementation that consumes and publish events
147
- # to log subscribers in a thread. You can use any queue implementation you want.
189
+ # Notifications ships with a queue implementation that consumes and publishes events
190
+ # to all log subscribers. You can use any queue implementation you want.
148
191
  #
149
192
  module Notifications
150
193
  class << self
@@ -154,6 +197,10 @@ module ActiveSupport
154
197
  notifier.publish(name, *args)
155
198
  end
156
199
 
200
+ def publish_event(event) # :nodoc:
201
+ notifier.publish_event(event)
202
+ end
203
+
157
204
  def instrument(name, payload = {})
158
205
  if notifier.listening?(name)
159
206
  instrumenter.instrument(name, payload) { yield payload if block_given? }
@@ -162,44 +209,64 @@ module ActiveSupport
162
209
  end
163
210
  end
164
211
 
165
- def subscribe(*args, &block)
166
- notifier.subscribe(*args, &block)
212
+ # Subscribe to a given event name with the passed +block+.
213
+ #
214
+ # You can subscribe to events by passing a String to match exact event
215
+ # names, or by passing a Regexp to match all events that match a pattern.
216
+ #
217
+ # ActiveSupport::Notifications.subscribe(/render/) do |*args|
218
+ # @event = ActiveSupport::Notifications::Event.new(*args)
219
+ # end
220
+ #
221
+ # The +block+ will receive five parameters with information about the event:
222
+ #
223
+ # ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
224
+ # name # => String, name of the event (such as 'render' from above)
225
+ # start # => Time, when the instrumented block started execution
226
+ # finish # => Time, when the instrumented block ended execution
227
+ # id # => String, unique ID for the instrumenter that fired the event
228
+ # payload # => Hash, the payload
229
+ # end
230
+ #
231
+ # If the block passed to the method only takes one parameter,
232
+ # it will yield an event object to the block:
233
+ #
234
+ # ActiveSupport::Notifications.subscribe(/render/) do |event|
235
+ # @event = event
236
+ # end
237
+ #
238
+ # Raises an error if invalid event name type is passed:
239
+ #
240
+ # ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
241
+ # #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
242
+ #
243
+ def subscribe(pattern = nil, callback = nil, &block)
244
+ notifier.subscribe(pattern, callback, monotonic: false, &block)
245
+ end
246
+
247
+ def monotonic_subscribe(pattern = nil, callback = nil, &block)
248
+ notifier.subscribe(pattern, callback, monotonic: true, &block)
167
249
  end
168
250
 
169
- def subscribed(callback, *args, &block)
170
- subscriber = subscribe(*args, &callback)
251
+ def subscribed(callback, pattern = nil, monotonic: false, &block)
252
+ subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
171
253
  yield
172
254
  ensure
173
255
  unsubscribe(subscriber)
174
256
  end
175
257
 
176
- def unsubscribe(args)
177
- notifier.unsubscribe(args)
258
+ def unsubscribe(subscriber_or_name)
259
+ notifier.unsubscribe(subscriber_or_name)
178
260
  end
179
261
 
180
262
  def instrumenter
181
- InstrumentationRegistry.instrumenter_for(notifier)
182
- end
183
- end
184
-
185
- # This class is a registry which holds all of the +Instrumenter+ objects
186
- # in a particular thread local. To access the +Instrumenter+ object for a
187
- # particular +notifier+, you can call the following method:
188
- #
189
- # InstrumentationRegistry.instrumenter_for(notifier)
190
- #
191
- # The instrumenters for multiple notifiers are held in a single instance of
192
- # this class.
193
- class InstrumentationRegistry # :nodoc:
194
- extend ActiveSupport::PerThreadRegistry
195
-
196
- def initialize
197
- @registry = {}
263
+ registry[notifier] ||= Instrumenter.new(notifier)
198
264
  end
199
265
 
200
- def instrumenter_for(notifier)
201
- @registry[notifier] ||= Instrumenter.new(notifier)
202
- end
266
+ private
267
+ def registry
268
+ ActiveSupport::IsolatedExecutionState[:active_support_notifications_registry] ||= {}
269
+ end
203
270
  end
204
271
 
205
272
  self.notifier = Fanout.new
@@ -0,0 +1,181 @@
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 (e.g.: 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
+ def options
140
+ @options ||= format_options.merge(opts)
141
+ end
142
+
143
+ def format_options
144
+ default_format_options.merge!(i18n_format_options)
145
+ end
146
+
147
+ def default_format_options
148
+ options = DEFAULTS[:format].dup
149
+ options.merge!(DEFAULTS[namespace][:format]) if namespace
150
+ options
151
+ end
152
+
153
+ def i18n_format_options
154
+ locale = opts[:locale]
155
+ options = I18n.translate(:'number.format', locale: locale, default: {}).dup
156
+
157
+ if namespace
158
+ options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {}))
159
+ end
160
+
161
+ options
162
+ end
163
+
164
+ def translate_number_value_with_default(key, **i18n_options)
165
+ I18n.translate(key, **{ default: default_value(key), scope: :number }.merge!(i18n_options))
166
+ end
167
+
168
+ def translate_in_locale(key, **i18n_options)
169
+ translate_number_value_with_default(key, **{ locale: options[:locale] }.merge(i18n_options))
170
+ end
171
+
172
+ def default_value(key)
173
+ key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
174
+ end
175
+
176
+ def valid_float?
177
+ Float(number, exception: false)
178
+ end
179
+ end
180
+ end
181
+ 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
+ format = options[:format]
12
+
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!(/^-/, "")
23
+ end
24
+
25
+ format.gsub("%n", number_s).gsub("%u", options[:unit])
26
+ end
27
+
28
+ private
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,30 @@
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
+ def parts
18
+ left, right = number.to_s.split(".")
19
+ left.gsub!(delimiter_pattern) do |digit_to_delimit|
20
+ "#{digit_to_delimit}#{options[:delimiter]}"
21
+ end
22
+ [left, right].compact
23
+ end
24
+
25
+ def delimiter_pattern
26
+ options.fetch(:delimiter_pattern, DEFAULT_DELIMITER_REGEX)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,69 @@
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
+ def format
35
+ options[:format] || translate_in_locale("human.decimal_units.format")
36
+ end
37
+
38
+ def determine_unit(units, exponent)
39
+ exp = DECIMAL_UNITS[exponent]
40
+ case units
41
+ when Hash
42
+ units[exp] || ""
43
+ when String, Symbol
44
+ I18n.translate("#{units}.#{exp}", locale: options[:locale], count: number.to_i)
45
+ else
46
+ translate_in_locale("human.decimal_units.units.#{exp}", count: number.to_i)
47
+ end
48
+ end
49
+
50
+ def calculate_exponent(units)
51
+ exponent = number != 0 ? Math.log10(number.abs).floor : 0
52
+ unit_exponents(units).find { |e| exponent >= e } || 0
53
+ end
54
+
55
+ def unit_exponents(units)
56
+ case units
57
+ when Hash
58
+ units
59
+ when String, Symbol
60
+ I18n.translate(units.to_s, locale: options[:locale], raise: true)
61
+ when nil
62
+ translate_in_locale("human.decimal_units.units", raise: true)
63
+ else
64
+ raise ArgumentError, ":units must be a Hash or String translation scope."
65
+ end.keys.map { |e_name| INVERTED_DECIMAL_UNITS[e_name] }.sort_by(&:-@)
66
+ end
67
+ end
68
+ end
69
+ 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 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
+ def conversion_format
32
+ translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true)
33
+ end
34
+
35
+ def unit
36
+ translate_number_value_with_default(storage_unit_key, locale: options[:locale], count: number.to_i, raise: true)
37
+ end
38
+
39
+ def storage_unit_key
40
+ key_end = smaller_than_base? ? "byte" : STORAGE_UNITS[exponent]
41
+ "human.storage_units.units.#{key_end}"
42
+ end
43
+
44
+ def exponent
45
+ max = STORAGE_UNITS.size - 1
46
+ exp = (Math.log(number) / Math.log(base)).to_i
47
+ exp = max if exp > max # avoid overflow for the highest unit
48
+ exp
49
+ end
50
+
51
+ def smaller_than_base?
52
+ number.to_i < base
53
+ end
54
+
55
+ def base
56
+ 1024
57
+ end
58
+ end
59
+ end
60
+ 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