activesupport 4.2.11.1 → 6.0.3.1

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

Potentially problematic release.


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

Files changed (263) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +399 -411
  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 +48 -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 +58 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +95 -91
  13. data/lib/active_support/cache/memory_store.rb +39 -36
  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 +75 -42
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +331 -217
  19. data/lib/active_support/callbacks.rb +650 -592
  20. data/lib/active_support/concern.rb +35 -6
  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 +13 -14
  24. data/lib/active_support/core_ext/array/access.rb +41 -1
  25. data/lib/active_support/core_ext/array/conversions.rb +24 -20
  26. data/lib/active_support/core_ext/array/extract.rb +21 -0
  27. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  28. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  29. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  30. data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
  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 +3 -1
  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 +45 -31
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  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 +25 -23
  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 +154 -65
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -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 +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +114 -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/compact.rb +4 -23
  61. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  62. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  63. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  64. data/lib/active_support/core_ext/hash/except.rb +12 -9
  65. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  66. data/lib/active_support/core_ext/hash/keys.rb +19 -42
  67. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  68. data/lib/active_support/core_ext/hash/slice.rb +5 -27
  69. data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
  70. data/lib/active_support/core_ext/hash.rb +10 -9
  71. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  72. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  73. data/lib/active_support/core_ext/integer/time.rb +11 -18
  74. data/lib/active_support/core_ext/integer.rb +5 -3
  75. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  76. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  78. data/lib/active_support/core_ext/kernel.rb +5 -5
  79. data/lib/active_support/core_ext/load_error.rb +3 -22
  80. data/lib/active_support/core_ext/marshal.rb +8 -8
  81. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  82. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  83. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  84. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -46
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  87. data/lib/active_support/core_ext/module/delegation.rb +133 -30
  88. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  89. data/lib/active_support/core_ext/module/introspection.rb +44 -19
  90. data/lib/active_support/core_ext/module/reachable.rb +5 -7
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -11
  94. data/lib/active_support/core_ext/name_error.rb +22 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
  97. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  99. data/lib/active_support/core_ext/numeric.rb +5 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  101. data/lib/active_support/core_ext/object/blank.rb +27 -3
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  104. data/lib/active_support/core_ext/object/duplicable.rb +13 -93
  105. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +51 -20
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  110. data/lib/active_support/core_ext/object/try.rb +81 -23
  111. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  112. data/lib/active_support/core_ext/object.rb +14 -13
  113. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  114. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  115. data/lib/active_support/core_ext/range/each.rb +18 -17
  116. data/lib/active_support/core_ext/range/include_range.rb +7 -21
  117. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  118. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  119. data/lib/active_support/core_ext/range.rb +7 -4
  120. data/lib/active_support/core_ext/regexp.rb +2 -0
  121. data/lib/active_support/core_ext/securerandom.rb +45 -0
  122. data/lib/active_support/core_ext/string/access.rb +16 -6
  123. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  124. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  125. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  126. data/lib/active_support/core_ext/string/filters.rb +48 -6
  127. data/lib/active_support/core_ext/string/indent.rb +6 -4
  128. data/lib/active_support/core_ext/string/inflections.rb +66 -24
  129. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  130. data/lib/active_support/core_ext/string/multibyte.rb +16 -7
  131. data/lib/active_support/core_ext/string/output_safety.rb +93 -40
  132. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  133. data/lib/active_support/core_ext/string/strip.rb +6 -5
  134. data/lib/active_support/core_ext/string/zones.rb +4 -2
  135. data/lib/active_support/core_ext/string.rb +15 -13
  136. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  137. data/lib/active_support/core_ext/time/calculations.rb +115 -52
  138. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  139. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  140. data/lib/active_support/core_ext/time/zones.rb +41 -7
  141. data/lib/active_support/core_ext/time.rb +7 -6
  142. data/lib/active_support/core_ext/uri.rb +6 -7
  143. data/lib/active_support/core_ext.rb +3 -1
  144. data/lib/active_support/current_attributes.rb +203 -0
  145. data/lib/active_support/dependencies/autoload.rb +2 -0
  146. data/lib/active_support/dependencies/interlock.rb +57 -0
  147. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  148. data/lib/active_support/dependencies.rb +208 -166
  149. data/lib/active_support/deprecation/behaviors.rb +44 -11
  150. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  151. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  152. data/lib/active_support/deprecation/method_wrappers.rb +61 -21
  153. data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
  154. data/lib/active_support/deprecation/reporting.rb +32 -12
  155. data/lib/active_support/deprecation.rb +12 -9
  156. data/lib/active_support/descendants_tracker.rb +57 -9
  157. data/lib/active_support/digest.rb +20 -0
  158. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  159. data/lib/active_support/duration/iso8601_serializer.rb +53 -0
  160. data/lib/active_support/duration.rb +315 -40
  161. data/lib/active_support/encrypted_configuration.rb +45 -0
  162. data/lib/active_support/encrypted_file.rb +100 -0
  163. data/lib/active_support/evented_file_update_checker.rb +234 -0
  164. data/lib/active_support/execution_wrapper.rb +129 -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/gem_version.rb +6 -4
  168. data/lib/active_support/gzip.rb +7 -5
  169. data/lib/active_support/hash_with_indifferent_access.rb +129 -30
  170. data/lib/active_support/i18n.rb +9 -6
  171. data/lib/active_support/i18n_railtie.rb +50 -14
  172. data/lib/active_support/inflections.rb +13 -11
  173. data/lib/active_support/inflector/inflections.rb +58 -13
  174. data/lib/active_support/inflector/methods.rb +159 -145
  175. data/lib/active_support/inflector/transliterate.rb +84 -34
  176. data/lib/active_support/inflector.rb +7 -5
  177. data/lib/active_support/json/decoding.rb +32 -30
  178. data/lib/active_support/json/encoding.rb +17 -60
  179. data/lib/active_support/json.rb +4 -2
  180. data/lib/active_support/key_generator.rb +11 -43
  181. data/lib/active_support/lazy_load_hooks.rb +53 -20
  182. data/lib/active_support/locale/en.rb +33 -0
  183. data/lib/active_support/locale/en.yml +2 -0
  184. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  185. data/lib/active_support/log_subscriber.rb +44 -19
  186. data/lib/active_support/logger.rb +9 -23
  187. data/lib/active_support/logger_silence.rb +32 -14
  188. data/lib/active_support/logger_thread_safe_level.rb +32 -8
  189. data/lib/active_support/message_encryptor.rb +166 -53
  190. data/lib/active_support/message_verifier.rb +149 -16
  191. data/lib/active_support/messages/metadata.rb +72 -0
  192. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  193. data/lib/active_support/messages/rotator.rb +56 -0
  194. data/lib/active_support/multibyte/chars.rb +56 -63
  195. data/lib/active_support/multibyte/unicode.rb +56 -290
  196. data/lib/active_support/multibyte.rb +4 -2
  197. data/lib/active_support/notifications/fanout.rb +109 -22
  198. data/lib/active_support/notifications/instrumenter.rb +107 -16
  199. data/lib/active_support/notifications.rb +51 -10
  200. data/lib/active_support/number_helper/number_converter.rb +16 -15
  201. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
  202. data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
  203. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
  204. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
  205. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  206. data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
  207. data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
  208. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  209. data/lib/active_support/number_helper.rb +105 -68
  210. data/lib/active_support/option_merger.rb +24 -4
  211. data/lib/active_support/ordered_hash.rb +7 -5
  212. data/lib/active_support/ordered_options.rb +27 -5
  213. data/lib/active_support/parameter_filter.rb +128 -0
  214. data/lib/active_support/per_thread_registry.rb +9 -4
  215. data/lib/active_support/proxy_object.rb +2 -0
  216. data/lib/active_support/rails.rb +10 -8
  217. data/lib/active_support/railtie.rb +43 -9
  218. data/lib/active_support/reloader.rb +130 -0
  219. data/lib/active_support/rescuable.rb +108 -53
  220. data/lib/active_support/security_utils.rb +15 -11
  221. data/lib/active_support/string_inquirer.rb +11 -4
  222. data/lib/active_support/subscriber.rb +74 -30
  223. data/lib/active_support/tagged_logging.rb +25 -13
  224. data/lib/active_support/test_case.rb +107 -44
  225. data/lib/active_support/testing/assertions.rb +151 -20
  226. data/lib/active_support/testing/autorun.rb +4 -2
  227. data/lib/active_support/testing/constant_lookup.rb +2 -1
  228. data/lib/active_support/testing/declarative.rb +3 -1
  229. data/lib/active_support/testing/deprecation.rb +13 -10
  230. data/lib/active_support/testing/file_fixtures.rb +38 -0
  231. data/lib/active_support/testing/isolation.rb +35 -26
  232. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  233. data/lib/active_support/testing/parallelization.rb +134 -0
  234. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  235. data/lib/active_support/testing/stream.rb +43 -0
  236. data/lib/active_support/testing/tagged_logging.rb +3 -1
  237. data/lib/active_support/testing/time_helpers.rb +84 -20
  238. data/lib/active_support/time.rb +14 -12
  239. data/lib/active_support/time_with_zone.rb +179 -39
  240. data/lib/active_support/values/time_zone.rb +203 -63
  241. data/lib/active_support/version.rb +3 -1
  242. data/lib/active_support/xml_mini/jdom.rb +116 -115
  243. data/lib/active_support/xml_mini/libxml.rb +16 -13
  244. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  245. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  246. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  247. data/lib/active_support/xml_mini/rexml.rb +11 -9
  248. data/lib/active_support/xml_mini.rb +38 -46
  249. data/lib/active_support.rb +13 -11
  250. metadata +84 -26
  251. data/lib/active_support/concurrency/latch.rb +0 -27
  252. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  253. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  254. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  255. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  256. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  257. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  258. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  259. data/lib/active_support/core_ext/object/itself.rb +0 -15
  260. data/lib/active_support/core_ext/struct.rb +0 -6
  261. data/lib/active_support/core_ext/thread.rb +0 -86
  262. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  263. 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
  #
