activesupport 2.3.2 → 2.3.3

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 (43) hide show
  1. data/CHANGELOG +7 -0
  2. data/lib/active_support/cache.rb +14 -1
  3. data/lib/active_support/cache/mem_cache_store.rb +16 -10
  4. data/lib/active_support/cache/strategy/local_cache.rb +1 -1
  5. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  6. data/lib/active_support/core_ext/hash/conversions.rb +13 -4
  7. data/lib/active_support/core_ext/kernel/debugger.rb +4 -2
  8. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  9. data/lib/active_support/core_ext/module/delegation.rb +12 -3
  10. data/lib/active_support/core_ext/module/model_naming.rb +8 -6
  11. data/lib/active_support/core_ext/numeric/bytes.rb +15 -9
  12. data/lib/active_support/core_ext/string/access.rb +29 -5
  13. data/lib/active_support/duration.rb +4 -2
  14. data/lib/active_support/json.rb +1 -22
  15. data/lib/active_support/json/backends/jsongem.rb +38 -0
  16. data/lib/active_support/json/backends/yaml.rb +85 -0
  17. data/lib/active_support/json/decoding.rb +23 -72
  18. data/lib/active_support/json/encoders/date.rb +9 -8
  19. data/lib/active_support/json/encoders/date_time.rb +9 -8
  20. data/lib/active_support/json/encoders/enumerable.rb +14 -9
  21. data/lib/active_support/json/encoders/false_class.rb +4 -2
  22. data/lib/active_support/json/encoders/hash.rb +21 -11
  23. data/lib/active_support/json/encoders/nil_class.rb +4 -2
  24. data/lib/active_support/json/encoders/numeric.rb +16 -0
  25. data/lib/active_support/json/encoders/object.rb +6 -2
  26. data/lib/active_support/json/encoders/regexp.rb +4 -0
  27. data/lib/active_support/json/encoders/string.rb +5 -32
  28. data/lib/active_support/json/encoders/symbol.rb +2 -2
  29. data/lib/active_support/json/encoders/time.rb +9 -8
  30. data/lib/active_support/json/encoders/true_class.rb +4 -2
  31. data/lib/active_support/json/encoding.rb +80 -9
  32. data/lib/active_support/ordered_hash.rb +28 -0
  33. data/lib/active_support/test_case.rb +7 -7
  34. data/lib/active_support/testing/deprecation.rb +2 -0
  35. data/lib/active_support/time_with_zone.rb +9 -8
  36. data/lib/active_support/vendor.rb +6 -7
  37. data/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb +0 -1
  38. data/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb +0 -1
  39. data/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb +0 -1
  40. data/lib/active_support/vendor/{memcache-client-1.6.5 → memcache-client-1.7.4}/memcache.rb +242 -70
  41. data/lib/active_support/version.rb +1 -1
  42. data/lib/active_support/xml_mini/jdom.rb +162 -0
  43. metadata +10 -4
@@ -1,82 +1,33 @@
1
- require 'yaml'
2
- require 'strscan'
1
+ require 'active_support/core_ext/module/attribute_accessors'
3
2
 
4
3
  module ActiveSupport
4
+ # Look for and parse json strings that look like ISO 8601 times.
5
+ mattr_accessor :parse_json_times
6
+
5
7
  module JSON
6
- class ParseError < StandardError
7
- end
8
-
9
8
  class << self
10
- # Converts a JSON string into a Ruby object.
11
- def decode(json)
12
- YAML.load(convert_json_to_yaml(json))
13
- rescue ArgumentError => e
14
- raise ParseError, "Invalid JSON string"
15
- end
16
-
17
- protected
18
- # matches YAML-formatted dates
19
- DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)$/
9
+ delegate :decode, :to => :backend
20
10
 
