activesupport 5.1.1 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (262) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +360 -442
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -4
  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 +65 -53
  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 +68 -22
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +305 -127
  19. data/lib/active_support/callbacks.rb +106 -98
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -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 +46 -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 +3 -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 +6 -101
  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 +7 -2
  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 +76 -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 +73 -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 +208 -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 +117 -0
  146. data/lib/active_support/dependencies.rb +135 -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 +30 -15
  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 +20 -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 +179 -41
  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 +3 -0
  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 +62 -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 +134 -37
  171. data/lib/active_support/i18n.rb +4 -1
  172. data/lib/active_support/i18n_railtie.rb +20 -11
  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 +33 -10
  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 +46 -13
  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 +101 -33
  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 +8 -7
  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 +16 -53
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +41 -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 +3 -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 +11 -10
  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 -4
  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 +8 -4
  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 +55 -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 +81 -35
  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:
@@ -9,9 +13,10 @@ module ActiveSupport
9
13
  self.validate_float = true
10
14
 
11
15
  def convert # :nodoc:
16
+ @number = RoundingHelper.new(options).round(number)
12
17
  @number = Float(number)
13
18
 
14
- # 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.
15
20
  unless options.key?(:strip_insignificant_zeros)
16
21
  options[:strip_insignificant_zeros] = true
17
22
  end
@@ -20,16 +25,12 @@ module ActiveSupport
20
25
  exponent = calculate_exponent(units)
21
26
  @number = number / (10**exponent)
22
27
 
23
- until (rounded_number = NumberToRoundedConverter.convert(number, options)) != NumberToRoundedConverter.convert(1000, options)
24
- @number = number / 1000.0
25
- exponent += 3
26
- end
28
+ rounded_number = NumberToRoundedConverter.convert(number, options)
27
29
  unit = determine_unit(units, exponent)
28
- format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, unit).strip
30
+ format.gsub("%n", rounded_number).gsub("%u", unit).strip
29
31
  end
30
32
 
31
33
  private
32
-
33
34
  def format
34
35
  options[:format] || translate_in_locale("human.decimal_units.format")
35
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:
@@ -5,40 +9,28 @@ module ActiveSupport
5
9
  self.validate_float = true
6
10
 
7
11
  def convert
8
- precision = options.delete :precision
9
-
10
- if precision
11
- case number
12
- when Float, String
13
- @number = BigDecimal(number.to_s)
14
- when Rational
15
- @number = BigDecimal(number, digit_count(number.to_i) + precision)
16
- else
17
- @number = number.to_d
18
- end
12
+ helper = RoundingHelper.new(options)
13
+ rounded_number = helper.round(number)
19
14
 
20
- if options.delete(:significant) && precision > 0
21
- digits, rounded_number = digits_and_rounded_number(precision)
15
+ if precision = options[:precision]
16
+ if options[:significant] && precision > 0
17
+ digits = helper.digit_count(rounded_number)
22
18
  precision -= digits
23
19
  precision = 0 if precision < 0 # don't let it be negative
24
- else
25
- rounded_number = number.round(precision)
26
- rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite?
27
- rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
28
20
  end
29
21
 
30
22
  formatted_string =
31
- if BigDecimal === rounded_number && rounded_number.finite?
23
+ if rounded_number.nan? || rounded_number.infinite? || rounded_number == rounded_number.to_i
24
+ "%00.#{precision}f" % rounded_number
25
+ else
32
26
  s = rounded_number.to_s("F")
33
- s << "0".freeze * precision
34
- a, b = s.split(".".freeze, 2)
35
- a << ".".freeze
27
+ s << "0" * precision
28
+ a, b = s.split(".", 2)
29
+ a << "."
36
30
  a << b[0, precision]
37
- else
38
- "%00.#{precision}f" % rounded_number
39
31
  end
40
32
  else
41
- formatted_string = number
33
+ formatted_string = rounded_number
42
34
  end
43
35
 
44
36
  delimited_number = NumberToDelimitedConverter.convert(formatted_string, options)
@@ -46,27 +38,6 @@ module ActiveSupport
46
38
  end
47
39
 
48
40
  private
49
-
50
- def digits_and_rounded_number(precision)
51
- if zero?
52
- [1, 0]
53
- else
54
- digits = digit_count(number)
55
- multiplier = 10**(digits - precision)
56
- rounded_number = calculate_rounded_number(multiplier)
57
- digits = digit_count(rounded_number) # After rounding, the number of digits may have changed
58
- [digits, rounded_number]
59
- end
60
- end
61
-
62
- def calculate_rounded_number(multiplier)
63
- (number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier
64
- end
65
-
66
- def digit_count(number)
67
- number.zero? ? 1 : (Math.log10(absolute_number(number)) + 1).floor
68
- end
69
-
70
41
  def strip_insignificant_zeros
71
42
  options[:strip_insignificant_zeros]
72
43
  end
@@ -79,14 +50,6 @@ module ActiveSupport
79
50
  number
80
51
  end
81
52
  end
82
-
83
- def absolute_number(number)
84
- number.respond_to?(:abs) ? number.abs : number.to_d.abs
85
- end
86
-
87
- def zero?
88
- number.respond_to?(:zero?) ? number.zero? : number.to_d.zero?
89
- end
90
53
  end
91
54
  end
92
55
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module NumberHelper
5
+ class RoundingHelper # :nodoc:
6
+ attr_reader :options
7
+
8
+ def initialize(options)
9
+ @options = options
10
+ end
11
+
12
+ def round(number)
13
+ precision = absolute_precision(number)
14
+ return number unless precision
15
+
16
+ rounded_number = convert_to_decimal(number).round(precision, options.fetch(:round_mode, :default))
17
+ rounded_number.zero? ? rounded_number.abs : rounded_number # prevent showing negative zeros
18
+ end
19
+
20
+ def digit_count(number)
21
+ return 1 if number.zero?
22
+ (Math.log10(number.abs) + 1).floor
23
+ end
24
+
25
+ private
26
+ def convert_to_decimal(number)
27
+ case number
28
+ when Float, String
29
+ BigDecimal(number.to_s)
30
+ when Rational
31
+ BigDecimal(number, digit_count(number.to_i) + options[:precision])
32
+ else
33
+ number.to_d
34
+ end
35
+ end
36
+
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
43
+ end
44
+
45
+ def significant
46
+ options[:significant]
47
+ end
48
+ end
49
+ end
50
+ end