activesupport 4.1.0 → 4.1.11

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.

Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +209 -0
  3. data/lib/active_support/cache/strategy/local_cache.rb +1 -0
  4. data/lib/active_support/cache.rb +1 -1
  5. data/lib/active_support/callbacks.rb +118 -76
  6. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  7. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -11
  8. data/lib/active_support/core_ext/hash/keys.rb +38 -16
  9. data/lib/active_support/core_ext/object/duplicable.rb +10 -0
  10. data/lib/active_support/core_ext/object/json.rb +3 -3
  11. data/lib/active_support/core_ext/object/to_param.rb +1 -62
  12. data/lib/active_support/core_ext/object/to_query.rb +58 -7
  13. data/lib/active_support/core_ext/string/filters.rb +1 -1
  14. data/lib/active_support/core_ext/string/output_safety.rb +7 -3
  15. data/lib/active_support/core_ext/time/zones.rb +1 -0
  16. data/lib/active_support/dependencies.rb +4 -4
  17. data/lib/active_support/duration.rb +5 -1
  18. data/lib/active_support/gem_version.rb +1 -1
  19. data/lib/active_support/hash_with_indifferent_access.rb +2 -1
  20. data/lib/active_support/i18n_railtie.rb +5 -1
  21. data/lib/active_support/inflector/methods.rb +1 -1
  22. data/lib/active_support/json/encoding.rb +4 -0
  23. data/lib/active_support/multibyte/unicode.rb +0 -1
  24. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
  25. data/lib/active_support/number_helper/number_to_rounded_converter.rb +2 -6
  26. data/lib/active_support/option_merger.rb +1 -1
  27. data/lib/active_support/subscriber.rb +10 -1
  28. data/lib/active_support/values/time_zone.rb +5 -2
  29. data/lib/active_support/xml_mini/jdom.rb +6 -5
  30. data/lib/active_support/xml_mini/rexml.rb +6 -5
  31. data/lib/active_support/xml_mini.rb +3 -0
  32. metadata +3 -3
@@ -151,7 +151,9 @@ class DateTime
151
151
  # Layers additional behavior on DateTime#<=> so that Time and
152
152
  # ActiveSupport::TimeWithZone instances can be compared with a DateTime.
153
153
  def <=>(other)
154
- if other.respond_to? :to_datetime
154
+ if other.kind_of?(Infinity)
155
+ super
156
+ elsif other.respond_to? :to_datetime
155
157
  super other.to_datetime
156
158
  else
157
159
  nil
@@ -1,27 +1,38 @@
1
1
  class Hash
2
2
  # Returns a new hash with +self+ and +other_hash+ merged recursively.
3
3
  #
4
- # h1 = { x: { y: [4, 5, 6] }, z: [7, 8, 9] }
5
- # h2 = { x: { y: [7, 8, 9] }, z: 'xyz' }
4
+ # h1 = { a: true, b: { c: [1, 2, 3] } }
5
+ # h2 = { a: false, b: { x: [3, 4, 5] } }
6
6
  #
7
- # h1.deep_merge(h2) # => {x: {y: [7, 8, 9]}, z: "xyz"}
8
- # h2.deep_merge(h1) # => {x: {y: [4, 5, 6]}, z: [7, 8, 9]}
9
- # h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
10
- # # => {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
7
+ # h1.deep_merge(h2) #=> { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
8
+ #
9
+ # Like with Hash#merge in the standard library, a block can be provided
10
+ # to merge values:
11
+ #
12
+ # h1 = { a: 100, b: 200, c: { c1: 100 } }
13
+ # h2 = { b: 250, c: { c1: 200 } }
14
+ # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
15
+ # # => { a: 100, b: 450, c: { c1: 300 } }
11
16
  def deep_merge(other_hash, &block)
12
17
  dup.deep_merge!(other_hash, &block)
13
18
  end
14
19
 
15
20
  # Same as +deep_merge+, but modifies +self+.
16
21
  def deep_merge!(other_hash, &block)
17
- other_hash.each_pair do |k,v|
18
- tv = self[k]
19
- if tv.is_a?(Hash) && v.is_a?(Hash)
20
- self[k] = tv.deep_merge(v, &block)
22
+ other_hash.each_pair do |current_key, other_value|
23
+ this_value = self[current_key]
24
+
25
+ self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
26
+ this_value.deep_merge(other_value, &block)
21
27
  else
22
- self[k] = block && tv ? block.call(k, tv, v) : v
28
+ if block_given? && key?(current_key)
29
+ block.call(current_key, this_value, other_value)
30
+ else
31
+ other_value
32
+ end
23
33
  end
24
34
  end
35
+
25
36
  self
26
37
  end
27
38
  end
@@ -75,34 +75,26 @@ class Hash
75
75
 
76
76
  # Returns a new hash with all keys converted by the block operation.
77
77
  # This includes the keys from the root hash and from all
78
- # nested hashes.
78
+ # nested hashes and arrays.
79
79
  #
80
80
  # hash = { person: { name: 'Rob', age: '28' } }
81
81
  #
82
82
  # hash.deep_transform_keys{ |key| key.to_s.upcase }
83
83
  # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
84
84
  def deep_transform_keys(&block)
85
- result = {}
86
- each do |key, value|
87
- result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
88
- end
89
- result
85
+ _deep_transform_keys_in_object(self, &block)
90
86
  end
91
87
 
92
88
  # Destructively convert all keys by using the block operation.
93
89
  # This includes the keys from the root hash and from all
94
- # nested hashes.
90
+ # nested hashes and arrays.
95
91
  def deep_transform_keys!(&block)
96
- keys.each do |key|
97
- value = delete(key)
98
- self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
99
- end
100
- self
92
+ _deep_transform_keys_in_object!(self, &block)
101
93
  end
102
94
 
103
95
  # Returns a new hash with all keys converted to strings.
104
96
  # This includes the keys from the root hash and from all
105
- # nested hashes.
97
+ # nested hashes and arrays.
106
98
  #
107
99
  # hash = { person: { name: 'Rob', age: '28' } }
108
100
  #
@@ -114,14 +106,14 @@ class Hash
114
106
 
115
107
  # Destructively convert all keys to strings.
116
108
  # This includes the keys from the root hash and from all
117
- # nested hashes.
109
+ # nested hashes and arrays.
118
110
  def deep_stringify_keys!
119
111
  deep_transform_keys!{ |key| key.to_s }
120
112
  end
121
113
 
122
114
  # Returns a new hash with all keys converted to symbols, as long as
123
115
  # they respond to +to_sym+. This includes the keys from the root hash
124
- # and from all nested hashes.
116
+ # and from all nested hashes and arrays.
125
117
  #
126
118
  # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
127
119
  #
@@ -133,8 +125,38 @@ class Hash
133
125
 
134
126
  # Destructively convert all keys to symbols, as long as they respond
135
127
  # to +to_sym+. This includes the keys from the root hash and from all
136
- # nested hashes.
128
+ # nested hashes and arrays.
137
129
  def deep_symbolize_keys!
138
130
  deep_transform_keys!{ |key| key.to_sym rescue key }
139
131
  end
132
+
133
+ private
134
+ # support methods for deep transforming nested hashes and arrays
135
+ def _deep_transform_keys_in_object(object, &block)
136
+ case object
137
+ when Hash
138
+ object.each_with_object({}) do |(key, value), result|
139
+ result[yield(key)] = _deep_transform_keys_in_object(value, &block)
140
+ end
141
+ when Array
142
+ object.map {|e| _deep_transform_keys_in_object(e, &block) }
143
+ else
144
+ object
145
+ end
146
+ end
147
+
148
+ def _deep_transform_keys_in_object!(object, &block)
149
+ case object
150
+ when Hash
151
+ object.keys.each do |key|
152
+ value = object.delete(key)
153
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
154
+ end
155
+ object
156
+ when Array
157
+ object.map! {|e| _deep_transform_keys_in_object!(e, &block)}
158
+ else
159
+ object
160
+ end
161
+ end
140
162
  end
@@ -88,3 +88,13 @@ class BigDecimal
88
88
  # can't dup, so use superclass implementation
89
89
  end
90
90
  end
91
+
92
+ class Method
93
+ # Methods are not duplicable:
94
+ #
95
+ # method(:puts).duplicable? # => false
96
+ # method(:puts).dup # => TypeError: allocator undefined for Method
97
+ def duplicable?
98
+ false
99
+ end
100
+ end
@@ -162,7 +162,7 @@ end
162
162
 
163
163
  class Time
164
164
  def as_json(options = nil) #:nodoc:
165
- if ActiveSupport.use_standard_json_time_format
165
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
166
166
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
167
167
  else
168
168
  %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
@@ -172,7 +172,7 @@ end
172
172
 
173
173
  class Date
174
174
  def as_json(options = nil) #:nodoc:
175
- if ActiveSupport.use_standard_json_time_format
175
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
176
176
  strftime("%Y-%m-%d")
177
177
  else
178
178
  strftime("%Y/%m/%d")
@@ -182,7 +182,7 @@ end
182
182
 
183
183
  class DateTime
184
184
  def as_json(options = nil) #:nodoc:
185
- if ActiveSupport.use_standard_json_time_format
185
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
186
186
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
187
187
  else
188
188
  strftime('%Y/%m/%d %H:%M:%S %z')
@@ -1,62 +1 @@
1
- class Object
2
- # Alias of <tt>to_s</tt>.
3
- def to_param
4
- to_s
5
- end
6
- end
7
-
8
- class NilClass
9
- # Returns +self+.
10
- def to_param
11
- self
12
- end
13
- end
14
-
15
- class TrueClass
16
- # Returns +self+.
17
- def to_param
18
- self
19
- end
20
- end
21
-
22
- class FalseClass
23
- # Returns +self+.
24
- def to_param
25
- self
26
- end
27
- end
28
-
29
- class Array
30
- # Calls <tt>to_param</tt> on all its elements and joins the result with
31
- # slashes. This is used by <tt>url_for</tt> in Action Pack.
32
- def to_param
33
- collect { |e| e.to_param }.join '/'
34
- end
35
- end
36
-
37
- class Hash
38
- # Returns a string representation of the receiver suitable for use as a URL
39
- # query string:
40
- #
41
- # {name: 'David', nationality: 'Danish'}.to_param
42
- # # => "name=David&nationality=Danish"
43
- #
44
- # An optional namespace can be passed to enclose the param names:
45
- #
46
- # {name: 'David', nationality: 'Danish'}.to_param('user')
47
- # # => "user[name]=David&user[nationality]=Danish"
48
- #
49
- # The string pairs "key=value" that conform the query string
50
- # are sorted lexicographically in ascending order.
51
- #
52
- # This method is also aliased as +to_query+.
53
- def to_param(namespace = nil)
54
- if empty?
55
- namespace ? nil.to_query(namespace) : ''
56
- else
57
- collect do |key, value|
58
- value.to_query(namespace ? "#{namespace}[#{key}]" : key)
59
- end.sort! * '&'
60
- end
61
- end
62
- end
1
+ require 'active_support/core_ext/object/to_query'
@@ -1,17 +1,45 @@
1
- require 'active_support/core_ext/object/to_param'
2
-
3
1
  class Object
4
- # Converts an object into a string suitable for use as a URL query string, using the given <tt>key</tt> as the
5
- # param name.
6
- #
7
- # Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
2
+ # Alias of <tt>to_s</tt>.
3
+ def to_param
4
+ to_s
5
+ end
6
+
7
+ # Converts an object into a string suitable for use as a URL query string,
8
+ # using the given <tt>key</tt> as the param name.
8
9
  def to_query(key)
9
10
  require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
10
11
  "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
11
12
  end
12
13
  end
13
14
 
15
+ class NilClass
16
+ # Returns +self+.
17
+ def to_param
18
+ self
19
+ end
20
+ end
21
+
22
+ class TrueClass
23
+ # Returns +self+.
24
+ def to_param
25
+ self
26
+ end
27
+ end
28
+
29
+ class FalseClass
30
+ # Returns +self+.
31
+ def to_param
32
+ self
33
+ end
34
+ end
35
+
14
36
  class Array
37
+ # Calls <tt>to_param</tt> on all its elements and joins the result with
38
+ # slashes. This is used by <tt>url_for</tt> in Action Pack.
39
+ def to_param
40
+ collect { |e| e.to_param }.join '/'
41
+ end
42
+
15
43
  # Converts an array into a string suitable for use as a URL query string,
16
44
  # using the given +key+ as the param name.
17
45
  #
@@ -28,5 +56,28 @@ class Array
28
56
  end
29
57
 
30
58
  class Hash
