activesupport 4.2.11.3 → 5.2.8.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 (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +435 -403
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +4 -5
  5. data/lib/active_support/all.rb +5 -3
  6. data/lib/active_support/array_inquirer.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +7 -5
  8. data/lib/active_support/benchmarkable.rb +6 -4
  9. data/lib/active_support/builder.rb +3 -1
  10. data/lib/active_support/cache/file_store.rb +41 -35
  11. data/lib/active_support/cache/mem_cache_store.rb +91 -91
  12. data/lib/active_support/cache/memory_store.rb +27 -30
  13. data/lib/active_support/cache/null_store.rb +7 -8
  14. data/lib/active_support/cache/redis_cache_store.rb +466 -0
  15. data/lib/active_support/cache/strategy/local_cache.rb +67 -34
  16. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  17. data/lib/active_support/cache.rb +287 -196
  18. data/lib/active_support/callbacks.rb +640 -590
  19. data/lib/active_support/concern.rb +11 -5
  20. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  21. data/lib/active_support/concurrency/share_lock.rb +227 -0
  22. data/lib/active_support/configurable.rb +8 -5
  23. data/lib/active_support/core_ext/array/access.rb +29 -1
  24. data/lib/active_support/core_ext/array/conversions.rb +22 -18
  25. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  27. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  28. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -3
  29. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  30. data/lib/active_support/core_ext/array.rb +9 -6
  31. data/lib/active_support/core_ext/benchmark.rb +3 -1
  32. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  33. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  34. data/lib/active_support/core_ext/class/attribute.rb +41 -22
  35. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  36. data/lib/active_support/core_ext/class/subclasses.rb +20 -6
  37. data/lib/active_support/core_ext/class.rb +4 -3
  38. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  39. data/lib/active_support/core_ext/date/blank.rb +14 -0
  40. data/lib/active_support/core_ext/date/calculations.rb +11 -9
  41. data/lib/active_support/core_ext/date/conversions.rb +25 -23
  42. data/lib/active_support/core_ext/date/zones.rb +4 -2
  43. data/lib/active_support/core_ext/date.rb +6 -4
  44. data/lib/active_support/core_ext/date_and_time/calculations.rb +170 -58
  45. data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
  46. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
  47. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  48. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  49. data/lib/active_support/core_ext/date_time/calculations.rb +36 -18
  50. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  51. data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
  52. data/lib/active_support/core_ext/date_time.rb +7 -5
  53. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  54. data/lib/active_support/core_ext/digest.rb +3 -0
  55. data/lib/active_support/core_ext/enumerable.rb +101 -33
  56. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  57. data/lib/active_support/core_ext/file.rb +3 -1
  58. data/lib/active_support/core_ext/hash/compact.rb +14 -9
  59. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  60. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  61. data/lib/active_support/core_ext/hash/except.rb +11 -8
  62. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  63. data/lib/active_support/core_ext/hash/keys.rb +33 -27
  64. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  65. data/lib/active_support/core_ext/hash/slice.rb +8 -8
  66. data/lib/active_support/core_ext/hash/transform_values.rb +14 -5
  67. data/lib/active_support/core_ext/hash.rb +11 -9
  68. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  69. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  70. data/lib/active_support/core_ext/integer/time.rb +11 -18
  71. data/lib/active_support/core_ext/integer.rb +5 -3
  72. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  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 +6 -5
  77. data/lib/active_support/core_ext/load_error.rb +3 -22
  78. data/lib/active_support/core_ext/marshal.rb +8 -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 +43 -40
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
  84. data/lib/active_support/core_ext/module/concerning.rb +11 -12
  85. data/lib/active_support/core_ext/module/delegation.rb +98 -36
  86. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  87. data/lib/active_support/core_ext/module/introspection.rb +9 -9
  88. data/lib/active_support/core_ext/module/reachable.rb +5 -2
  89. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  90. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  91. data/lib/active_support/core_ext/module.rb +14 -11
  92. data/lib/active_support/core_ext/name_error.rb +22 -2
  93. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  94. data/lib/active_support/core_ext/numeric/conversions.rb +78 -81
  95. data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
  96. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  97. data/lib/active_support/core_ext/numeric.rb +6 -3
  98. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  99. data/lib/active_support/core_ext/object/blank.rb +27 -2
  100. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  101. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  102. data/lib/active_support/core_ext/object/duplicable.rb +41 -14
  103. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  104. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  105. data/lib/active_support/core_ext/object/json.rb +49 -19
  106. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  107. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  108. data/lib/active_support/core_ext/object/try.rb +69 -21
  109. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  110. data/lib/active_support/core_ext/object.rb +14 -13
  111. data/lib/active_support/core_ext/range/compare_range.rb +61 -0
  112. data/lib/active_support/core_ext/range/conversions.rb +27 -7
  113. data/lib/active_support/core_ext/range/each.rb +19 -17
  114. data/lib/active_support/core_ext/range/include_range.rb +2 -22
  115. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  116. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  117. data/lib/active_support/core_ext/range.rb +7 -4
  118. data/lib/active_support/core_ext/regexp.rb +6 -0
  119. data/lib/active_support/core_ext/securerandom.rb +25 -0
  120. data/lib/active_support/core_ext/string/access.rb +8 -6
  121. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  122. data/lib/active_support/core_ext/string/conversions.rb +7 -4
  123. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  124. data/lib/active_support/core_ext/string/filters.rb +6 -5
  125. data/lib/active_support/core_ext/string/indent.rb +6 -4
  126. data/lib/active_support/core_ext/string/inflections.rb +61 -24
  127. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  128. data/lib/active_support/core_ext/string/multibyte.rb +15 -7
  129. data/lib/active_support/core_ext/string/output_safety.rb +62 -38
  130. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  131. data/lib/active_support/core_ext/string/strip.rb +4 -5
  132. data/lib/active_support/core_ext/string/zones.rb +4 -2
  133. data/lib/active_support/core_ext/string.rb +15 -13
  134. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  135. data/lib/active_support/core_ext/time/calculations.rb +85 -51
  136. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  137. data/lib/active_support/core_ext/time/conversions.rb +20 -13
  138. data/lib/active_support/core_ext/time/zones.rb +41 -7
  139. data/lib/active_support/core_ext/time.rb +7 -6
  140. data/lib/active_support/core_ext/uri.rb +6 -8
  141. data/lib/active_support/core_ext.rb +3 -1
  142. data/lib/active_support/current_attributes.rb +195 -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.rb +152 -161
  146. data/lib/active_support/deprecation/behaviors.rb +44 -11
  147. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  149. data/lib/active_support/deprecation/method_wrappers.rb +66 -20
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
  151. data/lib/active_support/deprecation/reporting.rb +32 -12
  152. data/lib/active_support/deprecation.rb +12 -9
  153. data/lib/active_support/descendants_tracker.rb +2 -0
  154. data/lib/active_support/digest.rb +20 -0
  155. data/lib/active_support/duration/iso8601_parser.rb +125 -0
  156. data/lib/active_support/duration/iso8601_serializer.rb +55 -0
  157. data/lib/active_support/duration.rb +314 -38
  158. data/lib/active_support/encrypted_configuration.rb +49 -0
  159. data/lib/active_support/encrypted_file.rb +99 -0
  160. data/lib/active_support/evented_file_update_checker.rb +205 -0
  161. data/lib/active_support/execution_wrapper.rb +131 -0
  162. data/lib/active_support/executor.rb +8 -0
  163. data/lib/active_support/file_update_checker.rb +63 -37
  164. data/lib/active_support/gem_version.rb +6 -4
  165. data/lib/active_support/gzip.rb +7 -5
  166. data/lib/active_support/hash_with_indifferent_access.rb +123 -28
  167. data/lib/active_support/i18n.rb +8 -6
  168. data/lib/active_support/i18n_railtie.rb +37 -13
  169. data/lib/active_support/inflections.rb +13 -11
  170. data/lib/active_support/inflector/inflections.rb +61 -12
  171. data/lib/active_support/inflector/methods.rb +163 -136
  172. data/lib/active_support/inflector/transliterate.rb +48 -27
  173. data/lib/active_support/inflector.rb +7 -5
  174. data/lib/active_support/json/decoding.rb +16 -13
  175. data/lib/active_support/json/encoding.rb +11 -58
  176. data/lib/active_support/json.rb +4 -2
  177. data/lib/active_support/key_generator.rb +25 -25
  178. data/lib/active_support/lazy_load_hooks.rb +50 -20
  179. data/lib/active_support/locale/en.yml +2 -0
  180. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  181. data/lib/active_support/log_subscriber.rb +13 -10
  182. data/lib/active_support/logger.rb +8 -7
  183. data/lib/active_support/logger_silence.rb +6 -4
  184. data/lib/active_support/logger_thread_safe_level.rb +7 -5
  185. data/lib/active_support/message_encryptor.rb +168 -53
  186. data/lib/active_support/message_verifier.rb +150 -17
  187. data/lib/active_support/messages/metadata.rb +71 -0
  188. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  189. data/lib/active_support/messages/rotator.rb +56 -0
  190. data/lib/active_support/multibyte/chars.rb +36 -23
  191. data/lib/active_support/multibyte/unicode.rb +100 -96
  192. data/lib/active_support/multibyte.rb +4 -2
  193. data/lib/active_support/notifications/fanout.rb +11 -9
  194. data/lib/active_support/notifications/instrumenter.rb +27 -7
  195. data/lib/active_support/notifications.rb +11 -7
  196. data/lib/active_support/number_helper/number_converter.rb +13 -11
  197. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
  198. data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
  199. data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
  200. data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
  201. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  202. data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
  203. data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
  204. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  205. data/lib/active_support/number_helper.rb +94 -68
  206. data/lib/active_support/option_merger.rb +3 -1
  207. data/lib/active_support/ordered_hash.rb +6 -4
  208. data/lib/active_support/ordered_options.rb +23 -5
  209. data/lib/active_support/per_thread_registry.rb +9 -4
  210. data/lib/active_support/proxy_object.rb +2 -0
  211. data/lib/active_support/rails.rb +16 -8
  212. data/lib/active_support/railtie.rb +43 -9
  213. data/lib/active_support/reloader.rb +131 -0
  214. data/lib/active_support/rescuable.rb +108 -53
  215. data/lib/active_support/security_utils.rb +15 -11
  216. data/lib/active_support/string_inquirer.rb +11 -3
  217. data/lib/active_support/subscriber.rb +21 -16
  218. data/lib/active_support/tagged_logging.rb +14 -11
  219. data/lib/active_support/test_case.rb +19 -47
  220. data/lib/active_support/testing/assertions.rb +137 -20
  221. data/lib/active_support/testing/autorun.rb +4 -2
  222. data/lib/active_support/testing/constant_lookup.rb +2 -1
  223. data/lib/active_support/testing/declarative.rb +3 -1
  224. data/lib/active_support/testing/deprecation.rb +14 -10
  225. data/lib/active_support/testing/file_fixtures.rb +36 -0
  226. data/lib/active_support/testing/isolation.rb +34 -25
  227. data/lib/active_support/testing/method_call_assertions.rb +43 -0
  228. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  229. data/lib/active_support/testing/stream.rb +44 -0
  230. data/lib/active_support/testing/tagged_logging.rb +3 -1
  231. data/lib/active_support/testing/time_helpers.rb +81 -15
  232. data/lib/active_support/time.rb +14 -12
  233. data/lib/active_support/time_with_zone.rb +169 -39
  234. data/lib/active_support/values/time_zone.rb +196 -61
  235. data/lib/active_support/values/unicode_tables.dat +0 -0
  236. data/lib/active_support/version.rb +3 -1
  237. data/lib/active_support/xml_mini/jdom.rb +116 -114
  238. data/lib/active_support/xml_mini/libxml.rb +16 -13
  239. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  240. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  241. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  242. data/lib/active_support/xml_mini/rexml.rb +11 -9
  243. data/lib/active_support/xml_mini.rb +37 -37
  244. data/lib/active_support.rb +12 -11
  245. metadata +57 -27
  246. data/lib/active_support/concurrency/latch.rb +0 -27
  247. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  248. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  249. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  250. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  251. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  252. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  253. data/lib/active_support/core_ext/object/itself.rb +0 -15
  254. data/lib/active_support/core_ext/struct.rb +0 -6
  255. data/lib/active_support/core_ext/thread.rb +0 -86
  256. data/lib/active_support/core_ext/time/marshal.rb +0 -30
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  # A typical module looks like this:
3
5
  #
@@ -111,10 +113,10 @@ module ActiveSupport
111
113
  def append_features(base)
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)
@@ -123,9 +125,13 @@ module ActiveSupport
123
125
 
