activesupport 5.1.7 → 6.1.7

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 (262) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +434 -490
  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 +6 -2
  8. data/lib/active_support/backtrace_cleaner.rb +31 -3
  9. data/lib/active_support/benchmarkable.rb +3 -1
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +37 -36
  12. data/lib/active_support/cache/mem_cache_store.rb +72 -56
  13. data/lib/active_support/cache/memory_store.rb +61 -33
  14. data/lib/active_support/cache/null_store.rb +10 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +67 -21
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +310 -126
  19. data/lib/active_support/callbacks.rb +106 -100
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  22. data/lib/active_support/concurrency/share_lock.rb +2 -1
  23. data/lib/active_support/configurable.rb +12 -14
  24. data/lib/active_support/configuration_file.rb +51 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +7 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +2 -0
  30. data/lib/active_support/core_ext/array/inquiry.rb +2 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +3 -1
  33. data/lib/active_support/core_ext/benchmark.rb +4 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
  35. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  36. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -40
  39. data/lib/active_support/core_ext/class.rb +2 -0
  40. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  41. data/lib/active_support/core_ext/date/blank.rb +2 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +8 -5
  43. data/lib/active_support/core_ext/date/conversions.rb +12 -10
  44. data/lib/active_support/core_ext/date/zones.rb +2 -0
  45. data/lib/active_support/core_ext/date.rb +2 -0
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  50. data/lib/active_support/core_ext/date_time/blank.rb +2 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  53. data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
  54. data/lib/active_support/core_ext/date_time.rb +2 -0
  55. data/lib/active_support/core_ext/digest/uuid.rb +4 -1
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +174 -71
  58. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  59. data/lib/active_support/core_ext/file.rb +2 -0
  60. data/lib/active_support/core_ext/hash/conversions.rb +7 -5
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
  65. data/lib/active_support/core_ext/hash/keys.rb +3 -30
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +3 -2
  69. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +7 -14
  72. data/lib/active_support/core_ext/integer.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  74. data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +2 -1
  77. data/lib/active_support/core_ext/load_error.rb +3 -8
  78. data/lib/active_support/core_ext/marshal.rb +4 -0
  79. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
  84. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  85. data/lib/active_support/core_ext/module/delegation.rb +103 -58
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +3 -1
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +131 -129
  94. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  95. data/lib/active_support/core_ext/numeric.rb +2 -1
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +13 -3
  98. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  99. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  100. data/lib/active_support/core_ext/object/duplicable.rb +9 -114
  101. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +22 -2
  104. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  105. data/lib/active_support/core_ext/object/to_query.rb +2 -0
  106. data/lib/active_support/core_ext/object/try.rb +19 -7
  107. data/lib/active_support/core_ext/object/with_options.rb +4 -2
  108. data/lib/active_support/core_ext/object.rb +2 -0
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +4 -1
  115. data/lib/active_support/core_ext/regexp.rb +10 -5
  116. data/lib/active_support/core_ext/securerandom.rb +25 -3
  117. data/lib/active_support/core_ext/string/access.rb +7 -16
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +3 -0
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +44 -1
  122. data/lib/active_support/core_ext/string/indent.rb +2 -0
  123. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  124. data/lib/active_support/core_ext/string/inquiry.rb +3 -0
  125. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  126. data/lib/active_support/core_ext/string/output_safety.rb +104 -20
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  129. data/lib/active_support/core_ext/string/zones.rb +2 -0
  130. data/lib/active_support/core_ext/string.rb +2 -0
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  134. data/lib/active_support/core_ext/time/calculations.rb +76 -18
  135. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +4 -0
  137. data/lib/active_support/core_ext/time/zones.rb +6 -4
  138. data/lib/active_support/core_ext/time.rb +2 -0
  139. data/lib/active_support/core_ext/uri.rb +11 -6
  140. data/lib/active_support/core_ext.rb +3 -1
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +210 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +2 -0
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +120 -0
  146. data/lib/active_support/dependencies.rb +134 -60
  147. data/lib/active_support/deprecation/behaviors.rb +43 -11
  148. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  151. data/lib/active_support/deprecation/method_wrappers.rb +29 -21
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
  153. data/lib/active_support/deprecation/reporting.rb +54 -9
  154. data/lib/active_support/deprecation.rb +9 -2
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +22 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +6 -6
  158. data/lib/active_support/duration/iso8601_serializer.rb +20 -14
  159. data/lib/active_support/duration.rb +102 -45
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +84 -117
  164. data/lib/active_support/execution_wrapper.rb +19 -13
  165. data/lib/active_support/executor.rb +2 -0
  166. data/lib/active_support/file_update_checker.rb +2 -1
  167. data/lib/active_support/fork_tracker.rb +64 -0
  168. data/lib/active_support/gem_version.rb +3 -1
  169. data/lib/active_support/gzip.rb +2 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +123 -41
  171. data/lib/active_support/i18n.rb +4 -1
  172. data/lib/active_support/i18n_railtie.rb +19 -14
  173. data/lib/active_support/inflections.rb +2 -0
  174. data/lib/active_support/inflector/inflections.rb +19 -8
  175. data/lib/active_support/inflector/methods.rb +87 -77
  176. data/lib/active_support/inflector/transliterate.rb +56 -18
  177. data/lib/active_support/inflector.rb +2 -0
  178. data/lib/active_support/json/decoding.rb +27 -26
  179. data/lib/active_support/json/encoding.rb +13 -3
  180. data/lib/active_support/json.rb +2 -0
  181. data/lib/active_support/key_generator.rb +3 -33
  182. data/lib/active_support/lazy_load_hooks.rb +7 -2
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +2 -0
  186. data/lib/active_support/log_subscriber.rb +42 -11
  187. data/lib/active_support/logger.rb +4 -17
  188. data/lib/active_support/logger_silence.rb +13 -20
  189. data/lib/active_support/logger_thread_safe_level.rb +54 -7
  190. data/lib/active_support/message_encryptor.rb +100 -32
  191. data/lib/active_support/message_verifier.rb +85 -14
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +12 -68
  196. data/lib/active_support/multibyte/unicode.rb +17 -327
  197. data/lib/active_support/multibyte.rb +2 -0
  198. data/lib/active_support/notifications/fanout.rb +118 -16
  199. data/lib/active_support/notifications/instrumenter.rb +73 -9
  200. data/lib/active_support/notifications.rb +74 -8
  201. data/lib/active_support/number_helper/number_converter.rb +7 -6
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -2
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -2
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
  209. data/lib/active_support/number_helper/rounding_helper.rb +16 -30
  210. data/lib/active_support/number_helper.rb +40 -12
  211. data/lib/active_support/option_merger.rb +24 -3
  212. data/lib/active_support/ordered_hash.rb +3 -1
  213. data/lib/active_support/ordered_options.rb +17 -5
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +4 -1
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +3 -10
  218. data/lib/active_support/railtie.rb +60 -9
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +7 -6
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +6 -3
  224. data/lib/active_support/subscriber.rb +74 -24
  225. data/lib/active_support/tagged_logging.rb +44 -8
  226. data/lib/active_support/test_case.rb +94 -2
  227. data/lib/active_support/testing/assertions.rb +58 -20
  228. data/lib/active_support/testing/autorun.rb +2 -0
  229. data/lib/active_support/testing/constant_lookup.rb +2 -0
  230. data/lib/active_support/testing/declarative.rb +2 -0
  231. data/lib/active_support/testing/deprecation.rb +2 -1
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +4 -2
  234. data/lib/active_support/testing/method_call_assertions.rb +30 -1
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  239. data/lib/active_support/testing/stream.rb +3 -2
  240. data/lib/active_support/testing/tagged_logging.rb +2 -0
  241. data/lib/active_support/testing/time_helpers.rb +78 -13
  242. data/lib/active_support/time.rb +2 -0
  243. data/lib/active_support/time_with_zone.rb +113 -41
  244. data/lib/active_support/values/time_zone.rb +54 -25
  245. data/lib/active_support/version.rb +2 -0
  246. data/lib/active_support/xml_mini/jdom.rb +5 -4
  247. data/lib/active_support/xml_mini/libxml.rb +4 -2
  248. data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
  249. data/lib/active_support/xml_mini/nokogiri.rb +4 -2
  250. data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
  251. data/lib/active_support/xml_mini/rexml.rb +12 -3
  252. data/lib/active_support/xml_mini.rb +5 -11
  253. data/lib/active_support.rb +18 -13
  254. metadata +71 -32
  255. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  256. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  257. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  258. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  259. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  260. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  261. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  262. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "securerandom"
