activesupport 5.0.0 → 6.1.0

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 (268) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +343 -590
  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 +5 -3
  7. data/lib/active_support/array_inquirer.rb +11 -5
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +45 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +81 -79
  13. data/lib/active_support/cache/memory_store.rb +69 -41
  14. data/lib/active_support/cache/null_store.rb +11 -4
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +74 -37
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +332 -161
  19. data/lib/active_support/callbacks.rb +657 -586
  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 +59 -19
  23. data/lib/active_support/configurable.rb +15 -17
  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 +20 -18
  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 +3 -1
  30. data/lib/active_support/core_ext/array/inquiry.rb +3 -1
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +9 -7
  33. data/lib/active_support/core_ext/benchmark.rb +5 -3
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -26
  39. data/lib/active_support/core_ext/class.rb +4 -2
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +3 -1
  42. data/lib/active_support/core_ext/date/calculations.rb +16 -13
  43. data/lib/active_support/core_ext/date/conversions.rb +23 -21
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +7 -5
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  51. data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
  53. data/lib/active_support/core_ext/date_time/conversions.rb +14 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +165 -29
  58. data/lib/active_support/core_ext/file/atomic.rb +7 -5
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/conversions.rb +40 -39
  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 +3 -2
  65. data/lib/active_support/core_ext/hash/keys.rb +9 -36
  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 +10 -9
  69. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +11 -18
  72. data/lib/active_support/core_ext/integer.rb +5 -3
  73. data/lib/active_support/core_ext/kernel/concern.rb +3 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +5 -4
  77. data/lib/active_support/core_ext/load_error.rb +2 -23
  78. data/lib/active_support/core_ext/marshal.rb +6 -2
  79. data/lib/active_support/core_ext/module/aliasing.rb +5 -48
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
  84. data/lib/active_support/core_ext/module/concerning.rb +16 -11
  85. data/lib/active_support/core_ext/module/delegation.rb +159 -44
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +23 -26
  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 +13 -12
  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 +129 -134
  94. data/lib/active_support/core_ext/numeric/time.rb +18 -26
  95. data/lib/active_support/core_ext/numeric.rb +5 -4
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +14 -2
  98. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  99. data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
  100. data/lib/active_support/core_ext/object/duplicable.rb +13 -62
  101. data/lib/active_support/core_ext/object/inclusion.rb +3 -1
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +42 -15
  104. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  105. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  106. data/lib/active_support/core_ext/object/try.rb +20 -8
  107. data/lib/active_support/core_ext/object/with_options.rb +15 -2
  108. data/lib/active_support/core_ext/object.rb +14 -12
  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 +7 -4
  115. data/lib/active_support/core_ext/regexp.rb +10 -1
  116. data/lib/active_support/core_ext/securerandom.rb +28 -6
  117. data/lib/active_support/core_ext/string/access.rb +9 -18
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +47 -4
  122. data/lib/active_support/core_ext/string/indent.rb +6 -4
  123. data/lib/active_support/core_ext/string/inflections.rb +78 -29
  124. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  125. data/lib/active_support/core_ext/string/multibyte.rb +10 -5
  126. data/lib/active_support/core_ext/string/output_safety.rb +86 -31
  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 +4 -2
  130. data/lib/active_support/core_ext/string.rb +15 -13
  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 +3 -1
  134. data/lib/active_support/core_ext/time/calculations.rb +117 -45
  135. data/lib/active_support/core_ext/time/compatibility.rb +13 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +18 -12
  137. data/lib/active_support/core_ext/time/zones.rb +9 -7
  138. data/lib/active_support/core_ext/time.rb +7 -5
  139. data/lib/active_support/core_ext/uri.rb +12 -7
  140. data/lib/active_support/core_ext.rb +3 -2
  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 +7 -1
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  146. data/lib/active_support/dependencies.rb +172 -98
  147. data/lib/active_support/deprecation/behaviors.rb +45 -13
  148. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  151. data/lib/active_support/deprecation/method_wrappers.rb +32 -17
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
  153. data/lib/active_support/deprecation/reporting.rb +61 -16
  154. data/lib/active_support/deprecation.rb +17 -9
  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 +67 -66
  158. data/lib/active_support/duration/iso8601_serializer.rb +25 -17
  159. data/lib/active_support/duration.rb +349 -46
  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 +88 -112
  164. data/lib/active_support/execution_wrapper.rb +25 -13
  165. data/lib/active_support/executor.rb +3 -1
  166. data/lib/active_support/file_update_checker.rb +56 -51
  167. data/lib/active_support/fork_tracker.rb +62 -0
  168. data/lib/active_support/gem_version.rb +4 -2
  169. data/lib/active_support/gzip.rb +7 -5
  170. data/lib/active_support/hash_with_indifferent_access.rb +153 -49
  171. data/lib/active_support/i18n.rb +9 -6
  172. data/lib/active_support/i18n_railtie.rb +30 -20
  173. data/lib/active_support/inflections.rb +13 -11
  174. data/lib/active_support/inflector/inflections.rb +28 -15
  175. data/lib/active_support/inflector/methods.rb +120 -109
  176. data/lib/active_support/inflector/transliterate.rb +60 -25
  177. data/lib/active_support/inflector.rb +7 -5
  178. data/lib/active_support/json/decoding.rb +30 -29
  179. data/lib/active_support/json/encoding.rb +22 -11
  180. data/lib/active_support/json.rb +4 -2
  181. data/lib/active_support/key_generator.rb +6 -36
  182. data/lib/active_support/lazy_load_hooks.rb +53 -20
  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 +11 -9
  186. data/lib/active_support/log_subscriber.rb +51 -18
  187. data/lib/active_support/logger.rb +9 -22
  188. data/lib/active_support/logger_silence.rb +14 -21
  189. data/lib/active_support/logger_thread_safe_level.rb +55 -8
  190. data/lib/active_support/message_encryptor.rb +170 -53
  191. data/lib/active_support/message_verifier.rb +91 -20
  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 +24 -78
  196. data/lib/active_support/multibyte/unicode.rb +21 -352
  197. data/lib/active_support/multibyte.rb +4 -2
  198. data/lib/active_support/notifications/fanout.rb +121 -19
  199. data/lib/active_support/notifications/instrumenter.rb +78 -14
  200. data/lib/active_support/notifications.rb +80 -12
  201. data/lib/active_support/number_helper/number_converter.rb +17 -16
  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 -3
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
  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 -4
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +45 -16
  211. data/lib/active_support/option_merger.rb +25 -4
  212. data/lib/active_support/ordered_hash.rb +6 -4
  213. data/lib/active_support/ordered_options.rb +23 -9
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +7 -5
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +8 -9
  218. data/lib/active_support/railtie.rb +62 -11
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +20 -11
  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 +12 -3
  224. data/lib/active_support/subscriber.rb +77 -23
  225. data/lib/active_support/tagged_logging.rb +52 -17
  226. data/lib/active_support/test_case.rb +106 -29
  227. data/lib/active_support/testing/assertions.rb +144 -8
  228. data/lib/active_support/testing/autorun.rb +5 -10
  229. data/lib/active_support/testing/constant_lookup.rb +2 -1
  230. data/lib/active_support/testing/declarative.rb +3 -1
  231. data/lib/active_support/testing/deprecation.rb +4 -2
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +19 -24
  234. data/lib/active_support/testing/method_call_assertions.rb +31 -2
  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 +13 -8
  239. data/lib/active_support/testing/stream.rb +30 -29
  240. data/lib/active_support/testing/tagged_logging.rb +3 -1
  241. data/lib/active_support/testing/time_helpers.rb +125 -24
  242. data/lib/active_support/time.rb +14 -12
  243. data/lib/active_support/time_with_zone.rb +142 -55
  244. data/lib/active_support/values/time_zone.rb +160 -53
  245. data/lib/active_support/version.rb +3 -1
  246. data/lib/active_support/xml_mini/jdom.rb +115 -114
  247. data/lib/active_support/xml_mini/libxml.rb +15 -14
  248. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  249. data/lib/active_support/xml_mini/nokogiri.rb +13 -13
  250. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  251. data/lib/active_support/xml_mini/rexml.rb +18 -9
  252. data/lib/active_support/xml_mini.rb +44 -42
  253. data/lib/active_support.rb +19 -10
  254. metadata +79 -37
  255. data/lib/active_support/concurrency/latch.rb +0 -19
  256. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  257. data/lib/active_support/core_ext/hash/compact.rb +0 -20
  258. data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
  259. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  260. data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
  261. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
  262. data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
  263. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  264. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  265. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  266. data/lib/active_support/core_ext/struct.rb +0 -3
  267. data/lib/active_support/core_ext/time/marshal.rb +0 -3
  268. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  # A typical module looks like this:
