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,20 +1,34 @@
|
|
1
1
|
module ActiveSupport
|
2
|
-
|
3
|
-
|
2
|
+
class Deprecation
|
3
|
+
module Reporting
|
4
|
+
# Whether to print a message (silent mode)
|
4
5
|
attr_accessor :silenced
|
6
|
+
# Name of gem where method is deprecated
|
7
|
+
attr_accessor :gem_name
|
5
8
|
|
6
|
-
# Outputs a deprecation warning to the output configured by
|
9
|
+
# Outputs a deprecation warning to the output configured by
|
10
|
+
# <tt>ActiveSupport::Deprecation.behavior</tt>.
|
7
11
|
#
|
8
|
-
# ActiveSupport::Deprecation.warn(
|
12
|
+
# ActiveSupport::Deprecation.warn('something broke!')
|
9
13
|
# # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
|
10
|
-
def warn(message = nil, callstack =
|
14
|
+
def warn(message = nil, callstack = nil)
|
11
15
|
return if silenced
|
16
|
+
|
17
|
+
callstack ||= caller(2)
|
12
18
|
deprecation_message(callstack, message).tap do |m|
|
13
19
|
behavior.each { |b| b.call(m, callstack) }
|
14
20
|
end
|
15
21
|
end
|
16
22
|
|
17
23
|
# Silence deprecation warnings within the block.
|
24
|
+
#
|
25
|
+
# ActiveSupport::Deprecation.warn('something broke!')
|
26
|
+
# # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
|
27
|
+
#
|
28
|
+
# ActiveSupport::Deprecation.silence do
|
29
|
+
# ActiveSupport::Deprecation.warn('something broke!')
|
30
|
+
# end
|
31
|
+
# # => nil
|
18
32
|
def silence
|
19
33
|
old_silenced, @silenced = @silenced, true
|
20
34
|
yield
|
@@ -22,16 +36,31 @@ module ActiveSupport
|
|
22
36
|
@silenced = old_silenced
|
23
37
|
end
|
24
38
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
when String then "#{warning} (#{message})"
|
30
|
-
else warning
|
39
|
+
def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
|
40
|
+
caller_backtrace ||= caller(2)
|
41
|
+
deprecated_method_warning(deprecated_method_name, message).tap do |msg|
|
42
|
+
warn(msg, caller_backtrace)
|
31
43
|
end
|
32
44
|
end
|
33
45
|
|
34
46
|
private
|
47
|
+
# Outputs a deprecation warning message
|
48
|
+
#
|
49
|
+
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name)
|
50
|
+
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon}"
|
51
|
+
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name, :another_method)
|
52
|
+
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (use another_method instead)"
|
53
|
+
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name, "Optional message")
|
54
|
+
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (Optional message)"
|
55
|
+
def deprecated_method_warning(method_name, message = nil)
|
56
|
+
warning = "#{method_name} is deprecated and will be removed from #{gem_name} #{deprecation_horizon}"
|
57
|
+
case message
|
58
|
+
when Symbol then "#{warning} (use #{message} instead)"
|
59
|
+
when String then "#{warning} (#{message})"
|
60
|
+
else warning
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
35
64
|
def deprecation_message(callstack, message = nil)
|
36
65
|
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
|
37
66
|
message += '.' unless message =~ /\.$/
|
@@ -2,35 +2,50 @@ module ActiveSupport
|
|
2
2
|
# This module provides an internal implementation to track descendants
|
3
3
|
# which is faster than iterating through ObjectSpace.
|
4
4
|
module DescendantsTracker
|
5
|
-
@@direct_descendants =
|
5
|
+
@@direct_descendants = {}
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
class << self
|
8
|
+
def direct_descendants(klass)
|
9
|
+
@@direct_descendants[klass] || []
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def descendants(klass)
|
13
|
+
arr = []
|
14
|
+
accumulate_descendants(klass, arr)
|
15
|
+
arr
|
15
16
|
end
|
16
|
-
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
def clear
|
19
|
+
if defined? ActiveSupport::Dependencies
|
20
|
+
@@direct_descendants.each do |klass, descendants|
|
21
|
+
if ActiveSupport::Dependencies.autoloaded?(klass)
|
22
|
+
@@direct_descendants.delete(klass)
|
23
|
+
else
|
24
|
+
descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
|
25
|
+
end
|
25
26
|
end
|
27
|
+
else
|
28
|
+
@@direct_descendants.clear
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# This is the only method that is not thread safe, but is only ever called
|
33
|
+
# during the eager loading phase.
|
34
|
+
def store_inherited(klass, descendant)
|
35
|
+
(@@direct_descendants[klass] ||= []) << descendant
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def accumulate_descendants(klass, acc)
|
40
|
+
if direct_descendants = @@direct_descendants[klass]
|
41
|
+
acc.concat(direct_descendants)
|
42
|
+
direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
|
26
43
|
end
|
27
|
-
else
|
28
|
-
@@direct_descendants.clear
|
29
44
|
end
|
30
45
|
end
|
31
46
|
|
32
47
|
def inherited(base)
|
33
|
-
self
|
48
|
+
DescendantsTracker.store_inherited(self, base)
|
34
49
|
super
|
35
50
|
end
|
36
51
|
|
@@ -1,16 +1,14 @@
|
|
1
|
-
require 'active_support/
|
1
|
+
require 'active_support/proxy_object'
|
2
2
|
require 'active_support/core_ext/array/conversions'
|
3
3
|
require 'active_support/core_ext/object/acts_like'
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
# Provides accurate date and time measurements using Date#advance and
|
7
7
|
# Time#advance, respectively. It mainly supports the methods on Numeric.
|
8
|
-
# Example:
|
9
8
|
#
|
10
|
-
# 1.month.ago # equivalent to Time.now.advance(:
|
11
|
-
class Duration <
|
9
|
+
# 1.month.ago # equivalent to Time.now.advance(months: -1)
|
10
|
+
class Duration < ProxyObject
|
12
11
|
attr_accessor :value, :parts
|
13
|
-
delegate :duplicable?, :to => :value # required when using ActiveSupport's BasicObject on 1.8
|
14
12
|
|
15
13
|
def initialize(value, parts) #:nodoc:
|
16
14
|
@value, @parts = value, parts
|
@@ -41,8 +39,8 @@ module ActiveSupport
|
|
41
39
|
end
|
42
40
|
alias :kind_of? :is_a?
|
43
41
|
|
44
|
-
# Returns true if
|
45
|
-
# same
|
42
|
+
# Returns +true+ if +other+ is also a Duration instance with the
|
43
|
+
# same +value+, or if <tt>other == value</tt>.
|
46
44
|
def ==(other)
|
47
45
|
if Duration === other
|
48
46
|
other.value == value
|
@@ -72,7 +70,7 @@ module ActiveSupport
|
|
72
70
|
alias :until :ago
|
73
71
|
|
74
72
|
def inspect #:nodoc:
|
75
|
-
consolidated = parts.inject(::Hash.new(0)) { |h,
|
73
|
+
consolidated = parts.inject(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }
|
76
74
|
parts = [:years, :months, :days, :minutes, :seconds].map do |length|
|
77
75
|
n = consolidated[length]
|
78
76
|
"#{n} #{n == 1 ? length.to_s.singularize : length.to_s}" if n.nonzero?
|
@@ -1,26 +1,21 @@
|
|
1
|
-
require "active_support/core_ext/array/wrap"
|
2
|
-
require "active_support/core_ext/array/extract_options"
|
3
|
-
|
4
1
|
module ActiveSupport
|
5
|
-
#
|
2
|
+
# FileUpdateChecker specifies the API used by Rails to watch files
|
6
3
|
# and control reloading. The API depends on four methods:
|
7
4
|
#
|
8
5
|
# * +initialize+ which expects two parameters and one block as
|
9
|
-
# described below
|
6
|
+
# described below.
|
10
7
|
#
|
11
8
|
# * +updated?+ which returns a boolean if there were updates in
|
12
|
-
# the filesystem or not
|
9
|
+
# the filesystem or not.
|
13
10
|
#
|
14
11
|
# * +execute+ which executes the given block on initialization
|
15
|
-
# and updates the
|
12
|
+
# and updates the latest watched files and timestamp.
|
16
13
|
#
|
17
|
-
# * +execute_if_updated+ which just executes the block if it was updated
|
14
|
+
# * +execute_if_updated+ which just executes the block if it was updated.
|
18
15
|
#
|
19
16
|
# After initialization, a call to +execute_if_updated+ must execute
|
20
17
|
# the block only if there was really a change in the filesystem.
|
21
18
|
#
|
22
|
-
# == Examples
|
23
|
-
#
|
24
19
|
# This class is used by Rails to reload the I18n framework whenever
|
25
20
|
# they are changed upon a new request.
|
26
21
|
#
|
@@ -31,52 +26,55 @@ module ActiveSupport
|
|
31
26
|
# ActionDispatch::Reloader.to_prepare do
|
32
27
|
# i18n_reloader.execute_if_updated
|
33
28
|
# end
|
34
|
-
#
|
35
29
|
class FileUpdateChecker
|
36
30
|
# It accepts two parameters on initialization. The first is an array
|
37
31
|
# of files and the second is an optional hash of directories. The hash must
|
38
32
|
# have directories as keys and the value is an array of extensions to be
|
39
33
|
# watched under that directory.
|
40
34
|
#
|
41
|
-
# This method must also receive a block that will be called once a path
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# This particular implementation checks for added and updated files,
|
46
|
-
# but not removed files. Directories lookup are compiled to a glob for
|
47
|
-
# performance. Therefore, while someone can add new files to the +files+
|
48
|
-
# array after initialization (and parts of Rails do depend on this feature),
|
49
|
-
# adding new directories after initialization is not allowed.
|
50
|
-
#
|
51
|
-
# Notice that other objects that implements FileUpdateChecker API may
|
52
|
-
# not even allow new files to be added after initialization. If this
|
53
|
-
# is the case, we recommend freezing the +files+ after initialization to
|
54
|
-
# avoid changes that won't make effect.
|
35
|
+
# This method must also receive a block that will be called once a path
|
36
|
+
# changes. The array of files and list of directories cannot be changed
|
37
|
+
# after FileUpdateChecker has been initialized.
|
55
38
|
def initialize(files, dirs={}, &block)
|
56
|
-
@files = files
|
39
|
+
@files = files.freeze
|
57
40
|
@glob = compile_glob(dirs)
|
58
41
|
@block = block
|
42
|
+
|
43
|
+
@watched = nil
|
59
44
|
@updated_at = nil
|
60
|
-
|
45
|
+
|
46
|
+
@last_watched = watched
|
47
|
+
@last_update_at = updated_at(@last_watched)
|
61
48
|
end
|
62
49
|
|
63
|
-
# Check if any of the entries were updated. If so, the
|
64
|
-
#
|
50
|
+
# Check if any of the entries were updated. If so, the watched and/or
|
51
|
+
# updated_at values are cached until the block is executed via +execute+
|
52
|
+
# or +execute_if_updated+.
|
65
53
|
def updated?
|
66
|
-
|
67
|
-
if @
|
68
|
-
@
|
54
|
+
current_watched = watched
|
55
|
+
if @last_watched.size != current_watched.size
|
56
|
+
@watched = current_watched
|
69
57
|
true
|
70
58
|
else
|
71
|
-
|
59
|
+
current_updated_at = updated_at(current_watched)
|
60
|
+
if @last_update_at < current_updated_at
|
61
|
+
@watched = current_watched
|
62
|
+
@updated_at = current_updated_at
|
63
|
+
true
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
72
67
|
end
|
73
68
|
end
|
74
69
|
|
75
|
-
# Executes the given block and updates the
|
70
|
+
# Executes the given block and updates the latest watched files and
|
71
|
+
# timestamp.
|
76
72
|
def execute
|
77
|
-
@
|
73
|
+
@last_watched = watched
|
74
|
+
@last_update_at = updated_at(@last_watched)
|
78
75
|
@block.call
|
79
76
|
ensure
|
77
|
+
@watched = nil
|
80
78
|
@updated_at = nil
|
81
79
|
end
|
82
80
|
|
@@ -92,28 +90,46 @@ module ActiveSupport
|
|
92
90
|
|
93
91
|
private
|
94
92
|
|
95
|
-
def
|
96
|
-
@
|
97
|
-
all =
|
98
|
-
all.concat
|
99
|
-
all
|
100
|
-
all.map { |path| File.mtime(path) }.max || Time.at(0)
|
93
|
+
def watched
|
94
|
+
@watched || begin
|
95
|
+
all = @files.select { |f| File.exists?(f) }
|
96
|
+
all.concat(Dir[@glob]) if @glob
|
97
|
+
all
|
101
98
|
end
|
102
99
|
end
|
103
100
|
|
104
|
-
def
|
101
|
+
def updated_at(paths)
|
102
|
+
@updated_at || max_mtime(paths) || Time.at(0)
|
103
|
+
end
|
104
|
+
|
105
|
+
# This method returns the maximum mtime of the files in +paths+, or +nil+
|
106
|
+
# if the array is empty.
|
107
|
+
#
|
108
|
+
# Files with a mtime in the future are ignored. Such abnormal situation
|
109
|
+
# can happen for example if the user changes the clock by hand. It is
|
110
|
+
# healthy to consider this edge case because with mtimes in the future
|
111
|
+
# reloading is not triggered.
|
112
|
+
def max_mtime(paths)
|
113
|
+
time_now = Time.now
|
114
|
+
paths.map {|path| File.mtime(path)}.reject {|mtime| time_now < mtime}.max
|
115
|
+
end
|
116
|
+
|
117
|
+
def compile_glob(hash)
|
105
118
|
hash.freeze # Freeze so changes aren't accidently pushed
|
106
119
|
return if hash.empty?
|
107
120
|
|
108
|
-
globs =
|
109
|
-
|
110
|
-
globs << "#{key}/**/*#{compile_ext(value)}"
|
121
|
+
globs = hash.map do |key, value|
|
122
|
+
"#{escape(key)}/**/*#{compile_ext(value)}"
|
111
123
|
end
|
112
124
|
"{#{globs.join(",")}}"
|
113
125
|
end
|
114
126
|
|
115
|
-
def
|
116
|
-
|
127
|
+
def escape(key)
|
128
|
+
key.gsub(',','\,')
|
129
|
+
end
|
130
|
+
|
131
|
+
def compile_ext(array)
|
132
|
+
array = Array(array)
|
117
133
|
return if array.empty?
|
118
134
|
".{#{array.join(",")}}"
|
119
135
|
end
|
data/lib/active_support/gzip.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
require 'zlib'
|
2
2
|
require 'stringio'
|
3
|
-
require 'active_support/core_ext/string/encoding'
|
4
3
|
|
5
4
|
module ActiveSupport
|
6
|
-
# A convenient wrapper for the zlib standard library that allows
|
5
|
+
# A convenient wrapper for the zlib standard library that allows
|
6
|
+
# compression/decompression of strings with gzip.
|
7
|
+
#
|
8
|
+
# gzip = ActiveSupport::Gzip.compress('compress me!')
|
9
|
+
# # => "\x1F\x8B\b\x00o\x8D\xCDO\x00\x03K\xCE\xCF-(J-.V\xC8MU\x04\x00R>n\x83\f\x00\x00\x00"
|
10
|
+
#
|
11
|
+
# ActiveSupport::Gzip.decompress(gzip)
|
12
|
+
# # => "compress me!"
|
7
13
|
module Gzip
|
8
14
|
class Stream < StringIO
|
9
15
|
def initialize(*)
|
10
16
|
super
|
11
|
-
set_encoding "BINARY"
|
17
|
+
set_encoding "BINARY"
|
12
18
|
end
|
13
19
|
def close; rewind; end
|
14
20
|
end
|
@@ -19,9 +25,9 @@ module ActiveSupport
|
|
19
25
|
end
|
20
26
|
|
21
27
|
# Compresses a string using gzip.
|
22
|
-
def self.compress(source)
|
28
|
+
def self.compress(source, level=Zlib::DEFAULT_COMPRESSION, strategy=Zlib::DEFAULT_STRATEGY)
|
23
29
|
output = Stream.new
|
24
|
-
gz = Zlib::GzipWriter.new(output)
|
30
|
+
gz = Zlib::GzipWriter.new(output, level, strategy)
|
25
31
|
gz.write(source)
|
26
32
|
gz.close
|
27
33
|
output.string
|
@@ -1,13 +1,47 @@
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
2
2
|
|
3
|
-
# This class has dubious semantics and we only have it so that
|
4
|
-
# people can write <tt>params[:key]</tt> instead of <tt>params['key']</tt>
|
5
|
-
# and they get the same value for both keys.
|
6
|
-
|
7
3
|
module ActiveSupport
|
4
|
+
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
|
5
|
+
# to be the same.
|
6
|
+
#
|
7
|
+
# rgb = ActiveSupport::HashWithIndifferentAccess.new
|
8
|
+
#
|
9
|
+
# rgb[:black] = '#000000'
|
10
|
+
# rgb[:black] # => '#000000'
|
11
|
+
# rgb['black'] # => '#000000'
|
12
|
+
#
|
13
|
+
# rgb['white'] = '#FFFFFF'
|
14
|
+
# rgb[:white] # => '#FFFFFF'
|
15
|
+
# rgb['white'] # => '#FFFFFF'
|
16
|
+
#
|
17
|
+
# Internally symbols are mapped to strings when used as keys in the entire
|
18
|
+
# writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
|
19
|
+
# mapping belongs to the public interface. For example, given:
|
20
|
+
#
|
21
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
|
22
|
+
#
|
23
|
+
# You are guaranteed that the key is returned as a string:
|
24
|
+
#
|
25
|
+
# hash.keys # => ["a"]
|
26
|
+
#
|
27
|
+
# Technically other types of keys are accepted:
|
28
|
+
#
|
29
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
|
30
|
+
# hash[0] = 0
|
31
|
+
# hash # => {"a"=>1, 0=>0}
|
32
|
+
#
|
33
|
+
# but this class is intended for use cases where strings or symbols are the
|
34
|
+
# expected keys and it is convenient to understand both as the same. For
|
35
|
+
# example the +params+ hash in Ruby on Rails.
|
36
|
+
#
|
37
|
+
# Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
|
38
|
+
#
|
39
|
+
# rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
|
40
|
+
#
|
41
|
+
# which may be handy.
|
8
42
|
class HashWithIndifferentAccess < Hash
|
9
|
-
|
10
|
-
#
|
43
|
+
# Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
|
44
|
+
# this class.
|
11
45
|
def extractable_options?
|
12
46
|
true
|
13
47
|
end
|
@@ -43,35 +77,60 @@ module ActiveSupport
|
|
43
77
|
end
|
44
78
|
end
|
45
79
|
|
80
|
+
def self.[](*args)
|
81
|
+
new.merge(Hash[*args])
|
82
|
+
end
|
83
|
+
|
46
84
|
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
47
85
|
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
48
86
|
|
49
87
|
# Assigns a new value to the hash:
|
50
88
|
#
|
51
|
-
# hash = HashWithIndifferentAccess.new
|
52
|
-
# hash[:key] =
|
89
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
90
|
+
# hash[:key] = 'value'
|
53
91
|
#
|
92
|
+
# This value can be later fetched using either +:key+ or +'key'+.
|
54
93
|
def []=(key, value)
|
55
94
|
regular_writer(convert_key(key), convert_value(value))
|
56
95
|
end
|
57
96
|
|
58
97
|
alias_method :store, :[]=
|
59
98
|
|
60
|
-
# Updates the
|
99
|
+
# Updates the receiver in-place, merging in the hash passed as argument:
|
61
100
|
#
|
62
|
-
# hash_1 = HashWithIndifferentAccess.new
|
63
|
-
# hash_1[:key] =
|
101
|
+
# hash_1 = ActiveSupport::HashWithIndifferentAccess.new
|
102
|
+
# hash_1[:key] = 'value'
|
64
103
|
#
|
65
|
-
# hash_2 = HashWithIndifferentAccess.new
|
66
|
-
# hash_2[:key] =
|
104
|
+
# hash_2 = ActiveSupport::HashWithIndifferentAccess.new
|
105
|
+
# hash_2[:key] = 'New Value!'
|
67
106
|
#
|
68
107
|
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
69
108
|
#
|
109
|
+
# The argument can be either an
|
110
|
+
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
|
111
|
+
# In either case the merge respects the semantics of indifferent access.
|
112
|
+
#
|
113
|
+
# If the argument is a regular hash with keys +:key+ and +"key"+ only one
|
114
|
+
# of the values end up in the receiver, but which one is unspecified.
|
115
|
+
#
|
116
|
+
# When given a block, the value for duplicated keys will be determined
|
117
|
+
# by the result of invoking the block with the duplicated key, the value
|
118
|
+
# in the receiver, and the value in +other_hash+. The rules for duplicated
|
119
|
+
# keys follow the semantics of indifferent access:
|
120
|
+
#
|
121
|
+
# hash_1[:key] = 10
|
122
|
+
# hash_2['key'] = 12
|
123
|
+
# hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
|
70
124
|
def update(other_hash)
|
71
125
|
if other_hash.is_a? HashWithIndifferentAccess
|
72
126
|
super(other_hash)
|
73
127
|
else
|
74
|
-
other_hash.each_pair
|
128
|
+
other_hash.each_pair do |key, value|
|
129
|
+
if block_given? && key?(key)
|
130
|
+
value = yield(convert_key(key), self[key], value)
|
131
|
+
end
|
132
|
+
regular_writer(convert_key(key), convert_value(value))
|
133
|
+
end
|
75
134
|
self
|
76
135
|
end
|
77
136
|
end
|
@@ -80,11 +139,10 @@ module ActiveSupport
|
|
80
139
|
|
81
140
|
# Checks the hash for a key matching the argument passed in:
|
82
141
|
#
|
83
|
-
# hash = HashWithIndifferentAccess.new
|
84
|
-
# hash[
|
85
|
-
# hash.key?
|
86
|
-
# hash.key?
|
87
|
-
#
|
142
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
143
|
+
# hash['key'] = 'value'
|
144
|
+
# hash.key?(:key) # => true
|
145
|
+
# hash.key?('key') # => true
|
88
146
|
def key?(key)
|
89
147
|
super(convert_key(key))
|
90
148
|
end
|
@@ -96,25 +154,23 @@ module ActiveSupport
|
|
96
154
|
# Same as <tt>Hash#fetch</tt> where the key passed as argument can be
|
97
155
|
# either a string or a symbol:
|
98
156
|
#
|
99
|
-
# counters = HashWithIndifferentAccess.new
|
157
|
+
# counters = ActiveSupport::HashWithIndifferentAccess.new
|
100
158
|
# counters[:foo] = 1
|
101
159
|
#
|
102
|
-
# counters.fetch(
|
160
|
+
# counters.fetch('foo') # => 1
|
103
161
|
# counters.fetch(:bar, 0) # => 0
|
104
162
|
# counters.fetch(:bar) {|key| 0} # => 0
|
105
163
|
# counters.fetch(:zoo) # => KeyError: key not found: "zoo"
|
106
|
-
#
|
107
164
|
def fetch(key, *extras)
|
108
165
|
super(convert_key(key), *extras)
|
109
166
|
end
|
110
167
|
|
111
168
|
# Returns an array of the values at the specified indices:
|
112
169
|
#
|
113
|
-
# hash = HashWithIndifferentAccess.new
|
114
|
-
# hash[:a] =
|
115
|
-
# hash[:b] =
|
116
|
-
# hash.values_at(
|
117
|
-
#
|
170
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
171
|
+
# hash[:a] = 'x'
|
172
|
+
# hash[:b] = 'y'
|
173
|
+
# hash.values_at('a', 'b') # => ["x", "y"]
|
118
174
|
def values_at(*indices)
|
119
175
|
indices.collect {|key| self[convert_key(key)]}
|
120
176
|
end
|
@@ -126,34 +182,52 @@ module ActiveSupport
|
|
126
182
|
end
|
127
183
|
end
|
128
184
|
|
129
|
-
#
|
130
|
-
#
|
131
|
-
|
132
|
-
|
185
|
+
# This method has the same semantics of +update+, except it does not
|
186
|
+
# modify the receiver but rather returns a new hash with indifferent
|
187
|
+
# access with the result of the merge.
|
188
|
+
def merge(hash, &block)
|
189
|
+
self.dup.update(hash, &block)
|
133
190
|
end
|
134
191
|
|
135
|
-
#
|
136
|
-
#
|
192
|
+
# Like +merge+ but the other way around: Merges the receiver into the
|
193
|
+
# argument and returns a new hash with indifferent access as result:
|
194
|
+
#
|
195
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
196
|
+
# hash['a'] = nil
|
197
|
+
# hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
|
137
198
|
def reverse_merge(other_hash)
|
138
|
-
super
|
199
|
+
super(self.class.new_from_hash_copying_default(other_hash))
|
139
200
|
end
|
140
201
|
|
202
|
+
# Same semantics as +reverse_merge+ but modifies the receiver in-place.
|
141
203
|
def reverse_merge!(other_hash)
|
142
204
|
replace(reverse_merge( other_hash ))
|
143
205
|
end
|
144
206
|
|
145
|
-
#
|
207
|
+
# Replaces the contents of this hash with other_hash.
|
208
|
+
#
|
209
|
+
# h = { "a" => 100, "b" => 200 }
|
210
|
+
# h.replace({ "c" => 300, "d" => 400 }) #=> {"c"=>300, "d"=>400}
|
211
|
+
def replace(other_hash)
|
212
|
+
super(self.class.new_from_hash_copying_default(other_hash))
|
213
|
+
end
|
214
|
+
|
215
|
+
# Removes the specified key from the hash.
|
146
216
|
def delete(key)
|
147
217
|
super(convert_key(key))
|
148
218
|
end
|
149
219
|
|
150
220
|
def stringify_keys!; self end
|
221
|
+
def deep_stringify_keys!; self end
|
151
222
|
def stringify_keys; dup end
|
223
|
+
def deep_stringify_keys; dup end
|
152
224
|
undef :symbolize_keys!
|
225
|
+
undef :deep_symbolize_keys!
|
153
226
|
def symbolize_keys; to_hash.symbolize_keys end
|
227
|
+
def deep_symbolize_keys; to_hash.deep_symbolize_keys end
|
154
228
|
def to_options!; self end
|
155
229
|
|
156
|
-
# Convert to a
|
230
|
+
# Convert to a regular hash with string keys.
|
157
231
|
def to_hash
|
158
232
|
Hash.new(default).merge!(self)
|
159
233
|
end
|
@@ -167,7 +241,8 @@ module ActiveSupport
|
|
167
241
|
if value.is_a? Hash
|
168
242
|
value.nested_under_indifferent_access
|
169
243
|
elsif value.is_a?(Array)
|
170
|
-
value.dup
|
244
|
+
value = value.dup if value.frozen?
|
245
|
+
value.map! { |e| convert_value(e) }
|
171
246
|
else
|
172
247
|
value
|
173
248
|
end
|