2
4
 
3
5
  module ActiveSupport
@@ -11,14 +13,15 @@ module ActiveSupport
11
13
  @notifier = notifier
12
14
  end
13
15
 
14
- # Instrument the given block by measuring the time taken to execute it
15
- # and publish it. Notice that events get sent even if an error occurs
16
- # in the passed-in block.
16
+ # Given a block, instrument it by measuring the time taken to execute
17
+ # and publish it. Without a block, simply send a message via the
18
+ # notifier. Notice that events get sent even if an error occurs in the
19
+ # passed-in block.
17
20
  def instrument(name, payload = {})
18
21
  # some of the listeners might have state
19
22
  listeners_state = start name, payload
20
23
  begin
21
- yield payload
24
+ yield payload if block_given?
22
25
  rescue Exception => e
23
26
  payload[:exception] = [e.class.name, e.message]
24
27
  payload[:exception_object] = e
@@ -43,15 +46,14 @@ module ActiveSupport
43
46
  end
44
47
 
45
48
  private
46
-
47
49
  def unique_id
48
50
  SecureRandom.hex(10)
49
51
  end
50
52
  end
51
53
 
52
54
  class Event
53
- attr_reader :name, :time, :transaction_id, :payload, :children
54
- attr_accessor :end
55
+ attr_reader :name, :time, :end, :transaction_id, :children
56
+ attr_accessor :payload
55
57
 