3
5
  #
@@ -17,7 +19,7 @@ module ActiveSupport
17
19
  # By using <tt>ActiveSupport::Concern</tt> the above module could instead be
18
20
  # written as:
19
21
  #
20
- # require 'active_support/concern'
22
+ # require "active_support/concern"
21
23
  #
22
24
  # module M
23
25
  # extend ActiveSupport::Concern
@@ -74,7 +76,7 @@ module ActiveSupport
74
76
  # is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
75
77
  # module dependencies are properly resolved:
76
78
  #
77
- # require 'active_support/concern'
79
+ # require "active_support/concern"
78
80
  #
79
81
  # module Foo
80
82
  # extend ActiveSupport::Concern
@@ -97,6 +99,14 @@ module ActiveSupport
97
99
  # class Host
98
100
  # include Bar # It works, now Bar takes care of its dependencies
99
101
  # end
102
+ #
103
+ # === Prepending concerns
104
+ #
105
+ # Just like <tt>include</tt>, concerns also support <tt>prepend</tt> with a corresponding
106
+ # <tt>prepended do</tt> callback. <tt>module ClassMethods</tt> or <tt>class_methods do</tt> are
107
+ # prepended as well.
108
+ #
109
+ # <tt>prepend</tt> is also used for any dependencies.
100
110
  module Concern