@@ -108,29 +110,56 @@ module ActiveSupport
108
110
  base.instance_variable_set(:@_dependencies, [])
109
111
  end
110
112
 
111
- def append_features(base)
113
+ def append_features(base) #:nodoc:
112
114
  if base.instance_variable_defined?(:@_dependencies)
113
115
  base.instance_variable_get(:@_dependencies) << self
114
- return false
116
+ false
115
117
  else
116
118
  return false if base < self
117
- @_dependencies.each { |dep| base.send(:include, dep) }
119
+ @_dependencies.each { |dep| base.include(dep) }
118
120
  super
119
121
  base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
120
122
  base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
121
123
  end
122
124
  end
123
125
 
126
+ # Evaluate given block in context of base class,
127
+ # so that you can write class macros here.
128
+ # When you define more than one +included+ block, it raises an exception.
124
129
  def included(base = nil, &block)
125
130
  if base.nil?
126
- raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
127
-
128
- @_included_block = block
131
+ if instance_variable_defined?(:@_included_block)
132
+ if @_included_block.source_location != block.source_location
133
+ raise MultipleIncludedBlocks
134
+ end
135
+ else
136
+ @_included_block = block
137
+ end
129
138
  else
130
139
  super
131
140
  end
132
141
  end
133
142
 