56
58
  def initialize(name, start, ending, transaction_id, payload)
57
59
  @name = name
@@ -60,7 +62,42 @@ module ActiveSupport
60
62
  @transaction_id = transaction_id
61
63
  @end = ending
62
64
  @children = []
63
- @duration = nil
65
+ @cpu_time_start = 0
66
+ @cpu_time_finish = 0
67
+ @allocation_count_start = 0
68
+ @allocation_count_finish = 0
69
+ end
70
+
71
+ # Record information at the time this event starts
72
+ def start!
73
+ @time = now
74
+ @cpu_time_start = now_cpu
75
+ @allocation_count_start = now_allocations
76
+ end
77
+
78
+ # Record information at the time this event finishes
79
+ def finish!
80
+ @cpu_time_finish = now_cpu
81
+ @end = now
82
+ @allocation_count_finish = now_allocations
83
+ end
84
+
85
+ # Returns the CPU time (in milliseconds) passed since the call to
86
+ # +start!+ and the call to +finish!+
87
+ def cpu_time
88
+ (@cpu_time_finish - @cpu_time_start) * 1000
89
+ end
90
+
91
+ # Returns the idle time time (in milliseconds) passed since the call to
92
+ # +start!+ and the call to +finish!+
93
+ def idle_time
94
+ duration - cpu_time
95
+ end
96
+
97
+ # Returns the number of allocations made since the call to +start!+ and
98
+ # the call to +finish!+
99
+ def allocations
100
+ @allocation_count_finish - @allocation_count_start
64
101
  end
65
102
 
66
103
  # Returns the difference in milliseconds between when the execution of the
@@ -76,7 +113,7 @@ module ActiveSupport
76
113
  #
77
114
  # @event.duration # => 1000.138
78
115
  def duration
79
- @duration ||= 1000.0 * (self.end - time)
116
+ 1000.0 * (self.end - time)
80
117
  end
81
118
 
82
119
  def <<(event)