101
111
  class MultipleIncludedBlocks < StandardError #:nodoc:
102
112
  def initialize
@@ -104,14 +114,20 @@ module ActiveSupport
104
114
  end
105
115
  end
106
116
 
117
+ class MultiplePrependBlocks < StandardError #:nodoc:
118
+ def initialize
119
+ super "Cannot define multiple 'prepended' blocks for a Concern"
120
+ end
121
+ end
122
+
107
123
  def self.extended(base) #:nodoc:
108
124
  base.instance_variable_set(:@_dependencies, [])
109
125
  end
110
126
 
111
- def append_features(base)
127
+ def append_features(base) #:nodoc:
112
128
  if base.instance_variable_defined?(:@_dependencies)
113
129
  base.instance_variable_get(:@_dependencies) << self
114
- return false
130
+ false
115
131
  else
116
132
  return false if base < self
117
133
  @_dependencies.each { |dep| base.include(dep) }
@@ -121,16 +137,73 @@ module ActiveSupport
121
137
  end
122
138
  end
123
139
 
140
+ def prepend_features(base) #:nodoc:
141
+ if base.instance_variable_defined?(:@_dependencies)
142
+ base.instance_variable_get(:@_dependencies).unshift self
143
+ false
144
+ else
145
+ return false if base < self
146
+ @_dependencies.each { |dep| base.prepend(dep) }
147
+ super
148
+ base.singleton_class.prepend const_get(:ClassMethods) if const_defined?(:ClassMethods)
149
+ base.class_eval(&@_prepended_block) if instance_variable_defined?(:@_prepended_block)
150
+ end
151
+ end
152
+
153
+ # Evaluate given block in context of base class,
154
+ # so that you can write class macros here.
155
+ # When you define more than one +included+ block, it raises an exception.
124
156
  def included(base = nil, &block)
125
157
  if base.nil?
126
- raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
158
+ if instance_variable_defined?(:@_included_block)
159
+ if @_included_block.source_location != block.source_location
160
+ raise MultipleIncludedBlocks
161
+ end
162
+ else
163
+ @_included_block = block
164
+ end
165
+ else
166
+ super
167
+ end
168
+ end
127
169
 
128
- @_included_block = block
170
+ # Evaluate given block in context of base class,
171
+ # so that you can write class macros here.
172
+ # When you define more than one +prepended+ block, it raises an exception.
173
+ def prepended(base = nil, &block)
174
+ if base.nil?
175
+ if instance_variable_defined?(:@_prepended_block)
176
+ if @_prepended_block.source_location != block.source_location
177
+ raise MultiplePrependBlocks
178
+ end
179
+ else
180
+ @_prepended_block = block
181
+ end
129
182
  else
130
183
  super
131
184
  end
132
185
  end
133
186
 
187
+ # Define class methods from given block.
188
+ # You can define private class methods as well.
189
+ #
190
+ # module Example
191
+ # extend ActiveSupport::Concern
192
+ #
193
+ # class_methods do
194
+ # def foo; puts 'foo'; end
195
+ #
196
+ # private
197
+ # def bar; puts 'bar'; end
198
+ # end
199
+ # end
200
+ #
201
+ # class Buzz
202
+ # include Example
203
+ # end
204
+ #
205
+ # Buzz.foo # => "foo"
206
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
134
207
  def class_methods(&class_methods_module_definition)
135
208
  mod = const_defined?(:ClassMethods, false) ?
136
209
  const_get(:ClassMethods) :
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ module ActiveSupport
6
+ module Concurrency
7
+ # A monitor that will permit dependency loading while blocked waiting for
8
+ # the lock.
9
+ class LoadInterlockAwareMonitor < Monitor
10
+ EXCEPTION_NEVER = { Exception => :never }.freeze
11
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
12
+ private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
13
+
14
+ # Enters an exclusive section, but allows dependency loading while blocked
15
+ def mon_enter
16
+ mon_try_enter ||
17
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
18
+ end
19
+
20
+ def synchronize
21
+ Thread.handle_interrupt(EXCEPTION_NEVER) do
22
+ mon_enter
23
+
24
+ begin
25
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE) do
26
+ yield
27
+ end
28
+ ensure
29
+ mon_exit
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,7 @@
1
- require 'thread'
2
- require 'monitor'
1
+ # frozen_string_literal: true
2
+
3
+ require "thread"
4
+ require "monitor"
3
5
 
4
6
  module ActiveSupport
5
7
  module Concurrency
@@ -13,6 +15,37 @@ module ActiveSupport
13
15
  # we need exclusive locks to be reentrant, and we need to be able
14
16
  # to upgrade share locks to exclusive.
15
17
 
18
+ def raw_state # :nodoc:
19
+ synchronize do
20
+ threads = @sleeping.keys | @sharing.keys | @waiting.keys
21
+ threads |= [@exclusive_thread] if @exclusive_thread
22
+
23
+ data = {}
24
+
25
+ threads.each do |thread|
26
+ purpose, compatible = @waiting[thread]
27
+
28
+ data[thread] = {
29
+ thread: thread,
30
+ sharing: @sharing[thread],
31
+ exclusive: @exclusive_thread == thread,
32
+ purpose: purpose,
33
+ compatible: compatible,
34
+ waiting: !!@waiting[thread],
35
+ sleeper: @sleeping[thread],
36
+ }
37
+ end
38
+
39
+ # NB: Yields while holding our *internal* synchronize lock,
40
+ # which is supposed to be used only for a few instructions at
41
+ # a time. This allows the caller to inspect additional state
42
+ # without things changing out from underneath, but would have
43
+ # disastrous effects upon normal operation. Fortunately, this
44
+ # method is only intended to be called when things have
45
+ # already gone wrong.
46
+ yield data
47
+ end
48
+ end
16
49
 
17
50
  def initialize
18
51
  super()
@@ -21,6 +54,7 @@ module ActiveSupport
21
54
 
22
55
  @sharing = Hash.new(0)
23
56
  @waiting = {}
57
+ @sleeping = {}
24
58
  @exclusive_thread = nil
25
59
  @exclusive_depth = 0
26
60
  end
@@ -46,7 +80,7 @@ module ActiveSupport
46
80
  return false if no_wait
47
81
 
48
82
  yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
49
- @cv.wait_while { busy_for_exclusive?(purpose) }
83
+ wait_for(:start_exclusive) { busy_for_exclusive?(purpose) }
50
84
  end
51
85
  end
52
86
  @exclusive_thread = Thread.current
@@ -69,7 +103,7 @@ module ActiveSupport
69
103
 
70
104
  if eligible_waiters?(compatible)
71
105
  yield_shares(compatible: compatible, block_share: true) do
72
- @cv.wait_while { @exclusive_thread || eligible_waiters?(compatible) }
106
+ wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) }
73
107
  end
74
108
  end
75
109
  @cv.broadcast
@@ -84,11 +118,11 @@ module ActiveSupport
84
118
  elsif @waiting[Thread.current]
85
119
  # We're nested inside a +yield_shares+ call: we'll resume as
86
120
  # soon as there isn't an exclusive lock in our way
87
- @cv.wait_while { @exclusive_thread }
121
+ wait_for(:start_sharing) { @exclusive_thread }
88
122
  else
89
123
  # This is an initial / outermost share call: any outstanding
90
124
  # requests for an exclusive lock get to go first
91
- @cv.wait_while { busy_for_sharing?(false) }
125
+ wait_for(:start_sharing) { busy_for_sharing?(false) }
92
126
  end
93
127
  @sharing[Thread.current] += 1
94
128
  end
@@ -153,7 +187,7 @@ module ActiveSupport
153
187
  yield
154
188
  ensure
155
189
  synchronize do
156
- @cv.wait_while { @exclusive_thread && @exclusive_thread != Thread.current }
190
+ wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current }
157
191
 
158
192
  if previous_wait
159
193
  @waiting[Thread.current] = previous_wait
@@ -166,21 +200,27 @@ module ActiveSupport
166
200
  end
167
201
 
168
202
  private
203
+ # Must be called within synchronize
204
+ def busy_for_exclusive?(purpose)
205
+ busy_for_sharing?(purpose) ||
206
+ @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0)
207
+ end
169
208
 
170
- # Must be called within synchronize
171
- def busy_for_exclusive?(purpose)
172
- busy_for_sharing?(purpose) ||
173
- @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0)
174
- end
209
+ def busy_for_sharing?(purpose)
210
+ (@exclusive_thread && @exclusive_thread != Thread.current) ||
211
+ @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) }
212
+ end
175
213
 
176
- def busy_for_sharing?(purpose)
177
- (@exclusive_thread && @exclusive_thread != Thread.current) ||
178
- @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) }
179
- end
214
+ def eligible_waiters?(compatible)
215
+ @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
216
+ end
180
217
 
181
- def eligible_waiters?(compatible)
182
- @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
183
- end
218
+ def wait_for(method)
219
+ @sleeping[Thread.current] = method
220
+ @cv.wait_while { yield }
221
+ ensure
222
+ @sleeping.delete Thread.current
223
+ end
184
224
  end
185
225
  end
186
226
  end
@@ -1,10 +1,11 @@
1
- require 'active_support/concern'
2
- require 'active_support/ordered_options'
3
- require 'active_support/core_ext/array/extract_options'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/ordered_options"
4
5
 
5
6
  module ActiveSupport
6
7
  # Configurable provides a <tt>config</tt> method to store and retrieve
7
- # configuration options as an <tt>OrderedHash</tt>.
8
+ # configuration options as an <tt>OrderedOptions</tt>.
8
9
  module Configurable
9
10
  extend ActiveSupport::Concern
10
11
 
@@ -66,8 +67,8 @@ module ActiveSupport
66
67
  # end
67
68
  # # => NameError: invalid config attribute name
68
69
  #
69
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
70
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
70
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
71
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
71
72
  #
72
73
  # class User
73
74
  # include ActiveSupport::Configurable
@@ -80,7 +81,7 @@ module ActiveSupport
80
81
  # User.new.allowed_access = true # => NoMethodError
81
82
  # User.new.allowed_access # => NoMethodError
82
83
  #
83
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
84
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
84
85
  #
85
86
  # class User
86
87
  # include ActiveSupport::Configurable
@@ -103,11 +104,9 @@ module ActiveSupport
103
104
  # end
104
105
  #
105
106
  # User.hair_colors # => [:brown, :black, :blonde, :red]
106
- def config_accessor(*names)
107
- options = names.extract_options!
108
-
107
+ def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
109
108
  names.each do |name|
110
- raise NameError.new('invalid config attribute name') unless name =~ /\A[_A-Za-z]\w*\z/
109
+ raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
111
110
 
112
111
  reader, reader_line = "def #{name}; config.#{name}; end", __LINE__
113
112
  writer, writer_line = "def #{name}=(value); config.#{name} = value; end", __LINE__
@@ -115,9 +114,9 @@ module ActiveSupport
115
114
  singleton_class.class_eval reader, __FILE__, reader_line
116
115
  singleton_class.class_eval writer, __FILE__, writer_line
117
116
 
118
- unless options[:instance_accessor] == false
119
- class_eval reader, __FILE__, reader_line unless options[:instance_reader] == false
120
- class_eval writer, __FILE__, writer_line unless options[:instance_writer] == false
117
+ if instance_accessor
118
+ class_eval reader, __FILE__, reader_line if instance_reader
119
+ class_eval writer, __FILE__, writer_line if instance_writer
121
120
  end
122
121
  send("#{name}=", yield) if block_given?
123
122
  end
@@ -125,9 +124,9 @@ module ActiveSupport
125
124
  private :config_accessor
126
125
  end
127
126
 
128
- # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
127
+ # Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
129
128
  #
130
- # require 'active_support/configurable'
129
+ # require "active_support/configurable"
131
130
  #
132
131
  # class User
133
132
  # include ActiveSupport::Configurable
@@ -145,4 +144,3 @@ module ActiveSupport
145
144
  end
146
145
  end
147
146
  end
148
-
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # Reads a YAML configuration file, evaluating any ERB, then
5
+ # parsing the resulting YAML.
6
+ #
7
+ # Warns in case of YAML confusing characters, like invisible
8
+ # non-breaking spaces.
9
+ class ConfigurationFile # :nodoc:
10
+ class FormatError < StandardError; end
11
+
12
+ def initialize(content_path)
13
+ @content_path = content_path.to_s
14
+ @content = read content_path
15
+ end
16
+
17
+ def self.parse(content_path, **options)
18
+ new(content_path).parse(**options)
19
+ end
20
+
21
+ def parse(context: nil, **options)
22
+ YAML.load(render(context), **options) || {}
23
+ rescue Psych::SyntaxError => error
24
+ raise "YAML syntax error occurred while parsing #{@content_path}. " \
25
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
26
+ "Error: #{error.message}"
27
+ end
28
+
29
+ private
30
+ def read(content_path)
31
+ require "yaml"
32
+ require "erb"
33
+
34
+ File.read(content_path).tap do |content|
35
+ if content.include?("\u00A0")
36
+ warn "File contains invisible non-breaking spaces, you may want to remove those"
37
+ end
38
+ end
39
+ end
40
+
41
+ def render(context)
42
+ erb = ERB.new(@content).tap { |e| e.filename = @content_path }
43
+ context ? erb.result(context) : erb.result
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # Returns the tail of the array from +position+.
3
5
  #
@@ -27,16 +29,28 @@ class Array
27
29
  end
28
30
  end
29
31
 
30
- # Returns a copy of the Array without the specified elements.
32
+ # Returns a new array that includes the passed elements.
33
+ #
34
+ # [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
35
+ # [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
36
+ def including(*elements)
37
+ self + elements.flatten(1)
38
+ end
39
+
40
+ # Returns a copy of the Array excluding the specified elements.
31
41
  #
32
- # people = ["David", "Rafael", "Aaron", "Todd"]
33
- # people.without "Aaron", "Todd"
34
- # => ["David", "Rafael"]
42
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
43
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
35
44
  #
36
- # Note: This is an optimization of `Enumerable#without` that uses `Array#-`
37
- # instead of `Array#reject` for performance reasons.
45
+ # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
46
+ # instead of <tt>Array#reject</tt> for performance reasons.
47
+ def excluding(*elements)
48
+ self - elements.flatten(1)
49
+ end
50
+
51
+ # Alias for #excluding.
38
52
  def without(*elements)
39
- self - elements
53
+ excluding(*elements)
40
54
  end
41
55
 
42
56
  # Equal to <tt>self[1]</tt>.
@@ -1,8 +1,10 @@
1
- require 'active_support/xml_mini'
2
- require 'active_support/core_ext/hash/keys'
3
- require 'active_support/core_ext/string/inflections'
4
- require 'active_support/core_ext/object/to_param'
5
- require 'active_support/core_ext/object/to_query'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/xml_mini"
4
+ require "active_support/core_ext/hash/keys"
5
+ require "active_support/core_ext/string/inflections"
6
+ require "active_support/core_ext/object/to_param"
7
+ require "active_support/core_ext/object/to_query"
6
8
 
7
9
  class Array
8
10
  # Converts the array to a comma-separated sentence where the last element is
@@ -60,9 +62,9 @@ class Array
60
62
  options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
61
63
 
62
64
  default_connectors = {
63
- :words_connector => ', ',
64
- :two_words_connector => ' and ',
65
- :last_word_connector => ', and '
65
+ words_connector: ", ",
66
+ two_words_connector: " and ",
67
+ last_word_connector: ", and "
66
68
  }
67
69
  if defined?(I18n)
68
70
  i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
@@ -72,13 +74,13 @@ class Array
72
74
 
73
75
  case length
74
76
  when 0
75
- ''
77
+ +""
76
78
  when 1
