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
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -14,12 +14,14 @@ The latest version of Active Support can be installed with RubyGems:
|
|
14
14
|
|
15
15
|
Source code can be downloaded as part of the Rails project on GitHub
|
16
16
|
|
17
|
-
* https://github.com/rails/rails/tree/
|
17
|
+
* https://github.com/rails/rails/tree/master/activesupport
|
18
18
|
|
19
19
|
|
20
20
|
== License
|
21
21
|
|
22
|
-
Active Support is released under the MIT license
|
22
|
+
Active Support is released under the MIT license:
|
23
|
+
|
24
|
+
* http://www.opensource.org/licenses/MIT
|
23
25
|
|
24
26
|
|
25
27
|
== Support
|
data/lib/active_support.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2013 David Heinemeier Hansson
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -22,59 +22,46 @@
|
|
22
22
|
#++
|
23
23
|
|
24
24
|
require 'securerandom'
|
25
|
-
|
26
|
-
module ActiveSupport
|
27
|
-
class << self
|
28
|
-
attr_accessor :load_all_hooks
|
29
|
-
def on_load_all(&hook) load_all_hooks << hook end
|
30
|
-
def load_all!; load_all_hooks.each { |hook| hook.call } end
|
31
|
-
end
|
32
|
-
self.load_all_hooks = []
|
33
|
-
|
34
|
-
on_load_all do
|
35
|
-
[Dependencies, Deprecation, Gzip, MessageVerifier, Multibyte]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
25
|
require "active_support/dependencies/autoload"
|
40
26
|
require "active_support/version"
|
27
|
+
require "active_support/logger"
|
28
|
+
require "active_support/lazy_load_hooks"
|
41
29
|
|
42
30
|
module ActiveSupport
|
43
31
|
extend ActiveSupport::Autoload
|
44
32
|
|
33
|
+
autoload :Concern
|
34
|
+
autoload :Dependencies
|
45
35
|
autoload :DescendantsTracker
|
46
36
|
autoload :FileUpdateChecker
|
47
37
|
autoload :LogSubscriber
|
48
38
|
autoload :Notifications
|
49
39
|
|
50
|
-
# TODO: Narrow this list down
|
51
40
|
eager_autoload do
|
52
41
|
autoload :BacktraceCleaner
|
53
|
-
autoload :Base64
|
54
42
|
autoload :BasicObject
|
43
|
+
autoload :ProxyObject
|
55
44
|
autoload :Benchmarkable
|
56
|
-
autoload :BufferedLogger
|
57
45
|
autoload :Cache
|
58
46
|
autoload :Callbacks
|
59
|
-
autoload :Concern
|
60
47
|
autoload :Configurable
|
61
48
|
autoload :Deprecation
|
62
49
|
autoload :Gzip
|
63
50
|
autoload :Inflector
|
64
51
|
autoload :JSON
|
65
|
-
autoload :
|
52
|
+
autoload :KeyGenerator
|
66
53
|
autoload :MessageEncryptor
|
67
54
|
autoload :MessageVerifier
|
68
55
|
autoload :Multibyte
|
69
56
|
autoload :OptionMerger
|
70
57
|
autoload :OrderedHash
|
71
58
|
autoload :OrderedOptions
|
72
|
-
autoload :Rescuable
|
73
59
|
autoload :StringInquirer
|
74
60
|
autoload :TaggedLogging
|
75
61
|
autoload :XmlMini
|
76
62
|
end
|
77
63
|
|
64
|
+
autoload :Rescuable
|
78
65
|
autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
|
79
66
|
autoload :TestCase
|
80
67
|
end
|
@@ -1,24 +1,29 @@
|
|
1
1
|
module ActiveSupport
|
2
|
-
# Backtraces often include many lines that are not relevant for the context
|
3
|
-
#
|
4
|
-
#
|
2
|
+
# Backtraces often include many lines that are not relevant for the context
|
3
|
+
# under review. This makes it hard to find the signal amongst the backtrace
|
4
|
+
# noise, and adds debugging time. With a BacktraceCleaner, filters and
|
5
|
+
# silencers are used to remove the noisy lines, so that only the most relevant
|
6
|
+
# lines remain.
|
5
7
|
#
|
6
|
-
# Filters are used to modify lines of data, while silencers are used to remove
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
8
|
+
# Filters are used to modify lines of data, while silencers are used to remove
|
9
|
+
# lines entirely. The typical filter use case is to remove lengthy path
|
10
|
+
# information from the start of each line, and view file paths relevant to the
|
11
|
+
# app directory instead of the file system root. The typical silencer use case
|
12
|
+
# is to exclude the output of a noisy library from the backtrace, so that you
|
13
|
+
# can focus on the rest.
|
12
14
|
#
|
13
15
|
# bc = BacktraceCleaner.new
|
14
16
|
# bc.add_filter { |line| line.gsub(Rails.root, '') }
|
15
17
|
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
|
16
18
|
# bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems
|
17
19
|
#
|
18
|
-
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# backtrace
|
20
|
+
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
21
|
+
# and show as much data as possible, you can always call
|
22
|
+
# <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the
|
23
|
+
# backtrace to a pristine state. If you need to reconfigure an existing
|
24
|
+
# BacktraceCleaner so that it does not filter or modify the paths of any lines
|
25
|
+
# of the backtrace, you can call BacktraceCleaner#remove_filters! These two
|
26
|
+
# methods will give you a completely untouched backtrace.
|
22
27
|
#
|
23
28
|
# Inspired by the Quiet Backtrace gem by Thoughtbot.
|
24
29
|
class BacktraceCleaner
|
@@ -26,9 +31,10 @@ module ActiveSupport
|
|
26
31
|
@filters, @silencers = [], []
|
27
32
|
end
|
28
33
|
|
29
|
-
# Returns the backtrace after all filters and silencers have been run
|
34
|
+
# Returns the backtrace after all filters and silencers have been run
|
35
|
+
# against it. Filters run first, then silencers.
|
30
36
|
def clean(backtrace, kind = :silent)
|
31
|
-
filtered =
|
37
|
+
filtered = filter_backtrace(backtrace)
|
32
38
|
|
33
39
|
case kind
|
34
40
|
when :silent
|
@@ -39,10 +45,10 @@ module ActiveSupport
|
|
39
45
|
filtered
|
40
46
|
end
|
41
47
|
end
|
48
|
+
alias :filter :clean
|
42
49
|
|
43
|
-
# Adds a filter from the block provided. Each line in the backtrace will be
|
44
|
-
#
|
45
|
-
# Example:
|
50
|
+
# Adds a filter from the block provided. Each line in the backtrace will be
|
51
|
+
# mapped against this filter.
|
46
52
|
#
|
47
53
|
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
|
48
54
|
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
|
@@ -50,10 +56,8 @@ module ActiveSupport
|
|
50
56
|
@filters << block
|
51
57
|
end
|
52
58
|
|
53
|
-
# Adds a silencer from the block provided. If the silencer returns true
|
54
|
-
# the clean backtrace.
|
55
|
-
#
|
56
|
-
# Example:
|
59
|
+
# Adds a silencer from the block provided. If the silencer returns +true+
|
60
|
+
# for a given line, it will be excluded from the clean backtrace.
|
57
61
|
#
|
58
62
|
# # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
|
59
63
|
# backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
|
@@ -61,18 +65,22 @@ module ActiveSupport
|
|
61
65
|
@silencers << block
|
62
66
|
end
|
63
67
|
|
64
|
-
# Will remove all silencers, but leave in the filters. This is useful if
|
65
|
-
# you suspect a bug in one of
|
68
|
+
# Will remove all silencers, but leave in the filters. This is useful if
|
69
|
+
# your context of debugging suddenly expands as you suspect a bug in one of
|
70
|
+
# the libraries you use.
|
66
71
|
def remove_silencers!
|
67
72
|
@silencers = []
|
68
73
|
end
|
69
74
|
|
75
|
+
# Removes all filters, but leaves in silencers. Useful if you suddenly
|
76
|
+
# need to see entire filepaths in the backtrace that you had already
|
77
|
+
# filtered out.
|
70
78
|
def remove_filters!
|
71
79
|
@filters = []
|
72
80
|
end
|
73
81
|
|
74
82
|
private
|
75
|
-
def
|
83
|
+
def filter_backtrace(backtrace)
|
76
84
|
@filters.each do |f|
|
77
85
|
backtrace = backtrace.map { |line| f.call(line) }
|
78
86
|
end
|
@@ -1,21 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# A class with no predefined methods that behaves similarly to Builder's
|
4
|
-
# BlankSlate. Used for proxy classes.
|
5
|
-
class BasicObject < ::BasicObject
|
6
|
-
undef_method :==
|
7
|
-
undef_method :equal?
|
1
|
+
require 'active_support/deprecation'
|
2
|
+
require 'active_support/proxy_object'
|
8
3
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
class BasicObject #:nodoc:
|
16
|
-
instance_methods.each do |m|
|
17
|
-
undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
|
18
|
-
end
|
4
|
+
module ActiveSupport
|
5
|
+
class BasicObject < ProxyObject # :nodoc:
|
6
|
+
def self.inherited(*)
|
7
|
+
::ActiveSupport::Deprecation.warn 'ActiveSupport::BasicObject is deprecated! Use ActiveSupport::ProxyObject instead.'
|
8
|
+
super
|
19
9
|
end
|
20
10
|
end
|
21
11
|
end
|
@@ -3,30 +3,33 @@ require 'active_support/core_ext/hash/keys'
|
|
3
3
|
|
4
4
|
module ActiveSupport
|
5
5
|
module Benchmarkable
|
6
|
-
# Allows you to measure the execution time of a block in a template and
|
7
|
-
# the log. Wrap this block around expensive operations
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# Allows you to measure the execution time of a block in a template and
|
7
|
+
# records the result to the log. Wrap this block around expensive operations
|
8
|
+
# or possible bottlenecks to get a time reading for the operation. For
|
9
|
+
# example, let's say you thought your file processing method was taking too
|
10
|
+
# long; you could wrap it in a benchmark block.
|
10
11
|
#
|
11
|
-
# <% benchmark
|
12
|
+
# <% benchmark 'Process data files' do %>
|
12
13
|
# <%= expensive_files_operation %>
|
13
14
|
# <% end %>
|
14
15
|
#
|
15
|
-
# That would add something like "Process data files (345.2ms)" to the log,
|
16
|
-
# use to compare timings when optimizing your code.
|
16
|
+
# That would add something like "Process data files (345.2ms)" to the log,
|
17
|
+
# which you can then use to compare timings when optimizing your code.
|
17
18
|
#
|
18
|
-
# You may give an optional logger level (
|
19
|
-
#
|
19
|
+
# You may give an optional logger level (<tt>:debug</tt>, <tt>:info</tt>,
|
20
|
+
# <tt>:warn</tt>, <tt>:error</tt>) as the <tt>:level</tt> option. The
|
21
|
+
# default logger level value is <tt>:info</tt>.
|
20
22
|
#
|
21
|
-
# <% benchmark
|
23
|
+
# <% benchmark 'Low-level files', level: :debug do %>
|
22
24
|
# <%= lowlevel_files_operation %>
|
23
25
|
# <% end %>
|
24
26
|
#
|
25
|
-
# Finally, you can pass true as the third argument to silence all log
|
26
|
-
# timing information) from inside the block. This
|
27
|
-
# just a single statement that
|
27
|
+
# Finally, you can pass true as the third argument to silence all log
|
28
|
+
# activity (other than the timing information) from inside the block. This
|
29
|
+
# is great for boiling down a noisy block to just a single statement that
|
30
|
+
# produces one log line:
|
28
31
|
#
|
29
|
-
# <% benchmark
|
32
|
+
# <% benchmark 'Process data files', level: :info, silence: true do %>
|
30
33
|
# <%= expensive_and_chatty_files_operation %>
|
31
34
|
# <% end %>
|
32
35
|
def benchmark(message = "Benchmarking", options = {})
|
@@ -44,8 +47,9 @@ module ActiveSupport
|
|
44
47
|
end
|
45
48
|
|
46
49
|
# Silence the logger during the execution of the block.
|
47
|
-
#
|
48
50
|
def silence
|
51
|
+
message = "ActiveSupport::Benchmarkable#silence is deprecated. It will be removed from Rails 4.1."
|
52
|
+
ActiveSupport::Deprecation.warn message
|
49
53
|
old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
|
50
54
|
yield
|
51
55
|
ensure
|
@@ -1,125 +1,21 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'logger'
|
3
|
-
require 'active_support/core_ext/logger'
|
4
|
-
require 'active_support/core_ext/class/attribute_accessors'
|
5
1
|
require 'active_support/deprecation'
|
6
|
-
require '
|
2
|
+
require 'active_support/logger'
|
7
3
|
|
8
4
|
module ActiveSupport
|
9
|
-
|
10
|
-
class BufferedLogger
|
11
|
-
module Severity
|
12
|
-
DEBUG = 0
|
13
|
-
INFO = 1
|
14
|
-
WARN = 2
|
15
|
-
ERROR = 3
|
16
|
-
FATAL = 4
|
17
|
-
UNKNOWN = 5
|
18
|
-
end
|
19
|
-
include Severity
|
20
|
-
|
21
|
-
MAX_BUFFER_SIZE = 1000
|
22
|
-
|
23
|
-
##
|
24
|
-
# :singleton-method:
|
25
|
-
# Set to false to disable the silencer
|
26
|
-
cattr_accessor :silencer
|
27
|
-
self.silencer = true
|
28
|
-
|
29
|
-
# Silences the logger for the duration of the block.
|
30
|
-
def silence(temporary_level = ERROR)
|
31
|
-
if silencer
|
32
|
-
begin
|
33
|
-
logger = self.class.new @log_dest.dup, temporary_level
|
34
|
-
yield logger
|
35
|
-
ensure
|
36
|
-
logger.close
|
37
|
-
end
|
38
|
-
else
|
39
|
-
yield self
|
40
|
-
end
|
41
|
-
end
|
42
|
-
deprecate :silence
|
43
|
-
|
44
|
-
attr_reader :auto_flushing
|
45
|
-
deprecate :auto_flushing
|
46
|
-
|
47
|
-
def initialize(log, level = DEBUG)
|
48
|
-
@log_dest = log
|
49
|
-
|
50
|
-
unless log.respond_to?(:write)
|
51
|
-
unless File.exist?(File.dirname(log))
|
52
|
-
ActiveSupport::Deprecation.warn(<<-eowarn)
|
53
|
-
Automatic directory creation for '#{log}' is deprecated. Please make sure the directory for your log file exists before creating the logger.
|
54
|
-
eowarn
|
55
|
-
FileUtils.mkdir_p(File.dirname(log))
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
@log = open_logfile log
|
60
|
-
self.level = level
|
61
|
-
end
|
62
|
-
|
63
|
-
def open_log(log, mode)
|
64
|
-
open(log, mode).tap do |open_log|
|
65
|
-
open_log.set_encoding(Encoding::BINARY) if open_log.respond_to?(:set_encoding)
|
66
|
-
open_log.sync = true
|
67
|
-
end
|
68
|
-
end
|
69
|
-
deprecate :open_log
|
70
|
-
|
71
|
-
def level
|
72
|
-
@log.level
|
73
|
-
end
|
74
|
-
|
75
|
-
def level=(l)
|
76
|
-
@log.level = l
|
77
|
-
end
|
5
|
+
class BufferedLogger < Logger
|
78
6
|
|
79
|
-
def
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
# Dynamically add methods such as:
|
84
|
-
# def info
|
85
|
-
# def warn
|
86
|
-
# def debug
|
87
|
-
Severity.constants.each do |severity|
|
88
|
-
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
89
|
-
def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
|
90
|
-
add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
|
91
|
-
end # end
|
92
|
-
|
93
|
-
def #{severity.downcase}? # def debug?
|
94
|
-
#{severity} >= level # DEBUG >= level
|
95
|
-
end # end
|
96
|
-
EOT
|
97
|
-
end
|
98
|
-
|
99
|
-
# Set the auto-flush period. Set to true to flush after every log message,
|
100
|
-
# to an integer to flush every N messages, or to false, nil, or zero to
|
101
|
-
# never auto-flush. If you turn auto-flushing off, be sure to regularly
|
102
|
-
# flush the log yourself -- it will eat up memory until you do.
|
103
|
-
def auto_flushing=(period)
|
104
|
-
end
|
105
|
-
deprecate :auto_flushing=
|
106
|
-
|
107
|
-
def flush
|
108
|
-
end
|
109
|
-
deprecate :flush
|
110
|
-
|
111
|
-
def respond_to?(method, include_private = false)
|
112
|
-
return false if method.to_s == "flush"
|
7
|
+
def initialize(*args)
|
8
|
+
self.class._deprecation_warning
|
113
9
|
super
|
114
10
|
end
|
115
11
|
|
116
|
-
def
|
117
|
-
|
12
|
+
def self.inherited(*)
|
13
|
+
_deprecation_warning
|
14
|
+
super
|
118
15
|
end
|
119
16
|
|
120
|
-
|
121
|
-
|
122
|
-
Logger.new log
|
17
|
+
def self._deprecation_warning
|
18
|
+
::ActiveSupport::Deprecation.warn 'ActiveSupport::BufferedLogger is deprecated! Use ActiveSupport::Logger instead.'
|
123
19
|
end
|
124
20
|
end
|
125
21
|
end
|
data/lib/active_support/cache.rb
CHANGED
@@ -3,7 +3,6 @@ require 'zlib'
|
|
3
3
|
require 'active_support/core_ext/array/extract_options'
|
4
4
|
require 'active_support/core_ext/array/wrap'
|
5
5
|
require 'active_support/core_ext/benchmark'
|
6
|
-
require 'active_support/core_ext/exception'
|
7
6
|
require 'active_support/core_ext/class/attribute_accessors'
|
8
7
|
require 'active_support/core_ext/numeric/bytes'
|
9
8
|
require 'active_support/core_ext/numeric/time'
|
@@ -45,8 +44,8 @@ module ActiveSupport
|
|
45
44
|
# Any additional arguments will be passed to the corresponding cache store
|
46
45
|
# class's constructor:
|
47
46
|
#
|
48
|
-
# ActiveSupport::Cache.lookup_store(:file_store,
|
49
|
-
# # => same as: ActiveSupport::Cache::FileStore.new(
|
47
|
+
# ActiveSupport::Cache.lookup_store(:file_store, '/tmp/cache')
|
48
|
+
# # => same as: ActiveSupport::Cache::FileStore.new('/tmp/cache')
|
50
49
|
#
|
51
50
|
# If the first argument is not a Symbol, then it will simply be returned:
|
52
51
|
#
|
@@ -91,6 +90,7 @@ module ActiveSupport
|
|
91
90
|
case
|
92
91
|
when key.respond_to?(:cache_key) then key.cache_key
|
93
92
|
when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
|
93
|
+
when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
|
94
94
|
else key.to_param
|
95
95
|
end.to_s
|
96
96
|
end
|
@@ -109,9 +109,9 @@ module ActiveSupport
|
|
109
109
|
#
|
110
110
|
# cache = ActiveSupport::Cache::MemoryStore.new
|
111
111
|
#
|
112
|
-
# cache.read(
|
113
|
-
# cache.write(
|
114
|
-
# cache.read(
|
112
|
+
# cache.read('city') # => nil
|
113
|
+
# cache.write('city', "Duckburgh")
|
114
|
+
# cache.read('city') # => "Duckburgh"
|
115
115
|
#
|
116
116
|
# Keys are always translated into Strings and are case sensitive. When an
|
117
117
|
# object is specified as a key and has a +cache_key+ method defined, this
|
@@ -120,7 +120,7 @@ module ActiveSupport
|
|
120
120
|
# elements will be delimited by slashes, and the elements within a Hash
|
121
121
|
# will be sorted by key so they are consistent.
|
122
122
|
#
|
123
|
-
# cache.read(
|
123
|
+
# cache.read('city') == cache.read(:city) # => true
|
124
124
|
#
|
125
125
|
# Nil values can be cached.
|
126
126
|
#
|
@@ -130,14 +130,13 @@ module ActiveSupport
|
|
130
130
|
# is a Proc, it will be invoked when each key is evaluated so that you can
|
131
131
|
# use application logic to invalidate keys.
|
132
132
|
#
|
133
|
-
# cache.namespace =
|
133
|
+
# cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
|
134
134
|
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
|
135
135
|
#
|
136
|
-
#
|
137
136
|
# Caches can also store values in a compressed format to save space and
|
138
137
|
# reduce time spent sending data. Since there is overhead, values must be
|
139
138
|
# large enough to warrant compression. To turn on compression either pass
|
140
|
-
# <tt
|
139
|
+
# <tt>compress: true</tt> in the initializer or as an option to +fetch+
|
141
140
|
# or +write+. To specify the threshold at which to compress values, set the
|
142
141
|
# <tt>:compress_threshold</tt> option. The default threshold is 16K.
|
143
142
|
class Store
|
@@ -147,8 +146,9 @@ module ActiveSupport
|
|
147
146
|
attr_reader :silence, :options
|
148
147
|
alias :silence? :silence
|
149
148
|
|
150
|
-
# Create a new cache. The options will be passed to any write method calls
|
151
|
-
# for
|
149
|
+
# Create a new cache. The options will be passed to any write method calls
|
150
|
+
# except for <tt>:namespace</tt> which can be used to set the global
|
151
|
+
# namespace for the cache.
|
152
152
|
def initialize(options = nil)
|
153
153
|
@options = options ? options.dup : {}
|
154
154
|
end
|
@@ -167,7 +167,8 @@ module ActiveSupport
|
|
167
167
|
@silence = previous_silence
|
168
168
|
end
|
169
169
|
|
170
|
-
# Set to true if cache stores should be instrumented.
|
170
|
+
# Set to +true+ if cache stores should be instrumented.
|
171
|
+
# Default is +false+.
|
171
172
|
def self.instrument=(boolean)
|
172
173
|
Thread.current[:instrument_cache_store] = boolean
|
173
174
|
end
|
@@ -179,125 +180,109 @@ module ActiveSupport
|
|
179
180
|
# Fetches data from the cache, using the given key. If there is data in
|
180
181
|
# the cache with the given key, then that data is returned.
|
181
182
|
#
|
182
|
-
# If there is no such data in the cache (a cache miss), then nil will be
|
183
|
-
# returned. However, if a block has been passed, that block will be
|
184
|
-
# in the event of a cache miss. The return value of the
|
185
|
-
# written to the cache under the given cache key, and that
|
186
|
-
# will be returned.
|
183
|
+
# If there is no such data in the cache (a cache miss), then +nil+ will be
|
184
|
+
# returned. However, if a block has been passed, that block will be passed
|
185
|
+
# the key and executed in the event of a cache miss. The return value of the
|
186
|
+
# block will be written to the cache under the given cache key, and that
|
187
|
+
# return value will be returned.
|
187
188
|
#
|
188
|
-
# cache.write(
|
189
|
-
# cache.fetch(
|
189
|
+
# cache.write('today', 'Monday')
|
190
|
+
# cache.fetch('today') # => "Monday"
|
190
191
|
#
|
191
|
-
# cache.fetch(
|
192
|
-
# cache.fetch(
|
193
|
-
#
|
192
|
+
# cache.fetch('city') # => nil
|
193
|
+
# cache.fetch('city') do
|
194
|
+
# 'Duckburgh'
|
194
195
|
# end
|
195
|
-
# cache.fetch(
|
196
|
+
# cache.fetch('city') # => "Duckburgh"
|
196
197
|
#
|
197
198
|
# You may also specify additional options via the +options+ argument.
|
198
|
-
# Setting <tt
|
199
|
+
# Setting <tt>force: true</tt> will force a cache miss:
|
199
200
|
#
|
200
|
-
# cache.write(
|
201
|
-
# cache.fetch(
|
201
|
+
# cache.write('today', 'Monday')
|
202
|
+
# cache.fetch('today', force: true) # => nil
|
202
203
|
#
|
203
204
|
# Setting <tt>:compress</tt> will store a large cache entry set by the call
|
204
205
|
# in a compressed format.
|
205
206
|
#
|
206
|
-
#
|
207
207
|
# Setting <tt>:expires_in</tt> will set an expiration time on the cache.
|
208
208
|
# All caches support auto-expiring content after a specified number of
|
209
209
|
# seconds. This value can be specified as an option to the constructor
|
210
210
|
# (in which case all entries will be affected), or it can be supplied to
|
211
211
|
# the +fetch+ or +write+ method to effect just one entry.
|
212
212
|
#
|
213
|
-
# cache = ActiveSupport::Cache::MemoryStore.new(:
|
214
|
-
# cache.write(key, value, :
|
215
|
-
#
|
216
|
-
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where
|
217
|
-
# is used very frequently and is under heavy load. If a
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
227
|
-
#
|
228
|
-
#
|
229
|
-
#
|
230
|
-
#
|
213
|
+
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
214
|
+
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
|
215
|
+
#
|
216
|
+
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where
|
217
|
+
# a cache entry is used very frequently and is under heavy load. If a
|
218
|
+
# cache expires and due to heavy load seven different processes will try
|
219
|
+
# to read data natively and then they all will try to write to cache. To
|
220
|
+
# avoid that case the first process to find an expired cache entry will
|
221
|
+
# bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>.
|
222
|
+
# Yes, this process is extending the time for a stale value by another few
|
223
|
+
# seconds. Because of extended life of the previous cache, other processes
|
224
|
+
# will continue to use slightly stale data for a just a big longer. In the
|
225
|
+
# meantime that first process will go ahead and will write into cache the
|
226
|
+
# new value. After that all the processes will start getting new value.
|
227
|
+
# The key is to keep <tt>:race_condition_ttl</tt> small.
|
228
|
+
#
|
229
|
+
# If the process regenerating the entry errors out, the entry will be
|
230
|
+
# regenerated after the specified number of seconds. Also note that the
|
231
|
+
# life of stale cache is extended only if it expired recently. Otherwise
|
232
|
+
# a new value is generated and <tt>:race_condition_ttl</tt> does not play
|
233
|
+
# any role.
|
231
234
|
#
|
232
235
|
# # Set all values to expire after one minute.
|
233
|
-
# cache = ActiveSupport::Cache::MemoryStore.new(:
|
236
|
+
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
|
234
237
|
#
|
235
|
-
# cache.write(
|
238
|
+
# cache.write('foo', 'original value')
|
236
239
|
# val_1 = nil
|
237
240
|
# val_2 = nil
|
238
241
|
# sleep 60
|
239
242
|
#
|
240
243
|
# Thread.new do
|
241
|
-
# val_1 = cache.fetch(
|
244
|
+
# val_1 = cache.fetch('foo', race_condition_ttl: 10) do
|
242
245
|
# sleep 1
|
243
|
-
#
|
246
|
+
# 'new value 1'
|
244
247
|
# end
|
245
248
|
# end
|
246
249
|
#
|
247
250
|
# Thread.new do
|
248
|
-
# val_2 = cache.fetch(
|
249
|
-
#
|
251
|
+
# val_2 = cache.fetch('foo', race_condition_ttl: 10) do
|
252
|
+
# 'new value 2'
|
250
253
|
# end
|
251
254
|
# end
|
252
255
|
#
|
253
256
|
# # val_1 => "new value 1"
|
254
257
|
# # val_2 => "original value"
|
255
258
|
# # sleep 10 # First thread extend the life of cache by another 10 seconds
|
256
|
-
# # cache.fetch(
|
259
|
+
# # cache.fetch('foo') => "new value 1"
|
257
260
|
#
|
258
261
|
# Other options will be handled by the specific cache store implementation.
|
259
|
-
# Internally, #fetch calls #read_entry, and calls #write_entry on a cache
|
260
|
-
# +options+ will be passed to the #read and #write calls.
|
262
|
+
# Internally, #fetch calls #read_entry, and calls #write_entry on a cache
|
263
|
+
# miss. +options+ will be passed to the #read and #write calls.
|
261
264
|
#
|
262
265
|
# For example, MemCacheStore's #write method supports the +:raw+
|
263
266
|
# option, which tells the memcached server to store all values as strings.
|
264
267
|
# We can use this option with #fetch too:
|
265
268
|
#
|
266
269
|
# cache = ActiveSupport::Cache::MemCacheStore.new
|
267
|
-
# cache.fetch("foo", :
|
270
|
+
# cache.fetch("foo", force: true, raw: true) do
|
268
271
|
# :bar
|
269
272
|
# end
|
270
|
-
# cache.fetch(
|
273
|
+
# cache.fetch('foo') # => "bar"
|
271
274
|
def fetch(name, options = nil)
|
272
275
|
if block_given?
|
273
276
|
options = merged_options(options)
|
274
277
|
key = namespaced_key(name, options)
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
read_entry(key, options)
|
279
|
-
end
|
280
|
-
end
|
281
|
-
if entry && entry.expired?
|
282
|
-
race_ttl = options[:race_condition_ttl].to_f
|
283
|
-
if race_ttl and Time.now.to_f - entry.expires_at <= race_ttl
|
284
|
-
entry.expires_at = Time.now + race_ttl
|
285
|
-
write_entry(key, entry, :expires_in => race_ttl * 2)
|
286
|
-
else
|
287
|
-
delete_entry(key, options)
|
288
|
-
end
|
289
|
-
entry = nil
|
290
|
-
end
|
278
|
+
|
279
|
+
cached_entry = find_cached_entry(key, name, options) unless options[:force]
|
280
|
+
entry = handle_expired_entry(cached_entry, key, options)
|
291
281
|
|
292
282
|
if entry
|
293
|
-
|
294
|
-
entry.value
|
283
|
+
get_entry_value(entry, name, options)
|
295
284
|
else
|
296
|
-
|
297
|
-
yield
|
298
|
-
end
|
299
|
-
write(name, result, options)
|
300
|
-
result
|
285
|
+
save_block_result_to_cache(name, options) { |_name| yield _name }
|
301
286
|
end
|
302
287
|
else
|
303
288
|
read(name, options)
|
@@ -306,7 +291,7 @@ module ActiveSupport
|
|
306
291
|
|
307
292
|
# Fetches data from the cache, using the given key. If there is data in
|
308
293
|
# the cache with the given key, then that data is returned. Otherwise,
|
309
|
-
# nil is returned.
|
294
|
+
# +nil+ is returned.
|
310
295
|
#
|
311
296
|
# Options are passed to the underlying cache implementation.
|
312
297
|
def read(name, options = nil)
|
@@ -375,18 +360,14 @@ module ActiveSupport
|
|
375
360
|
end
|
376
361
|
end
|
377
362
|
|
378
|
-
# Return true if the cache contains an entry for the given key.
|
363
|
+
# Return +true+ if the cache contains an entry for the given key.
|
379
364
|
#
|
380
365
|
# Options are passed to the underlying cache implementation.
|
381
366
|
def exist?(name, options = nil)
|
382
367
|
options = merged_options(options)
|
383
368
|
instrument(:exist?, name) do |payload|
|
384
369
|
entry = read_entry(namespaced_key(name, options), options)
|
385
|
-
|
386
|
-
true
|
387
|
-
else
|
388
|
-
false
|
389
|
-
end
|
370
|
+
entry && !entry.expired?
|
390
371
|
end
|
391
372
|
end
|
392
373
|
|
@@ -408,7 +389,7 @@ module ActiveSupport
|
|
408
389
|
raise NotImplementedError.new("#{self.class.name} does not support increment")
|
409
390
|
end
|
410
391
|
|
411
|
-
#
|
392
|
+
# Decrement an integer value in the cache.
|
412
393
|
#
|
413
394
|
# Options are passed to the underlying cache implementation.
|
414
395
|
#
|
@@ -437,9 +418,10 @@ module ActiveSupport
|
|
437
418
|
end
|
438
419
|
|
439
420
|
protected
|
440
|
-
# Add the namespace defined in the options to a pattern designed to
|
441
|
-
# Implementations that support delete_matched should call
|
442
|
-
# a pattern that matches names into one that
|
421
|
+
# Add the namespace defined in the options to a pattern designed to
|
422
|
+
# match keys. Implementations that support delete_matched should call
|
423
|
+
# this method to translate a pattern that matches names into one that
|
424
|
+
# matches namespaced keys.
|
443
425
|
def key_matcher(pattern, options)
|
444
426
|
prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
|
445
427
|
if prefix
|
@@ -455,17 +437,20 @@ module ActiveSupport
|
|
455
437
|
end
|
456
438
|
end
|
457
439
|
|
458
|
-
# Read an entry from the cache implementation. Subclasses must implement
|
440
|
+
# Read an entry from the cache implementation. Subclasses must implement
|
441
|
+
# this method.
|
459
442
|
def read_entry(key, options) # :nodoc:
|
460
443
|
raise NotImplementedError.new
|
461
444
|
end
|
462
445
|
|
463
|
-
# Write an entry to the cache implementation. Subclasses must implement
|
446
|
+
# Write an entry to the cache implementation. Subclasses must implement
|
447
|
+
# this method.
|
464
448
|
def write_entry(key, entry, options) # :nodoc:
|
465
449
|
raise NotImplementedError.new
|
466
450
|
end
|
467
451
|
|
468
|
-
# Delete an entry from the cache implementation. Subclasses must
|
452
|
+
# Delete an entry from the cache implementation. Subclasses must
|
453
|
+
# implement this method.
|
469
454
|
def delete_entry(key, options) # :nodoc:
|
470
455
|
raise NotImplementedError.new
|
471
456
|
end
|
@@ -481,7 +466,7 @@ module ActiveSupport
|
|
481
466
|
end
|
482
467
|
|
483
468
|
# Expand key to be a consistent string value. Invoke +cache_key+ if
|
484
|
-
# object responds to +cache_key+. Otherwise, to_param method will be
|
469
|
+
# object responds to +cache_key+. Otherwise, +to_param+ method will be
|
485
470
|
# called. If the key is a Hash, then keys will be sorted alphabetically.
|
486
471
|
def expanded_key(key) # :nodoc:
|
487
472
|
return key.cache_key.to_s if key.respond_to?(:cache_key)
|
@@ -500,7 +485,8 @@ module ActiveSupport
|
|
500
485
|
key.to_param
|
501
486
|
end
|
502
487
|
|
503
|
-
# Prefix a key with the namespace. Namespace and key will be delimited
|
488
|
+
# Prefix a key with the namespace. Namespace and key will be delimited
|
489
|
+
# with a colon.
|
504
490
|
def namespaced_key(key, options)
|
505
491
|
key = expanded_key(key)
|
506
492
|
namespace = options[:namespace] if options
|
@@ -525,114 +511,160 @@ module ActiveSupport
|
|
525
511
|
return unless logger && logger.debug? && !silence?
|
526
512
|
logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}")
|
527
513
|
end
|
528
|
-
end
|
529
514
|
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
515
|
+
def find_cached_entry(key, name, options)
|
516
|
+
instrument(:read, name, options) do |payload|
|
517
|
+
payload[:super_operation] = :fetch if payload
|
518
|
+
read_entry(key, options)
|
519
|
+
end
|
520
|
+
end
|
536
521
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
522
|
+
def handle_expired_entry(entry, key, options)
|
523
|
+
if entry && entry.expired?
|
524
|
+
race_ttl = options[:race_condition_ttl].to_i
|
525
|
+
if race_ttl && (Time.now - entry.expires_at <= race_ttl)
|
526
|
+
# When an entry has :race_condition_ttl defined, put the stale entry back into the cache
|
527
|
+
# for a brief period while the entry is begin recalculated.
|
528
|
+
entry.expires_at = Time.now + race_ttl
|
529
|
+
write_entry(key, entry, :expires_in => race_ttl * 2)
|
530
|
+
else
|
531
|
+
delete_entry(key, options)
|
532
|
+
end
|
533
|
+
entry = nil
|
534
|
+
end
|
547
535
|
entry
|
548
536
|
end
|
549
|
-
|
537
|
+
|
538
|
+
def get_entry_value(entry, name, options)
|
539
|
+
instrument(:fetch_hit, name, options) { |payload| }
|
540
|
+
entry.value
|
541
|
+
end
|
542
|
+
|
543
|
+
def save_block_result_to_cache(name, options)
|
544
|
+
result = instrument(:generate, name, options) do |payload|
|
545
|
+
yield(name)
|
546
|
+
end
|
547
|
+
write(name, result, options)
|
548
|
+
result
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
# This class is used to represent cache entries. Cache entries have a value and an optional
|
553
|
+
# expiration time. The expiration time is used to support the :race_condition_ttl option
|
554
|
+
# on the cache.
|
555
|
+
#
|
556
|
+
# Since cache entries in most instances will be serialized, the internals of this class are highly optimized
|
557
|
+
# using short instance variable names that are lazily defined.
|
558
|
+
class Entry # :nodoc:
|
559
|
+
DEFAULT_COMPRESS_LIMIT = 16.kilobytes
|
550
560
|
|
551
561
|
# Create a new cache entry for the specified value. Options supported are
|
552
562
|
# +:compress+, +:compress_threshold+, and +:expires_in+.
|
553
563
|
def initialize(value, options = {})
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
@created_at = Time.now.to_f
|
558
|
-
if value.nil?
|
559
|
-
@value = nil
|
564
|
+
if should_compress?(value, options)
|
565
|
+
@v = compress(value)
|
566
|
+
@c = true
|
560
567
|
else
|
561
|
-
@
|
562
|
-
if should_compress?(@value, options)
|
563
|
-
@value = Zlib::Deflate.deflate(@value)
|
564
|
-
@compressed = true
|
565
|
-
end
|
568
|
+
@v = value
|
566
569
|
end
|
567
|
-
|
568
|
-
|
569
|
-
# Get the raw value. This value may be serialized and compressed.
|
570
|
-
def raw_value
|
571
|
-
@value
|
572
|
-
end
|
573
|
-
|
574
|
-
# Get the value stored in the cache.
|
575
|
-
def value
|
576
|
-
# If the original value was exactly false @value is still true because
|
577
|
-
# it is marshalled and eventually compressed. Both operations yield
|
578
|
-
# strings.
|
579
|
-
if @value
|
580
|
-
# In rails 3.1 and earlier values in entries did not marshaled without
|
581
|
-
# options[:compress] and if it's Numeric.
|
582
|
-
# But after commit a263f377978fc07515b42808ebc1f7894fafaa3a
|
583
|
-
# all values in entries are marshalled. And after that code below expects
|
584
|
-
# that all values in entries will be marshaled (and will be strings).
|
585
|
-
# So here we need a check for old ones.
|
586
|
-
begin
|
587
|
-
Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value)
|
588
|
-
rescue TypeError
|
589
|
-
compressed? ? Zlib::Inflate.inflate(@value) : @value
|
590
|
-
end
|
570
|
+
if expires_in = options[:expires_in]
|
571
|
+
@x = (Time.now + expires_in).to_i
|
591
572
|
end
|
592
573
|
end
|
593
574
|
|
594
|
-
def
|
595
|
-
@
|
575
|
+
def value
|
576
|
+
convert_version_3_entry! if defined?(@value)
|
577
|
+
compressed? ? uncompress(@v) : @v
|
596
578
|
end
|
597
579
|
|
598
|
-
# Check if the entry is expired. The +expires_in+ parameter can override
|
599
|
-
# value set when the entry was created.
|
580
|
+
# Check if the entry is expired. The +expires_in+ parameter can override
|
581
|
+
# the value set when the entry was created.
|
600
582
|
def expired?
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
# Set a new time when the entry will expire.
|
605
|
-
def expires_at=(time)
|
606
|
-
if time
|
607
|
-
@expires_in = time.to_f - @created_at
|
583
|
+
convert_version_3_entry! if defined?(@value)
|
584
|
+
if defined?(@x)
|
585
|
+
@x && @x < Time.now.to_i
|
608
586
|
else
|
609
|
-
|
587
|
+
false
|
610
588
|
end
|
611
589
|
end
|
612
590
|
|
613
|
-
# Seconds since the epoch when the entry will expire.
|
614
591
|
def expires_at
|
615
|
-
@
|
592
|
+
Time.at(@x) if defined?(@x)
|
593
|
+
end
|
594
|
+
|
595
|
+
def expires_at=(value)
|
596
|
+
@x = value.to_i
|
616
597
|
end
|
617
598
|
|
618
|
-
# Returns the size of the cached value. This could be less than
|
619
|
-
# if the data is compressed.
|
599
|
+
# Returns the size of the cached value. This could be less than
|
600
|
+
# <tt>value.size</tt> if the data is compressed.
|
620
601
|
def size
|
621
|
-
if @
|
622
|
-
|
602
|
+
if defined?(@s)
|
603
|
+
@s
|
623
604
|
else
|
624
|
-
|
605
|
+
case value
|
606
|
+
when NilClass
|
607
|
+
0
|
608
|
+
when String
|
609
|
+
@v.bytesize
|
610
|
+
else
|
611
|
+
@s = Marshal.dump(@v).bytesize
|
612
|
+
end
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
# Duplicate the value in a class. This is used by cache implementations that don't natively
|
617
|
+
# serialize entries to protect against accidental cache modifications.
|
618
|
+
def dup_value!
|
619
|
+
convert_version_3_entry! if defined?(@value)
|
620
|
+
if @v && !compressed? && !(@v.is_a?(Numeric) || @v == true || @v == false)
|
621
|
+
if @v.is_a?(String)
|
622
|
+
@v = @v.dup
|
623
|
+
else
|
624
|
+
@v = Marshal.load(Marshal.dump(@v))
|
625
|
+
end
|
625
626
|
end
|
626
627
|
end
|
627
628
|
|
628
629
|
private
|
629
|
-
def should_compress?(
|
630
|
-
if options[:compress]
|
630
|
+
def should_compress?(value, options)
|
631
|
+
if value && options[:compress]
|
631
632
|
compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
|
632
|
-
|
633
|
+
serialized_value_size = (value.is_a?(String) ? value : Marshal.dump(value)).bytesize
|
634
|
+
return true if serialized_value_size >= compress_threshold
|
633
635
|
end
|
634
636
|
false
|
635
637
|
end
|
638
|
+
|
639
|
+
def compressed?
|
640
|
+
defined?(@c) ? @c : false
|
641
|
+
end
|
642
|
+
|
643
|
+
def compress(value)
|
644
|
+
Zlib::Deflate.deflate(Marshal.dump(value))
|
645
|
+
end
|
646
|
+
|
647
|
+
def uncompress(value)
|
648
|
+
Marshal.load(Zlib::Inflate.inflate(value))
|
649
|
+
end
|
650
|
+
|
651
|
+
# The internals of this method changed between Rails 3.x and 4.0. This method provides the glue
|
652
|
+
# to ensure that cache entries created under the old version still work with the new class definition.
|
653
|
+
def convert_version_3_entry!
|
654
|
+
if defined?(@value)
|
655
|
+
@v = @value
|
656
|
+
remove_instance_variable(:@value)
|
657
|
+
end
|
658
|
+
if defined?(@compressed)
|
659
|
+
@c = @compressed
|
660
|
+
remove_instance_variable(:@compressed)
|
661
|
+
end
|
662
|
+
if defined?(@expires_in) && defined?(@created_at) && @expires_in && @created_at
|
663
|
+
@x = (@created_at + @expires_in).to_i
|
664
|
+
remove_instance_variable(:@created_at)
|
665
|
+
remove_instance_variable(:@expires_in)
|
666
|
+
end
|
667
|
+
end
|
636
668
|
end
|
637
669
|
end
|
638
670
|
end
|