@@ -86,6 +123,33 @@ module ActiveSupport
86
123
  def parent_of?(event)
87
124
  @children.include? event
88
125
  end
126
+
127
+ private
128
+ def now
129
+ Concurrent.monotonic_time
130
+ end
131
+
132
+ begin
133
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
134
+
135
+ def now_cpu
136
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
137
+ end
138
+ rescue
139
+ def now_cpu
140
+ 0
141
+ end
142
+ end
143
+
144
+ if defined?(JRUBY_VERSION)
145
+ def now_allocations
146
+ 0
147
+ end
148
+ else
149
+ def now_allocations
150
+ GC.stat :total_allocated_objects
151
+ end
152
+ end
89
153
  end
90
154
  end
91
155
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/notifications/instrumenter"
2
4
  require "active_support/notifications/fanout"
3
5
  require "active_support/per_thread_registry"
@@ -32,10 +34,23 @@ module ActiveSupport
32
34
  # name # => String, name of the event (such as 'render' from above)
33
35
  # start # => Time, when the instrumented block started execution
34
36
  # finish # => Time, when the instrumented block ended execution
35
- # id # => String, unique ID for this notification
37
+ # id # => String, unique ID for the instrumenter that fired the event
38
+ # payload # => Hash, the payload
39
+ # end
40
+ #
41
+ # Here, the +start+ and +finish+ values represent wall-clock time. If you are
42
+ # concerned about accuracy, you can register a monotonic subscriber.
43
+ #
44
+ # ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
45
+ # name # => String, name of the event (such as 'render' from above)
46
+ # start # => Monotonic time, when the instrumented block started execution
47
+ # finish # => Monotonic time, when the instrumented block ended execution
48
+ # id # => String, unique ID for the instrumenter that fired the event
36
49
  # payload # => Hash, the payload
37
50
  # end
38
51
  #
52
+ # The +start+ and +finish+ values above represent monotonic time.
53
+ #
39
54
  # For instance, let's store all "render" events in an array:
40
55
  #
41
56
  # events = []
@@ -57,7 +72,7 @@ module ActiveSupport
57
72
  # event.payload # => { extra: :information }
58
73
  #
59
74
  # 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
75
+ # timestamp, end timestamp, a string with a unique identifier for that event's instrumenter
61
76
  # (something like "535801666f04d0298cd6"), and a hash with the payload, in
62
77
  # that order.
63
78
  #
@@ -65,9 +80,12 @@ module ActiveSupport
65
80
  # have a key <tt>:exception</tt> with an array of two elements as value: a string with
66
81
  # the name of the exception class, and the exception message.
67
82
  # The <tt>:exception_object</tt> key of the payload will have the exception
68
- # itself as the value.
83
+ # itself as the value:
84
+ #
85
+ # event.payload[:exception] # => ["ArgumentError", "Invalid value"]
86
+ # event.payload[:exception_object] # => #<ArgumentError: Invalid value>
69
87
  #
70
- # As the previous example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
88
+ # As the earlier example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
71
89
  # is able to take the arguments as they come and provide an object-oriented
72
90
  # interface to that data.
73
91
  #
@@ -130,6 +148,16 @@ module ActiveSupport
130
148
  # during the execution of the block. The callback is unsubscribed automatically
131
149
  # after that.
132
150
  #
151
+ # To record +started+ and +finished+ values with monotonic time,
152
+ # specify the optional <tt>:monotonic</tt> option to the
153
+ # <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
154
+ # to +false+ by default.
155
+ #
156
+ # callback = lambda {|name, started, finished, unique_id, payload| ... }
157
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
158
+ # ...
159
+ # end
160
+ #
133
161
  # === Manual Unsubscription
134
162
  #
135
163
  # The +subscribe+ method returns a subscriber object:
@@ -148,6 +176,15 @@ module ActiveSupport
148
176
  #
149
177
  # ActiveSupport::Notifications.unsubscribe("render")
150
178
  #
