activesupport 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/callbacks"
4
+ require "concurrent/hash"
5
+
6
+ module ActiveSupport
7
+ class ExecutionWrapper
8
+ include ActiveSupport::Callbacks
9
+
10
+ Null = Object.new # :nodoc:
11
+ def Null.complete! # :nodoc:
12
+ end
13
+
14
+ define_callbacks :run
15
+ define_callbacks :complete
16
+
17
+ def self.to_run(*args, &block)
18
+ set_callback(:run, *args, &block)
19
+ end
20
+
21
+ def self.to_complete(*args, &block)
22
+ set_callback(:complete, *args, &block)
23
+ end
24
+
25
+ RunHook = Struct.new(:hook) do # :nodoc:
26
+ def before(target)
27
+ hook_state = target.send(:hook_state)
28
+ hook_state[hook] = hook.run
29
+ end
30
+ end
31
+
32
+ CompleteHook = Struct.new(:hook) do # :nodoc:
33
+ def before(target)
34
+ hook_state = target.send(:hook_state)
35
+ if hook_state.key?(hook)
36
+ hook.complete hook_state[hook]
37
+ end
38
+ end
39
+ alias after before
40
+ end
41
+
42
+ # Register an object to be invoked during both the +run+ and
43
+ # +complete+ steps.
44
+ #
45
+ # +hook.complete+ will be passed the value returned from +hook.run+,
46
+ # and will only be invoked if +run+ has previously been called.
47
+ # (Mostly, this means it won't be invoked if an exception occurs in
48
+ # a preceding +to_run+ block; all ordinary +to_complete+ blocks are
49
+ # invoked in that situation.)
50
+ def self.register_hook(hook, outer: false)
51
+ if outer
52
+ to_run RunHook.new(hook), prepend: true
53
+ to_complete :after, CompleteHook.new(hook)
54
+ else
55
+ to_run RunHook.new(hook)
56
+ to_complete CompleteHook.new(hook)
57
+ end
58
+ end
59
+
60
+ # Run this execution.
61
+ #
62
+ # Returns an instance, whose +complete!+ method *must* be invoked
63
+ # after the work has been performed.
64
+ #
65
+ # Where possible, prefer +wrap+.
66
+ def self.run!
67
+ if active?
68
+ Null
69
+ else
70
+ new.tap do |instance|
71
+ success = nil
72
+ begin
73
+ instance.run!
74
+ success = true
75
+ ensure
76
+ instance.complete! unless success
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ # Perform the work in the supplied block as an execution.
83
+ def self.wrap
84
+ return yield if active?
85
+
86
+ instance = run!
87
+ begin
88
+ yield
89
+ ensure
90
+ instance.complete!
91
+ end
92
+ end
93
+
94
+ class << self # :nodoc:
95
+ attr_accessor :active
96
+ end
97
+
98
+ def self.inherited(other) # :nodoc:
99
+ super
100
+ other.active = Concurrent::Hash.new
101
+ end
102
+
103
+ self.active = Concurrent::Hash.new
104
+
105
+ def self.active? # :nodoc:
106
+ @active[Thread.current]
107
+ end
108
+
109
+ def run! # :nodoc:
110
+ self.class.active[Thread.current] = true
111
+ run_callbacks(:run)
112
+ end
113
+
114
+ # Complete this in-flight execution. This method *must* be called
115
+ # exactly once on the result of any call to +run!+.
116
+ #
117
+ # Where possible, prefer +wrap+.
118
+ def complete!
119
+ run_callbacks(:complete)
120
+ ensure
121
+ self.class.active.delete Thread.current
122
+ end
123
+
124
+ private
125
+ def hook_state
126
+ @_hook_state ||= {}
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/execution_wrapper"
4
+
5
+ module ActiveSupport
6
+ class Executor < ExecutionWrapper
7
+ end
8
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/time/calculations"
4
+
5
+ module ActiveSupport
6
+ # FileUpdateChecker specifies the API used by Rails to watch files
7
+ # and control reloading. The API depends on four methods:
8
+ #
9
+ # * +initialize+ which expects two parameters and one block as
10
+ # described below.
11
+ #
12
+ # * +updated?+ which returns a boolean if there were updates in
13
+ # the filesystem or not.
14
+ #
15
+ # * +execute+ which executes the given block on initialization
16
+ # and updates the latest watched files and timestamp.
17
+ #
18
+ # * +execute_if_updated+ which just executes the block if it was updated.
19
+ #
20
+ # After initialization, a call to +execute_if_updated+ must execute
21
+ # the block only if there was really a change in the filesystem.
22
+ #
23
+ # This class is used by Rails to reload the I18n framework whenever
24
+ # they are changed upon a new request.
25
+ #
26
+ # i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
27
+ # I18n.reload!
28
+ # end
29
+ #
30
+ # ActiveSupport::Reloader.to_prepare do
31
+ # i18n_reloader.execute_if_updated
32
+ # end
33
+ class FileUpdateChecker
34
+ # It accepts two parameters on initialization. The first is an array
35
+ # of files and the second is an optional hash of directories. The hash must
36
+ # have directories as keys and the value is an array of extensions to be
37
+ # watched under that directory.
38
+ #
39
+ # This method must also receive a block that will be called once a path
40
+ # changes. The array of files and list of directories cannot be changed
41
+ # after FileUpdateChecker has been initialized.
42
+ def initialize(files, dirs = {}, &block)
43
+ unless block
44
+ raise ArgumentError, "A block is required to initialize a FileUpdateChecker"
45
+ end
46
+
47
+ @files = files.freeze
48
+ @glob = compile_glob(dirs)
49
+ @block = block
50
+
51
+ @watched = nil
52
+ @updated_at = nil
53
+
54
+ @last_watched = watched
55
+ @last_update_at = updated_at(@last_watched)
56
+ end
57
+
58
+ # Check if any of the entries were updated. If so, the watched and/or
59
+ # updated_at values are cached until the block is executed via +execute+
60
+ # or +execute_if_updated+.
61
+ def updated?
62
+ current_watched = watched
63
+ if @last_watched.size != current_watched.size
64
+ @watched = current_watched
65
+ true
66
+ else
67
+ current_updated_at = updated_at(current_watched)
68
+ if @last_update_at < current_updated_at
69
+ @watched = current_watched
70
+ @updated_at = current_updated_at
71
+ true
72
+ else
73
+ false
74
+ end
75
+ end
76
+ end
77
+
78
+ # Executes the given block and updates the latest watched files and
79
+ # timestamp.
80
+ def execute
81
+ @last_watched = watched
82
+ @last_update_at = updated_at(@last_watched)
83
+ @block.call
84
+ ensure
85
+ @watched = nil
86
+ @updated_at = nil
87
+ end
88
+
89
+ # Execute the block given if updated.
90
+ def execute_if_updated
91
+ if updated?
92
+ yield if block_given?
93
+ execute
94
+ true
95
+ else
96
+ false
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def watched
103
+ @watched || begin
104
+ all = @files.select { |f| File.exist?(f) }
105
+ all.concat(Dir[@glob]) if @glob
106
+ all
107
+ end
108
+ end
109
+
110
+ def updated_at(paths)
111
+ @updated_at || max_mtime(paths) || Time.at(0)
112
+ end
113
+
114
+ # This method returns the maximum mtime of the files in +paths+, or +nil+
115
+ # if the array is empty.
116
+ #
117
+ # Files with a mtime in the future are ignored. Such abnormal situation
118
+ # can happen for example if the user changes the clock by hand. It is
119
+ # healthy to consider this edge case because with mtimes in the future
120
+ # reloading is not triggered.
121
+ def max_mtime(paths)
122
+ time_now = Time.now
123
+ max_mtime = nil
124
+
125
+ # Time comparisons are performed with #compare_without_coercion because
126
+ # AS redefines these operators in a way that is much slower and does not
127
+ # bring any benefit in this particular code.
128
+ #
129
+ # Read t1.compare_without_coercion(t2) < 0 as t1 < t2.
130
+ paths.each do |path|
131
+ mtime = File.mtime(path)
132
+
133
+ next if time_now.compare_without_coercion(mtime) < 0
134
+
135
+ if max_mtime.nil? || max_mtime.compare_without_coercion(mtime) < 0
136
+ max_mtime = mtime
137
+ end
138
+ end
139
+
140
+ max_mtime
141
+ end
142
+
143
+ def compile_glob(hash)
144
+ hash.freeze # Freeze so changes aren't accidentally pushed
145
+ return if hash.empty?
146
+
147
+ globs = hash.map do |key, value|
148
+ "#{escape(key)}/**/*#{compile_ext(value)}"
149
+ end
150
+ "{#{globs.join(",")}}"
151
+ end
152
+
153
+ def escape(key)
154
+ key.gsub(",", '\,')
155
+ end
156
+
157
+ def compile_ext(array)
158
+ array = Array(array)
159
+ return if array.empty?
160
+ ".{#{array.join(",")}}"
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt>.
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 6
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = nil
14
+
15
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zlib"
4
+ require "stringio"
5
+
6
+ module ActiveSupport
7
+ # A convenient wrapper for the zlib standard library that allows
8
+ # compression/decompression of strings with gzip.
9
+ #
10
+ # gzip = ActiveSupport::Gzip.compress('compress me!')
11
+ # # => "\x1F\x8B\b\x00o\x8D\xCDO\x00\x03K\xCE\xCF-(J-.V\xC8MU\x04\x00R>n\x83\f\x00\x00\x00"
12
+ #
13
+ # ActiveSupport::Gzip.decompress(gzip)
14
+ # # => "compress me!"
15
+ module Gzip
16
+ class Stream < StringIO
17
+ def initialize(*)
18
+ super
19
+ set_encoding "BINARY"
20
+ end
21
+ def close; rewind; end
22
+ end
23
+
24
+ # Decompresses a gzipped string.
25
+ def self.decompress(source)
26
+ Zlib::GzipReader.wrap(StringIO.new(source), &:read)
27
+ end
28
+
29
+ # Compresses a string using gzip.
30
+ def self.compress(source, level = Zlib::DEFAULT_COMPRESSION, strategy = Zlib::DEFAULT_STRATEGY)
31
+ output = Stream.new
32
+ gz = Zlib::GzipWriter.new(output, level, strategy)
33
+ gz.write(source)
34
+ gz.close
35
+ output.string
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,399 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/keys"
4
+ require "active_support/core_ext/hash/reverse_merge"
5
+ require "active_support/core_ext/hash/except"
6
+
7
+ module ActiveSupport
8
+ # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
9
+ # to be the same.
10
+ #
11
+ # rgb = ActiveSupport::HashWithIndifferentAccess.new
12
+ #
13
+ # rgb[:black] = '#000000'
14
+ # rgb[:black] # => '#000000'
15
+ # rgb['black'] # => '#000000'
16
+ #
17
+ # rgb['white'] = '#FFFFFF'
18
+ # rgb[:white] # => '#FFFFFF'
19
+ # rgb['white'] # => '#FFFFFF'
20
+ #
21
+ # Internally symbols are mapped to strings when used as keys in the entire
22
+ # writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
23
+ # mapping belongs to the public interface. For example, given:
24
+ #
25
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
26
+ #
27
+ # You are guaranteed that the key is returned as a string:
28
+ #
29
+ # hash.keys # => ["a"]
30
+ #
31
+ # Technically other types of keys are accepted:
32
+ #
33
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
34
+ # hash[0] = 0
35
+ # hash # => {"a"=>1, 0=>0}
36
+ #
37
+ # but this class is intended for use cases where strings or symbols are the
38
+ # expected keys and it is convenient to understand both as the same. For
39
+ # example the +params+ hash in Ruby on Rails.
40
+ #
41
+ # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
42
+ #
43
+ # rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
44
+ #
45
+ # which may be handy.
46
+ #
47
+ # To access this class outside of Rails, require the core extension with:
48
+ #
49
+ # require "active_support/core_ext/hash/indifferent_access"
50
+ #
51
+ # which will, in turn, require this file.
52
+ class HashWithIndifferentAccess < Hash
53
+ # Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
54
+ # this class.
55
+ def extractable_options?
56
+ true
57
+ end
58
+
59
+ def with_indifferent_access
60
+ dup
61
+ end
62
+
63
+ def nested_under_indifferent_access
64
+ self
65
+ end
66
+
67
+ def initialize(constructor = {})
68
+ if constructor.respond_to?(:to_hash)
69
+ super()
70
+ update(constructor)
71
+
72
+ hash = constructor.to_hash
73
+ self.default = hash.default if hash.default
74
+ self.default_proc = hash.default_proc if hash.default_proc
75
+ else
76
+ super(constructor)
77
+ end
78
+ end
79
+
80
+ def self.[](*args)
81
+ new.merge!(Hash[*args])
82
+ end
83
+
84
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
85
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
86
+
87
+ # Assigns a new value to the hash:
88
+ #
89
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
90
+ # hash[:key] = 'value'
91
+ #
92
+ # This value can be later fetched using either +:key+ or <tt>'key'</tt>.
93
+ def []=(key, value)
94
+ regular_writer(convert_key(key), convert_value(value, for: :assignment))
95
+ end
96
+
97
+ alias_method :store, :[]=
98
+
99
+ # Updates the receiver in-place, merging in the hash passed as argument:
100
+ #
101
+ # hash_1 = ActiveSupport::HashWithIndifferentAccess.new
102
+ # hash_1[:key] = 'value'
103
+ #
104
+ # hash_2 = ActiveSupport::HashWithIndifferentAccess.new
105
+ # hash_2[:key] = 'New Value!'
106
+ #
107
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
108
+ #
109
+ # The argument can be either an
110
+ # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
111
+ # In either case the merge respects the semantics of indifferent access.
112
+ #
113
+ # If the argument is a regular hash with keys +:key+ and +"key"+ only one
114
+ # of the values end up in the receiver, but which one is unspecified.
115
+ #
116
+ # When given a block, the value for duplicated keys will be determined
117
+ # by the result of invoking the block with the duplicated key, the value
118
+ # in the receiver, and the value in +other_hash+. The rules for duplicated
119
+ # keys follow the semantics of indifferent access:
120
+ #
121
+ # hash_1[:key] = 10
122
+ # hash_2['key'] = 12
123
+ # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
124
+ def update(other_hash)
125
+ if other_hash.is_a? HashWithIndifferentAccess
126
+ super(other_hash)
127
+ else
128
+ other_hash.to_hash.each_pair do |key, value|
129
+ if block_given? && key?(key)
130
+ value = yield(convert_key(key), self[key], value)
131
+ end
132
+ regular_writer(convert_key(key), convert_value(value))
133
+ end
134
+ self
135
+ end
136
+ end
137
+
138
+ alias_method :merge!, :update
139
+
140
+ # Checks the hash for a key matching the argument passed in:
141
+ #
142
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
143
+ # hash['key'] = 'value'
144
+ # hash.key?(:key) # => true
145
+ # hash.key?('key') # => true
146
+ def key?(key)
147
+ super(convert_key(key))
148
+ end
149
+
150
+ alias_method :include?, :key?
151
+ alias_method :has_key?, :key?
152
+ alias_method :member?, :key?
153
+
154
+ # Same as <tt>Hash#[]</tt> where the key passed as argument can be
155
+ # either a string or a symbol:
156
+ #
157
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
158
+ # counters[:foo] = 1
159
+ #
160
+ # counters['foo'] # => 1
161
+ # counters[:foo] # => 1
162
+ # counters[:zoo] # => nil
163
+ def [](key)
164
+ super(convert_key(key))
165
+ end
166
+
167
+ # Same as <tt>Hash#assoc</tt> where the key passed as argument can be
168
+ # either a string or a symbol:
169
+ #
170
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
171
+ # counters[:foo] = 1
172
+ #
173
+ # counters.assoc('foo') # => ["foo", 1]
174
+ # counters.assoc(:foo) # => ["foo", 1]
175
+ # counters.assoc(:zoo) # => nil
176
+ def assoc(key)
177
+ super(convert_key(key))
178
+ end
179
+
180
+ # Same as <tt>Hash#fetch</tt> where the key passed as argument can be
181
+ # either a string or a symbol:
182
+ #
183
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
184
+ # counters[:foo] = 1
185
+ #
186
+ # counters.fetch('foo') # => 1
187
+ # counters.fetch(:bar, 0) # => 0
188
+ # counters.fetch(:bar) { |key| 0 } # => 0
189
+ # counters.fetch(:zoo) # => KeyError: key not found: "zoo"
190
+ def fetch(key, *extras)
191
+ super(convert_key(key), *extras)
192
+ end
193
+
194
+ # Same as <tt>Hash#dig</tt> where the key passed as argument can be
195
+ # either a string or a symbol:
196
+ #
197
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
198
+ # counters[:foo] = { bar: 1 }
199
+ #
200
+ # counters.dig('foo', 'bar') # => 1
201
+ # counters.dig(:foo, :bar) # => 1
202
+ # counters.dig(:zoo) # => nil
203
+ def dig(*args)
204
+ args[0] = convert_key(args[0]) if args.size > 0
205
+ super(*args)
206
+ end
207
+
208
+ # Same as <tt>Hash#default</tt> where the key passed as argument can be
209
+ # either a string or a symbol:
210
+ #
211
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(1)
212
+ # hash.default # => 1
213
+ #
214
+ # hash = ActiveSupport::HashWithIndifferentAccess.new { |hash, key| key }
215
+ # hash.default # => nil
216
+ # hash.default('foo') # => 'foo'
217
+ # hash.default(:foo) # => 'foo'
218
+ def default(*args)
219
+ super(*args.map { |arg| convert_key(arg) })
220
+ end
221
+
222
+ # Returns an array of the values at the specified indices:
223
+ #
224
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
225
+ # hash[:a] = 'x'
226
+ # hash[:b] = 'y'
227
+ # hash.values_at('a', 'b') # => ["x", "y"]
228
+ def values_at(*keys)
229
+ super(*keys.map { |key| convert_key(key) })
230
+ end
231
+
232
+ # Returns an array of the values at the specified indices, but also
233
+ # raises an exception when one of the keys can't be found.
234
+ #
235
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
236
+ # hash[:a] = 'x'
237
+ # hash[:b] = 'y'
238
+ # hash.fetch_values('a', 'b') # => ["x", "y"]
239
+ # hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
240
+ # hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
241
+ def fetch_values(*indices, &block)
242
+ super(*indices.map { |key| convert_key(key) }, &block)
243
+ end
244
+
245
+ # Returns a shallow copy of the hash.
246
+ #
247
+ # hash = ActiveSupport::HashWithIndifferentAccess.new({ a: { b: 'b' } })
248
+ # dup = hash.dup
249
+ # dup[:a][:c] = 'c'
250
+ #
251
+ # hash[:a][:c] # => "c"
252
+ # dup[:a][:c] # => "c"
253
+ def dup
254
+ self.class.new(self).tap do |new_hash|
255
+ set_defaults(new_hash)
256
+ end
257
+ end
258
+
259
+ # This method has the same semantics of +update+, except it does not
260
+ # modify the receiver but rather returns a new hash with indifferent
261
+ # access with the result of the merge.
262
+ def merge(hash, &block)
263
+ dup.update(hash, &block)
264
+ end
265
+
266
+ # Like +merge+ but the other way around: Merges the receiver into the
267
+ # argument and returns a new hash with indifferent access as result:
268
+ #
269
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
270
+ # hash['a'] = nil
271
+ # hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
272
+ def reverse_merge(other_hash)
273
+ super(self.class.new(other_hash))
274
+ end
275
+ alias_method :with_defaults, :reverse_merge
276
+
277
+ # Same semantics as +reverse_merge+ but modifies the receiver in-place.
278
+ def reverse_merge!(other_hash)
279
+ super(self.class.new(other_hash))
280
+ end
281
+ alias_method :with_defaults!, :reverse_merge!
282
+
283
+ # Replaces the contents of this hash with other_hash.
284
+ #
285
+ # h = { "a" => 100, "b" => 200 }
286
+ # h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
287
+ def replace(other_hash)
288
+ super(self.class.new(other_hash))
289
+ end
290
+
291
+ # Removes the specified key from the hash.
292
+ def delete(key)
293
+ super(convert_key(key))
294
+ end
295
+
296
+ def except(*keys)
297
+ slice(*self.keys - keys.map { |key| convert_key(key) })
298
+ end
299
+ alias_method :without, :except
300
+
301
+ def stringify_keys!; self end
302
+ def deep_stringify_keys!; self end
303
+ def stringify_keys; dup end
304
+ def deep_stringify_keys; dup end
305
+ undef :symbolize_keys!
306
+ undef :deep_symbolize_keys!
307
+ def symbolize_keys; to_hash.symbolize_keys! end
308
+ alias_method :to_options, :symbolize_keys
309
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
310
+ def to_options!; self end
311
+
312
+ def select(*args, &block)
313
+ return to_enum(:select) unless block_given?
314
+ dup.tap { |hash| hash.select!(*args, &block) }
315
+ end
316
+
317
+ def reject(*args, &block)
318
+ return to_enum(:reject) unless block_given?
319
+ dup.tap { |hash| hash.reject!(*args, &block) }
320
+ end
321
+
322
+ def transform_values(*args, &block)
323
+ return to_enum(:transform_values) unless block_given?
324
+ dup.tap { |hash| hash.transform_values!(*args, &block) }
325
+ end
326
+
327
+ def transform_keys(*args, &block)
328
+ return to_enum(:transform_keys) unless block_given?
329
+ dup.tap { |hash| hash.transform_keys!(*args, &block) }
330
+ end
331
+
332
+ def transform_keys!
333
+ return enum_for(:transform_keys!) { size } unless block_given?
334
+ keys.each do |key|
335
+ self[yield(key)] = delete(key)
336
+ end
337
+ self
338
+ end
339
+
340
+ def slice(*keys)
341
+ keys.map! { |key| convert_key(key) }
342
+ self.class.new(super)
343
+ end
344
+
345
+ def slice!(*keys)
346
+ keys.map! { |key| convert_key(key) }
347
+ super
348
+ end
349
+
350
+ def compact
351
+ dup.tap(&:compact!)
352
+ end
353
+
354
+ # Convert to a regular hash with string keys.
355
+ def to_hash
356
+ _new_hash = Hash.new
357
+ set_defaults(_new_hash)
358
+
359
+ each do |key, value|
360
+ _new_hash[key] = convert_value(value, for: :to_hash)
361
+ end
362
+ _new_hash
363
+ end
364
+
365
+ private
366
+ def convert_key(key) # :doc:
367
+ key.kind_of?(Symbol) ? key.to_s : key
368
+ end
369
+
370
+ def convert_value(value, options = {}) # :doc:
371
+ if value.is_a? Hash
372
+ if options[:for] == :to_hash
373
+ value.to_hash
374
+ else
375
+ value.nested_under_indifferent_access
376
+ end
377
+ elsif value.is_a?(Array)
378
+ if options[:for] != :assignment || value.frozen?
379
+ value = value.dup
380
+ end
381
+ value.map! { |e| convert_value(e, options) }
382
+ else
383
+ value
384
+ end
385
+ end
386
+
387
+ def set_defaults(target) # :doc:
388
+ if default_proc
389
+ target.default_proc = default_proc.dup
390
+ else
391
+ target.default = default
392
+ end
393
+ end
394
+ end
395
+ end
396
+
397
+ # :stopdoc:
398
+
399
+ HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess