activesupport 4.2.11.1 → 6.1.7.3

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 (272) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +464 -391
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -7
  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 +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +34 -6
  9. data/lib/active_support/benchmarkable.rb +6 -4
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +61 -55
  12. data/lib/active_support/cache/mem_cache_store.rb +115 -100
  13. data/lib/active_support/cache/memory_store.rb +81 -58
  14. data/lib/active_support/cache/null_store.rb +11 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +90 -42
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +386 -225
  19. data/lib/active_support/callbacks.rb +661 -594
  20. data/lib/active_support/concern.rb +80 -7
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +226 -0
  23. data/lib/active_support/configurable.rb +16 -17
  24. data/lib/active_support/configuration_file.rb +51 -0
  25. data/lib/active_support/core_ext/array/access.rb +41 -1
  26. data/lib/active_support/core_ext/array/conversions.rb +24 -20
  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 +11 -18
  30. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  32. data/lib/active_support/core_ext/array.rb +9 -6
  33. data/lib/active_support/core_ext/benchmark.rb +5 -3
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +52 -48
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -25
  39. data/lib/active_support/core_ext/class.rb +4 -3
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +14 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  43. data/lib/active_support/core_ext/date/conversions.rb +27 -24
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +6 -4
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +167 -65
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +19 -3
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
  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 +14 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  53. data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +8 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +186 -22
  58. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +13 -10
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  65. data/lib/active_support/core_ext/hash/keys.rb +20 -43
  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 +5 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +5 -5
  77. data/lib/active_support/core_ext/load_error.rb +3 -22
  78. data/lib/active_support/core_ext/marshal.rb +10 -8
  79. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  80. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  81. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +63 -69
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +148 -0
  84. data/lib/active_support/core_ext/module/concerning.rb +19 -14
  85. data/lib/active_support/core_ext/module/delegation.rb +164 -51
  86. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  87. data/lib/active_support/core_ext/module/introspection.rb +23 -22
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  90. data/lib/active_support/core_ext/module.rb +13 -11
  91. data/lib/active_support/core_ext/name_error.rb +51 -4
  92. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +133 -136
  94. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  95. data/lib/active_support/core_ext/numeric.rb +5 -3
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +27 -3
  98. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  99. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  100. data/lib/active_support/core_ext/object/duplicable.rb +13 -93
  101. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  102. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  103. data/lib/active_support/core_ext/object/json.rb +63 -21
  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 +81 -23
  107. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  108. data/lib/active_support/core_ext/object.rb +14 -13
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  111. data/lib/active_support/core_ext/range/each.rb +18 -17
  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 +45 -0
  117. data/lib/active_support/core_ext/string/access.rb +9 -18
  118. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  119. data/lib/active_support/core_ext/string/conversions.rb +8 -4
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +48 -6
  122. data/lib/active_support/core_ext/string/indent.rb +6 -4
  123. data/lib/active_support/core_ext/string/inflections.rb +102 -26
  124. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  125. data/lib/active_support/core_ext/string/multibyte.rb +18 -9
  126. data/lib/active_support/core_ext/string/output_safety.rb +125 -40
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +6 -5
  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 +137 -53
  135. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +22 -13
  137. data/lib/active_support/core_ext/time/zones.rb +41 -7
  138. data/lib/active_support/core_ext/time.rb +7 -6
  139. data/lib/active_support/core_ext/uri.rb +11 -8
  140. data/lib/active_support/core_ext.rb +3 -1
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +210 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +57 -0
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +120 -0
  146. data/lib/active_support/dependencies.rb +241 -175
  147. data/lib/active_support/deprecation/behaviors.rb +58 -12
  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 +62 -21
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
  153. data/lib/active_support/deprecation/reporting.rb +81 -18
  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 +22 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  158. data/lib/active_support/duration/iso8601_serializer.rb +59 -0
  159. data/lib/active_support/duration.rb +364 -39
  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 +170 -0
  164. data/lib/active_support/execution_wrapper.rb +132 -0
  165. data/lib/active_support/executor.rb +8 -0
  166. data/lib/active_support/file_update_checker.rb +62 -37
  167. data/lib/active_support/fork_tracker.rb +64 -0
  168. data/lib/active_support/gem_version.rb +7 -5
  169. data/lib/active_support/gzip.rb +7 -5
  170. data/lib/active_support/hash_with_indifferent_access.rb +171 -48
  171. data/lib/active_support/i18n.rb +9 -6
  172. data/lib/active_support/i18n_railtie.rb +47 -16
  173. data/lib/active_support/inflections.rb +13 -11
  174. data/lib/active_support/inflector/inflections.rb +58 -14
  175. data/lib/active_support/inflector/methods.rb +186 -169
  176. data/lib/active_support/inflector/transliterate.rb +83 -33
  177. data/lib/active_support/inflector.rb +7 -5
  178. data/lib/active_support/json/decoding.rb +32 -30
  179. data/lib/active_support/json/encoding.rb +22 -61
  180. data/lib/active_support/json.rb +4 -2
  181. data/lib/active_support/key_generator.rb +11 -43
  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 +9 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  186. data/lib/active_support/log_subscriber.rb +52 -19
  187. data/lib/active_support/logger.rb +10 -24
  188. data/lib/active_support/logger_silence.rb +14 -20
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -10
  190. data/lib/active_support/message_encryptor.rb +167 -57
  191. data/lib/active_support/message_verifier.rb +151 -18
  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 +35 -80
  196. data/lib/active_support/multibyte/unicode.rb +22 -330
  197. data/lib/active_support/multibyte.rb +4 -2
  198. data/lib/active_support/notifications/fanout.rb +125 -23
  199. data/lib/active_support/notifications/instrumenter.rb +98 -16
  200. data/lib/active_support/notifications.rb +82 -14
  201. data/lib/active_support/number_helper/number_converter.rb +17 -16
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -14
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +14 -11
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +12 -10
  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 +15 -5
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +29 -57
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +123 -71
  211. data/lib/active_support/option_merger.rb +25 -4
  212. data/lib/active_support/ordered_hash.rb +7 -5
  213. data/lib/active_support/ordered_options.rb +35 -7
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +10 -4
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +10 -11
  218. data/lib/active_support/railtie.rb +66 -10
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +112 -57
  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 +13 -4
  224. data/lib/active_support/subscriber.rb +80 -31
  225. data/lib/active_support/tagged_logging.rb +54 -17
  226. data/lib/active_support/test_case.rb +107 -44
  227. data/lib/active_support/testing/assertions.rb +158 -20
  228. data/lib/active_support/testing/autorun.rb +4 -2
  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 +13 -10
  232. data/lib/active_support/testing/file_fixtures.rb +38 -0
  233. data/lib/active_support/testing/isolation.rb +35 -26
  234. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  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 +43 -0
  240. data/lib/active_support/testing/tagged_logging.rb +3 -1
  241. data/lib/active_support/testing/time_helpers.rb +121 -20
  242. data/lib/active_support/time.rb +14 -12
  243. data/lib/active_support/time_with_zone.rb +215 -51
  244. data/lib/active_support/values/time_zone.rb +223 -71
  245. data/lib/active_support/version.rb +3 -1
  246. data/lib/active_support/xml_mini/jdom.rb +116 -115
  247. data/lib/active_support/xml_mini/libxml.rb +16 -13
  248. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  249. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  250. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  251. data/lib/active_support/xml_mini/rexml.rb +18 -9
  252. data/lib/active_support/xml_mini.rb +38 -46
  253. data/lib/active_support.rb +25 -11
  254. metadata +100 -43
  255. data/lib/active_support/concurrency/latch.rb +0 -27
  256. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  257. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  258. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  259. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  260. data/lib/active_support/core_ext/hash/compact.rb +0 -24
  261. data/lib/active_support/core_ext/hash/transform_values.rb +0 -23
  262. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  263. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  264. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  265. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  266. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  267. data/lib/active_support/core_ext/object/itself.rb +0 -15
  268. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  269. data/lib/active_support/core_ext/struct.rb +0 -6
  270. data/lib/active_support/core_ext/thread.rb +0 -86
  271. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  272. 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,33 +114,96 @@ 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