143
+ # Define class methods from given block.
144
+ # You can define private class methods as well.
145
+ #
146
+ # module Example
147
+ # extend ActiveSupport::Concern
148
+ #
149
+ # class_methods do
150
+ # def foo; puts 'foo'; end
151
+ #
152
+ # private
153
+ # def bar; puts 'bar'; end
154
+ # end
155
+ # end
156
+ #
157
+ # class Buzz
158
+ # include Example
159
+ # end
160
+ #
161
+ # Buzz.foo # => "foo"
162
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
134
163
  def class_methods(&class_methods_module_definition)
135
164
  mod = const_defined?(:ClassMethods, false) ?
136
165
  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,6 +1,7 @@
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
@@ -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,13 +114,14 @@ 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
127
  # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
@@ -144,4 +144,3 @@ module ActiveSupport
144
144
  end
145
145
  end
146
146
  end
147
-
@@ -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
@@ -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
@@ -32,7 +34,7 @@ class Array
32
34
  # ['one', 'two', 'three'].to_sentence # => "one, two, and three"
33
35
  #
34
36
  # ['one', 'two'].to_sentence(passing: 'invalid option')
35
- # # => ArgumentError: Unknown key :passing
37
+ # # => ArgumentError: Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale
36
38
  #
37
39
  # ['one', 'two'].to_sentence(two_words_connector: '-')
38
40
  # # => "one-two"