31
- alias_method :to_query, :to_param
59
+ # Returns a string representation of the receiver suitable for use as a URL
60
+ # query string:
61
+ #
62
+ # {name: 'David', nationality: 'Danish'}.to_query
63
+ # # => "name=David&nationality=Danish"
64
+ #
65
+ # An optional namespace can be passed to enclose key names:
66
+ #
67
+ # {name: 'David', nationality: 'Danish'}.to_query('user')
68
+ # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
69
+ #
70
+ # The string pairs "key=value" that conform the query string
71
+ # are sorted lexicographically in ascending order.
72
+ #
73
+ # This method is also aliased as +to_param+.
74
+ def to_query(namespace = nil)
75
+ collect do |key, value|
76
+ unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
77
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
78
+ end
79
+ end.compact.sort! * '&'
80
+ end
81
+
82
+ alias_method :to_param, :to_query
32
83
  end
@@ -3,7 +3,7 @@ class String
3
3
  # the string, and then changing remaining consecutive whitespace
4
4
  # groups into one space each.
5
5
  #
6
- # Note that it handles both ASCII and Unicode whitespace like mongolian vowel separator (U+180E).
6
+ # Note that it handles both ASCII and Unicode whitespace.
7
7
  #
8
8
  # %{ Multi-line
9
9
  # string }.squish # => "Multi-line string"
@@ -6,7 +6,7 @@ class ERB
6
6
  HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
7
7
  JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
8
8
  HTML_ESCAPE_REGEXP = /[&"'><]/
9
- HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
9
+ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
10
10
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
11
11
 
12
12
  # A utility method for escaping HTML tag characters.
@@ -142,7 +142,11 @@ module ActiveSupport #:nodoc:
142
142
  else
143
143
  if html_safe?
144
144
  new_safe_buffer = super
145
- new_safe_buffer.instance_eval { @html_safe = true }
145
+
146
+ if new_safe_buffer
147
+ new_safe_buffer.instance_eval { @html_safe = true }
148
+ end
149
+
146
150
  new_safe_buffer
147
151
  else
148
152
  to_str[*args]
@@ -206,7 +210,7 @@ module ActiveSupport #:nodoc:
206
210
  end
207
211
 
208
212
  def encode_with(coder)
209
- coder.represent_scalar nil, to_str
213
+ coder.represent_object nil, to_str
210
214
  end
211
215
 
212
216
  UNSAFE_STRING_METHODS.each do |unsafe_method|
@@ -1,4 +1,5 @@
1
1
  require 'active_support/time_with_zone'
2
+ require 'active_support/core_ext/time/acts_like'
2
3
  require 'active_support/core_ext/date_and_time/zones'
3
4
 
4
5
  class Time
@@ -186,7 +186,7 @@ module ActiveSupport #:nodoc:
186
186
  # and we assume therefore the user wants to refer to a top-level constant.
187
187
  def guess_for_anonymous(const_name)
188
188
  if Object.const_defined?(const_name)
189
- raise NameError, "#{const_name} cannot be autoloaded from an anonymous class or module"
189
+ raise NameError.new "#{const_name} cannot be autoloaded from an anonymous class or module", const_name
190
190
  else
191
191
  Object
192
192
  end
@@ -515,9 +515,9 @@ module ActiveSupport #:nodoc:
515
515
  end
516
516
  end
517
517
 
518
- raise NameError,
519
- "uninitialized constant #{qualified_name}",
520
- caller.reject { |l| l.starts_with? __FILE__ }
518
+ name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
519
+ name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ })
520
+ raise name_error
521
521
  end
522
522
 
523
523
  # Remove the constants that have been autoloaded, and those that have been
@@ -49,6 +49,10 @@ module ActiveSupport
49
49
  end
50
50
  end
51
51
 
52
+ def eql?(other)
53
+ other.is_a?(Duration) && self == other
54
+ end
55
+
52
56
  def self.===(other) #:nodoc:
53
57
  other.is_a?(Duration)
54
58
  rescue ::NoMethodError
@@ -74,7 +78,7 @@ module ActiveSupport
74
78
  reduce(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }.
75
79
  sort_by {|unit, _ | [:years, :months, :days, :minutes, :seconds].index(unit)}.
76
80
  map {|unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}"}.
77
- to_sentence(:locale => :en)
81
+ to_sentence(locale: ::I18n.default_locale)
78
82
  end
79
83
 
80
84
  def as_json(options = nil) #:nodoc:
@@ -7,7 +7,7 @@ module ActiveSupport
7
7
  module VERSION
8
8
  MAJOR = 4
9
9
  MINOR = 1
10
- TINY = 0
10
+ TINY = 11
11
11
  PRE = nil
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")