activesupport 4.2.5 → 4.2.9
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 +175 -0
- data/lib/active_support.rb +9 -0
- data/lib/active_support/cache/mem_cache_store.rb +1 -1
- data/lib/active_support/callbacks.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +0 -2
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +22 -2
- data/lib/active_support/core_ext/date_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/enumerable.rb +16 -0
- data/lib/active_support/core_ext/hash/compact.rb +19 -15
- data/lib/active_support/core_ext/hash/conversions.rb +1 -2
- data/lib/active_support/core_ext/hash/transform_values.rb +2 -2
- data/lib/active_support/core_ext/marshal.rb +8 -5
- data/lib/active_support/core_ext/numeric/conversions.rb +9 -1
- data/lib/active_support/core_ext/object/duplicable.rb +58 -32
- data/lib/active_support/core_ext/string/access.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/time/calculations.rb +10 -1
- data/lib/active_support/core_ext/time/compatibility.rb +14 -0
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/hash_with_indifferent_access.rb +9 -0
- data/lib/active_support/inflector/methods.rb +1 -1
- data/lib/active_support/logger.rb +50 -0
- data/lib/active_support/logger_silence.rb +7 -4
- data/lib/active_support/logger_thread_safe_level.rb +32 -0
- data/lib/active_support/message_encryptor.rb +8 -1
- data/lib/active_support/per_thread_registry.rb +2 -0
- data/lib/active_support/security_utils.rb +7 -0
- data/lib/active_support/testing/time_helpers.rb +16 -13
- data/lib/active_support/time_with_zone.rb +28 -16
- data/lib/active_support/values/time_zone.rb +5 -3
- data/lib/active_support/xml_mini.rb +30 -15
- data/lib/active_support/xml_mini/libxml.rb +1 -3
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
- data/lib/active_support/xml_mini/nokogiri.rb +1 -3
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
- data/lib/active_support/xml_mini/rexml.rb +1 -3
- metadata +7 -23
@@ -1,7 +1,7 @@
|
|
1
1
|
#--
|
2
|
-
# Most objects are cloneable, but not all. For example you can't dup
|
2
|
+
# Most objects are cloneable, but not all. For example you can't dup methods:
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# method(:puts).dup # => TypeError: allocator undefined for Method
|
5
5
|
#
|
6
6
|
# Classes may signal their instances are not duplicable removing +dup+/+clone+
|
7
7
|
# or raising exceptions from them. So, to dup an arbitrary object you normally
|
@@ -27,52 +27,78 @@ class Object
|
|
27
27
|
end
|
28
28
|
|
29
29
|
class NilClass
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
begin
|
31
|
+
nil.dup
|
32
|
+
rescue TypeError
|
33
|
+
|
34
|
+
# +nil+ is not duplicable:
|
35
|
+
#
|
36
|
+
# nil.duplicable? # => false
|
37
|
+
# nil.dup # => TypeError: can't dup NilClass
|
38
|
+
def duplicable?
|
39
|
+
false
|
40
|
+
end
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
39
44
|
class FalseClass
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
begin
|
46
|
+
false.dup
|
47
|
+
rescue TypeError
|
48
|
+
|
49
|
+
# +false+ is not duplicable:
|
50
|
+
#
|
51
|
+
# false.duplicable? # => false
|
52
|
+
# false.dup # => TypeError: can't dup FalseClass
|
53
|
+
def duplicable?
|
54
|
+
false
|
55
|
+
end
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
49
59
|
class TrueClass
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
begin
|
61
|
+
true.dup
|
62
|
+
rescue TypeError
|
63
|
+
|
64
|
+
# +true+ is not duplicable:
|
65
|
+
#
|
66
|
+
# true.duplicable? # => false
|
67
|
+
# true.dup # => TypeError: can't dup TrueClass
|
68
|
+
def duplicable?
|
69
|
+
false
|
70
|
+
end
|
56
71
|
end
|
57
72
|
end
|
58
73
|
|
59
74
|
class Symbol
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
75
|
+
begin
|
76
|
+
:symbol.dup # Ruby 2.4.x.
|
77
|
+
'symbol_from_string'.to_sym.dup # Some symbols can't `dup` in Ruby 2.4.0.
|
78
|
+
rescue TypeError
|
79
|
+
|
80
|
+
# Symbols are not duplicable:
|
81
|
+
#
|
82
|
+
# :my_symbol.duplicable? # => false
|
83
|
+
# :my_symbol.dup # => TypeError: can't dup Symbol
|
84
|
+
def duplicable?
|
85
|
+
false
|
86
|
+
end
|
66
87
|
end
|
67
88
|
end
|
68
89
|
|
69
90
|
class Numeric
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
91
|
+
begin
|
92
|
+
1.dup
|
93
|
+
rescue TypeError
|
94
|
+
|
95
|
+
# Numbers are not duplicable:
|
96
|
+
#
|
97
|
+
# 3.duplicable? # => false
|
98
|
+
# 3.dup # => TypeError: can't dup Integer
|
99
|
+
def duplicable?
|
100
|
+
false
|
101
|
+
end
|
76
102
|
end
|
77
103
|
end
|
78
104
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class String
|
2
|
-
# If you pass a single
|
2
|
+
# If you pass a single integer, returns a substring of one character at that
|
3
3
|
# position. The first character of the string is at position 0, the next at
|
4
4
|
# position 1, and so on. If a range is supplied, a substring containing
|
5
5
|
# characters at offsets given by the range is returned. In both cases, if an
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/time/acts_like'
|
2
2
|
require 'active_support/core_ext/time/calculations'
|
3
|
+
require 'active_support/core_ext/time/compatibility'
|
3
4
|
require 'active_support/core_ext/time/conversions'
|
4
5
|
require 'active_support/core_ext/time/marshal'
|
5
6
|
require 'active_support/core_ext/time/zones'
|
@@ -63,6 +63,13 @@ class Time
|
|
63
63
|
end_of_day.to_i - to_i
|
64
64
|
end
|
65
65
|
|
66
|
+
# Returns the fraction of a second as a +Rational+
|
67
|
+
#
|
68
|
+
# Time.new(2012, 8, 29, 0, 0, 0.5).sec_fraction # => (1/2)
|
69
|
+
def sec_fraction
|
70
|
+
subsec
|
71
|
+
end
|
72
|
+
|
66
73
|
# Returns a new Time where one or more of the elements have been changed according
|
67
74
|
# to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
|
68
75
|
# <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
|
@@ -250,7 +257,9 @@ class Time
|
|
250
257
|
# can be chronologically compared with a Time
|
251
258
|
def compare_with_coercion(other)
|
252
259
|
# we're avoiding Time#to_datetime cause it's expensive
|
253
|
-
if other.
|
260
|
+
if other.class == Time
|
261
|
+
compare_without_coercion(other)
|
262
|
+
elsif other.is_a?(Time)
|
254
263
|
compare_without_coercion(other.to_time)
|
255
264
|
else
|
256
265
|
to_datetime <=> other
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "active_support/core_ext/date_and_time/compatibility"
|
2
|
+
require "active_support/core_ext/module/remove_method"
|
3
|
+
|
4
|
+
class Time
|
5
|
+
include DateAndTime::Compatibility
|
6
|
+
|
7
|
+
remove_possible_method :to_time
|
8
|
+
|
9
|
+
# Either return +self+ or the time in the local system timezone depending
|
10
|
+
# on the setting of +ActiveSupport.to_time_preserves_timezone+.
|
11
|
+
def to_time
|
12
|
+
preserve_timezone ? self : getlocal
|
13
|
+
end
|
14
|
+
end
|
@@ -245,6 +245,15 @@ module ActiveSupport
|
|
245
245
|
dup.tap { |hash| hash.reject!(*args, &block) }
|
246
246
|
end
|
247
247
|
|
248
|
+
def transform_values(*args, &block)
|
249
|
+
return to_enum(:transform_values) unless block_given?
|
250
|
+
dup.tap { |hash| hash.transform_values!(*args, &block) }
|
251
|
+
end
|
252
|
+
|
253
|
+
def compact
|
254
|
+
dup.tap(&:compact!)
|
255
|
+
end
|
256
|
+
|
248
257
|
# Convert to a regular hash with string keys.
|
249
258
|
def to_hash
|
250
259
|
_new_hash = Hash.new
|
@@ -153,7 +153,7 @@ module ActiveSupport
|
|
153
153
|
# 'TheManWithoutAPast'.titleize # => "The Man Without A Past"
|
154
154
|
# 'raiders_of_the_lost_ark'.titleize # => "Raiders Of The Lost Ark"
|
155
155
|
def titleize(word)
|
156
|
-
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) {
|
156
|
+
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
|
157
157
|
end
|
158
158
|
|
159
159
|
# Create the name of a table like Rails does for models to table names. This
|
@@ -1,11 +1,24 @@
|
|
1
1
|
require 'active_support/core_ext/module/attribute_accessors'
|
2
2
|
require 'active_support/logger_silence'
|
3
|
+
require 'active_support/logger_thread_safe_level'
|
3
4
|
require 'logger'
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
class Logger < ::Logger
|
8
|
+
include ActiveSupport::LoggerThreadSafeLevel
|
7
9
|
include LoggerSilence
|
8
10
|
|
11
|
+
# Returns true if the logger destination matches one of the sources
|
12
|
+
#
|
13
|
+
# logger = Logger.new(STDOUT)
|
14
|
+
# ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
|
15
|
+
# # => true
|
16
|
+
def self.logger_outputs_to?(logger, *sources)
|
17
|
+
logdev = logger.instance_variable_get("@logdev")
|
18
|
+
logger_source = logdev.dev if logdev.respond_to?(:dev)
|
19
|
+
sources.any? { |source| source == logger_source }
|
20
|
+
end
|
21
|
+
|
9
22
|
# Broadcasts logs to multiple loggers.
|
10
23
|
def self.broadcast(logger) # :nodoc:
|
11
24
|
Module.new do
|
@@ -38,12 +51,49 @@ module ActiveSupport
|
|
38
51
|
logger.level = level
|
39
52
|
super(level)
|
40
53
|
end
|
54
|
+
|
55
|
+
define_method(:local_level=) do |level|
|
56
|
+
logger.local_level = level if logger.respond_to?(:local_level=)
|
57
|
+
super(level) if respond_to?(:local_level=)
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method(:silence) do |level = Logger::ERROR, &block|
|
61
|
+
if logger.respond_to?(:silence) && logger.method(:silence).owner != ::Kernel
|
62
|
+
logger.silence(level) do
|
63
|
+
if respond_to?(:silence) && method(:silence).owner != ::Kernel
|
64
|
+
super(level, &block)
|
65
|
+
else
|
66
|
+
block.call(self)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
else
|
70
|
+
if respond_to?(:silence) && method(:silence).owner != ::Kernel
|
71
|
+
super(level, &block)
|
72
|
+
else
|
73
|
+
block.call(self)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
41
77
|
end
|
42
78
|
end
|
43
79
|
|
44
80
|
def initialize(*args)
|
45
81
|
super
|
46
82
|
@formatter = SimpleFormatter.new
|
83
|
+
after_initialize if respond_to? :after_initialize
|
84
|
+
end
|
85
|
+
|
86
|
+
def add(severity, message = nil, progname = nil, &block)
|
87
|
+
return true if @logdev.nil? || (severity || UNKNOWN) < level
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
91
|
+
Logger::Severity.constants.each do |severity|
|
92
|
+
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
93
|
+
def #{severity.downcase}? # def debug?
|
94
|
+
Logger::#{severity} >= level # DEBUG >= level
|
95
|
+
end # end
|
96
|
+
EOT
|
47
97
|
end
|
48
98
|
|
49
99
|
# Simple formatter which only displays the message.
|
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'active_support/concern'
|
2
|
+
require 'thread_safe'
|
2
3
|
|
3
4
|
module LoggerSilence
|
4
5
|
extend ActiveSupport::Concern
|
5
|
-
|
6
|
+
|
6
7
|
included do
|
7
8
|
cattr_accessor :silencer
|
8
9
|
self.silencer = true
|
@@ -12,13 +13,15 @@ module LoggerSilence
|
|
12
13
|
def silence(temporary_level = Logger::ERROR)
|
13
14
|
if silencer
|
14
15
|
begin
|
15
|
-
|
16
|
+
old_local_level = local_level
|
17
|
+
self.local_level = temporary_level
|
18
|
+
|
16
19
|
yield self
|
17
20
|
ensure
|
18
|
-
self.
|
21
|
+
self.local_level = old_local_level
|
19
22
|
end
|
20
23
|
else
|
21
24
|
yield self
|
22
25
|
end
|
23
26
|
end
|
24
|
-
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'thread_safe'
|
3
|
+
|
4
|
+
module ActiveSupport
|
5
|
+
module LoggerThreadSafeLevel
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def after_initialize
|
9
|
+
@local_levels = ThreadSafe::Cache.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def local_log_id
|
13
|
+
Thread.current.__id__
|
14
|
+
end
|
15
|
+
|
16
|
+
def local_level
|
17
|
+
@local_levels[local_log_id]
|
18
|
+
end
|
19
|
+
|
20
|
+
def local_level=(level)
|
21
|
+
if level
|
22
|
+
@local_levels[local_log_id] = level
|
23
|
+
else
|
24
|
+
@local_levels.delete(local_log_id)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def level
|
29
|
+
local_level || super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -18,6 +18,8 @@ module ActiveSupport
|
|
18
18
|
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
|
19
19
|
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
|
20
20
|
class MessageEncryptor
|
21
|
+
DEFAULT_CIPHER = "aes-256-cbc"
|
22
|
+
|
21
23
|
module NullSerializer #:nodoc:
|
22
24
|
def self.load(value)
|
23
25
|
value
|
@@ -64,6 +66,11 @@ module ActiveSupport
|
|
64
66
|
_decrypt(verifier.verify(value))
|
65
67
|
end
|
66
68
|
|
69
|
+
# Given a cipher, returns the key length of the cipher to help generate the key of desired size
|
70
|
+
def self.key_len(cipher = DEFAULT_CIPHER)
|
71
|
+
OpenSSL::Cipher.new(cipher).key_len
|
72
|
+
end
|
73
|
+
|
67
74
|
private
|
68
75
|
|
69
76
|
def _encrypt(value)
|
@@ -97,7 +104,7 @@ module ActiveSupport
|
|
97
104
|
end
|
98
105
|
|
99
106
|
def new_cipher
|
100
|
-
OpenSSL::Cipher
|
107
|
+
OpenSSL::Cipher.new(@cipher)
|
101
108
|
end
|
102
109
|
|
103
110
|
def verifier
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
module SecurityUtils
|
3
5
|
# Constant time string comparison.
|
@@ -16,5 +18,10 @@ module ActiveSupport
|
|
16
18
|
res == 0
|
17
19
|
end
|
18
20
|
module_function :secure_compare
|
21
|
+
|
22
|
+
def variable_size_secure_compare(a, b) # :nodoc:
|
23
|
+
secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
|
24
|
+
end
|
25
|
+
module_function :variable_size_secure_compare
|
19
26
|
end
|
20
27
|
end
|
@@ -7,7 +7,7 @@ module ActiveSupport
|
|
7
7
|
@stubs = {}
|
8
8
|
end
|
9
9
|
|
10
|
-
def stub_object(object, method_name,
|
10
|
+
def stub_object(object, method_name, &block)
|
11
11
|
key = [object.object_id, method_name]
|
12
12
|
|
13
13
|
if stub = @stubs[key]
|
@@ -19,7 +19,7 @@ module ActiveSupport
|
|
19
19
|
@stubs[key] = Stub.new(object, method_name, new_name)
|
20
20
|
|
21
21
|
object.singleton_class.send :alias_method, new_name, method_name
|
22
|
-
object.define_singleton_method(method_name)
|
22
|
+
object.define_singleton_method(method_name, &block)
|
23
23
|
end
|
24
24
|
|
25
25
|
def unstub_all!
|
@@ -42,12 +42,13 @@ module ActiveSupport
|
|
42
42
|
# Containing helpers that helps you test passage of time.
|
43
43
|
module TimeHelpers
|
44
44
|
# Changes current time to the time in the future or in the past by a given time difference by
|
45
|
-
# stubbing +Time.now+ and +
|
45
|
+
# stubbing +Time.now+, +Date.today+, and +DateTime.now+.
|
46
46
|
#
|
47
|
-
# Time.current
|
47
|
+
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
48
48
|
# travel 1.day
|
49
|
-
# Time.current
|
50
|
-
# Date.current
|
49
|
+
# Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
|
50
|
+
# Date.current # => Sun, 10 Nov 2013
|
51
|
+
# DateTime.current # => Sun, 10 Nov 2013 15:34:49 -0500
|
51
52
|
#
|
52
53
|
# This method also accepts a block, which will return the current time back to its original
|
53
54
|
# state at the end of the block:
|
@@ -61,13 +62,14 @@ module ActiveSupport
|
|
61
62
|
travel_to Time.now + duration, &block
|
62
63
|
end
|
63
64
|
|
64
|
-
# Changes current time to the given time by stubbing +Time.now
|
65
|
-
# +Date.today+ to return the time or date passed into this method.
|
65
|
+
# Changes current time to the given time by stubbing +Time.now+,
|
66
|
+
# +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
|
66
67
|
#
|
67
|
-
# Time.current
|
68
|
+
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
68
69
|
# travel_to Time.new(2004, 11, 24, 01, 04, 44)
|
69
|
-
# Time.current
|
70
|
-
# Date.current
|
70
|
+
# Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
|
71
|
+
# Date.current # => Wed, 24 Nov 2004
|
72
|
+
# DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
|
71
73
|
#
|
72
74
|
# Dates are taken as their timestamp at the beginning of the day in the
|
73
75
|
# application time zone. <tt>Time.current</tt> returns said timestamp,
|
@@ -97,8 +99,9 @@ module ActiveSupport
|
|
97
99
|
now = date_or_time.to_time.change(usec: 0)
|
98
100
|
end
|
99
101
|
|
100
|
-
simple_stubs.stub_object(Time, :now
|
101
|
-
simple_stubs.stub_object(Date, :today
|
102
|
+
simple_stubs.stub_object(Time, :now) { at(now.to_i) }
|
103
|
+
simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
|
104
|
+
simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
|
102
105
|
|
103
106
|
if block_given?
|
104
107
|
begin
|