- @_dependencies.each { |dep| base.send(:include, dep) }
133
+ @_dependencies.each { |dep| base.include(dep) }
118
134
  super
119
135
  base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
120
136
  base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
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
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thread"
4
+ require "monitor"
5
+
6
+ module ActiveSupport
7
+ module Concurrency
8
+ # A share/exclusive lock, otherwise known as a read/write lock.
9
+ #
10
+ # https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
11
+ class ShareLock
12
+ include MonitorMixin
13
+
14
+ # We track Thread objects, instead of just using counters, because
15
+ # we need exclusive locks to be reentrant, and we need to be able
16
+ # to upgrade share locks to exclusive.
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
49
+
50
+ def initialize
51
+ super()
52
+
53
+ @cv = new_cond
54
+
55
+ @sharing = Hash.new(0)
56
+ @waiting = {}
57
+ @sleeping = {}
58
+ @exclusive_thread = nil
59
+ @exclusive_depth = 0
60
+ end
61
+
62
+ # Returns false if +no_wait+ is set and the lock is not
63
+ # immediately available. Otherwise, returns true after the lock
64
+ # has been acquired.
65
+ #
66
+ # +purpose+ and +compatible+ work together; while this thread is
67
+ # waiting for the exclusive lock, it will yield its share (if any)
68
+ # to any other attempt whose +purpose+ appears in this attempt's
69
+ # +compatible+ list. This allows a "loose" upgrade, which, being
70
+ # less strict, prevents some classes of deadlocks.
71
+ #
72
+ # For many resources, loose upgrades are sufficient: if a thread
73
+ # is awaiting a lock, it is not running any other code. With
74
+ # +purpose+ matching, it is possible to yield only to other
75
+ # threads whose activity will not interfere.
76
+ def start_exclusive(purpose: nil, compatible: [], no_wait: false)
77
+ synchronize do
78
+ unless @exclusive_thread == Thread.current
79
+ if busy_for_exclusive?(purpose)
80
+ return false if no_wait
81
+
82
+ yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
83
+ wait_for(:start_exclusive) { busy_for_exclusive?(purpose) }
84
+ end
85
+ end
86
+ @exclusive_thread = Thread.current
87
+ end
88
+ @exclusive_depth += 1
89
+
90
+ true
91
+ end
92
+ end
93
+
94
+ # Relinquish the exclusive lock. Must only be called by the thread
95
+ # that called start_exclusive (and currently holds the lock).
96
+ def stop_exclusive(compatible: [])
97
+ synchronize do
98
+ raise "invalid unlock" if @exclusive_thread != Thread.current
99
+
100
+ @exclusive_depth -= 1
101
+ if @exclusive_depth == 0
102
+ @exclusive_thread = nil
103
+
104
+ if eligible_waiters?(compatible)
105
+ yield_shares(compatible: compatible, block_share: true) do
106
+ wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) }
107
+ end
108
+ end
109
+ @cv.broadcast
110
+ end
111
+ end
112
+ end
113
+
114
+ def start_sharing
115
+ synchronize do
116
+ if @sharing[Thread.current] > 0 || @exclusive_thread == Thread.current
117
+ # We already hold a lock; nothing to wait for
118
+ elsif @waiting[Thread.current]
119
+ # We're nested inside a +yield_shares+ call: we'll resume as
120
+ # soon as there isn't an exclusive lock in our way
121
+ wait_for(:start_sharing) { @exclusive_thread }
122
+ else
123
+ # This is an initial / outermost share call: any outstanding
124
+ # requests for an exclusive lock get to go first
125
+ wait_for(:start_sharing) { busy_for_sharing?(false) }
126
+ end
127
+ @sharing[Thread.current] += 1
128
+ end
129
+ end
130
+
131
+ def stop_sharing
132
+ synchronize do
133
+ if @sharing[Thread.current] > 1
134
+ @sharing[Thread.current] -= 1
135
+ else
136
+ @sharing.delete Thread.current
137
+ @cv.broadcast
138
+ end
139
+ end
140
+ end
141
+
142
+ # Execute the supplied block while holding the Exclusive lock. If
143
+ # +no_wait+ is set and the lock is not immediately available,
144
+ # returns +nil+ without yielding. Otherwise, returns the result of
145
+ # the block.
146
+ #
147
+ # See +start_exclusive+ for other options.
148
+ def exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false)
149
+ if start_exclusive(purpose: purpose, compatible: compatible, no_wait: no_wait)
150
+ begin
151
+ yield
152
+ ensure
153
+ stop_exclusive(compatible: after_compatible)
154
+ end
155
+ end
156
+ end
157
+
158
+ # Execute the supplied block while holding the Share lock.
159
+ def sharing
160
+ start_sharing
161
+ begin
162
+ yield
163
+ ensure
164
+ stop_sharing
165
+ end
166
+ end
167
+
168
+ # Temporarily give up all held Share locks while executing the
169
+ # supplied block, allowing any +compatible+ exclusive lock request
170
+ # to proceed.
171
+ def yield_shares(purpose: nil, compatible: [], block_share: false)
172
+ loose_shares = previous_wait = nil
173
+ synchronize do
174
+ if loose_shares = @sharing.delete(Thread.current)
175
+ if previous_wait = @waiting[Thread.current]
176
+ purpose = nil unless purpose == previous_wait[0]
177
+ compatible &= previous_wait[1]
178
+ end
179
+ compatible |= [false] unless block_share
180
+ @waiting[Thread.current] = [purpose, compatible]
181
+ end
182
+
183
+ @cv.broadcast
184
+ end
185
+
186
+ begin
187
+ yield
188
+ ensure
189
+ synchronize do
190
+ wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current }
191
+
192
+ if previous_wait
193
+ @waiting[Thread.current] = previous_wait
194
+ else
195
+ @waiting.delete Thread.current
196
+ end
197
+ @sharing[Thread.current] = loose_shares if loose_shares
198
+ end
199
+ end
200
+ end
201
+
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
208
+
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
213
+
214
+ def eligible_waiters?(compatible)
215
+ @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
216
+ end
217
+
218
+ def wait_for(method)
219
+ @sleeping[Thread.current] = method
220
+ @cv.wait_while { yield }
221
+ ensure
222
+ @sleeping.delete Thread.current
223
+ end
224
+ end
225
+ end
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,18 +114,19 @@ 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
124
123
  end
