activesupport 1.2.4 → 8.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +505 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +40 -0
- data/lib/active_support/actionable_error.rb +50 -0
- data/lib/active_support/all.rb +5 -0
- data/lib/active_support/array_inquirer.rb +50 -0
- data/lib/active_support/backtrace_cleaner.rb +234 -0
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +53 -0
- data/lib/active_support/broadcast_logger.rb +238 -0
- data/lib/active_support/builder.rb +8 -0
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +244 -0
- data/lib/active_support/cache/mem_cache_store.rb +288 -0
- data/lib/active_support/cache/memory_store.rb +264 -0
- data/lib/active_support/cache/null_store.rb +62 -0
- data/lib/active_support/cache/redis_cache_store.rb +498 -0
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +246 -0
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +1170 -0
- data/lib/active_support/callbacks.rb +960 -0
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +79 -0
- data/lib/active_support/concern.rb +217 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +225 -0
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +193 -0
- data/lib/active_support/configuration_file.rb +60 -0
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/access.rb +100 -0
- data/lib/active_support/core_ext/array/conversions.rb +209 -26
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/core_ext/array/grouping.rb +109 -0
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/core_ext/array.rb +8 -4
- data/lib/active_support/core_ext/benchmark.rb +6 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/active_support/core_ext/big_decimal.rb +3 -0
- data/lib/active_support/core_ext/class/attribute.rb +137 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/class/subclasses.rb +24 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/core_ext/date/blank.rb +18 -0
- data/lib/active_support/core_ext/date/calculations.rb +161 -0
- data/lib/active_support/core_ext/date/conversions.rb +95 -28
- data/lib/active_support/core_ext/date/zones.rb +8 -0
- data/lib/active_support/core_ext/date.rb +6 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
- data/lib/active_support/core_ext/date_time/blank.rb +18 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
- data/lib/active_support/core_ext/date_time.rb +7 -0
- data/lib/active_support/core_ext/digest/uuid.rb +76 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +277 -7
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/file/atomic.rb +72 -0
- data/lib/active_support/core_ext/file.rb +3 -0
- data/lib/active_support/core_ext/hash/conversions.rb +262 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +12 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
- data/lib/active_support/core_ext/hash/keys.rb +134 -44
- data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
- data/lib/active_support/core_ext/hash/slice.rb +27 -0
- data/lib/active_support/core_ext/hash.rb +9 -8
- data/lib/active_support/core_ext/integer/inflections.rb +29 -13
- data/lib/active_support/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/core_ext/integer/time.rb +22 -0
- data/lib/active_support/core_ext/integer.rb +4 -6
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/core_ext/kernel.rb +4 -78
- data/lib/active_support/core_ext/load_error.rb +6 -35
- data/lib/active_support/core_ext/module/aliasing.rb +31 -0
- data/lib/active_support/core_ext/module/anonymous.rb +30 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +225 -0
- data/lib/active_support/core_ext/module/deprecation.rb +25 -0
- data/lib/active_support/core_ext/module/introspection.rb +65 -0
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +17 -0
- data/lib/active_support/core_ext/module.rb +13 -0
- data/lib/active_support/core_ext/name_error.rb +59 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
- data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
- data/lib/active_support/core_ext/numeric/time.rb +64 -57
- data/lib/active_support/core_ext/numeric.rb +4 -6
- data/lib/active_support/core_ext/object/acts_like.rb +45 -0
- data/lib/active_support/core_ext/object/blank.rb +199 -0
- data/lib/active_support/core_ext/object/conversions.rb +6 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
- data/lib/active_support/core_ext/object/duplicable.rb +69 -0
- data/lib/active_support/core_ext/object/inclusion.rb +37 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
- data/lib/active_support/core_ext/object/json.rb +267 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -0
- data/lib/active_support/core_ext/object/to_query.rb +93 -0
- data/lib/active_support/core_ext/object/try.rb +158 -0
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +101 -0
- data/lib/active_support/core_ext/object.rb +17 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +58 -17
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +5 -4
- data/lib/active_support/core_ext/regexp.rb +14 -0
- data/lib/active_support/core_ext/securerandom.rb +57 -0
- data/lib/active_support/core_ext/string/access.rb +93 -56
- data/lib/active_support/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/core_ext/string/conversions.rb +57 -16
- data/lib/active_support/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/core_ext/string/filters.rb +151 -0
- data/lib/active_support/core_ext/string/indent.rb +45 -0
- data/lib/active_support/core_ext/string/inflections.rb +297 -54
- data/lib/active_support/core_ext/string/inquiry.rb +16 -0
- data/lib/active_support/core_ext/string/multibyte.rb +67 -0
- data/lib/active_support/core_ext/string/output_safety.rb +235 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
- data/lib/active_support/core_ext/string/strip.rb +27 -0
- data/lib/active_support/core_ext/string/zones.rb +16 -0
- data/lib/active_support/core_ext/string.rb +14 -10
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
- data/lib/active_support/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/core_ext/time/calculations.rb +358 -153
- data/lib/active_support/core_ext/time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/time/conversions.rb +69 -30
- data/lib/active_support/core_ext/time/zones.rb +97 -0
- data/lib/active_support/core_ext/time.rb +6 -6
- data/lib/active_support/core_ext.rb +5 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +243 -0
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +183 -0
- data/lib/active_support/dependencies/autoload.rb +72 -0
- data/lib/active_support/dependencies/interlock.rb +55 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +84 -222
- data/lib/active_support/deprecation/behaviors.rb +148 -0
- data/lib/active_support/deprecation/constant_accessor.rb +74 -0
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +54 -0
- data/lib/active_support/deprecation/method_wrappers.rb +68 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
- data/lib/active_support/deprecation/reporting.rb +162 -0
- data/lib/active_support/deprecation.rb +81 -0
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +112 -0
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +64 -0
- data/lib/active_support/duration.rb +524 -0
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +126 -0
- data/lib/active_support/encrypted_file.rb +133 -0
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +318 -0
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +185 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +110 -0
- data/lib/active_support/execution_wrapper.rb +150 -0
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +166 -0
- data/lib/active_support/fork_tracker.rb +43 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +41 -0
- data/lib/active_support/hash_with_indifferent_access.rb +464 -0
- data/lib/active_support/html_safe_translation.rb +56 -0
- data/lib/active_support/i18n.rb +17 -0
- data/lib/active_support/i18n_railtie.rb +140 -0
- data/lib/active_support/inflections.rb +68 -49
- data/lib/active_support/inflector/inflections.rb +290 -0
- data/lib/active_support/inflector/methods.rb +387 -0
- data/lib/active_support/inflector/transliterate.rb +147 -0
- data/lib/active_support/inflector.rb +7 -164
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +78 -0
- data/lib/active_support/json/encoding.rb +256 -0
- data/lib/active_support/json.rb +4 -0
- data/lib/active_support/key_generator.rb +66 -0
- data/lib/active_support/lazy_load_hooks.rb +107 -0
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +141 -0
- data/lib/active_support/log_subscriber/test_helper.rb +106 -0
- data/lib/active_support/log_subscriber.rb +188 -0
- data/lib/active_support/logger.rb +55 -0
- data/lib/active_support/logger_silence.rb +21 -0
- data/lib/active_support/logger_thread_safe_level.rb +50 -0
- data/lib/active_support/message_encryptor.rb +374 -0
- data/lib/active_support/message_encryptors.rb +193 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +310 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +377 -0
- data/lib/active_support/message_verifiers.rb +189 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +146 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotation_coordinator.rb +102 -0
- data/lib/active_support/messages/rotator.rb +69 -0
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +188 -0
- data/lib/active_support/multibyte/unicode.rb +42 -0
- data/lib/active_support/multibyte.rb +27 -0
- data/lib/active_support/notifications/fanout.rb +467 -0
- data/lib/active_support/notifications/instrumenter.rb +240 -0
- data/lib/active_support/notifications.rb +281 -0
- data/lib/active_support/number_helper/number_converter.rb +190 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
- data/lib/active_support/number_helper/rounding_helper.rb +46 -0
- data/lib/active_support/number_helper.rb +479 -0
- data/lib/active_support/option_merger.rb +38 -0
- data/lib/active_support/ordered_hash.rb +50 -0
- data/lib/active_support/ordered_options.rb +141 -25
- data/lib/active_support/parameter_filter.rb +157 -0
- data/lib/active_support/rails.rb +26 -0
- data/lib/active_support/railtie.rb +180 -0
- data/lib/active_support/reloader.rb +138 -0
- data/lib/active_support/rescuable.rb +176 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +38 -0
- data/lib/active_support/string_inquirer.rb +35 -0
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +141 -0
- data/lib/active_support/syntax_error_proxy.rb +67 -0
- data/lib/active_support/tagged_logging.rb +157 -0
- data/lib/active_support/test_case.rb +365 -0
- data/lib/active_support/testing/assertions.rb +369 -0
- data/lib/active_support/testing/autorun.rb +10 -0
- data/lib/active_support/testing/constant_lookup.rb +51 -0
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/declarative.rb +28 -0
- data/lib/active_support/testing/deprecation.rb +82 -0
- data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +121 -0
- data/lib/active_support/testing/method_call_assertions.rb +69 -0
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +98 -0
- data/lib/active_support/testing/parallelization/worker.rb +107 -0
- data/lib/active_support/testing/parallelization.rb +79 -0
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/setup_and_teardown.rb +57 -0
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +27 -0
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +273 -0
- data/lib/active_support/time.rb +20 -0
- data/lib/active_support/time_with_zone.rb +613 -0
- data/lib/active_support/values/time_zone.rb +599 -158
- data/lib/active_support/version.rb +7 -6
- data/lib/active_support/xml_mini/jdom.rb +175 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
- data/lib/active_support/xml_mini/nokogiri.rb +83 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
- data/lib/active_support/xml_mini/rexml.rb +137 -0
- data/lib/active_support/xml_mini.rb +212 -0
- data/lib/active_support.rb +122 -10
- metadata +524 -93
- data/CHANGELOG +0 -283
- data/lib/active_support/binding_of_caller.rb +0 -84
- data/lib/active_support/breakpoint.rb +0 -523
- data/lib/active_support/class_attribute_accessors.rb +0 -57
- data/lib/active_support/class_inheritable_attributes.rb +0 -117
- data/lib/active_support/clean_logger.rb +0 -36
- data/lib/active_support/core_ext/blank.rb +0 -38
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
- data/lib/active_support/core_ext/cgi.rb +0 -5
- data/lib/active_support/core_ext/exception.rb +0 -29
- data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
- data/lib/active_support/core_ext/object_and_class.rb +0 -44
- data/lib/active_support/module_attribute_accessors.rb +0 -57
- data/lib/active_support/whiny_nil.rb +0 -38
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module ClassAttribute # :nodoc:
|
|
5
|
+
class << self
|
|
6
|
+
def redefine(owner, name, namespaced_name, value)
|
|
7
|
+
if owner.singleton_class?
|
|
8
|
+
if owner.attached_object.is_a?(Module)
|
|
9
|
+
redefine_method(owner, namespaced_name, private: true) { value }
|
|
10
|
+
else
|
|
11
|
+
redefine_method(owner, name) { value }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
redefine_method(owner.singleton_class, namespaced_name, private: true) { value }
|
|
16
|
+
|
|
17
|
+
redefine_method(owner.singleton_class, "#{namespaced_name}=", private: true) do |new_value|
|
|
18
|
+
if owner.equal?(self)
|
|
19
|
+
value = new_value
|
|
20
|
+
else
|
|
21
|
+
::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, new_value)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def redefine_method(owner, name, private: false, &block)
|
|
27
|
+
owner.silence_redefinition_of_method(name)
|
|
28
|
+
owner.define_method(name, &block)
|
|
29
|
+
owner.send(:private, name) if private
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
class CodeGenerator # :nodoc:
|
|
5
|
+
class MethodSet
|
|
6
|
+
METHOD_CACHES = Hash.new { |h, k| h[k] = Module.new }
|
|
7
|
+
|
|
8
|
+
def initialize(namespace)
|
|
9
|
+
@cache = METHOD_CACHES[namespace]
|
|
10
|
+
@sources = []
|
|
11
|
+
@methods = {}
|
|
12
|
+
@canonical_methods = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def define_cached_method(canonical_name, as: nil)
|
|
16
|
+
canonical_name = canonical_name.to_sym
|
|
17
|
+
as = (as || canonical_name).to_sym
|
|
18
|
+
|
|
19
|
+
@methods.fetch(as) do
|
|
20
|
+
unless @cache.method_defined?(canonical_name) || @canonical_methods[canonical_name]
|
|
21
|
+
yield @sources
|
|
22
|
+
end
|
|
23
|
+
@canonical_methods[canonical_name] = true
|
|
24
|
+
@methods[as] = canonical_name
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def apply(owner, path, line)
|
|
29
|
+
unless @sources.empty?
|
|
30
|
+
@cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
|
|
31
|
+
end
|
|
32
|
+
@canonical_methods.clear
|
|
33
|
+
|
|
34
|
+
@methods.each do |as, canonical_name|
|
|
35
|
+
owner.define_method(as, @cache.instance_method(canonical_name))
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
def batch(owner, path, line)
|
|
42
|
+
if owner.is_a?(CodeGenerator)
|
|
43
|
+
yield owner
|
|
44
|
+
else
|
|
45
|
+
instance = new(owner, path, line)
|
|
46
|
+
result = yield instance
|
|
47
|
+
instance.execute
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def initialize(owner, path, line)
|
|
54
|
+
@owner = owner
|
|
55
|
+
@path = path
|
|
56
|
+
@line = line
|
|
57
|
+
@namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
|
|
58
|
+
@sources = []
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def class_eval
|
|
62
|
+
yield @sources
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def define_cached_method(canonical_name, namespace:, as: nil, &block)
|
|
66
|
+
@namespaces[namespace].define_cached_method(canonical_name, as: as, &block)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def execute
|
|
70
|
+
@namespaces.each_value do |method_set|
|
|
71
|
+
method_set.apply(@owner, @path, @line - 1)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
unless @sources.empty?
|
|
75
|
+
@owner.class_eval("# frozen_string_literal: true\n" + @sources.join(";"), @path, @line - 1)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
# = Active Support \Concern
|
|
5
|
+
#
|
|
6
|
+
# A typical module looks like this:
|
|
7
|
+
#
|
|
8
|
+
# module M
|
|
9
|
+
# def self.included(base)
|
|
10
|
+
# base.extend ClassMethods
|
|
11
|
+
# base.class_eval do
|
|
12
|
+
# scope :disabled, -> { where(disabled: true) }
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# module ClassMethods
|
|
17
|
+
# ...
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# By using +ActiveSupport::Concern+ the above module could instead be
|
|
22
|
+
# written as:
|
|
23
|
+
#
|
|
24
|
+
# require "active_support/concern"
|
|
25
|
+
#
|
|
26
|
+
# module M
|
|
27
|
+
# extend ActiveSupport::Concern
|
|
28
|
+
#
|
|
29
|
+
# included do
|
|
30
|
+
# scope :disabled, -> { where(disabled: true) }
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# class_methods do
|
|
34
|
+
# ...
|
|
35
|
+
# end
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# Moreover, it gracefully handles module dependencies. Given a +Foo+ module
|
|
39
|
+
# and a +Bar+ module which depends on the former, we would typically write the
|
|
40
|
+
# following:
|
|
41
|
+
#
|
|
42
|
+
# module Foo
|
|
43
|
+
# def self.included(base)
|
|
44
|
+
# base.class_eval do
|
|
45
|
+
# def self.method_injected_by_foo
|
|
46
|
+
# ...
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
# end
|
|
51
|
+
#
|
|
52
|
+
# module Bar
|
|
53
|
+
# def self.included(base)
|
|
54
|
+
# base.method_injected_by_foo
|
|
55
|
+
# end
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# class Host
|
|
59
|
+
# include Foo # We need to include this dependency for Bar
|
|
60
|
+
# include Bar # Bar is the module that Host really needs
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
63
|
+
# But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We
|
|
64
|
+
# could try to hide these from +Host+ directly including +Foo+ in +Bar+:
|
|
65
|
+
#
|
|
66
|
+
# module Bar
|
|
67
|
+
# include Foo
|
|
68
|
+
# def self.included(base)
|
|
69
|
+
# base.method_injected_by_foo
|
|
70
|
+
# end
|
|
71
|
+
# end
|
|
72
|
+
#
|
|
73
|
+
# class Host
|
|
74
|
+
# include Bar
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
|
|
78
|
+
# is the +Bar+ module, not the +Host+ class. With +ActiveSupport::Concern+,
|
|
79
|
+
# module dependencies are properly resolved:
|
|
80
|
+
#
|
|
81
|
+
# require "active_support/concern"
|
|
82
|
+
#
|
|
83
|
+
# module Foo
|
|
84
|
+
# extend ActiveSupport::Concern
|
|
85
|
+
# included do
|
|
86
|
+
# def self.method_injected_by_foo
|
|
87
|
+
# ...
|
|
88
|
+
# end
|
|
89
|
+
# end
|
|
90
|
+
# end
|
|
91
|
+
#
|
|
92
|
+
# module Bar
|
|
93
|
+
# extend ActiveSupport::Concern
|
|
94
|
+
# include Foo
|
|
95
|
+
#
|
|
96
|
+
# included do
|
|
97
|
+
# self.method_injected_by_foo
|
|
98
|
+
# end
|
|
99
|
+
# end
|
|
100
|
+
#
|
|
101
|
+
# class Host
|
|
102
|
+
# include Bar # It works, now Bar takes care of its dependencies
|
|
103
|
+
# end
|
|
104
|
+
#
|
|
105
|
+
# === Prepending concerns
|
|
106
|
+
#
|
|
107
|
+
# Just like <tt>include</tt>, concerns also support <tt>prepend</tt> with a corresponding
|
|
108
|
+
# <tt>prepended do</tt> callback. <tt>module ClassMethods</tt> or <tt>class_methods do</tt> are
|
|
109
|
+
# prepended as well.
|
|
110
|
+
#
|
|
111
|
+
# <tt>prepend</tt> is also used for any dependencies.
|
|
112
|
+
module Concern
|
|
113
|
+
class MultipleIncludedBlocks < StandardError # :nodoc:
|
|
114
|
+
def initialize
|
|
115
|
+
super "Cannot define multiple 'included' blocks for a Concern"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class MultiplePrependBlocks < StandardError # :nodoc:
|
|
120
|
+
def initialize
|
|
121
|
+
super "Cannot define multiple 'prepended' blocks for a Concern"
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.extended(base) # :nodoc:
|
|
126
|
+
base.instance_variable_set(:@_dependencies, [])
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def append_features(base) # :nodoc:
|
|
130
|
+
if base.instance_variable_defined?(:@_dependencies)
|
|
131
|
+
base.instance_variable_get(:@_dependencies) << self
|
|
132
|
+
false
|
|
133
|
+
else
|
|
134
|
+
return false if base < self
|
|
135
|
+
@_dependencies.each { |dep| base.include(dep) }
|
|
136
|
+
super
|
|
137
|
+
base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
|
|
138
|
+
base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def prepend_features(base) # :nodoc:
|
|
143
|
+
if base.instance_variable_defined?(:@_dependencies)
|
|
144
|
+
base.instance_variable_get(:@_dependencies).unshift self
|
|
145
|
+
false
|
|
146
|
+
else
|
|
147
|
+
return false if base < self
|
|
148
|
+
@_dependencies.each { |dep| base.prepend(dep) }
|
|
149
|
+
super
|
|
150
|
+
base.singleton_class.prepend const_get(:ClassMethods) if const_defined?(:ClassMethods)
|
|
151
|
+
base.class_eval(&@_prepended_block) if instance_variable_defined?(:@_prepended_block)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Evaluate given block in context of base class,
|
|
156
|
+
# so that you can write class macros here.
|
|
157
|
+
# When you define more than one +included+ block, it raises an exception.
|
|
158
|
+
def included(base = nil, &block)
|
|
159
|
+
if base.nil?
|
|
160
|
+
if instance_variable_defined?(:@_included_block)
|
|
161
|
+
if @_included_block.source_location != block.source_location
|
|
162
|
+
raise MultipleIncludedBlocks
|
|
163
|
+
end
|
|
164
|
+
else
|
|
165
|
+
@_included_block = block
|
|
166
|
+
end
|
|
167
|
+
else
|
|
168
|
+
super
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Evaluate given block in context of base class,
|
|
173
|
+
# so that you can write class macros here.
|
|
174
|
+
# When you define more than one +prepended+ block, it raises an exception.
|
|
175
|
+
def prepended(base = nil, &block)
|
|
176
|
+
if base.nil?
|
|
177
|
+
if instance_variable_defined?(:@_prepended_block)
|
|
178
|
+
if @_prepended_block.source_location != block.source_location
|
|
179
|
+
raise MultiplePrependBlocks
|
|
180
|
+
end
|
|
181
|
+
else
|
|
182
|
+
@_prepended_block = block
|
|
183
|
+
end
|
|
184
|
+
else
|
|
185
|
+
super
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Define class methods from given block.
|
|
190
|
+
# You can define private class methods as well.
|
|
191
|
+
#
|
|
192
|
+
# module Example
|
|
193
|
+
# extend ActiveSupport::Concern
|
|
194
|
+
#
|
|
195
|
+
# class_methods do
|
|
196
|
+
# def foo; puts 'foo'; end
|
|
197
|
+
#
|
|
198
|
+
# private
|
|
199
|
+
# def bar; puts 'bar'; end
|
|
200
|
+
# end
|
|
201
|
+
# end
|
|
202
|
+
#
|
|
203
|
+
# class Buzz
|
|
204
|
+
# include Example
|
|
205
|
+
# end
|
|
206
|
+
#
|
|
207
|
+
# Buzz.foo # => "foo"
|
|
208
|
+
# Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
|
|
209
|
+
def class_methods(&class_methods_module_definition)
|
|
210
|
+
mod = const_defined?(:ClassMethods, false) ?
|
|
211
|
+
const_get(:ClassMethods) :
|
|
212
|
+
const_set(:ClassMethods, Module.new)
|
|
213
|
+
|
|
214
|
+
mod.module_eval(&class_methods_module_definition)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
LoadInterlockAwareMonitor = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
|
|
10
|
+
"ActiveSupport::Concurrency::LoadInterlockAwareMonitor",
|
|
11
|
+
"::Monitor",
|
|
12
|
+
ActiveSupport.deprecator,
|
|
13
|
+
message: "ActiveSupport::Concurrency::LoadInterlockAwareMonitor is deprecated and will be " \
|
|
14
|
+
"removed in Rails 9.0. Use Monitor directly instead, as the loading interlock is " \
|
|
15
|
+
"no longer used."
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "monitor"
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
module Concurrency
|
|
7
|
+
# A share/exclusive lock, otherwise known as a read/write lock.
|
|
8
|
+
#
|
|
9
|
+
# https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
|
|
10
|
+
class ShareLock
|
|
11
|
+
include MonitorMixin
|
|
12
|
+
|
|
13
|
+
# We track Thread objects, instead of just using counters, because
|
|
14
|
+
# we need exclusive locks to be reentrant, and we need to be able
|
|
15
|
+
# to upgrade share locks to exclusive.
|
|
16
|
+
|
|
17
|
+
def raw_state # :nodoc:
|
|
18
|
+
synchronize do
|
|
19
|
+
threads = @sleeping.keys | @sharing.keys | @waiting.keys
|
|
20
|
+
threads |= [@exclusive_thread] if @exclusive_thread
|
|
21
|
+
|
|
22
|
+
data = {}
|
|
23
|
+
|
|
24
|
+
threads.each do |thread|
|
|
25
|
+
purpose, compatible = @waiting[thread]
|
|
26
|
+
|
|
27
|
+
data[thread] = {
|
|
28
|
+
thread: thread,
|
|
29
|
+
sharing: @sharing[thread],
|
|
30
|
+
exclusive: @exclusive_thread == thread,
|
|
31
|
+
purpose: purpose,
|
|
32
|
+
compatible: compatible,
|
|
33
|
+
waiting: !!@waiting[thread],
|
|
34
|
+
sleeper: @sleeping[thread],
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# NB: Yields while holding our *internal* synchronize lock,
|
|
39
|
+
# which is supposed to be used only for a few instructions at
|
|
40
|
+
# a time. This allows the caller to inspect additional state
|
|
41
|
+
# without things changing out from underneath, but would have
|
|
42
|
+
# disastrous effects upon normal operation. Fortunately, this
|
|
43
|
+
# method is only intended to be called when things have
|
|
44
|
+
# already gone wrong.
|
|
45
|
+
yield data
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def initialize
|
|
50
|
+
super()
|
|
51
|
+
|
|
52
|
+
@cv = new_cond
|
|
53
|
+
|
|
54
|
+
@sharing = Hash.new(0)
|
|
55
|
+
@waiting = {}
|
|
56
|
+
@sleeping = {}
|
|
57
|
+
@exclusive_thread = nil
|
|
58
|
+
@exclusive_depth = 0
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns false if +no_wait+ is set and the lock is not
|
|
62
|
+
# immediately available. Otherwise, returns true after the lock
|
|
63
|
+
# has been acquired.
|
|
64
|
+
#
|
|
65
|
+
# +purpose+ and +compatible+ work together; while this thread is
|
|
66
|
+
# waiting for the exclusive lock, it will yield its share (if any)
|
|
67
|
+
# to any other attempt whose +purpose+ appears in this attempt's
|
|
68
|
+
# +compatible+ list. This allows a "loose" upgrade, which, being
|
|
69
|
+
# less strict, prevents some classes of deadlocks.
|
|
70
|
+
#
|
|
71
|
+
# For many resources, loose upgrades are sufficient: if a thread
|
|
72
|
+
# is awaiting a lock, it is not running any other code. With
|
|
73
|
+
# +purpose+ matching, it is possible to yield only to other
|
|
74
|
+
# threads whose activity will not interfere.
|
|
75
|
+
def start_exclusive(purpose: nil, compatible: [], no_wait: false)
|
|
76
|
+
synchronize do
|
|
77
|
+
unless @exclusive_thread == Thread.current
|
|
78
|
+
if busy_for_exclusive?(purpose)
|
|
79
|
+
return false if no_wait
|
|
80
|
+
|
|
81
|
+
yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
|
|
82
|
+
wait_for(:start_exclusive) { busy_for_exclusive?(purpose) }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
@exclusive_thread = Thread.current
|
|
86
|
+
end
|
|
87
|
+
@exclusive_depth += 1
|
|
88
|
+
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Relinquish the exclusive lock. Must only be called by the thread
|
|
94
|
+
# that called start_exclusive (and currently holds the lock).
|
|
95
|
+
def stop_exclusive(compatible: [])
|
|
96
|
+
synchronize do
|
|
97
|
+
raise "invalid unlock" if @exclusive_thread != Thread.current
|
|
98
|
+
|
|
99
|
+
@exclusive_depth -= 1
|
|
100
|
+
if @exclusive_depth == 0
|
|
101
|
+
@exclusive_thread = nil
|
|
102
|
+
|
|
103
|
+
if eligible_waiters?(compatible)
|
|
104
|
+
yield_shares(compatible: compatible, block_share: true) do
|
|
105
|
+
wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
@cv.broadcast
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def start_sharing
|
|
114
|
+
synchronize do
|
|
115
|
+
if @sharing[Thread.current] > 0 || @exclusive_thread == Thread.current
|
|
116
|
+
# We already hold a lock; nothing to wait for
|
|
117
|
+
elsif @waiting[Thread.current]
|
|
118
|
+
# We're nested inside a +yield_shares+ call: we'll resume as
|
|
119
|
+
# soon as there isn't an exclusive lock in our way
|
|
120
|
+
wait_for(:start_sharing) { @exclusive_thread }
|
|
121
|
+
else
|
|
122
|
+
# This is an initial / outermost share call: any outstanding
|
|
123
|
+
# requests for an exclusive lock get to go first
|
|
124
|
+
wait_for(:start_sharing) { busy_for_sharing?(false) }
|
|
125
|
+
end
|
|
126
|
+
@sharing[Thread.current] += 1
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def stop_sharing
|
|
131
|
+
synchronize do
|
|
132
|
+
if @sharing[Thread.current] > 1
|
|
133
|
+
@sharing[Thread.current] -= 1
|
|
134
|
+
else
|
|
135
|
+
@sharing.delete Thread.current
|
|
136
|
+
@cv.broadcast
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Execute the supplied block while holding the Exclusive lock. If
|
|
142
|
+
# +no_wait+ is set and the lock is not immediately available,
|
|
143
|
+
# returns +nil+ without yielding. Otherwise, returns the result of
|
|
144
|
+
# the block.
|
|
145
|
+
#
|
|
146
|
+
# See +start_exclusive+ for other options.
|
|
147
|
+
def exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false)
|
|
148
|
+
if start_exclusive(purpose: purpose, compatible: compatible, no_wait: no_wait)
|
|
149
|
+
begin
|
|
150
|
+
yield
|
|
151
|
+
ensure
|
|
152
|
+
stop_exclusive(compatible: after_compatible)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Execute the supplied block while holding the Share lock.
|
|
158
|
+
def sharing
|
|
159
|
+
start_sharing
|
|
160
|
+
begin
|
|
161
|
+
yield
|
|
162
|
+
ensure
|
|
163
|
+
stop_sharing
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Temporarily give up all held Share locks while executing the
|
|
168
|
+
# supplied block, allowing any +compatible+ exclusive lock request
|
|
169
|
+
# to proceed.
|
|
170
|
+
def yield_shares(purpose: nil, compatible: [], block_share: false)
|
|
171
|
+
loose_shares = previous_wait = nil
|
|
172
|
+
synchronize do
|
|
173
|
+
if loose_shares = @sharing.delete(Thread.current)
|
|
174
|
+
if previous_wait = @waiting[Thread.current]
|
|
175
|
+
purpose = nil unless purpose == previous_wait[0]
|
|
176
|
+
compatible &= previous_wait[1]
|
|
177
|
+
end
|
|
178
|
+
compatible |= [false] unless block_share
|
|
179
|
+
@waiting[Thread.current] = [purpose, compatible]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
@cv.broadcast
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
begin
|
|
186
|
+
yield
|
|
187
|
+
ensure
|
|
188
|
+
synchronize do
|
|
189
|
+
wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current }
|
|
190
|
+
|
|
191
|
+
if previous_wait
|
|
192
|
+
@waiting[Thread.current] = previous_wait
|
|
193
|
+
else
|
|
194
|
+
@waiting.delete Thread.current
|
|
195
|
+
end
|
|
196
|
+
@sharing[Thread.current] = loose_shares if loose_shares
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
private
|
|
202
|
+
# Must be called within synchronize
|
|
203
|
+
def busy_for_exclusive?(purpose)
|
|
204
|
+
busy_for_sharing?(purpose) ||
|
|
205
|
+
@sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def busy_for_sharing?(purpose)
|
|
209
|
+
(@exclusive_thread && @exclusive_thread != Thread.current) ||
|
|
210
|
+
@waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def eligible_waiters?(compatible)
|
|
214
|
+
@waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def wait_for(method, &block)
|
|
218
|
+
@sleeping[Thread.current] = method
|
|
219
|
+
@cv.wait_while(&block)
|
|
220
|
+
ensure
|
|
221
|
+
@sleeping.delete Thread.current
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module Concurrency
|
|
5
|
+
class ThreadMonitor # :nodoc:
|
|
6
|
+
EXCEPTION_NEVER = { Exception => :never }.freeze
|
|
7
|
+
EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
|
|
8
|
+
private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@owner = nil
|
|
12
|
+
@count = 0
|
|
13
|
+
@mutex = Mutex.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def synchronize(&block)
|
|
17
|
+
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
|
18
|
+
mon_enter
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
|
22
|
+
ensure
|
|
23
|
+
mon_exit
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
def mon_try_enter
|
|
30
|
+
if @owner != Thread.current
|
|
31
|
+
return false unless @mutex.try_lock
|
|
32
|
+
@owner = Thread.current
|
|
33
|
+
end
|
|
34
|
+
@count += 1
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def mon_enter
|
|
38
|
+
@mutex.lock if @owner != Thread.current
|
|
39
|
+
@owner = Thread.current
|
|
40
|
+
@count += 1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def mon_exit
|
|
44
|
+
unless @owner == Thread.current
|
|
45
|
+
raise ThreadError, "current thread not owner"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@count -= 1
|
|
49
|
+
return unless @count == 0
|
|
50
|
+
@owner = nil
|
|
51
|
+
@mutex.unlock
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|