124
126
  def included(base = nil, &block)
125
127
  if base.nil?
126
- raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
127
-
128
- @_included_block = block
128
+ if instance_variable_defined?(:@_included_block)
129
+ if @_included_block.source_location != block.source_location
130
+ raise MultipleIncludedBlocks
131
+ end
132
+ else
133
+ @_included_block = block
134
+ end
129
135
  else
130
136
  super
131
137
  end
@@ -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,227 @@
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
+
204
+ # Must be called within synchronize
205
+ def busy_for_exclusive?(purpose)
206
+ busy_for_sharing?(purpose) ||
207
+ @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0)
208
+ end
209
+
210
+ def busy_for_sharing?(purpose)
211
+ (@exclusive_thread && @exclusive_thread != Thread.current) ||
212
+ @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) }
213
+ end
214
+
215
+ def eligible_waiters?(compatible)
216
+ @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
217
+ end
218
+
219
+ def wait_for(method)
220
+ @sleeping[Thread.current] = method
221
+ @cv.wait_while { yield }
222
+ ensure
223
+ @sleeping.delete Thread.current
224
+ end
225
+ end
226
+ end
227
+ end
@@ -1,6 +1,9 @@
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"
5
+ require "active_support/core_ext/array/extract_options"
6
+ require "active_support/core_ext/regexp"
4
7
 
