activesupport 1.2.4 → 8.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +505 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support/actionable_error.rb +50 -0
  6. data/lib/active_support/all.rb +5 -0
  7. data/lib/active_support/array_inquirer.rb +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +234 -0
  9. data/lib/active_support/benchmark.rb +21 -0
  10. data/lib/active_support/benchmarkable.rb +53 -0
  11. data/lib/active_support/broadcast_logger.rb +238 -0
  12. data/lib/active_support/builder.rb +8 -0
  13. data/lib/active_support/cache/coder.rb +153 -0
  14. data/lib/active_support/cache/entry.rb +134 -0
  15. data/lib/active_support/cache/file_store.rb +244 -0
  16. data/lib/active_support/cache/mem_cache_store.rb +288 -0
  17. data/lib/active_support/cache/memory_store.rb +264 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +498 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +246 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1170 -0
  24. data/lib/active_support/callbacks.rb +960 -0
  25. data/lib/active_support/class_attribute.rb +33 -0
  26. data/lib/active_support/code_generator.rb +79 -0
  27. data/lib/active_support/concern.rb +217 -0
  28. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  29. data/lib/active_support/concurrency/null_lock.rb +13 -0
  30. data/lib/active_support/concurrency/share_lock.rb +225 -0
  31. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  32. data/lib/active_support/configurable.rb +193 -0
  33. data/lib/active_support/configuration_file.rb +60 -0
  34. data/lib/active_support/continuous_integration.rb +145 -0
  35. data/lib/active_support/core_ext/array/access.rb +100 -0
  36. data/lib/active_support/core_ext/array/conversions.rb +209 -26
  37. data/lib/active_support/core_ext/array/extract.rb +21 -0
  38. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  39. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  40. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  41. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  42. data/lib/active_support/core_ext/array.rb +8 -4
  43. data/lib/active_support/core_ext/benchmark.rb +6 -0
  44. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  45. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  46. data/lib/active_support/core_ext/class/attribute.rb +137 -0
  47. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  48. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  49. data/lib/active_support/core_ext/class.rb +4 -0
  50. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  51. data/lib/active_support/core_ext/date/blank.rb +18 -0
  52. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  53. data/lib/active_support/core_ext/date/conversions.rb +95 -28
  54. data/lib/active_support/core_ext/date/zones.rb +8 -0
  55. data/lib/active_support/core_ext/date.rb +6 -5
  56. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  57. data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
  58. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  59. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  60. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  62. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  63. data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
  64. data/lib/active_support/core_ext/date_time.rb +7 -0
  65. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  66. data/lib/active_support/core_ext/digest.rb +3 -0
  67. data/lib/active_support/core_ext/enumerable.rb +277 -7
  68. data/lib/active_support/core_ext/erb/util.rb +201 -0
  69. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  70. data/lib/active_support/core_ext/file.rb +3 -0
  71. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  72. data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
  73. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  74. data/lib/active_support/core_ext/hash/except.rb +12 -0
  75. data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
  76. data/lib/active_support/core_ext/hash/keys.rb +134 -44
  77. data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
  78. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  79. data/lib/active_support/core_ext/hash.rb +9 -8
  80. data/lib/active_support/core_ext/integer/inflections.rb +29 -13
  81. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  82. data/lib/active_support/core_ext/integer/time.rb +22 -0
  83. data/lib/active_support/core_ext/integer.rb +4 -6
  84. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  85. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  86. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  87. data/lib/active_support/core_ext/kernel.rb +4 -78
  88. data/lib/active_support/core_ext/load_error.rb +6 -35
  89. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  90. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  91. data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
  92. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  93. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  94. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  95. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  96. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  97. data/lib/active_support/core_ext/module/introspection.rb +65 -0
  98. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  99. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  100. data/lib/active_support/core_ext/module.rb +13 -0
  101. data/lib/active_support/core_ext/name_error.rb +59 -0
  102. data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
  103. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  104. data/lib/active_support/core_ext/numeric/time.rb +64 -57
  105. data/lib/active_support/core_ext/numeric.rb +4 -6
  106. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  107. data/lib/active_support/core_ext/object/blank.rb +199 -0
  108. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  109. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  110. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  111. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  112. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  113. data/lib/active_support/core_ext/object/json.rb +267 -0
  114. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  115. data/lib/active_support/core_ext/object/to_query.rb +93 -0
  116. data/lib/active_support/core_ext/object/try.rb +158 -0
  117. data/lib/active_support/core_ext/object/with.rb +46 -0
  118. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  119. data/lib/active_support/core_ext/object.rb +17 -0
  120. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  121. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  122. data/lib/active_support/core_ext/pathname.rb +4 -0
  123. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  124. data/lib/active_support/core_ext/range/conversions.rb +58 -17
  125. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  126. data/lib/active_support/core_ext/range/sole.rb +17 -0
  127. data/lib/active_support/core_ext/range.rb +5 -4
  128. data/lib/active_support/core_ext/regexp.rb +14 -0
  129. data/lib/active_support/core_ext/securerandom.rb +57 -0
  130. data/lib/active_support/core_ext/string/access.rb +93 -56
  131. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  132. data/lib/active_support/core_ext/string/conversions.rb +57 -16
  133. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  134. data/lib/active_support/core_ext/string/filters.rb +151 -0
  135. data/lib/active_support/core_ext/string/indent.rb +45 -0
  136. data/lib/active_support/core_ext/string/inflections.rb +297 -54
  137. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  138. data/lib/active_support/core_ext/string/multibyte.rb +67 -0
  139. data/lib/active_support/core_ext/string/output_safety.rb +235 -0
  140. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
  141. data/lib/active_support/core_ext/string/strip.rb +27 -0
  142. data/lib/active_support/core_ext/string/zones.rb +16 -0
  143. data/lib/active_support/core_ext/string.rb +14 -10
  144. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  145. data/lib/active_support/core_ext/symbol.rb +3 -0
  146. data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
  147. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  148. data/lib/active_support/core_ext/time/calculations.rb +358 -153
  149. data/lib/active_support/core_ext/time/compatibility.rb +15 -0
  150. data/lib/active_support/core_ext/time/conversions.rb +69 -30
  151. data/lib/active_support/core_ext/time/zones.rb +97 -0
  152. data/lib/active_support/core_ext/time.rb +6 -6
  153. data/lib/active_support/core_ext.rb +5 -1
  154. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  155. data/lib/active_support/current_attributes.rb +243 -0
  156. data/lib/active_support/deep_mergeable.rb +53 -0
  157. data/lib/active_support/delegation.rb +183 -0
  158. data/lib/active_support/dependencies/autoload.rb +72 -0
  159. data/lib/active_support/dependencies/interlock.rb +55 -0
  160. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  161. data/lib/active_support/dependencies.rb +84 -222
  162. data/lib/active_support/deprecation/behaviors.rb +148 -0
  163. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  164. data/lib/active_support/deprecation/deprecators.rb +104 -0
  165. data/lib/active_support/deprecation/disallowed.rb +54 -0
  166. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  167. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  168. data/lib/active_support/deprecation/reporting.rb +162 -0
  169. data/lib/active_support/deprecation.rb +81 -0
  170. data/lib/active_support/deprecator.rb +7 -0
  171. data/lib/active_support/descendants_tracker.rb +112 -0
  172. data/lib/active_support/digest.rb +22 -0
  173. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  174. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  175. data/lib/active_support/duration.rb +524 -0
  176. data/lib/active_support/editor.rb +70 -0
  177. data/lib/active_support/encrypted_configuration.rb +126 -0
  178. data/lib/active_support/encrypted_file.rb +133 -0
  179. data/lib/active_support/environment_inquirer.rb +40 -0
  180. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  181. data/lib/active_support/error_reporter.rb +318 -0
  182. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  183. data/lib/active_support/event_reporter.rb +592 -0
  184. data/lib/active_support/evented_file_update_checker.rb +185 -0
  185. data/lib/active_support/execution_context/test_helper.rb +13 -0
  186. data/lib/active_support/execution_context.rb +110 -0
  187. data/lib/active_support/execution_wrapper.rb +150 -0
  188. data/lib/active_support/executor/test_helper.rb +7 -0
  189. data/lib/active_support/executor.rb +8 -0
  190. data/lib/active_support/file_update_checker.rb +166 -0
  191. data/lib/active_support/fork_tracker.rb +43 -0
  192. data/lib/active_support/gem_version.rb +17 -0
  193. data/lib/active_support/gzip.rb +41 -0
  194. data/lib/active_support/hash_with_indifferent_access.rb +464 -0
  195. data/lib/active_support/html_safe_translation.rb +56 -0
  196. data/lib/active_support/i18n.rb +17 -0
  197. data/lib/active_support/i18n_railtie.rb +140 -0
  198. data/lib/active_support/inflections.rb +68 -49
  199. data/lib/active_support/inflector/inflections.rb +290 -0
  200. data/lib/active_support/inflector/methods.rb +387 -0
  201. data/lib/active_support/inflector/transliterate.rb +147 -0
  202. data/lib/active_support/inflector.rb +7 -164
  203. data/lib/active_support/isolated_execution_state.rb +76 -0
  204. data/lib/active_support/json/decoding.rb +78 -0
  205. data/lib/active_support/json/encoding.rb +256 -0
  206. data/lib/active_support/json.rb +4 -0
  207. data/lib/active_support/key_generator.rb +66 -0
  208. data/lib/active_support/lazy_load_hooks.rb +107 -0
  209. data/lib/active_support/locale/en.rb +33 -0
  210. data/lib/active_support/locale/en.yml +141 -0
  211. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  212. data/lib/active_support/log_subscriber.rb +188 -0
  213. data/lib/active_support/logger.rb +55 -0
  214. data/lib/active_support/logger_silence.rb +21 -0
  215. data/lib/active_support/logger_thread_safe_level.rb +50 -0
  216. data/lib/active_support/message_encryptor.rb +374 -0
  217. data/lib/active_support/message_encryptors.rb +193 -0
  218. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  219. data/lib/active_support/message_pack/extensions.rb +310 -0
  220. data/lib/active_support/message_pack/serializer.rb +63 -0
  221. data/lib/active_support/message_pack.rb +50 -0
  222. data/lib/active_support/message_verifier.rb +377 -0
  223. data/lib/active_support/message_verifiers.rb +189 -0
  224. data/lib/active_support/messages/codec.rb +65 -0
  225. data/lib/active_support/messages/metadata.rb +146 -0
  226. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  227. data/lib/active_support/messages/rotation_coordinator.rb +102 -0
  228. data/lib/active_support/messages/rotator.rb +69 -0
  229. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  230. data/lib/active_support/multibyte/chars.rb +188 -0
  231. data/lib/active_support/multibyte/unicode.rb +42 -0
  232. data/lib/active_support/multibyte.rb +27 -0
  233. data/lib/active_support/notifications/fanout.rb +467 -0
  234. data/lib/active_support/notifications/instrumenter.rb +240 -0
  235. data/lib/active_support/notifications.rb +281 -0
  236. data/lib/active_support/number_helper/number_converter.rb +190 -0
  237. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  238. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  239. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  240. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  241. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  242. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  243. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  244. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  245. data/lib/active_support/number_helper.rb +479 -0
  246. data/lib/active_support/option_merger.rb +38 -0
  247. data/lib/active_support/ordered_hash.rb +50 -0
  248. data/lib/active_support/ordered_options.rb +141 -25
  249. data/lib/active_support/parameter_filter.rb +157 -0
  250. data/lib/active_support/rails.rb +26 -0
  251. data/lib/active_support/railtie.rb +180 -0
  252. data/lib/active_support/reloader.rb +138 -0
  253. data/lib/active_support/rescuable.rb +176 -0
  254. data/lib/active_support/secure_compare_rotator.rb +58 -0
  255. data/lib/active_support/security_utils.rb +38 -0
  256. data/lib/active_support/string_inquirer.rb +35 -0
  257. data/lib/active_support/structured_event_subscriber.rb +99 -0
  258. data/lib/active_support/subscriber.rb +141 -0
  259. data/lib/active_support/syntax_error_proxy.rb +67 -0
  260. data/lib/active_support/tagged_logging.rb +157 -0
  261. data/lib/active_support/test_case.rb +365 -0
  262. data/lib/active_support/testing/assertions.rb +369 -0
  263. data/lib/active_support/testing/autorun.rb +10 -0
  264. data/lib/active_support/testing/constant_lookup.rb +51 -0
  265. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  266. data/lib/active_support/testing/declarative.rb +28 -0
  267. data/lib/active_support/testing/deprecation.rb +82 -0
  268. data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
  269. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  270. data/lib/active_support/testing/file_fixtures.rb +38 -0
  271. data/lib/active_support/testing/isolation.rb +121 -0
  272. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  273. data/lib/active_support/testing/notification_assertions.rb +92 -0
  274. data/lib/active_support/testing/parallelization/server.rb +98 -0
  275. data/lib/active_support/testing/parallelization/worker.rb +107 -0
  276. data/lib/active_support/testing/parallelization.rb +79 -0
  277. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  278. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  279. data/lib/active_support/testing/stream.rb +41 -0
  280. data/lib/active_support/testing/tagged_logging.rb +27 -0
  281. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  282. data/lib/active_support/testing/time_helpers.rb +273 -0
  283. data/lib/active_support/time.rb +20 -0
  284. data/lib/active_support/time_with_zone.rb +613 -0
  285. data/lib/active_support/values/time_zone.rb +599 -158
  286. data/lib/active_support/version.rb +7 -6
  287. data/lib/active_support/xml_mini/jdom.rb +175 -0
  288. data/lib/active_support/xml_mini/libxml.rb +80 -0
  289. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  290. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  291. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  292. data/lib/active_support/xml_mini/rexml.rb +137 -0
  293. data/lib/active_support/xml_mini.rb +212 -0
  294. data/lib/active_support.rb +122 -10
  295. metadata +524 -93
  296. data/CHANGELOG +0 -283
  297. data/lib/active_support/binding_of_caller.rb +0 -84
  298. data/lib/active_support/breakpoint.rb +0 -523
  299. data/lib/active_support/class_attribute_accessors.rb +0 -57
  300. data/lib/active_support/class_inheritable_attributes.rb +0 -117
  301. data/lib/active_support/clean_logger.rb +0 -36
  302. data/lib/active_support/core_ext/blank.rb +0 -38
  303. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
  304. data/lib/active_support/core_ext/cgi.rb +0 -5
  305. data/lib/active_support/core_ext/exception.rb +0 -29
  306. data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
  307. data/lib/active_support/core_ext/object_and_class.rb +0 -44
  308. data/lib/active_support/module_attribute_accessors.rb +0 -57
  309. data/lib/active_support/whiny_nil.rb +0 -38
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/delegation"
4
+ require "securerandom"
5
+
6
+ module ActiveSupport
7
+ module Notifications
8
+ # Instrumenters are stored in a thread local.
9
+ class Instrumenter
10
+ attr_reader :id
11
+
12
+ def initialize(notifier)
13
+ unless notifier.respond_to?(:build_handle)
14
+ notifier = LegacyHandle::Wrapper.new(notifier)
15
+ end
16
+
17
+ @id = unique_id
18
+ @notifier = notifier
19
+ end
20
+
21
+ class LegacyHandle # :nodoc:
22
+ class Wrapper # :nodoc:
23
+ def initialize(notifier)
24
+ @notifier = notifier
25
+ end
26
+
27
+ def build_handle(name, id, payload)
28
+ LegacyHandle.new(@notifier, name, id, payload)
29
+ end
30
+
31
+ delegate :start, :finish, to: :@notifier
32
+ end
33
+
34
+ def initialize(notifier, name, id, payload)
35
+ @notifier = notifier
36
+ @name = name
37
+ @id = id
38
+ @payload = payload
39
+ end
40
+
41
+ def start
42
+ @listener_state = @notifier.start @name, @id, @payload
43
+ end
44
+
45
+ def finish
46
+ @notifier.finish(@name, @id, @payload, @listener_state)
47
+ end
48
+ end
49
+
50
+ # Given a block, instrument it by measuring the time taken to execute
51
+ # and publish it. Without a block, simply send a message via the
52
+ # notifier. Notice that events get sent even if an error occurs in the
53
+ # passed-in block.
54
+ def instrument(name, payload = {})
55
+ handle = build_handle(name, payload)
56
+ handle.start
57
+ begin
58
+ yield payload if block_given?
59
+ rescue Exception => e
60
+ payload[:exception] = [e.class.name, e.message]
61
+ payload[:exception_object] = e
62
+ raise e
63
+ ensure
64
+ handle.finish
65
+ end
66
+ end
67
+
68
+ # Returns a "handle" for an event with the given +name+ and +payload+.
69
+ #
70
+ # #start and #finish must each be called exactly once on the returned object.
71
+ #
72
+ # Where possible, it's best to use #instrument, which will record the
73
+ # start and finish of the event and correctly handle any exceptions.
74
+ # +build_handle+ is a low-level API intended for cases where using
75
+ # +instrument+ isn't possible.
76
+ #
77
+ # See ActiveSupport::Notifications::Fanout::Handle.
78
+ def build_handle(name, payload)
79
+ @notifier.build_handle(name, @id, payload)
80
+ end
81
+
82
+ def new_event(name, payload = {}) # :nodoc:
83
+ Event.new(name, nil, nil, @id, payload)
84
+ end
85
+
86
+ # Send a start notification with +name+ and +payload+.
87
+ def start(name, payload)
88
+ @notifier.start name, @id, payload
89
+ end
90
+
91
+ # Send a finish notification with +name+ and +payload+.
92
+ def finish(name, payload)
93
+ @notifier.finish name, @id, payload
94
+ end
95
+
96
+ def finish_with_state(listeners_state, name, payload)
97
+ @notifier.finish name, @id, payload, listeners_state
98
+ end
99
+
100
+ private
101
+ def unique_id
102
+ SecureRandom.hex(10)
103
+ end
104
+ end
105
+
106
+ class Event
107
+ attr_reader :name, :transaction_id
108
+ attr_accessor :payload
109
+
110
+ def initialize(name, start, ending, transaction_id, payload)
111
+ @name = name
112
+ @payload = payload.dup
113
+ @time = start ? start.to_f * 1_000.0 : start
114
+ @transaction_id = transaction_id
115
+ @end = ending ? ending.to_f * 1_000.0 : ending
116
+ @cpu_time_start = 0.0
117
+ @cpu_time_finish = 0.0
118
+ @allocation_count_start = 0
119
+ @allocation_count_finish = 0
120
+ @gc_time_start = 0
121
+ @gc_time_finish = 0
122
+ end
123
+
124
+ def time
125
+ @time / 1000.0 if @time
126
+ end
127
+
128
+ def end
129
+ @end / 1000.0 if @end
130
+ end
131
+
132
+ def record # :nodoc:
133
+ start!
134
+ begin
135
+ yield payload if block_given?
136
+ rescue Exception => e
137
+ payload[:exception] = [e.class.name, e.message]
138
+ payload[:exception_object] = e
139
+ raise e
140
+ ensure
141
+ finish!
142
+ end
143
+ end
144
+
145
+ # Record information at the time this event starts
146
+ def start!
147
+ @time = now
148
+ @cpu_time_start = now_cpu
149
+ @gc_time_start = now_gc
150
+ @allocation_count_start = now_allocations
151
+ end
152
+
153
+ # Record information at the time this event finishes
154
+ def finish!
155
+ @cpu_time_finish = now_cpu
156
+ @gc_time_finish = now_gc
157
+ @end = now
158
+ @allocation_count_finish = now_allocations
159
+ end
160
+
161
+ # Returns the CPU time (in milliseconds) passed between the call to
162
+ # #start! and the call to #finish!.
163
+ def cpu_time
164
+ @cpu_time_finish - @cpu_time_start
165
+ end
166
+
167
+ # Returns the idle time (in milliseconds) passed between the call to
168
+ # #start! and the call to #finish!.
169
+ def idle_time
170
+ diff = duration - cpu_time
171
+ diff > 0.0 ? diff : 0.0
172
+ end
173
+
174
+ # Returns the number of allocations made between the call to #start! and
175
+ # the call to #finish!.
176
+ def allocations
177
+ @allocation_count_finish - @allocation_count_start
178
+ end
179
+
180
+ # Returns the time spent in GC (in milliseconds) between the call to #start!
181
+ # and the call to #finish!
182
+ def gc_time
183
+ (@gc_time_finish - @gc_time_start) / 1_000_000.0
184
+ end
185
+
186
+ # Returns the difference in milliseconds between when the execution of the
187
+ # event started and when it ended.
188
+ #
189
+ # ActiveSupport::Notifications.subscribe('wait') do |event|
190
+ # @event = event
191
+ # end
192
+ #
193
+ # ActiveSupport::Notifications.instrument('wait') do
194
+ # sleep 1
195
+ # end
196
+ #
197
+ # @event.duration # => 1000.138
198
+ def duration
199
+ @end - @time
200
+ end
201
+
202
+ private
203
+ def now
204
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
205
+ end
206
+
207
+ begin
208
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
209
+
210
+ def now_cpu
211
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
212
+ end
213
+ rescue
214
+ def now_cpu
215
+ 0.0
216
+ end
217
+ end
218
+
219
+ if GC.respond_to?(:total_time)
220
+ def now_gc
221
+ GC.total_time
222
+ end
223
+ else
224
+ def now_gc
225
+ 0
226
+ end
227
+ end
228
+
229
+ if GC.stat.key?(:total_allocated_objects)
230
+ def now_allocations
231
+ GC.stat(:total_allocated_objects)
232
+ end
233
+ else # Likely on JRuby, TruffleRuby
234
+ def now_allocations
235
+ 0
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,281 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/notifications/instrumenter"
4
+ require "active_support/notifications/fanout"
5
+
6
+ module ActiveSupport
7
+ # = \Notifications
8
+ #
9
+ # +ActiveSupport::Notifications+ provides an instrumentation API for
10
+ # Ruby.
11
+ #
12
+ # == Instrumenters
13
+ #
14
+ # To instrument an event you just need to do:
15
+ #
16
+ # ActiveSupport::Notifications.instrument('render', extra: :information) do
17
+ # render plain: 'Foo'
18
+ # end
19
+ #
20
+ # That first executes the block and then notifies all subscribers once done.
21
+ #
22
+ # In the example above +render+ is the name of the event, and the rest is called
23
+ # the _payload_. The payload is a mechanism that allows instrumenters to pass
24
+ # extra information to subscribers. Payloads consist of a hash whose contents
25
+ # are arbitrary and generally depend on the event.
26
+ #
27
+ # == Subscribers
28
+ #
29
+ # You can consume those events and the information they provide by registering
30
+ # a subscriber.
31
+ #
32
+ # ActiveSupport::Notifications.subscribe('render') do |event|
33
+ # event.name # => "render"
34
+ # event.duration # => 10 (in milliseconds)
35
+ # event.payload # => { extra: :information }
36
+ # event.allocations # => 1826 (objects)
37
+ # end
38
+ #
39
+ # +Event+ objects record CPU time and allocations. If you don't need this
40
+ # it's also possible to pass a block that accepts five arguments:
41
+ #
42
+ # ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
43
+ # name # => String, name of the event (such as 'render' from above)
44
+ # start # => Time, when the instrumented block started execution
45
+ # finish # => Time, when the instrumented block ended execution
46
+ # id # => String, unique ID for the instrumenter that fired the event
47
+ # payload # => Hash, the payload
48
+ # end
49
+ #
50
+ # Here, the +start+ and +finish+ values represent wall-clock time. If you are
51
+ # concerned about accuracy, you can register a monotonic subscriber.
52
+ #
53
+ # ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
54
+ # name # => String, name of the event (such as 'render' from above)
55
+ # start # => Float, monotonic time when the instrumented block started execution
56
+ # finish # => Float, monotonic time when the instrumented block ended execution
57
+ # id # => String, unique ID for the instrumenter that fired the event
58
+ # payload # => Hash, the payload
59
+ # end
60
+ #
61
+ # For instance, let's store all "render" events in an array:
62
+ #
63
+ # events = []
64
+ #
65
+ # ActiveSupport::Notifications.subscribe('render') do |event|
66
+ # events << event
67
+ # end
68
+ #
69
+ # That code returns right away, you are just subscribing to "render" events.
70
+ # The block is saved and will be called whenever someone instruments "render":
71
+ #
72
+ # ActiveSupport::Notifications.instrument('render', extra: :information) do
73
+ # render plain: 'Foo'
74
+ # end
75
+ #
76
+ # event = events.first
77
+ # event.name # => "render"
78
+ # event.duration # => 10 (in milliseconds)
79
+ # event.payload # => { extra: :information }
80
+ # event.allocations # => 1826 (objects)
81
+ #
82
+ # If an exception happens during that particular instrumentation the payload will
83
+ # have a key <tt>:exception</tt> with an array of two elements as value: a string with
84
+ # the name of the exception class, and the exception message.
85
+ # The <tt>:exception_object</tt> key of the payload will have the exception
86
+ # itself as the value:
87
+ #
88
+ # event.payload[:exception] # => ["ArgumentError", "Invalid value"]
89
+ # event.payload[:exception_object] # => #<ArgumentError: Invalid value>
90
+ #
91
+ # As the earlier example depicts, the class ActiveSupport::Notifications::Event
92
+ # is able to take the arguments as they come and provide an object-oriented
93
+ # interface to that data.
94
+ #
95
+ # It is also possible to pass an object which responds to <tt>call</tt> method
96
+ # as the second parameter to the <tt>subscribe</tt> method instead of a block:
97
+ #
98
+ # module ActionController
99
+ # class PageRequest
100
+ # def call(name, started, finished, unique_id, payload)
101
+ # Rails.logger.debug ['notification:', name, started, finished, unique_id, payload].join(' ')
102
+ # end
103
+ # end
104
+ # end
105
+ #
106
+ # ActiveSupport::Notifications.subscribe('process_action.action_controller', ActionController::PageRequest.new)
107
+ #
108
+ # resulting in the following output within the logs including a hash with the payload:
109
+ #
110
+ # notification: process_action.action_controller 2012-04-13 01:08:35 +0300 2012-04-13 01:08:35 +0300 af358ed7fab884532ec7 {
111
+ # controller: "Devise::SessionsController",
112
+ # action: "new",
113
+ # params: {"action"=>"new", "controller"=>"devise/sessions"},
114
+ # format: :html,
115
+ # method: "GET",
116
+ # path: "/login/sign_in",
117
+ # status: 200,
118
+ # view_runtime: 279.3080806732178,
119
+ # db_runtime: 40.053
120
+ # }
121
+ #
122
+ # You can also subscribe to all events whose name matches a certain regexp:
123
+ #
124
+ # ActiveSupport::Notifications.subscribe(/render/) do |*args|
125
+ # ...
126
+ # end
127
+ #
128
+ # and even pass no argument to <tt>subscribe</tt>, in which case you are subscribing
129
+ # to all events.
130
+ #
131
+ # == Temporary Subscriptions
132
+ #
133
+ # Sometimes you do not want to subscribe to an event for the entire life of
134
+ # the application. There are two ways to unsubscribe.
135
+ #
136
+ # WARNING: The instrumentation framework is designed for long-running subscribers,
137
+ # use this feature sparingly because it wipes some internal caches and that has
138
+ # a negative impact on performance.
139
+ #
140
+ # === Subscribe While a Block Runs
141
+ #
142
+ # You can subscribe to some event temporarily while some block runs. For
143
+ # example, in
144
+ #
145
+ # callback = lambda {|event| ... }
146
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
147
+ # ...
148
+ # end
149
+ #
150
+ # the callback will be called for all "sql.active_record" events instrumented
151
+ # during the execution of the block. The callback is unsubscribed automatically
152
+ # after that.
153
+ #
154
+ # To record +started+ and +finished+ values with monotonic time,
155
+ # specify the optional <tt>:monotonic</tt> option to the
156
+ # <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
157
+ # to +false+ by default.
158
+ #
159
+ # callback = lambda {|name, started, finished, unique_id, payload| ... }
160
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
161
+ # ...
162
+ # end
163
+ #
164
+ # === Manual Unsubscription
165
+ #
166
+ # The +subscribe+ method returns a subscriber object:
167
+ #
168
+ # subscriber = ActiveSupport::Notifications.subscribe("render") do |event|
169
+ # ...
170
+ # end
171
+ #
172
+ # To prevent that block from being called anymore, just unsubscribe passing
173
+ # that reference:
174
+ #
175
+ # ActiveSupport::Notifications.unsubscribe(subscriber)
176
+ #
177
+ # You can also unsubscribe by passing the name of the subscriber object. Note
178
+ # that this will unsubscribe all subscriptions with the given name:
179
+ #
180
+ # ActiveSupport::Notifications.unsubscribe("render")
181
+ #
182
+ # Subscribers using a regexp or other pattern-matching object will remain subscribed
183
+ # to all events that match their original pattern, unless those events match a string
184
+ # passed to +unsubscribe+:
185
+ #
186
+ # subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
187
+ # ActiveSupport::Notifications.unsubscribe('render_template.action_view')
188
+ # subscriber.matches?('render_template.action_view') # => false
189
+ # subscriber.matches?('render_partial.action_view') # => true
190
+ #
191
+ # == Default Queue
192
+ #
193
+ # Notifications ships with a queue implementation that consumes and publishes events
194
+ # to all log subscribers. You can use any queue implementation you want.
195
+ #
196
+ module Notifications
197
+ class << self
198
+ attr_accessor :notifier
199
+
200
+ def publish(name, *args)
201
+ notifier.publish(name, *args)
202
+ end
203
+
204
+ def publish_event(event) # :nodoc:
205
+ notifier.publish_event(event)
206
+ end
207
+
208
+ def instrument(name, payload = {})
209
+ if notifier.listening?(name)
210
+ instrumenter.instrument(name, payload) { yield payload if block_given? }
211
+ else
212
+ yield payload if block_given?
213
+ end
214
+ end
215
+
216
+ # Subscribe to a given event name with the passed +block+.
217
+ #
218
+ # You can subscribe to events by passing a String to match exact event
219
+ # names, or by passing a Regexp to match all events that match a pattern.
220
+ #
221
+ # If the block passed to the method only takes one argument,
222
+ # it will yield an +Event+ object to the block:
223
+ #
224
+ # ActiveSupport::Notifications.subscribe(/render/) do |event|
225
+ # @event = event
226
+ # end
227
+ #
228
+ # Otherwise the +block+ will receive five arguments with information
229
+ # about the event:
230
+ #
231
+ # ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
232
+ # name # => String, name of the event (such as 'render' from above)
233
+ # start # => Time, when the instrumented block started execution
234
+ # finish # => Time, when the instrumented block ended execution
235
+ # id # => String, unique ID for the instrumenter that fired the event
236
+ # payload # => Hash, the payload
237
+ # end
238
+ #
239
+ # Raises an error if invalid event name type is passed:
240
+ #
241
+ # ActiveSupport::Notifications.subscribe(:render) {|event| ...}
242
+ # #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
243
+ #
244
+ def subscribe(pattern = nil, callback = nil, &block)
245
+ notifier.subscribe(pattern, callback, monotonic: false, &block)
246
+ end
247
+
248
+ # Performs the same functionality as #subscribe, but the +start+ and
249
+ # +finish+ block arguments are in monotonic time instead of wall-clock
250
+ # time. Monotonic time will not jump forward or backward (due to NTP or
251
+ # Daylights Savings). Use +monotonic_subscribe+ when accuracy of time
252
+ # duration is important. For example, computing elapsed time between
253
+ # two events.
254
+ def monotonic_subscribe(pattern = nil, callback = nil, &block)
255
+ notifier.subscribe(pattern, callback, monotonic: true, &block)
256
+ end
257
+
258
+ def subscribed(callback, pattern = nil, monotonic: false, &block)
259
+ subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
260
+ yield
261
+ ensure
262
+ unsubscribe(subscriber)
263
+ end
264
+
265
+ def unsubscribe(subscriber_or_name)
266
+ notifier.unsubscribe(subscriber_or_name)
267
+ end
268
+
269
+ def instrumenter
270
+ registry[notifier] ||= Instrumenter.new(notifier)
271
+ end
272
+
273
+ private
274
+ def registry
275
+ ActiveSupport::IsolatedExecutionState[:active_support_notifications_registry] ||= {}
276
+ end
277
+ end
278
+
279
+ self.notifier = Fanout.new
280
+ end
281
+ end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "bigdecimal/util"
5
+ require "active_support/core_ext/big_decimal/conversions"
6
+ require "active_support/core_ext/hash/keys"
7
+ require "active_support/i18n"
8
+ require "active_support/core_ext/class/attribute"
9
+
10
+ module ActiveSupport
11
+ module NumberHelper
12
+ class NumberConverter # :nodoc:
13
+ # Default and i18n option namespace per class
14
+ class_attribute :namespace
15
+
16
+ # Does the object need a number that is a valid float?
17
+ class_attribute :validate_float
18
+
19
+ attr_reader :number, :opts
20
+
21
+ DEFAULTS = {
22
+ # Used in number_to_delimited
23
+ # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
24
+ format: {
25
+ # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
26
+ separator: ".",
27
+ # Delimits thousands (e.g. 1,000,000 is a million) (always in groups of three)
28
+ delimiter: ",",
29
+ # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
30
+ precision: 3,
31
+ # If set to true, precision will mean the number of significant digits instead
32
+ # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
33
+ significant: false,
34
+ # If set, the zeros after the decimal separator will always be stripped (e.g.: 1.200 will be 1.2)
35
+ strip_insignificant_zeros: false
36
+ },
37
+
38
+ # Used in number_to_currency
39
+ currency: {
40
+ format: {
41
+ format: "%u%n",
42
+ negative_format: "-%u%n",
43
+ unit: "$",
44
+ # These five are to override number.format and are optional
45
+ separator: ".",
46
+ delimiter: ",",
47
+ precision: 2,
48
+ significant: false,
49
+ strip_insignificant_zeros: false
50
+ }
51
+ },
52
+
53
+ # Used in number_to_percentage
54
+ percentage: {
55
+ format: {
56
+ delimiter: "",
57
+ format: "%n%"
58
+ }
59
+ },
60
+
61
+ # Used in number_to_rounded
62
+ precision: {
63
+ format: {
64
+ delimiter: ""
65
+ }
66
+ },
67
+
68
+ # Used in number_to_human_size and number_to_human
69
+ human: {
70
+ format: {
71
+ # These five are to override number.format and are optional
72
+ delimiter: "",
73
+ precision: 3,
74
+ significant: true,
75
+ strip_insignificant_zeros: true
76
+ },
77
+ # Used in number_to_human_size
78
+ storage_units: {
79
+ # Storage units output formatting.
80
+ # %u is the storage unit, %n is the number (default: 2 MB)
81
+ format: "%n %u",
82
+ units: {
83
+ byte: "Bytes",
84
+ kb: "KB",
85
+ mb: "MB",
86
+ gb: "GB",
87
+ tb: "TB"
88
+ }
89
+ },
90
+ # Used in number_to_human
91
+ decimal_units: {
92
+ format: "%n %u",
93
+ # Decimal units output formatting
94
+ # By default we will only quantify some of the exponents
95
+ # but the commented ones might be defined or overridden
96
+ # by the user.
97
+ units: {
98
+ # femto: Quadrillionth
99
+ # pico: Trillionth
100
+ # nano: Billionth
101
+ # micro: Millionth
102
+ # mili: Thousandth
103
+ # centi: Hundredth
104
+ # deci: Tenth
105
+ unit: "",
106
+ # ten:
107
+ # one: Ten
108
+ # other: Tens
109
+ # hundred: Hundred
110
+ thousand: "Thousand",
111
+ million: "Million",
112
+ billion: "Billion",
113
+ trillion: "Trillion",
114
+ quadrillion: "Quadrillion"
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ def self.convert(number, options)
121
+ new(number, options).execute
122
+ end
123
+
124
+ def initialize(number, options)
125
+ @number = number
126
+ @opts = options.symbolize_keys
127
+ @options = nil
128
+ end
129
+
130
+ def execute
131
+ if !number
132
+ nil
133
+ elsif validate_float? && !valid_bigdecimal
134
+ number
135
+ else
136
+ convert
137
+ end
138
+ end
139
+
140
+ private
141
+ def options
142
+ @options ||= format_options.merge(opts)
143
+ end
144
+
145
+ def format_options
146
+ default_format_options.merge!(i18n_format_options)
147
+ end
148
+
149
+ def default_format_options
150
+ options = DEFAULTS[:format].dup
151
+ options.merge!(DEFAULTS[namespace][:format]) if namespace
152
+ options
153
+ end
154
+
155
+ def i18n_format_options
156
+ locale = opts[:locale]
157
+ options = I18n.translate(:'number.format', locale: locale, default: {}).dup
158
+
159
+ if namespace
160
+ options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {}))
161
+ end
162
+
163
+ options
164
+ end
165
+
166
+ def translate_number_value_with_default(key, **i18n_options)
167
+ I18n.translate(key, default: default_value(key), scope: :number, **i18n_options)
168
+ end
169
+
170
+ def translate_in_locale(key, **i18n_options)
171
+ translate_number_value_with_default(key, locale: options[:locale], **i18n_options)
172
+ end
173
+
174
+ def default_value(key)
175
+ key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
176
+ end
177
+
178
+ def valid_bigdecimal
179
+ case number
180
+ when Float, Rational
181
+ number.to_d(0)
182
+ when String
183
+ BigDecimal(number, exception: false)
184
+ else
185
+ number.to_d rescue nil
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end