@@ -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,27 +74,29 @@ class Array
72
74
 
73
75
  case length
74
76
  when 0
75
- ''
77
+ +""
76
78
  when 1
77
- self[0].to_s.dup
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
 
85
87
  # Extends <tt>Array#to_s</tt> to convert a collection of elements into a
86
88
  # comma separated id list if <tt>:db</tt> argument is given as the format.
87
89
  #
88
- # Blog.all.to_formatted_s(:db) # => "1,2,3"
90
+ # Blog.all.to_formatted_s(:db) # => "1,2,3"
91
+ # Blog.none.to_formatted_s(:db) # => "null"
92
+ # [1,2].to_formatted_s # => "[1, 2]"
89
93
  def to_formatted_s(format = :default)
90
94
  case format
91
95
  when :db
92
96
  if empty?
93
- 'null'
97
+ "null"
94
98
  else
95
- collect { |element| element.id }.join(',')
99
+ collect(&:id).join(",")
96
100
  end
97
101
  else
98
102
  to_default_s
@@ -177,7 +181,7 @@ class Array
177
181
  # </messages>
178
182
  #
179
183
  def to_xml(options = {})
180
- require 'active_support/builder' unless defined?(Builder)
184
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
181
185
 
182
186
  options = options.dup
183
187
  options[:indent] ||= 2
@@ -185,9 +189,9 @@ class Array
185
189
  options[:root] ||= \
186
190
  if first.class != Hash && all? { |e| e.is_a?(first.class) }
187
191
  underscored = ActiveSupport::Inflector.underscore(first.class.name)
188
- ActiveSupport::Inflector.pluralize(underscored).tr('/', '_')
192
+ ActiveSupport::Inflector.pluralize(underscored).tr("/", "_")
189
193
  else
190
- 'objects'
194
+ "objects"
191
195
  end
192
196
 
193
197
  builder = options[:builder]
@@ -195,7 +199,7 @@ class Array
195
199
 
196
200
  root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
197
201
  children = options.delete(:children) || root.singularize
198
- attributes = options[:skip_types] ? {} : { type: 'array' }
202
+ attributes = options[:skip_types] ? {} : { type: "array" }
199
203
 
200
204
  if empty?
201
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,28 +91,19 @@ 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)
94
+ arr = dup
95
+ result = []
92
96
  if block_given?
93
- inject([[]]) do |results, element|
94
- if yield(element)
95
- results << []
96
- else
97
- results.last << element
98
- end
99
-
100
- results
97
+ while (idx = arr.index { |i| yield i })
98
+ result << arr.shift(idx)
99
+ arr.shift
101
100
  end
102
101
  else
103
- results, arr = [[]], self.dup
104
- until arr.empty?
105
- if (idx = arr.index(value))
106
- results.last.concat(arr.shift(idx))
107
- arr.shift
108
- results << []
109
- else
110
- results.last.concat(arr.shift(arr.size))
111
- end
102
+ while (idx = arr.index(value))
103
+ result << arr.shift(idx)
104
+ arr.shift
112
105
  end
113
- results
114
106
  end
107
+ result << arr
115
108
  end
116
109
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/array_inquirer"
4
+
5
+ class Array
6
+ # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way
7
+ # to check its string-like contents.
8
+ #
9
+ # pets = [:cat, :dog].inquiry
10
+ #
11
+ # pets.cat? # => true
12
+ # pets.ferret? # => false
13
+ #
14
+ # pets.any?(:cat, :ferret) # => true
15
+ # pets.any?(:ferret, :alligator) # => false
16
+ def inquiry
17
+ ActiveSupport::ArrayInquirer.new(self)
18
+ end
19
+ end
@@ -1,7 +1,5 @@
1
- class Array
2
- # The human way of thinking about adding stuff to the end of a list is with append.
3
- alias_method :append, :<<
1
+ # frozen_string_literal: true
4
2
 
5
- # The human way of thinking about adding stuff to the beginning of a list is with prepend.
6
- alias_method :prepend, :unshift
7
- end
3
+ require "active_support/deprecation"
4
+
5
+ ActiveSupport::Deprecation.warn "Ruby 2.5+ (required by Rails 6) provides Array#append and Array#prepend natively, so requiring active_support/core_ext/array/prepend_and_append is no longer necessary. Requiring it will raise LoadError in Rails 6.1."