179
+ # Subscribers using a regexp or other pattern-matching object will remain subscribed
180
+ # to all events that match their original pattern, unless those events match a string
181
+ # passed to +unsubscribe+:
182
+ #
183
+ # subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
184
+ # ActiveSupport::Notifications.unsubscribe('render_template.action_view')
185
+ # subscriber.matches?('render_template.action_view') # => false
186
+ # subscriber.matches?('render_partial.action_view') # => true
187
+ #
151
188
  # == Default Queue
152
189
  #
153
190
  # Notifications ships with a queue implementation that consumes and publishes events
@@ -169,12 +206,41 @@ module ActiveSupport
169
206
  end
170
207
  end
171
208
 
172
- def subscribe(*args, &block)
173
- notifier.subscribe(*args, &block)
209
+ # Subscribe to a given event name with the passed +block+.
210
+ #
211
+ # You can subscribe to events by passing a String to match exact event
212
+ # names, or by passing a Regexp to match all events that match a pattern.
213
+ #
214
+ # ActiveSupport::Notifications.subscribe(/render/) do |*args|
215
+ # @event = ActiveSupport::Notifications::Event.new(*args)
216
+ # end
217
+ #
218
+ # The +block+ will receive five parameters with information about the event:
219
+ #
220
+ # ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
221
+ # name # => String, name of the event (such as 'render' from above)
222
+ # start # => Time, when the instrumented block started execution
223
+ # finish # => Time, when the instrumented block ended execution
224
+ # id # => String, unique ID for the instrumenter that fired the event
225
+ # payload # => Hash, the payload
226
+ # end
227
+ #
228
+ # If the block passed to the method only takes one parameter,
229
+ # it will yield an event object to the block:
230
+ #
231
+ # ActiveSupport::Notifications.subscribe(/render/) do |event|
232
+ # @event = event
233
+ # end
234
+ def subscribe(pattern = nil, callback = nil, &block)
235
+ notifier.subscribe(pattern, callback, monotonic: false, &block)
236
+ end
237
+
238
+ def monotonic_subscribe(pattern = nil, callback = nil, &block)
239
+ notifier.subscribe(pattern, callback, monotonic: true, &block)
174
240
  end
175
241
 
176
- def subscribed(callback, *args, &block)
177
- subscriber = subscribe(*args, &callback)
242
+ def subscribed(callback, pattern = nil, monotonic: false, &block)
243
+ subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
178
244
  yield
179
245
  ensure
180
246
  unsubscribe(subscriber)
@@ -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)
@@ -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
@@ -9,21 +11,16 @@ module ActiveSupport
9
11
  number = self.number.to_s.strip
10
12
  format = options[:format]
11
13
 
12
- if number.to_f.negative?
14
+ if number.sub!(/^-/, "") &&
15
+ (options[:precision] != 0 || number.to_f > 0.5)
13
16
  format = options[:negative_format]
14
- number = absolute_value(number)
15
17
  end
16
18
 
17
19
  rounded_number = NumberToRoundedConverter.convert(number, options)
18
- format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, options[:unit])
20
+ format.gsub("%n", rounded_number).gsub("%u", options[:unit])
19
21
  end
20
22
 
21
23
  private
22
-
23
- def absolute_value(number)
24
- number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "")
25
- end
26
-
27
24
  def options
28
25
  @options ||= begin
29
26
  defaults = default_format_options.merge(i18n_opts)
@@ -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 NumberToDelimitedConverter < NumberConverter #:nodoc:
@@ -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,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 NumberToHumanSizeConverter < NumberConverter #:nodoc:
@@ -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
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,57 +10,41 @@ 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]
37
+ def absolute_precision(number)
38
+ if significant && options[:precision] > 0
39
+ options[:precision] - digit_count(convert_to_decimal(number))
40
+ else
41
+ options[:precision]
42
+ end
53
43
  end
54
44
 
55
45
  def significant
56
46
  options[:significant]
57
47
  end
58
-
59
- def absolute_number(number)
60
- number.respond_to?(:abs) ? number.abs : number.to_d.abs
61
- end
62
48
  end
63
49
  end
64
50
  end