activesupport 3.2.22.5 → 4.0.0.beta1
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 +4 -4
- data/CHANGELOG.md +325 -136
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/lib/active_support.rb +8 -21
- data/lib/active_support/backtrace_cleaner.rb +33 -25
- data/lib/active_support/basic_object.rb +7 -17
- data/lib/active_support/benchmarkable.rb +19 -15
- data/lib/active_support/buffered_logger.rb +9 -113
- data/lib/active_support/cache.rb +203 -171
- data/lib/active_support/cache/file_store.rb +12 -12
- data/lib/active_support/cache/mem_cache_store.rb +24 -30
- data/lib/active_support/cache/memory_store.rb +2 -0
- data/lib/active_support/callbacks.rb +195 -247
- data/lib/active_support/concern.rb +16 -23
- data/lib/active_support/concurrency/latch.rb +27 -0
- data/lib/active_support/configurable.rb +69 -12
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/array/access.rb +17 -9
- data/lib/active_support/core_ext/array/conversions.rb +113 -55
- data/lib/active_support/core_ext/array/extract_options.rb +2 -2
- data/lib/active_support/core_ext/array/grouping.rb +21 -22
- data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
- data/lib/active_support/core_ext/array/wrap.rb +11 -14
- data/lib/active_support/core_ext/big_decimal/conversions.rb +7 -24
- data/lib/active_support/core_ext/class/attribute.rb +12 -8
- data/lib/active_support/core_ext/class/attribute_accessors.rb +14 -12
- data/lib/active_support/core_ext/class/delegating_attributes.rb +15 -19
- data/lib/active_support/core_ext/class/subclasses.rb +11 -5
- data/lib/active_support/core_ext/date.rb +6 -0
- data/lib/active_support/core_ext/date/calculations.rb +34 -188
- data/lib/active_support/core_ext/date/conversions.rb +16 -38
- data/lib/active_support/core_ext/date/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/date/zones.rb +25 -2
- data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
- data/lib/active_support/core_ext/date_time.rb +5 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +73 -65
- data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
- data/lib/active_support/core_ext/date_time/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/date_time/zones.rb +11 -8
- data/lib/active_support/core_ext/enumerable.rb +26 -73
- data/lib/active_support/core_ext/file.rb +0 -1
- data/lib/active_support/core_ext/file/atomic.rb +27 -11
- data/lib/active_support/core_ext/hash.rb +0 -1
- data/lib/active_support/core_ext/hash/conversions.rb +145 -79
- data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
- data/lib/active_support/core_ext/hash/diff.rb +5 -4
- data/lib/active_support/core_ext/hash/except.rb +1 -9
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
- data/lib/active_support/core_ext/hash/keys.rb +108 -24
- data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
- data/lib/active_support/core_ext/hash/slice.rb +12 -12
- data/lib/active_support/core_ext/infinite_comparable.rb +35 -0
- data/lib/active_support/core_ext/integer/inflections.rb +13 -1
- data/lib/active_support/core_ext/integer/time.rb +17 -12
- data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
- data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
- data/lib/active_support/core_ext/load_error.rb +7 -5
- data/lib/active_support/core_ext/logger.rb +7 -23
- data/lib/active_support/core_ext/marshal.rb +19 -0
- data/lib/active_support/core_ext/module.rb +1 -3
- data/lib/active_support/core_ext/module/aliasing.rb +8 -9
- data/lib/active_support/core_ext/module/anonymous.rb +2 -7
- data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
- data/lib/active_support/core_ext/module/delegation.rb +57 -40
- data/lib/active_support/core_ext/module/deprecation.rb +19 -3
- data/lib/active_support/core_ext/module/introspection.rb +17 -27
- data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
- data/lib/active_support/core_ext/module/remove_method.rb +1 -5
- data/lib/active_support/core_ext/numeric.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
- data/lib/active_support/core_ext/numeric/infinite_comparable.rb +9 -0
- data/lib/active_support/core_ext/numeric/time.rb +6 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +4 -4
- data/lib/active_support/core_ext/object/blank.rb +7 -23
- data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
- data/lib/active_support/core_ext/object/duplicable.rb +1 -30
- data/lib/active_support/core_ext/object/inclusion.rb +6 -6
- data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
- data/lib/active_support/core_ext/object/to_json.rb +8 -0
- data/lib/active_support/core_ext/object/to_param.rb +5 -2
- data/lib/active_support/core_ext/object/try.rb +46 -25
- data/lib/active_support/core_ext/object/with_options.rb +7 -8
- data/lib/active_support/core_ext/proc.rb +3 -0
- data/lib/active_support/core_ext/range.rb +0 -2
- data/lib/active_support/core_ext/range/conversions.rb +0 -2
- data/lib/active_support/core_ext/range/include_range.rb +1 -1
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/string.rb +2 -2
- data/lib/active_support/core_ext/string/access.rb +95 -90
- data/lib/active_support/core_ext/string/conversions.rb +29 -38
- data/lib/active_support/core_ext/string/encoding.rb +6 -9
- data/lib/active_support/core_ext/string/filters.rb +24 -18
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/active_support/core_ext/string/inflections.rb +70 -60
- data/lib/active_support/core_ext/string/inquiry.rb +2 -2
- data/lib/active_support/core_ext/string/multibyte.rb +41 -64
- data/lib/active_support/core_ext/string/output_safety.rb +59 -51
- data/lib/active_support/core_ext/string/zones.rb +13 -0
- data/lib/active_support/core_ext/struct.rb +6 -0
- data/lib/active_support/core_ext/thread.rb +74 -0
- data/lib/active_support/core_ext/time.rb +6 -0
- data/lib/active_support/core_ext/time/calculations.rb +105 -193
- data/lib/active_support/core_ext/time/conversions.rb +27 -51
- data/lib/active_support/core_ext/time/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/time/marshal.rb +0 -27
- data/lib/active_support/core_ext/time/zones.rb +27 -17
- data/lib/active_support/core_ext/uri.rb +13 -17
- data/lib/active_support/dependencies.rb +160 -141
- data/lib/active_support/dependencies/autoload.rb +47 -20
- data/lib/active_support/deprecation.rb +39 -14
- data/lib/active_support/deprecation/behaviors.rb +44 -30
- data/lib/active_support/deprecation/instance_delegator.rb +24 -0
- data/lib/active_support/deprecation/method_wrappers.rb +33 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
- data/lib/active_support/deprecation/reporting.rb +40 -11
- data/lib/active_support/descendants_tracker.rb +34 -19
- data/lib/active_support/duration.rb +6 -8
- data/lib/active_support/file_update_checker.rb +63 -47
- data/lib/active_support/gzip.rb +11 -5
- data/lib/active_support/hash_with_indifferent_access.rb +112 -37
- data/lib/active_support/i18n.rb +4 -0
- data/lib/active_support/i18n_railtie.rb +5 -22
- data/lib/active_support/inflections.rb +14 -12
- data/lib/active_support/inflector/inflections.rb +108 -71
- data/lib/active_support/inflector/methods.rb +181 -160
- data/lib/active_support/inflector/transliterate.rb +16 -17
- data/lib/active_support/json/decoding.rb +18 -17
- data/lib/active_support/json/encoding.rb +93 -39
- data/lib/active_support/json/variable.rb +10 -1
- data/lib/active_support/key_generator.rb +75 -0
- data/lib/active_support/lazy_load_hooks.rb +21 -19
- data/lib/active_support/locale/en.yml +100 -3
- data/lib/active_support/log_subscriber.rb +56 -36
- data/lib/active_support/log_subscriber/test_helper.rb +18 -15
- data/lib/active_support/logger.rb +57 -0
- data/lib/active_support/logger_silence.rb +24 -0
- data/lib/active_support/message_encryptor.rb +32 -29
- data/lib/active_support/message_verifier.rb +8 -14
- data/lib/active_support/multibyte.rb +5 -28
- data/lib/active_support/multibyte/chars.rb +80 -333
- data/lib/active_support/multibyte/unicode.rb +74 -64
- data/lib/active_support/notifications.rb +57 -25
- data/lib/active_support/notifications/fanout.rb +105 -18
- data/lib/active_support/notifications/instrumenter.rb +32 -13
- data/lib/active_support/number_helper.rb +636 -0
- data/lib/active_support/ordered_hash.rb +8 -190
- data/lib/active_support/ordered_options.rb +21 -23
- data/lib/active_support/proxy_object.rb +13 -0
- data/lib/active_support/rails.rb +27 -0
- data/lib/active_support/railtie.rb +12 -32
- data/lib/active_support/rescuable.rb +9 -4
- data/lib/active_support/string_inquirer.rb +13 -8
- data/lib/active_support/tagged_logging.rb +51 -73
- data/lib/active_support/test_case.rb +46 -17
- data/lib/active_support/testing/assertions.rb +56 -26
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/constant_lookup.rb +52 -0
- data/lib/active_support/testing/declarative.rb +1 -1
- data/lib/active_support/testing/deprecation.rb +0 -19
- data/lib/active_support/testing/isolation.rb +25 -58
- data/lib/active_support/testing/pending.rb +5 -43
- data/lib/active_support/testing/setup_and_teardown.rb +6 -92
- data/lib/active_support/testing/tagged_logging.rb +25 -0
- data/lib/active_support/time.rb +6 -21
- data/lib/active_support/time_with_zone.rb +78 -43
- data/lib/active_support/values/time_zone.rb +77 -58
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +4 -4
- data/lib/active_support/xml_mini.rb +35 -17
- data/lib/active_support/xml_mini/jdom.rb +9 -17
- data/lib/active_support/xml_mini/libxml.rb +1 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -2
- data/lib/active_support/xml_mini/nokogiri.rb +1 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -2
- data/lib/active_support/xml_mini/rexml.rb +6 -8
- metadata +107 -77
- data/lib/active_support/base64.rb +0 -54
- data/lib/active_support/core_ext/array/random_access.rb +0 -30
- data/lib/active_support/core_ext/date/freeze.rb +0 -33
- 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.rb +0 -1
- data/lib/active_support/core_ext/float/rounding.rb +0 -19
- data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
- data/lib/active_support/core_ext/io.rb +0 -15
- data/lib/active_support/core_ext/module/method_names.rb +0 -14
- data/lib/active_support/core_ext/module/synchronization.rb +0 -45
- data/lib/active_support/core_ext/process.rb +0 -1
- data/lib/active_support/core_ext/process/daemon.rb +0 -23
- 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/interpolation.rb +0 -2
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
- data/lib/active_support/memoizable.rb +0 -116
- 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/security_utils.rb +0 -27
- data/lib/active_support/testing/mochaing.rb +0 -7
- data/lib/active_support/testing/performance.rb +0 -317
- 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.rb +0 -152
- 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/time/autoload.rb +0 -5
- data/lib/active_support/whiny_nil.rb +0 -24
@@ -1,35 +1,39 @@
|
|
1
1
|
require 'active_support/inflector/methods'
|
2
|
-
require 'active_support/core_ext/time/publicize_conversion_methods'
|
3
2
|
require 'active_support/values/time_zone'
|
4
3
|
|
5
4
|
class Time
|
6
5
|
DATE_FORMATS = {
|
7
|
-
:db =>
|
8
|
-
:number =>
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
6
|
+
:db => '%Y-%m-%d %H:%M:%S',
|
7
|
+
:number => '%Y%m%d%H%M%S',
|
8
|
+
:nsec => '%Y%m%d%H%M%S%9N',
|
9
|
+
:time => '%H:%M',
|
10
|
+
:short => '%d %b %H:%M',
|
11
|
+
:long => '%B %d, %Y %H:%M',
|
12
|
+
:long_ordinal => lambda { |time|
|
13
|
+
day_format = ActiveSupport::Inflector.ordinalize(time.day)
|
14
|
+
time.strftime("%B #{day_format}, %Y %H:%M")
|
15
|
+
},
|
16
|
+
:rfc822 => lambda { |time|
|
17
|
+
offset_format = time.formatted_offset(false)
|
18
|
+
time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}")
|
19
|
+
}
|
14
20
|
}
|
15
21
|
|
16
|
-
DATE_FORMATS[:nsec] = '%Y%m%d%H%M%S%9N' if RUBY_VERSION >= '1.9'
|
17
|
-
|
18
22
|
# Converts to a formatted string. See DATE_FORMATS for builtin formats.
|
19
23
|
#
|
20
24
|
# This method is aliased to <tt>to_s</tt>.
|
21
25
|
#
|
22
|
-
# time = Time.now
|
26
|
+
# time = Time.now # => Thu Jan 18 06:10:17 CST 2007
|
23
27
|
#
|
24
|
-
# time.to_formatted_s(:time)
|
25
|
-
# time.to_s(:time)
|
28
|
+
# time.to_formatted_s(:time) # => "06:10"
|
29
|
+
# time.to_s(:time) # => "06:10"
|
26
30
|
#
|
27
|
-
# time.to_formatted_s(:db)
|
28
|
-
# time.to_formatted_s(:number)
|
29
|
-
# time.to_formatted_s(:short)
|
30
|
-
# time.to_formatted_s(:long)
|
31
|
-
# time.to_formatted_s(:long_ordinal)
|
32
|
-
# time.to_formatted_s(:rfc822)
|
31
|
+
# time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
|
32
|
+
# time.to_formatted_s(:number) # => "20070118061017"
|
33
|
+
# time.to_formatted_s(:short) # => "18 Jan 06:10"
|
34
|
+
# time.to_formatted_s(:long) # => "January 18, 2007 06:10"
|
35
|
+
# time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
|
36
|
+
# time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
|
33
37
|
#
|
34
38
|
# == Adding your own time formats to +to_formatted_s+
|
35
39
|
# You can add your own formats to the Time::DATE_FORMATS hash.
|
@@ -37,8 +41,8 @@ class Time
|
|
37
41
|
# or Proc instance that takes a time argument as the value.
|
38
42
|
#
|
39
43
|
# # config/initializers/time_formats.rb
|
40
|
-
# Time::DATE_FORMATS[:month_and_year] =
|
41
|
-
# Time::DATE_FORMATS[:short_ordinal]
|
44
|
+
# Time::DATE_FORMATS[:month_and_year] = '%B %Y'
|
45
|
+
# Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
|
42
46
|
def to_formatted_s(format = :default)
|
43
47
|
if formatter = DATE_FORMATS[format]
|
44
48
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
@@ -51,37 +55,9 @@ class Time
|
|
51
55
|
|
52
56
|
# Returns the UTC offset as an +HH:MM formatted string.
|
53
57
|
#
|
54
|
-
# Time.local(2000).formatted_offset
|
55
|
-
# Time.local(2000).formatted_offset(false)
|
58
|
+
# Time.local(2000).formatted_offset # => "-06:00"
|
59
|
+
# Time.local(2000).formatted_offset(false) # => "-0600"
|
56
60
|
def formatted_offset(colon = true, alternate_utc_string = nil)
|
57
61
|
utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
|
58
62
|
end
|
59
|
-
|
60
|
-
# Converts a Time object to a Date, dropping hour, minute, and second precision.
|
61
|
-
#
|
62
|
-
# my_time = Time.now # => Mon Nov 12 22:59:51 -0500 2007
|
63
|
-
# my_time.to_date # => Mon, 12 Nov 2007
|
64
|
-
#
|
65
|
-
# your_time = Time.parse("1/13/2009 1:13:03 P.M.") # => Tue Jan 13 13:13:03 -0500 2009
|
66
|
-
# your_time.to_date # => Tue, 13 Jan 2009
|
67
|
-
def to_date
|
68
|
-
::Date.new(year, month, day)
|
69
|
-
end unless method_defined?(:to_date)
|
70
|
-
|
71
|
-
# A method to keep Time, Date and DateTime instances interchangeable on conversions.
|
72
|
-
# In this case, it simply returns +self+.
|
73
|
-
def to_time
|
74
|
-
self
|
75
|
-
end unless method_defined?(:to_time)
|
76
|
-
|
77
|
-
# Converts a Time instance to a Ruby DateTime instance, preserving UTC offset.
|
78
|
-
#
|
79
|
-
# my_time = Time.now # => Mon Nov 12 23:04:21 -0500 2007
|
80
|
-
# my_time.to_datetime # => Mon, 12 Nov 2007 23:04:21 -0500
|
81
|
-
#
|
82
|
-
# your_time = Time.parse("1/13/2009 1:13:03 P.M.") # => Tue Jan 13 13:13:03 -0500 2009
|
83
|
-
# your_time.to_datetime # => Tue, 13 Jan 2009 13:13:03 -0500
|
84
|
-
def to_datetime
|
85
|
-
::DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400))
|
86
|
-
end unless method_defined?(:to_datetime)
|
87
63
|
end
|
@@ -1,30 +1,3 @@
|
|
1
|
-
# Pre-1.9 versions of Ruby have a bug with marshaling Time instances, where utc instances are
|
2
|
-
# unmarshalled in the local zone, instead of utc. We're layering behavior on the _dump and _load
|
3
|
-
# methods so that utc instances can be flagged on dump, and coerced back to utc on load.
|
4
|
-
if !Marshal.load(Marshal.dump(Time.now.utc)).utc?
|
5
|
-
class Time
|
6
|
-
class << self
|
7
|
-
alias_method :_load_without_utc_flag, :_load
|
8
|
-
def _load(marshaled_time)
|
9
|
-
time = _load_without_utc_flag(marshaled_time)
|
10
|
-
time.instance_eval do
|
11
|
-
if defined?(@marshal_with_utc_coercion)
|
12
|
-
val = remove_instance_variable("@marshal_with_utc_coercion")
|
13
|
-
end
|
14
|
-
val ? utc : self
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
alias_method :_dump_without_utc_flag, :_dump
|
20
|
-
def _dump(*args)
|
21
|
-
obj = dup
|
22
|
-
obj.instance_variable_set('@marshal_with_utc_coercion', utc?)
|
23
|
-
obj.send :_dump_without_utc_flag, *args
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
1
|
# Ruby 1.9.2 adds utc_offset and zone to Time, but marshaling only
|
29
2
|
# preserves utc_offset. Preserve zone also, even though it may not
|
30
3
|
# work in some edge cases.
|
@@ -26,11 +26,11 @@ class Time
|
|
26
26
|
# around_filter :set_time_zone
|
27
27
|
#
|
28
28
|
# def set_time_zone
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
29
|
+
# if logged_in?
|
30
|
+
# Time.use_zone(current_user.time_zone) { yield }
|
31
|
+
# else
|
32
|
+
# yield
|
33
|
+
# end
|
34
34
|
# end
|
35
35
|
# end
|
36
36
|
def zone=(time_zone)
|
@@ -50,13 +50,21 @@ class Time
|
|
50
50
|
|
51
51
|
# Returns a TimeZone instance or nil, or raises an ArgumentError for invalid timezones.
|
52
52
|
def find_zone!(time_zone)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
|
54
|
+
time_zone
|
55
|
+
else
|
56
|
+
# lookup timezone based on identifier (unless we've been passed a TZInfo::Timezone)
|
57
|
+
unless time_zone.respond_to?(:period_for_local)
|
58
|
+
time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return if a TimeZone instance, or wrap in a TimeZone instance if a TZInfo::Timezone
|
62
|
+
if time_zone.is_a?(ActiveSupport::TimeZone)
|
63
|
+
time_zone
|
64
|
+
else
|
65
|
+
ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone)
|
66
|
+
end
|
57
67
|
end
|
58
|
-
# Return if a TimeZone instance, or wrap in a TimeZone instance if a TZInfo::Timezone
|
59
|
-
time_zone.is_a?(ActiveSupport::TimeZone) ? time_zone : ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone)
|
60
68
|
rescue TZInfo::InvalidTimezoneIdentifier
|
61
69
|
raise ArgumentError, "Invalid Timezone: #{time_zone}"
|
62
70
|
end
|
@@ -68,8 +76,8 @@ class Time
|
|
68
76
|
|
69
77
|
# Returns the simultaneous time in <tt>Time.zone</tt>.
|
70
78
|
#
|
71
|
-
# Time.zone = 'Hawaii'
|
72
|
-
# Time.utc(2000).in_time_zone
|
79
|
+
# Time.zone = 'Hawaii' # => 'Hawaii'
|
80
|
+
# Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
|
73
81
|
#
|
74
82
|
# This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
|
75
83
|
# instead of the operating system's time zone.
|
@@ -77,10 +85,12 @@ class Time
|
|
77
85
|
# You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
|
78
86
|
# and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
|
79
87
|
#
|
80
|
-
# Time.utc(2000).in_time_zone('Alaska')
|
88
|
+
# Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
|
81
89
|
def in_time_zone(zone = ::Time.zone)
|
82
|
-
|
83
|
-
|
84
|
-
|
90
|
+
if zone
|
91
|
+
ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.find_zone!(zone))
|
92
|
+
else
|
93
|
+
self
|
94
|
+
end
|
85
95
|
end
|
86
96
|
end
|
@@ -1,22 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require 'uri'
|
4
|
+
str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
|
5
|
+
parser = URI::Parser.new
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# YK: My initial experiments say yes, but let's be sure please
|
16
|
-
enc = str.encoding
|
17
|
-
enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
|
18
|
-
str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(enc)
|
19
|
-
end
|
7
|
+
unless str == parser.unescape(parser.escape(str))
|
8
|
+
URI::Parser.class_eval do
|
9
|
+
remove_method :unescape
|
10
|
+
def unescape(str, escaped = /%[a-fA-F\d]{2}/)
|
11
|
+
# TODO: Are we actually sure that ASCII == UTF-8?
|
12
|
+
# YK: My initial experiments say yes, but let's be sure please
|
13
|
+
enc = str.encoding
|
14
|
+
enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
|
15
|
+
str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(enc)
|
20
16
|
end
|
21
17
|
end
|
22
18
|
end
|
@@ -24,7 +20,7 @@ end
|
|
24
20
|
module URI
|
25
21
|
class << self
|
26
22
|
def parser
|
27
|
-
@parser ||= URI
|
23
|
+
@parser ||= URI::Parser.new
|
28
24
|
end
|
29
25
|
end
|
30
26
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'thread'
|
3
|
+
require 'thread_safe'
|
3
4
|
require 'pathname'
|
4
5
|
require 'active_support/core_ext/module/aliasing'
|
5
6
|
require 'active_support/core_ext/module/attribute_accessors'
|
@@ -43,8 +44,9 @@ module ActiveSupport #:nodoc:
|
|
43
44
|
mattr_accessor :autoload_once_paths
|
44
45
|
self.autoload_once_paths = []
|
45
46
|
|
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
|
47
|
+
# An array of qualified constant names that have been loaded. Adding a name
|
48
|
+
# to this array will cause it to be unloaded the next time Dependencies are
|
49
|
+
# cleared.
|
48
50
|
mattr_accessor :autoloaded_constants
|
49
51
|
self.autoloaded_constants = []
|
50
52
|
|
@@ -53,30 +55,32 @@ module ActiveSupport #:nodoc:
|
|
53
55
|
mattr_accessor :explicitly_unloadable_constants
|
54
56
|
self.explicitly_unloadable_constants = []
|
55
57
|
|
56
|
-
# The logger is used for generating information on the action run-time
|
57
|
-
# Can be set to nil for no logging.
|
58
|
+
# The logger is used for generating information on the action run-time
|
59
|
+
# (including benchmarking) if available. Can be set to nil for no logging.
|
60
|
+
# Compatible with both Ruby's own Logger and Log4r loggers.
|
58
61
|
mattr_accessor :logger
|
59
62
|
|
60
|
-
# Set to true to enable logging of const_missing and file loads
|
63
|
+
# Set to +true+ to enable logging of const_missing and file loads.
|
61
64
|
mattr_accessor :log_activity
|
62
65
|
self.log_activity = false
|
63
66
|
|
64
|
-
# The WatchStack keeps a stack of the modules being watched as files are
|
65
|
-
# If a file in the process of being loaded (parent.rb) triggers the
|
66
|
-
# another file (child.rb) the stack will ensure that child.rb
|
67
|
-
# constants.
|
67
|
+
# The WatchStack keeps a stack of the modules being watched as files are
|
68
|
+
# loaded. If a file in the process of being loaded (parent.rb) triggers the
|
69
|
+
# load of another file (child.rb) the stack will ensure that child.rb
|
70
|
+
# handles the new constants.
|
68
71
|
#
|
69
72
|
# If child.rb is being autoloaded, its constants will be added to
|
70
73
|
# autoloaded_constants. If it was being `require`d, they will be discarded.
|
71
74
|
#
|
72
75
|
# 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
|
76
|
+
# found by child.rb to the list of original constants in parent.rb.
|
74
77
|
class WatchStack
|
75
78
|
include Enumerable
|
76
79
|
|
77
80
|
# @watching is a stack of lists of constants being watched. For instance,
|
78
|
-
# if parent.rb is autoloaded, the stack will look like [[Object]]. If
|
79
|
-
# then requires namespace/child.rb, the stack will look like
|
81
|
+
# if parent.rb is autoloaded, the stack will look like [[Object]]. If
|
82
|
+
# parent.rb then requires namespace/child.rb, the stack will look like
|
83
|
+
# [[Object], [Namespace]].
|
80
84
|
|
81
85
|
def initialize
|
82
86
|
@watching = []
|
@@ -91,7 +95,8 @@ module ActiveSupport #:nodoc:
|
|
91
95
|
!@watching.empty?
|
92
96
|
end
|
93
97
|
|
94
|
-
#
|
98
|
+
# Returns a list of new constants found since the last call to
|
99
|
+
# <tt>watch_namespaces</tt>.
|
95
100
|
def new_constants
|
96
101
|
constants = []
|
97
102
|
|
@@ -105,7 +110,7 @@ module ActiveSupport #:nodoc:
|
|
105
110
|
next unless mod.is_a?(Module)
|
106
111
|
|
107
112
|
# Get a list of the constants that were added
|
108
|
-
new_constants = mod.
|
113
|
+
new_constants = mod.local_constants - original_constants
|
109
114
|
|
110
115
|
# self[namespace] returns an Array of the constants that are being evaluated
|
111
116
|
# for that namespace. For instance, if parent.rb requires child.rb, the first
|
@@ -127,18 +132,17 @@ module ActiveSupport #:nodoc:
|
|
127
132
|
pop_modules(@watching.pop)
|
128
133
|
end
|
129
134
|
|
130
|
-
# Add a set of modules to the watch stack, remembering the initial
|
135
|
+
# Add a set of modules to the watch stack, remembering the initial
|
136
|
+
# constants.
|
131
137
|
def watch_namespaces(namespaces)
|
132
|
-
watching
|
133
|
-
namespaces.map do |namespace|
|
138
|
+
@watching << namespaces.map do |namespace|
|
134
139
|
module_name = Dependencies.to_constant_name(namespace)
|
135
140
|
original_constants = Dependencies.qualified_const_defined?(module_name) ?
|
136
|
-
Inflector.constantize(module_name).
|
141
|
+
Inflector.constantize(module_name).local_constants : []
|
137
142
|
|
138
|
-
watching << module_name
|
139
143
|
@stack[module_name] << original_constants
|
144
|
+
module_name
|
140
145
|
end
|
141
|
-
@watching << watching
|
142
146
|
end
|
143
147
|
|
144
148
|
private
|
@@ -151,7 +155,7 @@ module ActiveSupport #:nodoc:
|
|
151
155
|
mattr_accessor :constant_watch_stack
|
152
156
|
self.constant_watch_stack = WatchStack.new
|
153
157
|
|
154
|
-
# Module includes this module
|
158
|
+
# Module includes this module.
|
155
159
|
module ModuleConstMissing #:nodoc:
|
156
160
|
def self.append_features(base)
|
157
161
|
base.class_eval do
|
@@ -170,36 +174,13 @@ module ActiveSupport #:nodoc:
|
|
170
174
|
end
|
171
175
|
end
|
172
176
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
# even though it might not be, such as in the case of
|
181
|
-
# class Foo::Bar; Baz; end
|
182
|
-
nesting = []
|
183
|
-
klass_name.to_s.scan(/::|$/) { nesting.unshift $` }
|
184
|
-
end
|
185
|
-
|
186
|
-
# If there are multiple levels of nesting to search under, the top
|
187
|
-
# level is the one we want to report as the lookup fail.
|
188
|
-
error = nil
|
189
|
-
|
190
|
-
nesting.each do |namespace|
|
191
|
-
begin
|
192
|
-
return Dependencies.load_missing_constant Inflector.constantize(namespace), const_name
|
193
|
-
rescue NoMethodError then raise
|
194
|
-
rescue NameError => e
|
195
|
-
error ||= e
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
# Raise the first error for this set. If this const_missing came from an
|
200
|
-
# earlier const_missing, this will result in the real error bubbling
|
201
|
-
# all the way up
|
202
|
-
raise error
|
177
|
+
def const_missing(const_name)
|
178
|
+
# The interpreter does not pass nesting information, and in the
|
179
|
+
# case of anonymous modules we cannot even make the trade-off of
|
180
|
+
# assuming their name reflects the nesting. Resort to Object as
|
181
|
+
# the only meaningful guess we can make.
|
182
|
+
from_mod = anonymous? ? ::Object : self
|
183
|
+
Dependencies.load_missing_constant(from_mod, const_name)
|
203
184
|
end
|
204
185
|
|
205
186
|
def unloadable(const_desc = self)
|
@@ -207,7 +188,7 @@ module ActiveSupport #:nodoc:
|
|
207
188
|
end
|
208
189
|
end
|
209
190
|
|
210
|
-
# Object includes this module
|
191
|
+
# Object includes this module.
|
211
192
|
module Loadable #:nodoc:
|
212
193
|
def self.exclude_from(base)
|
213
194
|
base.class_eval { define_method(:load, Kernel.instance_method(:load)) }
|
@@ -222,11 +203,7 @@ module ActiveSupport #:nodoc:
|
|
222
203
|
raise ArgumentError, "the file name must be a String -- you passed #{file_name.inspect}"
|
223
204
|
end
|
224
205
|
|
225
|
-
Dependencies.depend_on(file_name,
|
226
|
-
end
|
227
|
-
|
228
|
-
def require_association(file_name)
|
229
|
-
Dependencies.associate_with(file_name)
|
206
|
+
Dependencies.depend_on(file_name, message)
|
230
207
|
end
|
231
208
|
|
232
209
|
def load_dependency(file)
|
@@ -252,25 +229,25 @@ module ActiveSupport #:nodoc:
|
|
252
229
|
result
|
253
230
|
end
|
254
231
|
|
255
|
-
# Mark the given constant as unloadable. Unloadable constants are removed
|
256
|
-
# time dependencies are cleared.
|
232
|
+
# Mark the given constant as unloadable. Unloadable constants are removed
|
233
|
+
# each time dependencies are cleared.
|
257
234
|
#
|
258
235
|
# Note that marking a constant for unloading need only be done once. Setup
|
259
236
|
# or init scripts may list each unloadable constant that may need unloading;
|
260
|
-
# each constant will be removed for every subsequent clear, as opposed to
|
261
|
-
# the first clear.
|
237
|
+
# each constant will be removed for every subsequent clear, as opposed to
|
238
|
+
# for the first clear.
|
262
239
|
#
|
263
240
|
# The provided constant descriptor may be a (non-anonymous) module or class,
|
264
241
|
# or a qualified constant name as a string or symbol.
|
265
242
|
#
|
266
|
-
# Returns true if the constant was not previously marked for unloading,
|
267
|
-
# otherwise.
|
243
|
+
# Returns +true+ if the constant was not previously marked for unloading,
|
244
|
+
# +false+ otherwise.
|
268
245
|
def unloadable(const_desc)
|
269
246
|
Dependencies.mark_for_unload const_desc
|
270
247
|
end
|
271
248
|
end
|
272
249
|
|
273
|
-
# Exception file-blaming
|
250
|
+
# Exception file-blaming.
|
274
251
|
module Blamable #:nodoc:
|
275
252
|
def blame_file!(file)
|
276
253
|
(@blamed_files ||= []).unshift file
|
@@ -295,33 +272,26 @@ module ActiveSupport #:nodoc:
|
|
295
272
|
Object.class_eval { include Loadable }
|
296
273
|
Module.class_eval { include ModuleConstMissing }
|
297
274
|
Exception.class_eval { include Blamable }
|
298
|
-
true
|
299
275
|
end
|
300
276
|
|
301
277
|
def unhook!
|
302
278
|
ModuleConstMissing.exclude_from(Module)
|
303
279
|
Loadable.exclude_from(Object)
|
304
|
-
true
|
305
280
|
end
|
306
281
|
|
307
282
|
def load?
|
308
283
|
mechanism == :load
|
309
284
|
end
|
310
285
|
|
311
|
-
def depend_on(file_name,
|
286
|
+
def depend_on(file_name, message = "No such file to load -- %s.rb")
|
312
287
|
path = search_for_file(file_name)
|
313
288
|
require_or_load(path || file_name)
|
314
289
|
rescue LoadError => load_error
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
end
|
319
|
-
raise
|
290
|
+
if file_name = load_error.message[/ -- (.*?)(\.rb)?$/, 1]
|
291
|
+
load_error.message.replace(message % file_name)
|
292
|
+
load_error.copy_blame!(load_error)
|
320
293
|
end
|
321
|
-
|
322
|
-
|
323
|
-
def associate_with(file_name)
|
324
|
-
depend_on(file_name, true)
|
294
|
+
raise
|
325
295
|
end
|
326
296
|
|
327
297
|
def clear
|
@@ -332,7 +302,7 @@ module ActiveSupport #:nodoc:
|
|
332
302
|
|
333
303
|
def require_or_load(file_name, const_path = nil)
|
334
304
|
log_call file_name, const_path
|
335
|
-
file_name =
|
305
|
+
file_name = $` if file_name =~ /\.rb\z/
|
336
306
|
expanded = File.expand_path(file_name)
|
337
307
|
return if loaded.include?(expanded)
|
338
308
|
|
@@ -365,36 +335,19 @@ module ActiveSupport #:nodoc:
|
|
365
335
|
|
366
336
|
# Record history *after* loading so first load gets warnings.
|
367
337
|
history << expanded
|
368
|
-
|
338
|
+
result
|
369
339
|
end
|
370
340
|
|
371
341
|
# Is the provided constant path defined?
|
372
|
-
|
373
|
-
|
374
|
-
Object.qualified_const_defined?(path.sub(/^::/, ''))
|
375
|
-
end
|
376
|
-
else
|
377
|
-
def qualified_const_defined?(path)
|
378
|
-
Object.qualified_const_defined?(path.sub(/^::/, ''), false)
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
if Module.method(:const_defined?).arity == 1
|
383
|
-
# Does this module define this constant?
|
384
|
-
# Wrapper to accommodate changing Module#const_defined? in Ruby 1.9
|
385
|
-
def local_const_defined?(mod, const)
|
386
|
-
mod.const_defined?(const)
|
387
|
-
end
|
388
|
-
else
|
389
|
-
def local_const_defined?(mod, const) #:nodoc:
|
390
|
-
mod.const_defined?(const, false)
|
391
|
-
end
|
342
|
+
def qualified_const_defined?(path)
|
343
|
+
Object.qualified_const_defined?(path.sub(/^::/, ''), false)
|
392
344
|
end
|
393
345
|
|
394
|
-
# Given +path+, a filesystem path to a ruby file, return an array of
|
395
|
-
# paths which would cause Dependencies to attempt to load this
|
346
|
+
# Given +path+, a filesystem path to a ruby file, return an array of
|
347
|
+
# constant paths which would cause Dependencies to attempt to load this
|
348
|
+
# file.
|
396
349
|
def loadable_constants_for_path(path, bases = autoload_paths)
|
397
|
-
path =
|
350
|
+
path = $` if path =~ /\.rb\z/
|
398
351
|
expanded_path = File.expand_path(path)
|
399
352
|
paths = []
|
400
353
|
|
@@ -425,7 +378,8 @@ module ActiveSupport #:nodoc:
|
|
425
378
|
end
|
426
379
|
|
427
380
|
# Does the provided path_suffix correspond to an autoloadable module?
|
428
|
-
# Instead of returning a boolean, the autoload base for this module is
|
381
|
+
# Instead of returning a boolean, the autoload base for this module is
|
382
|
+
# returned.
|
429
383
|
def autoloadable_module?(path_suffix)
|
430
384
|
autoload_paths.each do |load_path|
|
431
385
|
return load_path if File.directory? File.join(load_path, path_suffix)
|
@@ -439,16 +393,16 @@ module ActiveSupport #:nodoc:
|
|
439
393
|
end
|
440
394
|
|
441
395
|
# Attempt to autoload the provided module name by searching for a directory
|
442
|
-
# matching the expected path suffix. If found, the module is created and
|
443
|
-
# to +into+'s constants with the name +const_name+. Provided that
|
444
|
-
# was loaded from a reloadable base path, it is added to the
|
445
|
-
# that are to be unloaded.
|
396
|
+
# matching the expected path suffix. If found, the module is created and
|
397
|
+
# assigned to +into+'s constants with the name +const_name+. Provided that
|
398
|
+
# the directory was loaded from a reloadable base path, it is added to the
|
399
|
+
# set of constants that are to be unloaded.
|
446
400
|
def autoload_module!(into, const_name, qualified_name, path_suffix)
|
447
401
|
return nil unless base_path = autoloadable_module?(path_suffix)
|
448
402
|
mod = Module.new
|
449
403
|
into.const_set const_name, mod
|
450
404
|
autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
|
451
|
-
|
405
|
+
mod
|
452
406
|
end
|
453
407
|
|
454
408
|
# Load the file at the provided path. +const_paths+ is a set of qualified
|
@@ -456,13 +410,13 @@ module ActiveSupport #:nodoc:
|
|
456
410
|
# addition of these constants. Each that is defined will be marked as
|
457
411
|
# autoloaded, and will be removed when Dependencies.clear is next called.
|
458
412
|
#
|
459
|
-
# If the second parameter is left off, then Dependencies will construct a
|
460
|
-
# of names that the file at +path+ may define. See
|
413
|
+
# If the second parameter is left off, then Dependencies will construct a
|
414
|
+
# set of names that the file at +path+ may define. See
|
461
415
|
# +loadable_constants_for_path+ for more details.
|
462
416
|
def load_file(path, const_paths = loadable_constants_for_path(path))
|
463
417
|
log_call path, const_paths
|
464
418
|
const_paths = [const_paths].compact unless const_paths.is_a? Array
|
465
|
-
parent_paths = const_paths.collect { |const_path|
|
419
|
+
parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || :Object }
|
466
420
|
|
467
421
|
result = nil
|
468
422
|
newly_defined_paths = new_constants_in(*parent_paths) do
|
@@ -472,18 +426,18 @@ module ActiveSupport #:nodoc:
|
|
472
426
|
autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
|
473
427
|
autoloaded_constants.uniq!
|
474
428
|
log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty?
|
475
|
-
|
429
|
+
result
|
476
430
|
end
|
477
431
|
|
478
|
-
#
|
432
|
+
# Returns the constant path for the provided parent and constant name.
|
479
433
|
def qualified_name_for(mod, name)
|
480
434
|
mod_name = to_constant_name mod
|
481
435
|
mod_name == "Object" ? name.to_s : "#{mod_name}::#{name}"
|
482
436
|
end
|
483
437
|
|
484
438
|
# Load the constant named +const_name+ which is missing from +from_mod+. If
|
485
|
-
# it is not possible to load the constant into from_mod, try its parent
|
486
|
-
# using const_missing
|
439
|
+
# it is not possible to load the constant into from_mod, try its parent
|
440
|
+
# module using +const_missing+.
|
487
441
|
def load_missing_constant(from_mod, const_name)
|
488
442
|
log_call from_mod, const_name
|
489
443
|
|
@@ -491,26 +445,52 @@ module ActiveSupport #:nodoc:
|
|
491
445
|
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
|
492
446
|
end
|
493
447
|
|
494
|
-
raise NameError, "#{from_mod} is not missing constant #{const_name}!" if
|
448
|
+
raise NameError, "#{from_mod} is not missing constant #{const_name}!" if from_mod.const_defined?(const_name, false)
|
495
449
|
|
496
450
|
qualified_name = qualified_name_for from_mod, const_name
|
497
451
|
path_suffix = qualified_name.underscore
|
498
452
|
|
499
453
|
file_path = search_for_file(path_suffix)
|
500
454
|
|
501
|
-
if file_path
|
502
|
-
|
503
|
-
|
504
|
-
|
455
|
+
if file_path
|
456
|
+
expanded = File.expand_path(file_path)
|
457
|
+
expanded.sub!(/\.rb\z/, '')
|
458
|
+
|
459
|
+
if loaded.include?(expanded)
|
460
|
+
raise "Circular dependency detected while autoloading constant #{qualified_name}"
|
461
|
+
else
|
462
|
+
require_or_load(expanded)
|
463
|
+
raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
|
464
|
+
return from_mod.const_get(const_name)
|
465
|
+
end
|
505
466
|
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
|
506
467
|
return mod
|
507
468
|
elsif (parent = from_mod.parent) && parent != from_mod &&
|
508
|
-
! from_mod.parents.any? { |p|
|
469
|
+
! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
|
509
470
|
# If our parents do not have a constant named +const_name+ then we are free
|
510
471
|
# to attempt to load upwards. If they do have such a constant, then this
|
511
472
|
# const_missing must be due to from_mod::const_name, which should not
|
512
473
|
# return constants from from_mod's parents.
|
513
474
|
begin
|
475
|
+
# Since Ruby does not pass the nesting at the point the unknown
|
476
|
+
# constant triggered the callback we cannot fully emulate constant
|
477
|
+
# name lookup and need to make a trade-off: we are going to assume
|
478
|
+
# that the nesting in the body of Foo::Bar is [Foo::Bar, Foo] even
|
479
|
+
# though it might not be. Counterexamples are
|
480
|
+
#
|
481
|
+
# class Foo::Bar
|
482
|
+
# Module.nesting # => [Foo::Bar]
|
483
|
+
# end
|
484
|
+
#
|
485
|
+
# or
|
486
|
+
#
|
487
|
+
# module M::N
|
488
|
+
# module S::T
|
489
|
+
# Module.nesting # => [S::T, M::N]
|
490
|
+
# end
|
491
|
+
# end
|
492
|
+
#
|
493
|
+
# for example.
|
514
494
|
return parent.const_missing(const_name)
|
515
495
|
rescue NameError => e
|
516
496
|
raise unless e.missing_name? qualified_name_for(parent, const_name)
|
@@ -519,7 +499,7 @@ module ActiveSupport #:nodoc:
|
|
519
499
|
|
520
500
|
raise NameError,
|
521
501
|
"uninitialized constant #{qualified_name}",
|
522
|
-
caller.reject {|l| l.starts_with? __FILE__ }
|
502
|
+
caller.reject { |l| l.starts_with? __FILE__ }
|
523
503
|
end
|
524
504
|
|
525
505
|
# Remove the constants that have been autoloaded, and those that have been
|
@@ -538,7 +518,7 @@ module ActiveSupport #:nodoc:
|
|
538
518
|
|
539
519
|
class ClassCache
|
540
520
|
def initialize
|
541
|
-
@store =
|
521
|
+
@store = ThreadSafe::Cache.new
|
542
522
|
end
|
543
523
|
|
544
524
|
def empty?
|
@@ -557,10 +537,7 @@ module ActiveSupport #:nodoc:
|
|
557
537
|
|
558
538
|
def safe_get(key)
|
559
539
|
key = key.name if key.respond_to?(:name)
|
560
|
-
@store[key]
|
561
|
-
klass = Inflector.safe_constantize(key)
|
562
|
-
@store[key] = klass
|
563
|
-
end
|
540
|
+
@store[key] ||= Inflector.safe_constantize(key)
|
564
541
|
end
|
565
542
|
|
566
543
|
def store(klass)
|
@@ -589,14 +566,13 @@ module ActiveSupport #:nodoc:
|
|
589
566
|
end
|
590
567
|
|
591
568
|
# Get the reference for class named +name+ if one exists.
|
592
|
-
# Otherwise returns nil
|
569
|
+
# Otherwise returns +nil+.
|
593
570
|
def safe_constantize(name)
|
594
571
|
Reference.safe_get(name)
|
595
572
|
end
|
596
573
|
|
597
574
|
# Determine if the given constant has been automatically loaded.
|
598
575
|
def autoloaded?(desc)
|
599
|
-
# No name => anonymous module.
|
600
576
|
return false if desc.is_a?(Module) && desc.anonymous?
|
601
577
|
name = to_constant_name desc
|
602
578
|
return false unless qualified_const_defined? name
|
@@ -614,10 +590,10 @@ module ActiveSupport #:nodoc:
|
|
614
590
|
def mark_for_unload(const_desc)
|
615
591
|
name = to_constant_name const_desc
|
616
592
|
if explicitly_unloadable_constants.include? name
|
617
|
-
|
593
|
+
false
|
618
594
|
else
|
619
595
|
explicitly_unloadable_constants << name
|
620
|
-
|
596
|
+
true
|
621
597
|
end
|
622
598
|
end
|
623
599
|
|
@@ -645,10 +621,10 @@ module ActiveSupport #:nodoc:
|
|
645
621
|
return new_constants unless aborting
|
646
622
|
|
647
623
|
log "Error during loading, removing partially loaded constants "
|
648
|
-
new_constants.each {|c| remove_constant(c) }.clear
|
624
|
+
new_constants.each { |c| remove_constant(c) }.clear
|
649
625
|
end
|
650
626
|
|
651
|
-
|
627
|
+
[]
|
652
628
|
end
|
653
629
|
|
654
630
|
# Convert the provided const desc to a qualified constant name (as a string).
|
@@ -665,19 +641,62 @@ module ActiveSupport #:nodoc:
|
|
665
641
|
end
|
666
642
|
|
667
643
|
def remove_constant(const) #:nodoc:
|
668
|
-
|
644
|
+
# Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo.
|
645
|
+
normalized = const.to_s.sub(/\A::/, '')
|
646
|
+
normalized.sub!(/\A(Object::)+/, '')
|
669
647
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
648
|
+
constants = normalized.split('::')
|
649
|
+
to_remove = constants.pop
|
650
|
+
|
651
|
+
if constants.empty?
|
652
|
+
parent = Object
|
653
|
+
else
|
654
|
+
# This method is robust to non-reachable constants.
|
655
|
+
#
|
656
|
+
# Non-reachable constants may be passed if some of the parents were
|
657
|
+
# autoloaded and already removed. It is easier to do a sanity check
|
658
|
+
# here than require the caller to be clever. We check the parent
|
659
|
+
# rather than the very const argument because we do not want to
|
660
|
+
# trigger Kernel#autoloads, see the comment below.
|
661
|
+
parent_name = constants.join('::')
|
662
|
+
return unless qualified_const_defined?(parent_name)
|
663
|
+
parent = constantize(parent_name)
|
664
|
+
end
|
674
665
|
|
675
666
|
log "removing constant #{const}"
|
676
|
-
constantized = constantize(const)
|
677
|
-
constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
|
678
|
-
parent.instance_eval { remove_const to_remove }
|
679
667
|
|
680
|
-
|
668
|
+
# In an autoloaded user.rb like this
|
669
|
+
#
|
670
|
+
# autoload :Foo, 'foo'
|
671
|
+
#
|
672
|
+
# class User < ActiveRecord::Base
|
673
|
+
# end
|
674
|
+
#
|
675
|
+
# we correctly register "Foo" as being autoloaded. But if the app does
|
676
|
+
# not use the "Foo" constant we need to be careful not to trigger
|
677
|
+
# loading "foo.rb" ourselves. While #const_defined? and #const_get? do
|
678
|
+
# require the file, #autoload? and #remove_const don't.
|
679
|
+
#
|
680
|
+
# We are going to remove the constant nonetheless ---which exists as
|
681
|
+
# far as Ruby is concerned--- because if the user removes the macro
|
682
|
+
# call from a class or module that were not autoloaded, as in the
|
683
|
+
# example above with Object, accessing to that constant must err.
|
684
|
+
unless parent.autoload?(to_remove)
|
685
|
+
begin
|
686
|
+
constantized = parent.const_get(to_remove, false)
|
687
|
+
rescue NameError
|
688
|
+
log "the constant #{const} is not reachable anymore, skipping"
|
689
|
+
return
|
690
|
+
else
|
691
|
+
constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
begin
|
696
|
+
parent.instance_eval { remove_const to_remove }
|
697
|
+
rescue NameError
|
698
|
+
log "the constant #{const} is not reachable anymore, skipping"
|
699
|
+
end
|
681
700
|
end
|
682
701
|
|
683
702
|
protected
|