21
- # Ensure that ":" and "," are always followed by a space
22
- def convert_json_to_yaml(json) #:nodoc:
23
- scanner, quoting, marks, pos, times = StringScanner.new(json), false, [], nil, []
24
- while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/)
25
- case char = scanner[1]
26
- when '"', "'"
27
- if !quoting
28
- quoting = char
29
- pos = scanner.pos
30
- elsif quoting == char
31
- if json[pos..scanner.pos-2] =~ DATE_REGEX
32
- # found a date, track the exact positions of the quotes so we can remove them later.
33
- # oh, and increment them for each current mark, each one is an extra padded space that bumps
34
- # the position in the final YAML output
35
- total_marks = marks.size
36
- times << pos+total_marks << scanner.pos+total_marks
37
- end
38
- quoting = false
39
- end
40
- when ":",","
41
- marks << scanner.pos - 1 unless quoting
42
- end
43
- end
11
+ def backend
12
+ self.backend = "Yaml" unless defined?(@backend)
13
+ @backend
14
+ end
44
15
 
45
- if marks.empty?
46
- json.gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
47
- ustr = $1
48
- if ustr.starts_with?('u')
49
- [ustr[1..-1].to_i(16)].pack("U")
50
- elsif ustr == '\\'
51
- '\\\\'
52
- else
53
- ustr
54
- end
55
- end
56
- else
57
- left_pos = [-1].push(*marks)
58
- right_pos = marks << scanner.pos + scanner.rest_size
59
- output = []
60
- left_pos.each_with_index do |left, i|
61
- scanner.pos = left.succ
62
- output << scanner.peek(right_pos[i] - scanner.pos + 1).gsub(/\\([\\\/]|u[[:xdigit:]]{4})/) do
63
- ustr = $1
64
- if ustr.starts_with?('u')
65
- [ustr[1..-1].to_i(16)].pack("U")
66
- elsif ustr == '\\'
67
- '\\\\'
68
- else
69
- ustr
70
- end
71
- end
72
- end
73
- output = output * " "
74
-
75
- times.each { |i| output[i-1] = ' ' }
76
- output.gsub!(/\\\//, '/')
77
- output
78
- end
16
+ def backend=(name)
17
+ if name.is_a?(Module)
18
+ @backend = name
19
+ else
20
+ require "active_support/json/backends/#{name.to_s.downcase}.rb"
21
+ @backend = ActiveSupport::JSON::Backends::const_get(name)
79
22
  end
23
+ end
24
+
25
+ def with_backend(name)
26
+ old_backend, self.backend = backend, name
27
+ yield
28
+ ensure
29
+ self.backend = old_backend
30
+ end
80
31
  end
81
32
  end
82
33
  end
@@ -1,21 +1,22 @@
1
1
  class Date
2
- # Returns a JSON string representing the date. If ActiveSupport.use_standard_json_time_format is set to true, the
3
- # ISO 8601 format is used.
2
+ # Coerces the date to a string for JSON encoding.
3
+ #
4
+ # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set.
4
5
  #
5
6
  # ==== Examples
6
7
  #
7
- # # With ActiveSupport.use_standard_json_time_format = true
8
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
8
9
  # Date.new(2005,2,1).to_json
9
10
  # # => "2005-02-01"
10
11
  #
11
- # # With ActiveSupport.use_standard_json_time_format = false
12
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
12
13
  # Date.new(2005,2,1).to_json
13
14
  # # => "2005/02/01"
14
- def to_json(options = nil)
15
- if ActiveSupport.use_standard_json_time_format
16
- %("#{strftime("%Y-%m-%d")}")
15
+ def as_json(options = nil)
16
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
17
+ strftime("%Y-%m-%d")
17
18
  else
18
- %("#{strftime("%Y/%m/%d")}")
19
+ strftime("%Y/%m/%d")
19
20
  end
20
21
  end
21
22
  end
@@ -1,21 +1,22 @@
1
1
  class DateTime
2
- # Returns a JSON string representing the datetime. If ActiveSupport.use_standard_json_time_format is set to true, the
3
- # ISO 8601 format is used.
2
+ # Coerces the datetime to a string for JSON encoding.
3
+ #
4
+ # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set.
4
5
  #
5
6
  # ==== Examples
6
7
  #
7
- # # With ActiveSupport.use_standard_json_time_format = true
8
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
8
9
  # DateTime.civil(2005,2,1,15,15,10).to_json
9
10
  # # => "2005-02-01T15:15:10+00:00"
10
11
  #
11
- # # With ActiveSupport.use_standard_json_time_format = false
12
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
12
13
  # DateTime.civil(2005,2,1,15,15,10).to_json
13
14
  # # => "2005/02/01 15:15:10 +0000"
14
- def to_json(options = nil)
15
- if ActiveSupport.use_standard_json_time_format
16
- xmlschema.inspect
15
+ def as_json(options = nil)
16
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
17
+ xmlschema
17
18
  else
18
- strftime('"%Y/%m/%d %H:%M:%S %z"')
19
+ strftime('%Y/%m/%d %H:%M:%S %z')
19
20
  end
20
21
  end
21
22
  end
@@ -1,12 +1,17 @@
1
1
  module Enumerable
2
- # Returns a JSON string representing the enumerable. Any +options+
3
- # given will be passed on to its elements. For example:
4
- #
5
- # users = User.find(:all)
6
- # # => users.to_json(:only => :name)
7
- #
8
- # will pass the <tt>:only => :name</tt> option to each user.
9
- def to_json(options = {}) #:nodoc:
10
- "[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ', '}]"
2
+ # Coerces the enumerable to an array for JSON encoding.
3
+ def as_json(options = nil) #:nodoc:
4
+ to_a
5
+ end
6
+ end
7
+
8
+ class Array
9
+ # Returns a JSON string representing the Array. +options+ are passed to each element.
10
+ def to_json(options = nil) #:nodoc:
11
+ "[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ','}]"
12
+ end
13
+
14
+ def as_json(options = nil) #:nodoc:
15
+ self
11
16
  end
12
17
  end
@@ -1,5 +1,7 @@
1
1
  class FalseClass
2
- def to_json(options = nil) #:nodoc:
3
- 'false'
2
+ AS_JSON = ActiveSupport::JSON::Variable.new('false').freeze
3
+
4
+ def as_json(options = nil) #:nodoc:
5
+ AS_JSON
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/array/wrapper'
2
+
1
3
  class Hash
2
4
  # Returns a JSON string representing the hash.
3
5
  #
@@ -28,19 +30,27 @@ class Hash
28
30
  # would pass the <tt>:include => :posts</tt> option to <tt>users</tt>,
29
31
  # allowing the posts association in the User model to be converted to JSON
30
32
  # as well.
31
- def to_json(options = {}) #:nodoc:
32
- hash_keys = self.keys
33
-
34
- if except = options[:except]
35
- hash_keys = hash_keys - Array.wrap(except)
36
- elsif only = options[:only]
37
- hash_keys = hash_keys & Array.wrap(only)
38
- end
33
+ def to_json(options = nil) #:nodoc:
34
+ hash = as_json(options)
39
35
 
40
36
  result = '{'
41
- result << hash_keys.map do |key|
42
- "#{ActiveSupport::JSON.encode(key.to_s)}: #{ActiveSupport::JSON.encode(self[key], options)}"
43
- end * ', '
37
+ result << hash.map do |key, value|
38
+ "#{ActiveSupport::JSON.encode(key.to_s)}:#{ActiveSupport::JSON.encode(value, options)}"
39
+ end * ','
44
40
  result << '}'
45
41
  end
42
+
43
+ def as_json(options = nil) #:nodoc:
44
+ if options
45
+ if attrs = options[:except]
46
+ except(*Array.wrap(attrs))
47
+ elsif attrs = options[:only]
48
+ slice(*Array.wrap(attrs))
49
+ else
50
+ self
51
+ end
52
+ else
53
+ self
54
+ end
55
+ end
46
56
  end
@@ -1,5 +1,7 @@
1
1
  class NilClass
2
- def to_json(options = nil) #:nodoc:
3
- 'null'
2
+ AS_JSON = ActiveSupport::JSON::Variable.new('null').freeze
3
+
4
+ def as_json(options = nil) #:nodoc:
5
+ AS_JSON
4
6
  end
5
7
  end
@@ -2,4 +2,20 @@ class Numeric
2
2
  def to_json(options = nil) #:nodoc:
3
3
  to_s
4
4
  end
5
+
6
+ def as_json(options = nil) #:nodoc:
7
+ self
8
+ end
9
+ end
10
+
11
+ class Float
12
+ def to_json(options = nil) #:nodoc:
13
+ to_s
14
+ end
15
+ end
16
+
17
+ class Integer
18
+ def to_json(options = nil) #:nodoc:
19
+ to_s
20
+ end
5
21
  end
@@ -1,6 +1,10 @@
1
1
  class Object
2
2
  # Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.
3
- def to_json(options = {})
4
- ActiveSupport::JSON.encode(instance_values, options)
3
+ def to_json(options = nil)
4
+ ActiveSupport::JSON.encode(as_json(options))
5
+ end
6
+
7
+ def as_json(options = nil)
8
+ instance_values
5
9
  end
6
10
  end
@@ -2,4 +2,8 @@ class Regexp
2
2
  def to_json(options = nil) #:nodoc:
3
3
  inspect
4
4
  end
5
+
6
+ def as_json(options = nil) #:nodoc:
7
+ self
8
+ end
5
9
  end
@@ -1,36 +1,9 @@
1
- module ActiveSupport
2
- module JSON
3
- module Encoding
4
- mattr_accessor :escape_regex
5
-
6
- ESCAPED_CHARS = {
7
- "\010" => '\b',
8
- "\f" => '\f',
9
- "\n" => '\n',
10
- "\r" => '\r',
11
- "\t" => '\t',
12
- '"' => '\"',
13
- '\\' => '\\\\',
14
- '>' => '\u003E',
15
- '<' => '\u003C',
16
- '&' => '\u0026'
17
- }
18
- end
19
- end
20
- end
21
-
22
- ActiveSupport.escape_html_entities_in_json = true
23
-
24
1
  class String
25
2
  def to_json(options = nil) #:nodoc:
26
- json = '"' + gsub(ActiveSupport::JSON::Encoding.escape_regex) { |s|
27
- ActiveSupport::JSON::Encoding::ESCAPED_CHARS[s]
28
- }
29
- json.force_encoding('ascii-8bit') if respond_to?(:force_encoding)
30
- json.gsub(/([\xC0-\xDF][\x80-\xBF]|
31
- [\xE0-\xEF][\x80-\xBF]{2}|
32
- [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
33
- s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&')
34
- } + '"'
3
+ ActiveSupport::JSON::Encoding.escape(self)
4
+ end
5
+
6
+ def as_json(options = nil) #:nodoc:
7
+ self
35
8
  end
36
9
  end
@@ -1,5 +1,5 @@
1
1
  class Symbol
2
- def to_json(options = {}) #:nodoc:
3
- ActiveSupport::JSON.encode(to_s, options)
2
+ def as_json(options = nil) #:nodoc:
3
+ to_s
4
4
  end
5
5
  end
@@ -1,21 +1,22 @@
1
1
  class Time
2
- # Returns a JSON string representing the time. If ActiveSupport.use_standard_json_time_format is set to true, the
3
- # ISO 8601 format is used.
2
+ # Coerces the time to a string for JSON encoding.
3
+ #
4
+ # ISO 8601 format is used if ActiveSupport::JSON::Encoding.use_standard_json_time_format is set.
4
5
  #
5
6
  # ==== Examples
6
7
  #
7
- # # With ActiveSupport.use_standard_json_time_format = true
8
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
8
9
  # Time.utc(2005,2,1,15,15,10).to_json
9
10
  # # => "2005-02-01T15:15:10Z"
10
11
  #
11
- # # With ActiveSupport.use_standard_json_time_format = false
12
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
12
13
  # Time.utc(2005,2,1,15,15,10).to_json
13
14
  # # => "2005/02/01 15:15:10 +0000"
14
- def to_json(options = nil)
15
- if ActiveSupport.use_standard_json_time_format
16
- xmlschema.inspect
15
+ def as_json(options = nil)
16
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
17
+ xmlschema
17
18
  else
18
- %("#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}")
19
+ %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
19
20
  end
20
21
  end
21
22
  end
@@ -1,5 +1,7 @@
1
1
  class TrueClass
2
- def to_json(options = nil) #:nodoc:
3
- 'true'
2
+ AS_JSON = ActiveSupport::JSON::Variable.new('true').freeze
3
+
4
+ def as_json(options = nil) #:nodoc:
5
+ AS_JSON
4
6
  end
5
7
  end
@@ -1,20 +1,91 @@
1
+ # encoding: utf-8
2
+ require 'active_support/core_ext/module/delegation'
3
+ require 'active_support/deprecation'
4
+
1
5
  module ActiveSupport
6
+ class << self
7
+ delegate :use_standard_json_time_format, :use_standard_json_time_format=,
8
+ :escape_html_entities_in_json, :escape_html_entities_in_json=,
9
+ :to => :'ActiveSupport::JSON::Encoding'
10
+ end
11
+
2
12
  module JSON
3
- class CircularReferenceError < StandardError
13
+ # matches YAML-formatted dates
14
+ DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
15
+
16
+ class << self
17
+ delegate :encode, :to => :'ActiveSupport::JSON::Encoding'
4
18
  end
5
19
 
6
- # Converts a Ruby object into a JSON string.
7
- def self.encode(value, options = {})
8
- seen = (options[:seen] ||= [])
9
- raise CircularReferenceError, 'object references itself' if seen.include?(value)
10
- seen << value
11
- value.send(:to_json, options)
12
- ensure
13
- seen.pop
20
+ module Encoding #:nodoc:
21
+ class CircularReferenceError < StandardError
22
+ end
23
+
24
+ ESCAPED_CHARS = {
25
+ "\010" => '\b',
26
+ "\f" => '\f',
27
+ "\n" => '\n',
28
+ "\r" => '\r',
29
+ "\t" => '\t',
30
+ '"' => '\"',
31
+ '\\' => '\\\\',
32
+ '>' => '\u003E',
33
+ '<' => '\u003C',
34
+ '&' => '\u0026' }
35
+
36
+ class << self
37
+ # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format.
38
+ attr_accessor :use_standard_json_time_format
39
+
40
+ attr_accessor :escape_regex
41
+ attr_reader :escape_html_entities_in_json
42
+
43
+ def escape_html_entities_in_json=(value)
44
+ self.escape_regex = \
45
+ if @escape_html_entities_in_json = value
46
+ /[\010\f\n\r\t"\\><&]/
47
+ else
48
+ /[\010\f\n\r\t"\\]/
49
+ end
50
+ end
51
+
52
+ def escape(string)
53
+ string = string.dup.force_encoding(::Encoding::BINARY) if string.respond_to?(:force_encoding)
54
+ json = string.
55
+ gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
56
+ gsub(/([\xC0-\xDF][\x80-\xBF]|
57
+ [\xE0-\xEF][\x80-\xBF]{2}|
58
+ [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
59
+ s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
60
+ }
61
+ %("#{json}")
62
+ end
63
+
64
+ # Converts a Ruby object into a JSON string.
65
+ def encode(value, options = nil)
66
+ options = {} unless Hash === options
67
+ seen = (options[:seen] ||= [])
68
+ raise CircularReferenceError, 'object references itself' if seen.include?(value)
69
+ seen << value
70
+ value.to_json(options)
71
+ ensure
72
+ seen.pop
73
+ end
74
+ end
75
+
76
+ self.escape_html_entities_in_json = true
14
77
  end
78
+
79
+ CircularReferenceError = Deprecation::DeprecatedConstantProxy.new('ActiveSupport::JSON::CircularReferenceError', Encoding::CircularReferenceError)
15
80
  end
16
81
  end
17
82
 
83
+ # Hack to load json gem first so we can overwrite its to_json.
84
+ begin
85
+ require 'json'
86
+ rescue LoadError
87
+ end
88
+
18
89
  require 'active_support/json/variable'
19
90
  require 'active_support/json/encoders/date'
20
91
  require 'active_support/json/encoders/date_time'