77
- "#{self[0]}"
79
+ +"#{self[0]}"
78
80
  when 2
79
- "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
81
+ +"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
80
82
  else
81
- "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
83
+ +"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
82
84
  end
83
85
  end
84
86
 
@@ -92,9 +94,9 @@ class Array
92
94
  case format
93
95
  when :db
94
96
  if empty?
95
- 'null'
97
+ "null"
96
98
  else
97
- collect(&:id).join(',')
99
+ collect(&:id).join(",")
98
100
  end
99
101
  else
100
102
  to_default_s
@@ -179,7 +181,7 @@ class Array
179
181
  # </messages>
180
182
  #
181
183
  def to_xml(options = {})
182
- require 'active_support/builder' unless defined?(Builder)
184
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
183
185
 
184
186
  options = options.dup
185
187
  options[:indent] ||= 2
@@ -187,9 +189,9 @@ class Array
187
189
  options[:root] ||= \
188
190
  if first.class != Hash && all? { |e| e.is_a?(first.class) }
189
191
  underscored = ActiveSupport::Inflector.underscore(first.class.name)
190
- ActiveSupport::Inflector.pluralize(underscored).tr('/', '_')
192
+ ActiveSupport::Inflector.pluralize(underscored).tr("/", "_")
191
193
  else
192
- 'objects'
194
+ "objects"
193
195
  end
194
196
 
195
197
  builder = options[:builder]
@@ -197,7 +199,7 @@ class Array
197
199
 
198
200
  root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
199
201
  children = options.delete(:children) || root.singularize
200
- attributes = options[:skip_types] ? {} : { type: 'array' }
202
+ attributes = options[:skip_types] ? {} : { type: "array" }
201
203
 
202
204
  if empty?
203
205
  builder.tag!(root, attributes)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Removes and returns the elements for which the block returns a true value.
5
+ # If no block is given, an Enumerator is returned instead.
6
+ #
7
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
9
+ # numbers # => [0, 2, 4, 6, 8]
10
+ def extract!
11
+ return to_enum(:extract!) { size } unless block_given?
12
+
13
+ extracted_elements = []
14
+
15
+ reject! do |element|
16
+ extracted_elements << element if yield(element)
17
+ end
18
+
19
+ extracted_elements
20
+ end
21
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Hash
2
4
  # By default, only instances of Hash itself are extractable.
3
5
  # Subclasses of Hash may implement this method and return
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # Splits or iterates over the array in groups of size +number+,
3
5
  # padding any remaining slots with +fill_with+ unless it is +false+.
@@ -89,7 +91,7 @@ class Array
89
91
  # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
90
92
  # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
91
93
  def split(value = nil)
92
- arr = self.dup
94
+ arr = dup
93
95
  result = []
94
96
  if block_given?
95
97
  while (idx = arr.index { |i| yield i })
@@ -1,4 +1,6 @@
1
- require 'active_support/array_inquirer'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/array_inquirer"
2
4
 
3
5
  class Array
4
6
  # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # Wraps its argument in an array unless it is already an array (or array-like).
3
5
  #
@@ -1,7 +1,9 @@
1
- require 'active_support/core_ext/array/wrap'
2
- require 'active_support/core_ext/array/access'
3
- require 'active_support/core_ext/array/conversions'
4
- require 'active_support/core_ext/array/extract_options'
5
- require 'active_support/core_ext/array/grouping'
6
- require 'active_support/core_ext/array/prepend_and_append'
7
- require 'active_support/core_ext/array/inquiry'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/wrap"
4
+ require "active_support/core_ext/array/access"
5
+ require "active_support/core_ext/array/conversions"
6
+ require "active_support/core_ext/array/extract"
7
+ require "active_support/core_ext/array/extract_options"
8
+ require "active_support/core_ext/array/grouping"
9
+ require "active_support/core_ext/array/inquiry"
@@ -1,4 +1,6 @@
1
- require 'benchmark'
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark"
2
4
 
3
5
  class << Benchmark
4
6
  # Benchmark realtime in milliseconds.
@@ -8,7 +10,7 @@ class << Benchmark
8
10
  #
9
11
  # Benchmark.ms { User.all }
10
12
  # # => 0.074
11
- def ms
12
- 1000 * realtime { yield }
13
+ def ms(&block)
14
+ 1000 * realtime(&block)
13
15
  end
14
16
  end