5
8
  module ActiveSupport
6
9
  # Configurable provides a <tt>config</tt> method to store and retrieve
@@ -107,7 +110,7 @@ module ActiveSupport
107
110
  options = names.extract_options!
108
111
 
109
112
  names.each do |name|
110
- raise NameError.new('invalid config attribute name') unless name =~ /\A[_A-Za-z]\w*\z/
113
+ raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
111
114
 
112
115
  reader, reader_line = "def #{name}; config.#{name}; end", __LINE__
113
116
  writer, writer_line = "def #{name}=(value); config.#{name} = value; end", __LINE__
@@ -122,6 +125,7 @@ module ActiveSupport
122
125
  send("#{name}=", yield) if block_given?
123
126
  end
124
127
  end
128
+ private :config_accessor
125
129
  end
126
130
 
127
131
  # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
@@ -144,4 +148,3 @@ module ActiveSupport
144
148
  end
145
149
  end
146
150
  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,24 @@ 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 copy of the Array without the specified elements.
33
+ #
34
+ # people = ["David", "Rafael", "Aaron", "Todd"]
35
+ # people.without "Aaron", "Todd"
36
+ # # => ["David", "Rafael"]
37
+ #
38
+ # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt>
39
+ # instead of <tt>Array#reject</tt> for performance reasons.
40
+ def without(*elements)
41
+ self - elements
42
+ end
43
+
30
44
  # Equal to <tt>self[1]</tt>.
31
45
  #
32
46
  # %w( a b c d e ).second # => "b"
@@ -61,4 +75,18 @@ class Array
61
75
  def forty_two
62
76
  self[41]
63
77
  end
78
+
79
+ # Equal to <tt>self[-3]</tt>.
80
+ #
81
+ # %w( a b c d e ).third_to_last # => "c"
82
+ def third_to_last
83
+ self[-3]
84
+ end
85
+
86
+ # Equal to <tt>self[-2]</tt>.
87
+ #
88
+ # %w( a b c d e ).second_to_last # => "d"
89
+ def second_to_last
90
+ self[-2]
91
+ end
64
92
  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,9 +74,9 @@ 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
81
  "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
80
82
  else
@@ -85,14 +87,16 @@ class Array
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)
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)
@@ -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,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # The human way of thinking about adding stuff to the end of a list is with append.
3
- alias_method :append, :<<
5
+ alias_method :append, :push unless [].respond_to?(:append)
4
6
 
5
7
  # The human way of thinking about adding stuff to the beginning of a list is with prepend.
6
- alias_method :prepend, :unshift
7
- end
8
+ alias_method :prepend, :unshift unless [].respond_to?(:prepend)
9
+ end
@@ -1,9 +1,11 @@
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
  #
4
6
  # Specifically:
5
7
  #
6
- # * If the argument is +nil+ an empty list is returned.
8
+ # * If the argument is +nil+ an empty array is returned.
7
9
  # * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
8
10
  # * Otherwise, returns an array with the argument as its single element.
9
11
  #
@@ -15,12 +17,13 @@ class Array
15
17
  #
16
18
  # * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
17
19
  # moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns
18
- # +nil+ right away.
20
+ # an array with the argument as its single element right away.
19
21
  # * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt>
20
22
  # raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
21
- # * It does not call +to_a+ on the argument, but returns an empty array if argument is +nil+.
23
+ # * It does not call +to_a+ on the argument, if the argument does not respond to +to_ary+
24
+ # it returns an array with the argument as its single element.
22
25
  #
23
- # The second point is easily explained with some enumerables:
26
+ # The last point is easily explained with some enumerables:
24
27
  #
25
28
  # Array(foo: :bar) # => [[:foo, :bar]]
26
29
  # Array.wrap(foo: :bar) # => [{:foo=>:bar}]
@@ -1,6 +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'
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_options"
7
+ require "active_support/core_ext/array/grouping"
8
+ require "active_support/core_ext/array/prepend_and_append"
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.
@@ -1,16 +1,14 @@
1
- require 'bigdecimal'
2
- require 'bigdecimal/util'
1
+ # frozen_string_literal: true
3
2
 
4
- class BigDecimal
5
- DEFAULT_STRING_FORMAT = 'F'
6
- def to_formatted_s(*args)
7
- if args[0].is_a?(Symbol)
8
- super
9
- else
10
- format = args[0] || DEFAULT_STRING_FORMAT
11
- _original_to_s(format)
3
+ require "bigdecimal"
4
+ require "bigdecimal/util"
5
+
6
+ module ActiveSupport
7
+ module BigDecimalWithDefaultFormat #:nodoc:
8
+ def to_s(format = "F")
9
+ super(format)
12
10
  end
13
11
  end
14
- alias_method :_original_to_s, :to_s
15
- alias_method :to_s, :to_formatted_s
16
12
  end
13
+
14
+ BigDecimal.prepend(ActiveSupport::BigDecimalWithDefaultFormat)
@@ -1 +1,3 @@
1
- require 'active_support/core_ext/big_decimal/conversions'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/big_decimal/conversions"