124
+ private :config_accessor
125
125
  end
126
126
 
127
- # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
127
+ # Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
128
128
  #
129
- # require 'active_support/configurable'
129
+ # require "active_support/configurable"
130
130
  #
131
131
  # class User
132
132
  # include ActiveSupport::Configurable
@@ -144,4 +144,3 @@ module ActiveSupport
144
144
  end
145
145
  end
146
146
  end
147
-
@@ -0,0 +1,51 @@
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
+ source = render(context)
23
+ if YAML.respond_to?(:unsafe_load)
24
+ YAML.unsafe_load(source, **options) || {}
25
+ else
26
+ YAML.load(source, **options) || {}
27
+ end
28
+ rescue Psych::SyntaxError => error
29
+ raise "YAML syntax error occurred while parsing #{@content_path}. " \
30
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
31
+ "Error: #{error.message}"
32
+ end
33
+
34
+ private
35
+ def read(content_path)
36
+ require "yaml"
37
+ require "erb"
38
+
39
+ File.read(content_path).tap do |content|
40
+ if content.include?("\u00A0")
41
+ warn "File contains invisible non-breaking spaces, you may want to remove those"
42
+ end
43
+ end
44
+ end
45
+
46
+ def render(context)
47
+ erb = ERB.new(@content).tap { |e| e.filename = @content_path }
48
+ context ? erb.result(context) : erb.result
49
+ end
50
+ end
51
+ 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
  #
@@ -21,12 +23,36 @@ class Array
21
23
  # %w( a b c ).to(-10) # => []
22
24
  def to(position)
23
25
  if position >= 0
24
- first position + 1
26
+ take position + 1
25
27
  else
26
28
  self[0..position]
27
29
  end
28
30
  end
29
31
 
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.
41
+ #
42
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
43
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
44
+ #
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.
52
+ def without(*elements)
53
+ excluding(*elements)
54
+ end
55
+
30
56
  # Equal to <tt>self[1]</tt>.
31
57
  #
32
58
  # %w( a b c d e ).second # => "b"
@@ -61,4 +87,18 @@ class Array
61
87
  def forty_two
62
88
  self[41]
63
89
  end
90
+
91
+ # Equal to <tt>self[-3]</tt>.
92
+ #
93
+ # %w( a b c d e ).third_to_last # => "c"
94
+ def third_to_last
95
+ self[-3]
96
+ end
97
+
98
+ # Equal to <tt>self[-2]</tt>.
99
+ #
100
+ # %w( a b c d e ).second_to_last # => "d"
101
+ def second_to_last
102
+ self[-2]
103
+ end
64
104
  end