activesupport 3.1.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +798 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +13 -7
- data/lib/active_support/array_inquirer.rb +44 -0
- data/lib/active_support/backtrace_cleaner.rb +38 -34
- data/lib/active_support/benchmarkable.rb +17 -28
- data/lib/active_support/cache/file_store.rb +85 -70
- data/lib/active_support/cache/mem_cache_store.rb +75 -66
- data/lib/active_support/cache/memory_store.rb +31 -23
- data/lib/active_support/cache/null_store.rb +41 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -70
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
- data/lib/active_support/cache.rb +360 -294
- data/lib/active_support/callbacks.rb +563 -393
- data/lib/active_support/concern.rb +42 -34
- data/lib/active_support/concurrency/latch.rb +19 -0
- data/lib/active_support/concurrency/share_lock.rb +186 -0
- data/lib/active_support/configurable.rb +70 -12
- data/lib/active_support/core_ext/array/access.rb +53 -9
- data/lib/active_support/core_ext/array/conversions.rb +109 -62
- data/lib/active_support/core_ext/array/extract_options.rb +2 -2
- data/lib/active_support/core_ext/array/grouping.rb +39 -32
- data/lib/active_support/core_ext/array/inquiry.rb +17 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
- data/lib/active_support/core_ext/array/wrap.rb +16 -18
- data/lib/active_support/core_ext/array.rb +2 -2
- data/lib/active_support/core_ext/benchmark.rb +7 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -36
- data/lib/active_support/core_ext/class/attribute.rb +47 -34
- data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -79
- data/lib/active_support/core_ext/class/subclasses.rb +12 -7
- data/lib/active_support/core_ext/class.rb +0 -3
- data/lib/active_support/core_ext/date/blank.rb +12 -0
- data/lib/active_support/core_ext/date/calculations.rb +57 -167
- data/lib/active_support/core_ext/date/conversions.rb +31 -42
- data/lib/active_support/core_ext/date/zones.rb +2 -10
- data/lib/active_support/core_ext/date.rb +5 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -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 +1 -0
- data/lib/active_support/core_ext/date_time/blank.rb +12 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +132 -65
- data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +36 -34
- data/lib/active_support/core_ext/date_time.rb +5 -0
- data/lib/active_support/core_ext/digest/uuid.rb +51 -0
- data/lib/active_support/core_ext/enumerable.rb +81 -74
- data/lib/active_support/core_ext/file/atomic.rb +53 -26
- data/lib/active_support/core_ext/file.rb +0 -1
- data/lib/active_support/core_ext/hash/compact.rb +20 -0
- data/lib/active_support/core_ext/hash/conversions.rb +175 -70
- data/lib/active_support/core_ext/hash/deep_merge.rb +30 -8
- data/lib/active_support/core_ext/hash/except.rb +11 -12
- data/lib/active_support/core_ext/hash/indifferent_access.rb +7 -8
- data/lib/active_support/core_ext/hash/keys.rb +147 -24
- data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
- data/lib/active_support/core_ext/hash/slice.rb +22 -14
- data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
- data/lib/active_support/core_ext/hash.rb +2 -2
- data/lib/active_support/core_ext/integer/inflections.rb +13 -1
- data/lib/active_support/core_ext/integer/multiple.rb +4 -0
- data/lib/active_support/core_ext/integer/time.rb +12 -22
- data/lib/active_support/core_ext/kernel/agnostics.rb +2 -2
- data/lib/active_support/core_ext/kernel/concern.rb +12 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +2 -15
- data/lib/active_support/core_ext/kernel/reporting.rb +12 -62
- data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
- data/lib/active_support/core_ext/kernel.rb +2 -3
- data/lib/active_support/core_ext/load_error.rb +14 -7
- data/lib/active_support/core_ext/marshal.rb +22 -0
- data/lib/active_support/core_ext/module/aliasing.rb +16 -12
- data/lib/active_support/core_ext/module/anonymous.rb +12 -8
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +165 -13
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
- data/lib/active_support/core_ext/module/concerning.rb +135 -0
- data/lib/active_support/core_ext/module/delegation.rb +141 -68
- data/lib/active_support/core_ext/module/deprecation.rb +17 -3
- data/lib/active_support/core_ext/module/introspection.rb +9 -31
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
- data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
- data/lib/active_support/core_ext/module/reachable.rb +1 -3
- data/lib/active_support/core_ext/module/remove_method.rb +24 -5
- data/lib/active_support/core_ext/module.rb +3 -3
- data/lib/active_support/core_ext/name_error.rb +15 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
- data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
- data/lib/active_support/core_ext/numeric/time.rb +31 -36
- data/lib/active_support/core_ext/numeric.rb +2 -0
- data/lib/active_support/core_ext/object/acts_like.rb +4 -4
- data/lib/active_support/core_ext/object/blank.rb +52 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
- data/lib/active_support/core_ext/object/duplicable.rb +12 -20
- data/lib/active_support/core_ext/object/inclusion.rb +13 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
- data/lib/active_support/core_ext/object/json.rb +205 -0
- data/lib/active_support/core_ext/object/to_param.rb +1 -55
- data/lib/active_support/core_ext/object/to_query.rb +66 -9
- data/lib/active_support/core_ext/object/try.rb +124 -33
- data/lib/active_support/core_ext/object/with_options.rb +37 -11
- data/lib/active_support/core_ext/object.rb +2 -1
- data/lib/active_support/core_ext/range/conversions.rb +17 -7
- data/lib/active_support/core_ext/range/each.rb +21 -0
- data/lib/active_support/core_ext/range/include_range.rb +20 -18
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +23 -0
- data/lib/active_support/core_ext/string/access.rb +95 -90
- data/lib/active_support/core_ext/string/behavior.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +41 -38
- data/lib/active_support/core_ext/string/exclude.rb +6 -1
- data/lib/active_support/core_ext/string/filters.rb +70 -17
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/active_support/core_ext/string/inflections.rb +139 -59
- data/lib/active_support/core_ext/string/inquiry.rb +2 -2
- data/lib/active_support/core_ext/string/multibyte.rb +46 -65
- data/lib/active_support/core_ext/string/output_safety.rb +153 -56
- data/lib/active_support/core_ext/string/strip.rb +3 -6
- data/lib/active_support/core_ext/string/zones.rb +14 -0
- data/lib/active_support/core_ext/string.rb +2 -3
- data/lib/active_support/core_ext/struct.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +173 -173
- data/lib/active_support/core_ext/time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/time/conversions.rb +33 -29
- data/lib/active_support/core_ext/time/marshal.rb +2 -56
- data/lib/active_support/core_ext/time/zones.rb +57 -32
- data/lib/active_support/core_ext/time.rb +5 -0
- data/lib/active_support/core_ext/uri.rb +13 -19
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/dependencies/autoload.rb +47 -20
- data/lib/active_support/dependencies/interlock.rb +51 -0
- data/lib/active_support/dependencies.rb +315 -265
- data/lib/active_support/deprecation/behaviors.rb +71 -30
- data/lib/active_support/deprecation/instance_delegator.rb +24 -0
- data/lib/active_support/deprecation/method_wrappers.rb +59 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +82 -14
- data/lib/active_support/deprecation/reporting.rb +61 -14
- data/lib/active_support/deprecation.rb +38 -13
- data/lib/active_support/descendants_tracker.rb +34 -19
- data/lib/active_support/duration/iso8601_parser.rb +122 -0
- data/lib/active_support/duration/iso8601_serializer.rb +51 -0
- data/lib/active_support/duration.rb +85 -14
- data/lib/active_support/evented_file_update_checker.rb +194 -0
- data/lib/active_support/execution_wrapper.rb +117 -0
- data/lib/active_support/executor.rb +6 -0
- data/lib/active_support/file_update_checker.rb +138 -17
- data/lib/active_support/gem_version.rb +15 -0
- data/lib/active_support/gzip.rb +11 -5
- data/lib/active_support/hash_with_indifferent_access.rb +199 -49
- data/lib/active_support/i18n.rb +6 -2
- data/lib/active_support/i18n_railtie.rb +40 -21
- data/lib/active_support/inflections.rb +22 -13
- data/lib/active_support/inflector/inflections.rb +175 -144
- data/lib/active_support/inflector/methods.rb +328 -91
- data/lib/active_support/inflector/transliterate.rb +51 -37
- data/lib/active_support/json/decoding.rb +31 -22
- data/lib/active_support/json/encoding.rb +88 -248
- data/lib/active_support/key_generator.rb +71 -0
- data/lib/active_support/lazy_load_hooks.rb +27 -25
- data/lib/active_support/locale/en.yml +102 -3
- data/lib/active_support/log_subscriber/test_helper.rb +24 -21
- data/lib/active_support/log_subscriber.rb +36 -49
- data/lib/active_support/logger.rb +106 -0
- data/lib/active_support/logger_silence.rb +28 -0
- data/lib/active_support/logger_thread_safe_level.rb +31 -0
- data/lib/active_support/message_encryptor.rb +72 -36
- data/lib/active_support/message_verifier.rb +96 -24
- data/lib/active_support/multibyte/chars.rb +88 -333
- data/lib/active_support/multibyte/unicode.rb +156 -136
- data/lib/active_support/multibyte.rb +5 -28
- data/lib/active_support/notifications/fanout.rb +115 -19
- data/lib/active_support/notifications/instrumenter.rb +52 -15
- data/lib/active_support/notifications.rb +168 -33
- data/lib/active_support/number_helper/number_converter.rb +182 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
- data/lib/active_support/number_helper.rb +368 -0
- data/lib/active_support/option_merger.rb +1 -1
- data/lib/active_support/ordered_hash.rb +18 -183
- data/lib/active_support/ordered_options.rb +44 -24
- data/lib/active_support/per_thread_registry.rb +58 -0
- data/lib/active_support/proxy_object.rb +13 -0
- data/lib/active_support/rails.rb +27 -0
- data/lib/active_support/railtie.rb +25 -34
- data/lib/active_support/reloader.rb +129 -0
- data/lib/active_support/rescuable.rb +98 -48
- data/lib/active_support/security_utils.rb +27 -0
- data/lib/active_support/string_inquirer.rb +14 -9
- data/lib/active_support/subscriber.rb +120 -0
- data/lib/active_support/tagged_logging.rb +78 -0
- data/lib/active_support/test_case.rb +69 -17
- data/lib/active_support/testing/assertions.rb +43 -41
- data/lib/active_support/testing/autorun.rb +12 -0
- data/lib/active_support/testing/constant_lookup.rb +50 -0
- data/lib/active_support/testing/declarative.rb +7 -21
- data/lib/active_support/testing/deprecation.rb +14 -33
- data/lib/active_support/testing/file_fixtures.rb +34 -0
- data/lib/active_support/testing/isolation.rb +53 -95
- data/lib/active_support/testing/method_call_assertions.rb +41 -0
- data/lib/active_support/testing/setup_and_teardown.rb +21 -82
- data/lib/active_support/testing/stream.rb +42 -0
- data/lib/active_support/testing/tagged_logging.rb +25 -0
- data/lib/active_support/testing/time_helpers.rb +134 -0
- data/lib/active_support/time.rb +6 -23
- data/lib/active_support/time_with_zone.rb +239 -92
- data/lib/active_support/values/time_zone.rb +236 -160
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +5 -7
- data/lib/active_support/xml_mini/jdom.rb +19 -13
- data/lib/active_support/xml_mini/libxml.rb +3 -4
- data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
- data/lib/active_support/xml_mini/nokogiri.rb +3 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
- data/lib/active_support/xml_mini/rexml.rb +8 -10
- data/lib/active_support/xml_mini.rb +66 -34
- data/lib/active_support.rb +40 -23
- metadata +185 -134
- data/CHANGELOG +0 -1534
- data/lib/active_support/base64.rb +0 -42
- data/lib/active_support/basic_object.rb +0 -21
- data/lib/active_support/buffered_logger.rb +0 -137
- data/lib/active_support/cache/compressed_mem_cache_store.rb +0 -13
- data/lib/active_support/cache/synchronized_memory_store.rb +0 -11
- data/lib/active_support/core_ext/array/random_access.rb +0 -30
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -44
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +0 -178
- data/lib/active_support/core_ext/date/freeze.rb +0 -31
- data/lib/active_support/core_ext/date_time/zones.rb +0 -21
- data/lib/active_support/core_ext/exception.rb +0 -3
- data/lib/active_support/core_ext/file/path.rb +0 -5
- data/lib/active_support/core_ext/float/rounding.rb +0 -19
- data/lib/active_support/core_ext/float.rb +0 -1
- data/lib/active_support/core_ext/hash/deep_dup.rb +0 -11
- data/lib/active_support/core_ext/hash/diff.rb +0 -13
- data/lib/active_support/core_ext/kernel/requires.rb +0 -28
- data/lib/active_support/core_ext/logger.rb +0 -81
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +0 -31
- data/lib/active_support/core_ext/module/method_names.rb +0 -14
- data/lib/active_support/core_ext/module/synchronization.rb +0 -43
- data/lib/active_support/core_ext/object/to_json.rb +0 -19
- data/lib/active_support/core_ext/proc.rb +0 -14
- data/lib/active_support/core_ext/process/daemon.rb +0 -23
- data/lib/active_support/core_ext/process.rb +0 -1
- data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
- data/lib/active_support/core_ext/range/cover.rb +0 -3
- data/lib/active_support/core_ext/rexml.rb +0 -46
- data/lib/active_support/core_ext/string/encoding.rb +0 -11
- data/lib/active_support/core_ext/string/interpolation.rb +0 -2
- data/lib/active_support/core_ext/string/xchar.rb +0 -18
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -9
- data/lib/active_support/memoizable.rb +0 -105
- data/lib/active_support/multibyte/exceptions.rb +0 -8
- data/lib/active_support/multibyte/utils.rb +0 -60
- data/lib/active_support/ruby/shim.rb +0 -22
- data/lib/active_support/secure_random.rb +0 -6
- data/lib/active_support/testing/mochaing.rb +0 -7
- data/lib/active_support/testing/pending.rb +0 -52
- data/lib/active_support/testing/performance/jruby.rb +0 -115
- data/lib/active_support/testing/performance/rubinius.rb +0 -113
- data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
- data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
- data/lib/active_support/testing/performance/ruby.rb +0 -152
- data/lib/active_support/testing/performance.rb +0 -317
- data/lib/active_support/time/autoload.rb +0 -5
- data/lib/active_support/whiny_nil.rb +0 -60
@@ -1,21 +1,51 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'thread'
|
3
|
+
require 'concurrent/map'
|
3
4
|
require 'pathname'
|
4
5
|
require 'active_support/core_ext/module/aliasing'
|
5
6
|
require 'active_support/core_ext/module/attribute_accessors'
|
6
7
|
require 'active_support/core_ext/module/introspection'
|
7
8
|
require 'active_support/core_ext/module/anonymous'
|
8
|
-
require 'active_support/core_ext/module/
|
9
|
+
require 'active_support/core_ext/module/qualified_const'
|
9
10
|
require 'active_support/core_ext/object/blank'
|
11
|
+
require 'active_support/core_ext/kernel/reporting'
|
10
12
|
require 'active_support/core_ext/load_error'
|
11
13
|
require 'active_support/core_ext/name_error'
|
12
14
|
require 'active_support/core_ext/string/starts_ends_with'
|
15
|
+
require "active_support/dependencies/interlock"
|
13
16
|
require 'active_support/inflector'
|
14
17
|
|
15
18
|
module ActiveSupport #:nodoc:
|
16
19
|
module Dependencies #:nodoc:
|
17
20
|
extend self
|
18
21
|
|
22
|
+
mattr_accessor :interlock
|
23
|
+
self.interlock = Interlock.new
|
24
|
+
|
25
|
+
# :doc:
|
26
|
+
|
27
|
+
# Execute the supplied block without interference from any
|
28
|
+
# concurrent loads.
|
29
|
+
def self.run_interlock
|
30
|
+
Dependencies.interlock.running { yield }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Execute the supplied block while holding an exclusive lock,
|
34
|
+
# preventing any other thread from being inside a #run_interlock
|
35
|
+
# block at the same time.
|
36
|
+
def self.load_interlock
|
37
|
+
Dependencies.interlock.loading { yield }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Execute the supplied block while holding an exclusive lock,
|
41
|
+
# preventing any other thread from being inside a #run_interlock
|
42
|
+
# block at the same time.
|
43
|
+
def self.unload_interlock
|
44
|
+
Dependencies.interlock.unloading { yield }
|
45
|
+
end
|
46
|
+
|
47
|
+
# :nodoc:
|
48
|
+
|
19
49
|
# Should we turn on Ruby warnings on the first load of dependent files?
|
20
50
|
mattr_accessor :warnings_on_first_load
|
21
51
|
self.warnings_on_first_load = false
|
@@ -28,6 +58,10 @@ module ActiveSupport #:nodoc:
|
|
28
58
|
mattr_accessor :loaded
|
29
59
|
self.loaded = Set.new
|
30
60
|
|
61
|
+
# Stack of files being loaded.
|
62
|
+
mattr_accessor :loading
|
63
|
+
self.loading = []
|
64
|
+
|
31
65
|
# Should we load files or require them?
|
32
66
|
mattr_accessor :mechanism
|
33
67
|
self.mechanism = ENV['NO_RELOAD'] ? :require : :load
|
@@ -43,8 +77,9 @@ module ActiveSupport #:nodoc:
|
|
43
77
|
mattr_accessor :autoload_once_paths
|
44
78
|
self.autoload_once_paths = []
|
45
79
|
|
46
|
-
# An array of qualified constant names that have been loaded. Adding a name
|
47
|
-
# this array will cause it to be unloaded the next time Dependencies are
|
80
|
+
# An array of qualified constant names that have been loaded. Adding a name
|
81
|
+
# to this array will cause it to be unloaded the next time Dependencies are
|
82
|
+
# cleared.
|
48
83
|
mattr_accessor :autoloaded_constants
|
49
84
|
self.autoloaded_constants = []
|
50
85
|
|
@@ -53,35 +88,39 @@ module ActiveSupport #:nodoc:
|
|
53
88
|
mattr_accessor :explicitly_unloadable_constants
|
54
89
|
self.explicitly_unloadable_constants = []
|
55
90
|
|
56
|
-
# The
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
# Set to true to enable logging of const_missing and file loads
|
61
|
-
mattr_accessor :log_activity
|
62
|
-
self.log_activity = false
|
63
|
-
|
64
|
-
# The WatchStack keeps a stack of the modules being watched as files are loaded.
|
65
|
-
# If a file in the process of being loaded (parent.rb) triggers the load of
|
66
|
-
# another file (child.rb) the stack will ensure that child.rb handles the new
|
67
|
-
# constants.
|
91
|
+
# The WatchStack keeps a stack of the modules being watched as files are
|
92
|
+
# loaded. If a file in the process of being loaded (parent.rb) triggers the
|
93
|
+
# load of another file (child.rb) the stack will ensure that child.rb
|
94
|
+
# handles the new constants.
|
68
95
|
#
|
69
96
|
# If child.rb is being autoloaded, its constants will be added to
|
70
97
|
# autoloaded_constants. If it was being `require`d, they will be discarded.
|
71
98
|
#
|
72
99
|
# This is handled by walking back up the watch stack and adding the constants
|
73
|
-
# found by child.rb to the list of original constants in parent.rb
|
74
|
-
class WatchStack
|
100
|
+
# found by child.rb to the list of original constants in parent.rb.
|
101
|
+
class WatchStack
|
102
|
+
include Enumerable
|
103
|
+
|
75
104
|
# @watching is a stack of lists of constants being watched. For instance,
|
76
|
-
# if parent.rb is autoloaded, the stack will look like [[Object]]. If
|
77
|
-
# then requires namespace/child.rb, the stack will look like
|
105
|
+
# if parent.rb is autoloaded, the stack will look like [[Object]]. If
|
106
|
+
# parent.rb then requires namespace/child.rb, the stack will look like
|
107
|
+
# [[Object], [Namespace]].
|
78
108
|
|
79
109
|
def initialize
|
80
110
|
@watching = []
|
81
|
-
|
111
|
+
@stack = Hash.new { |h,k| h[k] = [] }
|
82
112
|
end
|
83
113
|
|
84
|
-
|
114
|
+
def each(&block)
|
115
|
+
@stack.each(&block)
|
116
|
+
end
|
117
|
+
|
118
|
+
def watching?
|
119
|
+
!@watching.empty?
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns a list of new constants found since the last call to
|
123
|
+
# <tt>watch_namespaces</tt>.
|
85
124
|
def new_constants
|
86
125
|
constants = []
|
87
126
|
|
@@ -89,26 +128,26 @@ module ActiveSupport #:nodoc:
|
|
89
128
|
@watching.last.each do |namespace|
|
90
129
|
# Retrieve the constants that were present under the namespace when watch_namespaces
|
91
130
|
# was originally called
|
92
|
-
original_constants =
|
131
|
+
original_constants = @stack[namespace].last
|
93
132
|
|
94
133
|
mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
|
95
134
|
next unless mod.is_a?(Module)
|
96
135
|
|
97
136
|
# Get a list of the constants that were added
|
98
|
-
new_constants = mod.
|
137
|
+
new_constants = mod.constants(false) - original_constants
|
99
138
|
|
100
|
-
#
|
139
|
+
# @stack[namespace] returns an Array of the constants that are being evaluated
|
101
140
|
# for that namespace. For instance, if parent.rb requires child.rb, the first
|
102
|
-
# element of
|
141
|
+
# element of @stack[Object] will be an Array of the constants that were present
|
103
142
|
# before parent.rb was required. The second element will be an Array of the
|
104
143
|
# constants that were present before child.rb was required.
|
105
|
-
|
144
|
+
@stack[namespace].each do |namespace_constants|
|
106
145
|
namespace_constants.concat(new_constants)
|
107
146
|
end
|
108
147
|
|
109
148
|
# Normalize the list of new constants, and add them to the list we will return
|
110
149
|
new_constants.each do |suffix|
|
111
|
-
constants << ([namespace, suffix] - ["Object"]).join("::")
|
150
|
+
constants << ([namespace, suffix] - ["Object"]).join("::".freeze)
|
112
151
|
end
|
113
152
|
end
|
114
153
|
constants
|
@@ -117,22 +156,22 @@ module ActiveSupport #:nodoc:
|
|
117
156
|
pop_modules(@watching.pop)
|
118
157
|
end
|
119
158
|
|
120
|
-
# Add a set of modules to the watch stack, remembering the initial
|
159
|
+
# Add a set of modules to the watch stack, remembering the initial
|
160
|
+
# constants.
|
121
161
|
def watch_namespaces(namespaces)
|
122
|
-
watching
|
123
|
-
namespaces.map do |namespace|
|
162
|
+
@watching << namespaces.map do |namespace|
|
124
163
|
module_name = Dependencies.to_constant_name(namespace)
|
125
164
|
original_constants = Dependencies.qualified_const_defined?(module_name) ?
|
126
|
-
Inflector.constantize(module_name).
|
165
|
+
Inflector.constantize(module_name).constants(false) : []
|
127
166
|
|
128
|
-
|
129
|
-
|
167
|
+
@stack[module_name] << original_constants
|
168
|
+
module_name
|
130
169
|
end
|
131
|
-
@watching << watching
|
132
170
|
end
|
133
171
|
|
172
|
+
private
|
134
173
|
def pop_modules(modules)
|
135
|
-
modules.each { |mod|
|
174
|
+
modules.each { |mod| @stack[mod].pop }
|
136
175
|
end
|
137
176
|
end
|
138
177
|
|
@@ -140,7 +179,7 @@ module ActiveSupport #:nodoc:
|
|
140
179
|
mattr_accessor :constant_watch_stack
|
141
180
|
self.constant_watch_stack = WatchStack.new
|
142
181
|
|
143
|
-
# Module includes this module
|
182
|
+
# Module includes this module.
|
144
183
|
module ModuleConstMissing #:nodoc:
|
145
184
|
def self.append_features(base)
|
146
185
|
base.class_eval do
|
@@ -159,36 +198,22 @@ module ActiveSupport #:nodoc:
|
|
159
198
|
end
|
160
199
|
end
|
161
200
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
unless nesting
|
168
|
-
# We'll assume that the nesting of Foo::Bar is ["Foo::Bar", "Foo"]
|
169
|
-
# even though it might not be, such as in the case of
|
170
|
-
# class Foo::Bar; Baz; end
|
171
|
-
nesting = []
|
172
|
-
klass_name.to_s.scan(/::|$/) { nesting.unshift $` }
|
173
|
-
end
|
174
|
-
|
175
|
-
# If there are multiple levels of nesting to search under, the top
|
176
|
-
# level is the one we want to report as the lookup fail.
|
177
|
-
error = nil
|
201
|
+
def const_missing(const_name)
|
202
|
+
from_mod = anonymous? ? guess_for_anonymous(const_name) : self
|
203
|
+
Dependencies.load_missing_constant(from_mod, const_name)
|
204
|
+
end
|
178
205
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
206
|
+
# We assume that the name of the module reflects the nesting
|
207
|
+
# (unless it can be proven that is not the case) and the path to the file
|
208
|
+
# that defines the constant. Anonymous modules cannot follow these
|
209
|
+
# conventions and therefore we assume that the user wants to refer to a
|
210
|
+
# top-level constant.
|
211
|
+
def guess_for_anonymous(const_name)
|
212
|
+
if Object.const_defined?(const_name)
|
213
|
+
raise NameError.new "#{const_name} cannot be autoloaded from an anonymous class or module", const_name
|
214
|
+
else
|
215
|
+
Object
|
186
216
|
end
|
187
|
-
|
188
|
-
# Raise the first error for this set. If this const_missing came from an
|
189
|
-
# earlier const_missing, this will result in the real error bubbling
|
190
|
-
# all the way up
|
191
|
-
raise error
|
192
217
|
end
|
193
218
|
|
194
219
|
def unloadable(const_desc = self)
|
@@ -196,70 +221,81 @@ module ActiveSupport #:nodoc:
|
|
196
221
|
end
|
197
222
|
end
|
198
223
|
|
199
|
-
# Object includes this module
|
224
|
+
# Object includes this module.
|
200
225
|
module Loadable #:nodoc:
|
201
226
|
def self.exclude_from(base)
|
202
|
-
base.class_eval
|
227
|
+
base.class_eval do
|
228
|
+
define_method(:load, Kernel.instance_method(:load))
|
229
|
+
private :load
|
230
|
+
end
|
203
231
|
end
|
204
232
|
|
205
233
|
def require_or_load(file_name)
|
206
234
|
Dependencies.require_or_load(file_name)
|
207
235
|
end
|
208
236
|
|
237
|
+
# Interprets a file using <tt>mechanism</tt> and marks its defined
|
238
|
+
# constants as autoloaded. <tt>file_name</tt> can be either a string or
|
239
|
+
# respond to <tt>to_path</tt>.
|
240
|
+
#
|
241
|
+
# Use this method in code that absolutely needs a certain constant to be
|
242
|
+
# defined at that point. A typical use case is to make constant name
|
243
|
+
# resolution deterministic for constants with the same relative name in
|
244
|
+
# different namespaces whose evaluation would depend on load order
|
245
|
+
# otherwise.
|
209
246
|
def require_dependency(file_name, message = "No such file to load -- %s")
|
247
|
+
file_name = file_name.to_path if file_name.respond_to?(:to_path)
|
210
248
|
unless file_name.is_a?(String)
|
211
|
-
raise ArgumentError, "the file name must be a String -- you passed #{file_name.inspect}"
|
249
|
+
raise ArgumentError, "the file name must either be a String or implement #to_path -- you passed #{file_name.inspect}"
|
212
250
|
end
|
213
251
|
|
214
|
-
Dependencies.depend_on(file_name,
|
215
|
-
end
|
216
|
-
|
217
|
-
def require_association(file_name)
|
218
|
-
Dependencies.associate_with(file_name)
|
252
|
+
Dependencies.depend_on(file_name, message)
|
219
253
|
end
|
220
254
|
|
221
255
|
def load_dependency(file)
|
222
|
-
if Dependencies.load?
|
223
|
-
Dependencies.new_constants_in(Object) { yield }
|
256
|
+
if Dependencies.load? && Dependencies.constant_watch_stack.watching?
|
257
|
+
Dependencies.new_constants_in(Object) { yield }
|
224
258
|
else
|
225
259
|
yield
|
226
260
|
end
|
227
261
|
rescue Exception => exception # errors from loading file
|
228
|
-
exception.blame_file! file
|
262
|
+
exception.blame_file! file if exception.respond_to? :blame_file!
|
229
263
|
raise
|
230
264
|
end
|
231
265
|
|
232
|
-
|
233
|
-
|
234
|
-
load_dependency(file) { result = super }
|
235
|
-
result
|
236
|
-
end
|
237
|
-
|
238
|
-
def require(file, *)
|
239
|
-
result = false
|
240
|
-
load_dependency(file) { result = super }
|
241
|
-
result
|
242
|
-
end
|
243
|
-
|
244
|
-
# Mark the given constant as unloadable. Unloadable constants are removed each
|
245
|
-
# time dependencies are cleared.
|
266
|
+
# Mark the given constant as unloadable. Unloadable constants are removed
|
267
|
+
# each time dependencies are cleared.
|
246
268
|
#
|
247
269
|
# Note that marking a constant for unloading need only be done once. Setup
|
248
270
|
# or init scripts may list each unloadable constant that may need unloading;
|
249
|
-
# each constant will be removed for every subsequent clear, as opposed to
|
250
|
-
# the first clear.
|
271
|
+
# each constant will be removed for every subsequent clear, as opposed to
|
272
|
+
# for the first clear.
|
251
273
|
#
|
252
274
|
# The provided constant descriptor may be a (non-anonymous) module or class,
|
253
275
|
# or a qualified constant name as a string or symbol.
|
254
276
|
#
|
255
|
-
# Returns true if the constant was not previously marked for unloading,
|
256
|
-
# otherwise.
|
277
|
+
# Returns +true+ if the constant was not previously marked for unloading,
|
278
|
+
# +false+ otherwise.
|
257
279
|
def unloadable(const_desc)
|
258
280
|
Dependencies.mark_for_unload const_desc
|
259
281
|
end
|
282
|
+
|
283
|
+
private
|
284
|
+
|
285
|
+
def load(file, wrap = false)
|
286
|
+
result = false
|
287
|
+
load_dependency(file) { result = super }
|
288
|
+
result
|
289
|
+
end
|
290
|
+
|
291
|
+
def require(file)
|
292
|
+
result = false
|
293
|
+
load_dependency(file) { result = super }
|
294
|
+
result
|
295
|
+
end
|
260
296
|
end
|
261
297
|
|
262
|
-
# Exception file-blaming
|
298
|
+
# Exception file-blaming.
|
263
299
|
module Blamable #:nodoc:
|
264
300
|
def blame_file!(file)
|
265
301
|
(@blamed_files ||= []).unshift file
|
@@ -284,117 +320,100 @@ module ActiveSupport #:nodoc:
|
|
284
320
|
Object.class_eval { include Loadable }
|
285
321
|
Module.class_eval { include ModuleConstMissing }
|
286
322
|
Exception.class_eval { include Blamable }
|
287
|
-
true
|
288
323
|
end
|
289
324
|
|
290
325
|
def unhook!
|
291
326
|
ModuleConstMissing.exclude_from(Module)
|
292
327
|
Loadable.exclude_from(Object)
|
293
|
-
true
|
294
328
|
end
|
295
329
|
|
296
330
|
def load?
|
297
331
|
mechanism == :load
|
298
332
|
end
|
299
333
|
|
300
|
-
def depend_on(file_name,
|
334
|
+
def depend_on(file_name, message = "No such file to load -- %s.rb")
|
301
335
|
path = search_for_file(file_name)
|
302
336
|
require_or_load(path || file_name)
|
303
337
|
rescue LoadError => load_error
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
end
|
308
|
-
raise
|
338
|
+
if file_name = load_error.message[/ -- (.*?)(\.rb)?$/, 1]
|
339
|
+
load_error.message.replace(message % file_name)
|
340
|
+
load_error.copy_blame!(load_error)
|
309
341
|
end
|
310
|
-
|
311
|
-
|
312
|
-
def associate_with(file_name)
|
313
|
-
depend_on(file_name, true)
|
342
|
+
raise
|
314
343
|
end
|
315
344
|
|
316
345
|
def clear
|
317
|
-
|
318
|
-
|
319
|
-
|
346
|
+
Dependencies.unload_interlock do
|
347
|
+
loaded.clear
|
348
|
+
loading.clear
|
349
|
+
remove_unloadable_constants!
|
350
|
+
end
|
320
351
|
end
|
321
352
|
|
322
353
|
def require_or_load(file_name, const_path = nil)
|
323
|
-
|
324
|
-
file_name = $1 if file_name =~ /^(.*)\.rb$/
|
354
|
+
file_name = $` if file_name =~ /\.rb\z/
|
325
355
|
expanded = File.expand_path(file_name)
|
326
356
|
return if loaded.include?(expanded)
|
327
357
|
|
328
|
-
|
329
|
-
|
330
|
-
|
358
|
+
Dependencies.load_interlock do
|
359
|
+
# Maybe it got loaded while we were waiting for our lock:
|
360
|
+
return if loaded.include?(expanded)
|
331
361
|
|
332
|
-
|
333
|
-
|
334
|
-
|
362
|
+
# Record that we've seen this file *before* loading it to avoid an
|
363
|
+
# infinite loop with mutual dependencies.
|
364
|
+
loaded << expanded
|
365
|
+
loading << expanded
|
335
366
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
367
|
+
begin
|
368
|
+
if load?
|
369
|
+
# Enable warnings if this file has not been loaded before and
|
370
|
+
# warnings_on_first_load is set.
|
371
|
+
load_args = ["#{file_name}.rb"]
|
372
|
+
load_args << const_path unless const_path.nil?
|
373
|
+
|
374
|
+
if !warnings_on_first_load or history.include?(expanded)
|
375
|
+
result = load_file(*load_args)
|
376
|
+
else
|
377
|
+
enable_warnings { result = load_file(*load_args) }
|
378
|
+
end
|
343
379
|
else
|
344
|
-
|
380
|
+
result = require file_name
|
345
381
|
end
|
346
|
-
|
347
|
-
|
348
|
-
|
382
|
+
rescue Exception
|
383
|
+
loaded.delete expanded
|
384
|
+
raise
|
385
|
+
ensure
|
386
|
+
loading.pop
|
349
387
|
end
|
350
|
-
rescue Exception
|
351
|
-
loaded.delete expanded
|
352
|
-
raise
|
353
|
-
end
|
354
388
|
|
355
|
-
|
356
|
-
|
357
|
-
|
389
|
+
# Record history *after* loading so first load gets warnings.
|
390
|
+
history << expanded
|
391
|
+
result
|
392
|
+
end
|
358
393
|
end
|
359
394
|
|
360
395
|
# Is the provided constant path defined?
|
361
396
|
def qualified_const_defined?(path)
|
362
|
-
|
363
|
-
|
364
|
-
names.inject(Object) do |mod, name|
|
365
|
-
return false unless local_const_defined?(mod, name)
|
366
|
-
mod.const_get name
|
367
|
-
end
|
397
|
+
Object.const_defined?(path, false)
|
368
398
|
end
|
369
399
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
def local_const_defined?(mod, const)
|
374
|
-
mod.const_defined?(const)
|
375
|
-
end
|
376
|
-
else
|
377
|
-
def local_const_defined?(mod, const) #:nodoc:
|
378
|
-
mod.const_defined?(const, false)
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
# Given +path+, a filesystem path to a ruby file, return an array of constant
|
383
|
-
# paths which would cause Dependencies to attempt to load this file.
|
400
|
+
# Given +path+, a filesystem path to a ruby file, return an array of
|
401
|
+
# constant paths which would cause Dependencies to attempt to load this
|
402
|
+
# file.
|
384
403
|
def loadable_constants_for_path(path, bases = autoload_paths)
|
385
|
-
path =
|
404
|
+
path = $` if path =~ /\.rb\z/
|
386
405
|
expanded_path = File.expand_path(path)
|
387
406
|
paths = []
|
388
407
|
|
389
408
|
bases.each do |root|
|
390
409
|
expanded_root = File.expand_path(root)
|
391
|
-
next unless
|
410
|
+
next unless expanded_path.start_with?(expanded_root)
|
392
411
|
|
393
|
-
|
394
|
-
|
395
|
-
next if nesting.blank?
|
412
|
+
root_size = expanded_root.size
|
413
|
+
next if expanded_path[root_size] != ?/.freeze
|
396
414
|
|
397
|
-
|
415
|
+
nesting = expanded_path[(root_size + 1)..-1]
|
416
|
+
paths << nesting.camelize unless nesting.blank?
|
398
417
|
end
|
399
418
|
|
400
419
|
paths.uniq!
|
@@ -403,7 +422,7 @@ module ActiveSupport #:nodoc:
|
|
403
422
|
|
404
423
|
# Search for a file in autoload_paths matching the provided suffix.
|
405
424
|
def search_for_file(path_suffix)
|
406
|
-
path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb")
|
425
|
+
path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb".freeze)
|
407
426
|
|
408
427
|
autoload_paths.each do |root|
|
409
428
|
path = File.join(root, path_suffix)
|
@@ -413,7 +432,8 @@ module ActiveSupport #:nodoc:
|
|
413
432
|
end
|
414
433
|
|
415
434
|
# Does the provided path_suffix correspond to an autoloadable module?
|
416
|
-
# Instead of returning a boolean, the autoload base for this module is
|
435
|
+
# Instead of returning a boolean, the autoload base for this module is
|
436
|
+
# returned.
|
417
437
|
def autoloadable_module?(path_suffix)
|
418
438
|
autoload_paths.each do |load_path|
|
419
439
|
return load_path if File.directory? File.join(load_path, path_suffix)
|
@@ -422,20 +442,22 @@ module ActiveSupport #:nodoc:
|
|
422
442
|
end
|
423
443
|
|
424
444
|
def load_once_path?(path)
|
425
|
-
|
445
|
+
# to_s works around a ruby issue where String#starts_with?(Pathname)
|
446
|
+
# will raise a TypeError: no implicit conversion of Pathname into String
|
447
|
+
autoload_once_paths.any? { |base| path.starts_with? base.to_s }
|
426
448
|
end
|
427
449
|
|
428
450
|
# Attempt to autoload the provided module name by searching for a directory
|
429
|
-
# matching the
|
430
|
-
# to +into+'s constants with the name +const_name+. Provided that
|
431
|
-
# was loaded from a reloadable base path, it is added to the
|
432
|
-
# that are to be unloaded.
|
451
|
+
# matching the expected path suffix. If found, the module is created and
|
452
|
+
# assigned to +into+'s constants with the name +const_name+. Provided that
|
453
|
+
# the directory was loaded from a reloadable base path, it is added to the
|
454
|
+
# set of constants that are to be unloaded.
|
433
455
|
def autoload_module!(into, const_name, qualified_name, path_suffix)
|
434
456
|
return nil unless base_path = autoloadable_module?(path_suffix)
|
435
457
|
mod = Module.new
|
436
458
|
into.const_set const_name, mod
|
437
459
|
autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
|
438
|
-
|
460
|
+
mod
|
439
461
|
end
|
440
462
|
|
441
463
|
# Load the file at the provided path. +const_paths+ is a set of qualified
|
@@ -443,13 +465,12 @@ module ActiveSupport #:nodoc:
|
|
443
465
|
# addition of these constants. Each that is defined will be marked as
|
444
466
|
# autoloaded, and will be removed when Dependencies.clear is next called.
|
445
467
|
#
|
446
|
-
# If the second parameter is left off, then Dependencies will construct a
|
447
|
-
# of names that the file at +path+ may define. See
|
468
|
+
# If the second parameter is left off, then Dependencies will construct a
|
469
|
+
# set of names that the file at +path+ may define. See
|
448
470
|
# +loadable_constants_for_path+ for more details.
|
449
471
|
def load_file(path, const_paths = loadable_constants_for_path(path))
|
450
|
-
log_call path, const_paths
|
451
472
|
const_paths = [const_paths].compact unless const_paths.is_a? Array
|
452
|
-
parent_paths = const_paths.collect { |const_path|
|
473
|
+
parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || ::Object }
|
453
474
|
|
454
475
|
result = nil
|
455
476
|
newly_defined_paths = new_constants_in(*parent_paths) do
|
@@ -458,55 +479,76 @@ module ActiveSupport #:nodoc:
|
|
458
479
|
|
459
480
|
autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
|
460
481
|
autoloaded_constants.uniq!
|
461
|
-
|
462
|
-
return result
|
482
|
+
result
|
463
483
|
end
|
464
484
|
|
465
|
-
#
|
485
|
+
# Returns the constant path for the provided parent and constant name.
|
466
486
|
def qualified_name_for(mod, name)
|
467
487
|
mod_name = to_constant_name mod
|
468
488
|
mod_name == "Object" ? name.to_s : "#{mod_name}::#{name}"
|
469
489
|
end
|
470
490
|
|
471
491
|
# Load the constant named +const_name+ which is missing from +from_mod+. If
|
472
|
-
# it is not possible to load the constant into from_mod, try its parent
|
473
|
-
# using const_missing
|
492
|
+
# it is not possible to load the constant into from_mod, try its parent
|
493
|
+
# module using +const_missing+.
|
474
494
|
def load_missing_constant(from_mod, const_name)
|
475
|
-
log_call from_mod, const_name
|
476
|
-
|
477
495
|
unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod)
|
478
496
|
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
|
479
497
|
end
|
480
498
|
|
481
|
-
raise NameError, "#{from_mod} is not missing constant #{const_name}!" if local_const_defined?(from_mod, const_name)
|
482
|
-
|
483
499
|
qualified_name = qualified_name_for from_mod, const_name
|
484
500
|
path_suffix = qualified_name.underscore
|
485
501
|
|
486
502
|
file_path = search_for_file(path_suffix)
|
487
503
|
|
488
|
-
if file_path
|
489
|
-
|
490
|
-
|
491
|
-
|
504
|
+
if file_path
|
505
|
+
expanded = File.expand_path(file_path)
|
506
|
+
expanded.sub!(/\.rb\z/, ''.freeze)
|
507
|
+
|
508
|
+
if loading.include?(expanded)
|
509
|
+
raise "Circular dependency detected while autoloading constant #{qualified_name}"
|
510
|
+
else
|
511
|
+
require_or_load(expanded, qualified_name)
|
512
|
+
raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
|
513
|
+
return from_mod.const_get(const_name)
|
514
|
+
end
|
492
515
|
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
|
493
516
|
return mod
|
494
517
|
elsif (parent = from_mod.parent) && parent != from_mod &&
|
495
|
-
! from_mod.parents.any? { |p|
|
518
|
+
! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
|
496
519
|
# If our parents do not have a constant named +const_name+ then we are free
|
497
520
|
# to attempt to load upwards. If they do have such a constant, then this
|
498
521
|
# const_missing must be due to from_mod::const_name, which should not
|
499
522
|
# return constants from from_mod's parents.
|
500
523
|
begin
|
524
|
+
# Since Ruby does not pass the nesting at the point the unknown
|
525
|
+
# constant triggered the callback we cannot fully emulate constant
|
526
|
+
# name lookup and need to make a trade-off: we are going to assume
|
527
|
+
# that the nesting in the body of Foo::Bar is [Foo::Bar, Foo] even
|
528
|
+
# though it might not be. Counterexamples are
|
529
|
+
#
|
530
|
+
# class Foo::Bar
|
531
|
+
# Module.nesting # => [Foo::Bar]
|
532
|
+
# end
|
533
|
+
#
|
534
|
+
# or
|
535
|
+
#
|
536
|
+
# module M::N
|
537
|
+
# module S::T
|
538
|
+
# Module.nesting # => [S::T, M::N]
|
539
|
+
# end
|
540
|
+
# end
|
541
|
+
#
|
542
|
+
# for example.
|
501
543
|
return parent.const_missing(const_name)
|
502
544
|
rescue NameError => e
|
503
545
|
raise unless e.missing_name? qualified_name_for(parent, const_name)
|
504
546
|
end
|
505
547
|
end
|
506
548
|
|
507
|
-
|
508
|
-
|
509
|
-
|
549
|
+
name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
|
550
|
+
name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ })
|
551
|
+
raise name_error
|
510
552
|
end
|
511
553
|
|
512
554
|
# Remove the constants that have been autoloaded, and those that have been
|
@@ -525,7 +567,7 @@ module ActiveSupport #:nodoc:
|
|
525
567
|
|
526
568
|
class ClassCache
|
527
569
|
def initialize
|
528
|
-
@store =
|
570
|
+
@store = Concurrent::Map.new
|
529
571
|
end
|
530
572
|
|
531
573
|
def empty?
|
@@ -536,40 +578,21 @@ module ActiveSupport #:nodoc:
|
|
536
578
|
@store.key?(key)
|
537
579
|
end
|
538
580
|
|
539
|
-
def
|
540
|
-
return unless key.respond_to?(:name)
|
541
|
-
|
542
|
-
raise(ArgumentError, 'anonymous classes cannot be cached') if key.name.blank?
|
543
|
-
|
544
|
-
@store[key.name] = value
|
545
|
-
end
|
546
|
-
|
547
|
-
def [](key)
|
581
|
+
def get(key)
|
548
582
|
key = key.name if key.respond_to?(:name)
|
549
|
-
|
550
|
-
@store[key]
|
583
|
+
@store[key] ||= Inflector.constantize(key)
|
551
584
|
end
|
552
|
-
alias :
|
585
|
+
alias :[] :get
|
553
586
|
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
end
|
558
|
-
|
559
|
-
def get
|
560
|
-
Reference.get @name
|
561
|
-
end
|
562
|
-
deprecate :get
|
563
|
-
end
|
564
|
-
|
565
|
-
def new(name)
|
566
|
-
self[name] = name
|
567
|
-
Getter.new(name)
|
587
|
+
def safe_get(key)
|
588
|
+
key = key.name if key.respond_to?(:name)
|
589
|
+
@store[key] ||= Inflector.safe_constantize(key)
|
568
590
|
end
|
569
|
-
deprecate :new
|
570
591
|
|
571
|
-
def store(
|
572
|
-
self
|
592
|
+
def store(klass)
|
593
|
+
return self unless klass.respond_to?(:name)
|
594
|
+
raise(ArgumentError, 'anonymous classes cannot be cached') if klass.name.empty?
|
595
|
+
@store[klass.name] = klass
|
573
596
|
self
|
574
597
|
end
|
575
598
|
|
@@ -580,27 +603,28 @@ module ActiveSupport #:nodoc:
|
|
580
603
|
|
581
604
|
Reference = ClassCache.new
|
582
605
|
|
583
|
-
def ref(name)
|
584
|
-
Reference.new(name)
|
585
|
-
end
|
586
|
-
deprecate :ref
|
587
|
-
|
588
606
|
# Store a reference to a class +klass+.
|
589
607
|
def reference(klass)
|
590
608
|
Reference.store klass
|
591
609
|
end
|
592
610
|
|
593
611
|
# Get the reference for class named +name+.
|
612
|
+
# Raises an exception if referenced class does not exist.
|
594
613
|
def constantize(name)
|
595
614
|
Reference.get(name)
|
596
615
|
end
|
597
616
|
|
617
|
+
# Get the reference for class named +name+ if one exists.
|
618
|
+
# Otherwise returns +nil+.
|
619
|
+
def safe_constantize(name)
|
620
|
+
Reference.safe_get(name)
|
621
|
+
end
|
622
|
+
|
598
623
|
# Determine if the given constant has been automatically loaded.
|
599
624
|
def autoloaded?(desc)
|
600
|
-
# No name => anonymous module.
|
601
625
|
return false if desc.is_a?(Module) && desc.anonymous?
|
602
626
|
name = to_constant_name desc
|
603
|
-
return false unless qualified_const_defined?
|
627
|
+
return false unless qualified_const_defined?(name)
|
604
628
|
return autoloaded_constants.include?(name)
|
605
629
|
end
|
606
630
|
|
@@ -615,10 +639,10 @@ module ActiveSupport #:nodoc:
|
|
615
639
|
def mark_for_unload(const_desc)
|
616
640
|
name = to_constant_name const_desc
|
617
641
|
if explicitly_unloadable_constants.include? name
|
618
|
-
|
642
|
+
false
|
619
643
|
else
|
620
644
|
explicitly_unloadable_constants << name
|
621
|
-
|
645
|
+
true
|
622
646
|
end
|
623
647
|
end
|
624
648
|
|
@@ -631,25 +655,20 @@ module ActiveSupport #:nodoc:
|
|
631
655
|
# exception, any new constants are regarded as being only partially defined
|
632
656
|
# and will be removed immediately.
|
633
657
|
def new_constants_in(*descs)
|
634
|
-
log_call(*descs)
|
635
|
-
|
636
658
|
constant_watch_stack.watch_namespaces(descs)
|
637
|
-
|
659
|
+
success = false
|
638
660
|
|
639
661
|
begin
|
640
662
|
yield # Now yield to the code that is to define new constants.
|
641
|
-
|
663
|
+
success = true
|
642
664
|
ensure
|
643
665
|
new_constants = constant_watch_stack.new_constants
|
644
666
|
|
645
|
-
|
646
|
-
return new_constants unless aborting
|
667
|
+
return new_constants if success
|
647
668
|
|
648
|
-
|
649
|
-
new_constants.each {|c| remove_constant(c) }
|
669
|
+
# Remove partially loaded constants.
|
670
|
+
new_constants.each { |c| remove_constant(c) }
|
650
671
|
end
|
651
|
-
|
652
|
-
return []
|
653
672
|
end
|
654
673
|
|
655
674
|
# Convert the provided const desc to a qualified constant name (as a string).
|
@@ -659,45 +678,76 @@ module ActiveSupport #:nodoc:
|
|
659
678
|
when String then desc.sub(/^::/, '')
|
660
679
|
when Symbol then desc.to_s
|
661
680
|
when Module
|
662
|
-
desc.name
|
681
|
+
desc.name ||
|
663
682
|
raise(ArgumentError, "Anonymous modules have no name to be referenced by")
|
664
683
|
else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
|
665
684
|
end
|
666
685
|
end
|
667
686
|
|
668
687
|
def remove_constant(const) #:nodoc:
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
names = const.to_s.sub(/^::(Object)?/, 'Object::').split("::")
|
673
|
-
to_remove = names.pop
|
674
|
-
parent = Inflector.constantize(names * '::')
|
688
|
+
# Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo.
|
689
|
+
normalized = const.to_s.sub(/\A::/, '')
|
690
|
+
normalized.sub!(/\A(Object::)+/, '')
|
675
691
|
|
676
|
-
|
677
|
-
|
678
|
-
constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
|
679
|
-
parent.instance_eval { remove_const to_remove }
|
692
|
+
constants = normalized.split('::')
|
693
|
+
to_remove = constants.pop
|
680
694
|
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
arg_str = args.collect { |arg| arg.inspect } * ', '
|
688
|
-
/in `([a-z_\?\!]+)'/ =~ caller(1).first
|
689
|
-
selector = $1 || '<unknown>'
|
690
|
-
log "called #{selector}(#{arg_str})"
|
691
|
-
end
|
695
|
+
# Remove the file path from the loaded list.
|
696
|
+
file_path = search_for_file(const.underscore)
|
697
|
+
if file_path
|
698
|
+
expanded = File.expand_path(file_path)
|
699
|
+
expanded.sub!(/\.rb\z/, '')
|
700
|
+
self.loaded.delete(expanded)
|
692
701
|
end
|
693
702
|
|
694
|
-
|
695
|
-
|
703
|
+
if constants.empty?
|
704
|
+
parent = Object
|
705
|
+
else
|
706
|
+
# This method is robust to non-reachable constants.
|
707
|
+
#
|
708
|
+
# Non-reachable constants may be passed if some of the parents were
|
709
|
+
# autoloaded and already removed. It is easier to do a sanity check
|
710
|
+
# here than require the caller to be clever. We check the parent
|
711
|
+
# rather than the very const argument because we do not want to
|
712
|
+
# trigger Kernel#autoloads, see the comment below.
|
713
|
+
parent_name = constants.join('::')
|
714
|
+
return unless qualified_const_defined?(parent_name)
|
715
|
+
parent = constantize(parent_name)
|
716
|
+
end
|
717
|
+
|
718
|
+
# In an autoloaded user.rb like this
|
719
|
+
#
|
720
|
+
# autoload :Foo, 'foo'
|
721
|
+
#
|
722
|
+
# class User < ActiveRecord::Base
|
723
|
+
# end
|
724
|
+
#
|
725
|
+
# we correctly register "Foo" as being autoloaded. But if the app does
|
726
|
+
# not use the "Foo" constant we need to be careful not to trigger
|
727
|
+
# loading "foo.rb" ourselves. While #const_defined? and #const_get? do
|
728
|
+
# require the file, #autoload? and #remove_const don't.
|
729
|
+
#
|
730
|
+
# We are going to remove the constant nonetheless ---which exists as
|
731
|
+
# far as Ruby is concerned--- because if the user removes the macro
|
732
|
+
# call from a class or module that were not autoloaded, as in the
|
733
|
+
# example above with Object, accessing to that constant must err.
|
734
|
+
unless parent.autoload?(to_remove)
|
735
|
+
begin
|
736
|
+
constantized = parent.const_get(to_remove, false)
|
737
|
+
rescue NameError
|
738
|
+
# The constant is no longer reachable, just skip it.
|
739
|
+
return
|
740
|
+
else
|
741
|
+
constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
|
742
|
+
end
|
696
743
|
end
|
697
744
|
|
698
|
-
|
699
|
-
|
745
|
+
begin
|
746
|
+
parent.instance_eval { remove_const to_remove }
|
747
|
+
rescue NameError
|
748
|
+
# The constant is no longer reachable, just skip it.
|
700
749
|
end
|
750
|
+
end
|
701
751
|
end
|
702
752
|
end
|
703
753
|
|