aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r--activesupport/lib/active_support/benchmarkable.rb1
-rw-r--r--activesupport/lib/active_support/cache.rb1
-rw-r--r--activesupport/lib/active_support/cache/compressed_mem_cache_store.rb2
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb1
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb1
-rw-r--r--activesupport/lib/active_support/callbacks.rb77
-rw-r--r--activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/class/delegating_attributes.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/loading.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module/synchronization.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/object/extending.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_param.rb2
-rw-r--r--activesupport/lib/active_support/deprecation/method_wrappers.rb1
-rw-r--r--activesupport/lib/active_support/duration.rb1
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb1
-rw-r--r--activesupport/lib/active_support/message_verifier.rb3
-rw-r--r--activesupport/lib/active_support/rescuable.rb2
-rw-r--r--activesupport/lib/active_support/testing/performance.rb1
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb1
-rw-r--r--activesupport/lib/active_support/xml_mini/jdom.rb2
-rw-r--r--activesupport/lib/active_support/xml_mini/libxml.rb110
-rw-r--r--activesupport/lib/active_support/xml_mini/libxmlsax.rb84
-rw-r--r--activesupport/lib/active_support/xml_mini/nokogiri.rb51
-rw-r--r--activesupport/lib/active_support/xml_mini/nokogirisax.rb82
28 files changed, 309 insertions, 131 deletions
diff --git a/activesupport/lib/active_support/benchmarkable.rb b/activesupport/lib/active_support/benchmarkable.rb
index 6a41aab166..ee02ecb043 100644
--- a/activesupport/lib/active_support/benchmarkable.rb
+++ b/activesupport/lib/active_support/benchmarkable.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/benchmark'
+require 'active_support/core_ext/hash/keys'
module ActiveSupport
module Benchmarkable
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index f2d957f154..ad238c1d96 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -4,6 +4,7 @@ require 'active_support/core_ext/benchmark'
require 'active_support/core_ext/exception'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/object/to_param'
+require 'active_support/core_ext/string/inflections'
module ActiveSupport
# See ActiveSupport::Cache::Store for documentation.
diff --git a/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb b/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb
index d87eb17337..d2370d78c5 100644
--- a/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb
@@ -1,3 +1,5 @@
+require 'active_support/gzip'
+
module ActiveSupport
module Cache
class CompressedMemCacheStore < MemCacheStore
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index 1b6b820ca4..d584c9e254 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -1,4 +1,5 @@
require 'memcache'
+require 'active_support/core_ext/array/extract_options'
module ActiveSupport
module Cache
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index 5f6fe22416..86c7703c27 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/duplicable'
+require 'active_support/core_ext/string/inflections'
module ActiveSupport
module Cache
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 05bc453dbf..8719dc0e3f 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/object/metaclass'
module ActiveSupport
# Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
@@ -367,12 +368,6 @@ module ActiveSupport
method << "halted ? false : (block_given? ? value : true)"
method.compact.join("\n")
end
-
- def clone(klass)
- chain = CallbackChain.new(@name, @config.dup)
- callbacks = map { |c| c.clone(chain, klass) }
- chain.push(*callbacks)
- end
end
module ClassMethods
@@ -389,10 +384,16 @@ module ActiveSupport
# key. See #define_callbacks for more information.
#
def __define_runner(symbol) #:nodoc:
+ send("_update_#{symbol}_superclass_callbacks")
body = send("_#{symbol}_callbacks").compile(nil)
body, line = <<-RUBY_EVAL, __LINE__
def _run_#{symbol}_callbacks(key = nil, &blk)
+ if self.class.send("_update_#{symbol}_superclass_callbacks")
+ self.class.__define_runner(#{symbol.inspect})
+ return _run_#{symbol}_callbacks(key, &blk)
+ end
+
if key
name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
@@ -431,6 +432,8 @@ module ActiveSupport
# CallbackChain.
#
def __update_callbacks(name, filters = [], block = nil) #:nodoc:
+ send("_update_#{name}_superclass_callbacks")
+
type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
options = filters.last.is_a?(Hash) ? filters.pop : {}
filters.unshift(block) if block
@@ -470,7 +473,8 @@ module ActiveSupport
def set_callback(name, *filter_list, &block)
__update_callbacks(name, filter_list, block) do |chain, type, filters, options|
filters.map! do |filter|
- chain.delete_if {|c| c.matches?(type, filter) }
+ removed = chain.delete_if {|c| c.matches?(type, filter) }
+ send("_removed_#{name}_callbacks").push(*removed)
Callback.new(chain, filter, type, options.dup, self)
end
@@ -482,16 +486,17 @@ module ActiveSupport
#
def skip_callback(name, *filter_list, &block)
__update_callbacks(name, filter_list, block) do |chain, type, filters, options|
- chain = send("_#{name}_callbacks=", chain.clone(self))
-
filters.each do |filter|
filter = chain.find {|c| c.matches?(type, filter) }
if filter && options.any?
- filter.recompile!(options, options[:per_key] || {})
- else
- chain.delete(filter)
+ new_filter = filter.clone(chain, self)
+ chain.insert(chain.index(filter), new_filter)
+ new_filter.recompile!(options, options[:per_key] || {})
end
+
+ chain.delete(filter)
+ send("_removed_#{name}_callbacks") << filter
end
end
end
@@ -499,7 +504,9 @@ module ActiveSupport
# Reset callbacks for a given type.
#
def reset_callbacks(symbol)
- send("_#{symbol}_callbacks").clear
+ callbacks = send("_#{symbol}_callbacks")
+ callbacks.clear
+ send("_removed_#{symbol}_callbacks").concat(callbacks)
__define_runner(symbol)
end
@@ -546,14 +553,46 @@ module ActiveSupport
#
# Defaults to :kind.
#
- def define_callbacks(*symbols)
- config = symbols.last.is_a?(Hash) ? symbols.pop : {}
- symbols.each do |symbol|
- extlib_inheritable_accessor("_#{symbol}_callbacks") do
- CallbackChain.new(symbol, config)
+ def define_callbacks(*callbacks)
+ config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
+ callbacks.each do |callback|
+ extlib_inheritable_reader("_#{callback}_callbacks") do
+ CallbackChain.new(callback, config)
+ end
+
+ extlib_inheritable_reader("_removed_#{callback}_callbacks") do
+ []
end
- __define_runner(symbol)
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
+ def self._#{callback}_superclass_callbacks
+ if superclass.respond_to?(:_#{callback}_callbacks)
+ superclass._#{callback}_callbacks + superclass._#{callback}_superclass_callbacks
+ else
+ []
+ end
+ end
+
+ def self._update_#{callback}_superclass_callbacks
+ changed, index = false, 0
+
+ callbacks = (_#{callback}_superclass_callbacks -
+ _#{callback}_callbacks) - _removed_#{callback}_callbacks
+
+ callbacks.each do |callback|
+ if new_index = _#{callback}_callbacks.index(callback)
+ index = new_index + 1
+ else
+ changed = true
+ _#{callback}_callbacks.insert(index, callback)
+ index = index + 1
+ end
+ end
+ changed
+ end
+ METHOD
+
+ __define_runner(callback)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb b/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
index 1c3ef05526..d3c3575748 100644
--- a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
+++ b/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
@@ -1,3 +1,5 @@
+require 'cgi'
+
class CGI #:nodoc:
if RUBY_VERSION >= '1.9'
def self.escape_skipping_slashes(str)
diff --git a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
index 301c09fc73..72e0eefb0a 100644
--- a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
@@ -1,5 +1,4 @@
require 'active_support/core_ext/object/blank'
-require 'active_support/core_ext/object/duplicable'
require 'active_support/core_ext/array/extract_options'
class Class
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
index e4d22516c1..2b8e2b544f 100644
--- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -159,7 +159,7 @@ class Class
# (error out or do the same as other methods above) instead of silently
# moving on). In particular, this makes the return value of this function
# less useful.
- def extlib_inheritable_reader(*ivars)
+ def extlib_inheritable_reader(*ivars, &block)
options = ivars.extract_options!
ivars.each do |ivar|
@@ -178,6 +178,7 @@ class Class
end
RUBY
end
+ instance_variable_set(:"@#{ivar}", yield) if block_given?
end
end
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 2b76b93153..9d2ad2bbcf 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -1,6 +1,7 @@
require 'date'
require 'active_support/duration'
require 'active_support/core_ext/time/zones'
+require 'active_support/core_ext/object/acts_like'
class Date
class << self
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index e93abfa4a3..26979aa906 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -1,4 +1,5 @@
require 'rational' unless RUBY_VERSION >= '1.9.2'
+require 'active_support/core_ext/object/acts_like'
class DateTime
class << self
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 35ccec5df4..cfd840fb93 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -1,6 +1,8 @@
require 'active_support/time'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/hash/reverse_merge'
+require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/inflections'
class Hash
# This module exists to decorate files deserialized using Hash.from_xml with
diff --git a/activesupport/lib/active_support/core_ext/module/loading.rb b/activesupport/lib/active_support/core_ext/module/loading.rb
index 4b4b110b25..43d0578ae6 100644
--- a/activesupport/lib/active_support/core_ext/module/loading.rb
+++ b/activesupport/lib/active_support/core_ext/module/loading.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/inflections'
+
class Module
# Returns String#underscore applied to the module name minus trailing classes.
#
diff --git a/activesupport/lib/active_support/core_ext/module/synchronization.rb b/activesupport/lib/active_support/core_ext/module/synchronization.rb
index f72d512340..115b8abd4e 100644
--- a/activesupport/lib/active_support/core_ext/module/synchronization.rb
+++ b/activesupport/lib/active_support/core_ext/module/synchronization.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/module/aliasing'
+require 'active_support/core_ext/array/extract_options'
class Module
# Synchronize access around a method, delegating synchronization to a
diff --git a/activesupport/lib/active_support/core_ext/object/extending.rb b/activesupport/lib/active_support/core_ext/object/extending.rb
index de8121f274..b8b6970382 100644
--- a/activesupport/lib/active_support/core_ext/object/extending.rb
+++ b/activesupport/lib/active_support/core_ext/object/extending.rb
@@ -1,3 +1,6 @@
+require 'active_support/core_ext/class/removal'
+require 'active_support/core_ext/object/blank'
+
class Class
# Rubinius
if defined?(Class.__subclasses__)
diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb
index 7ca763cbad..49e41e919a 100644
--- a/activesupport/lib/active_support/core_ext/object/to_param.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_param.rb
@@ -1,3 +1,5 @@
+
+
class Object
# Alias of <tt>to_s</tt>.
def to_param
diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb
index deb29a82b8..cec8024b17 100644
--- a/activesupport/lib/active_support/deprecation/method_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/module/deprecation'
require 'active_support/core_ext/module/aliasing'
+require 'active_support/core_ext/array/extract_options'
module ActiveSupport
class << Deprecation
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 713ae1b671..c1f0e4bf81 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -1,5 +1,6 @@
require 'active_support/basic_object'
require 'active_support/core_ext/array/conversions'
+require 'active_support/core_ext/object/acts_like'
module ActiveSupport
# Provides accurate date and time measurements using Date#advance and
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index 347af9dc76..51fa626b45 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -1,4 +1,5 @@
require 'openssl'
+require 'active_support/base64'
module ActiveSupport
# MessageEncryptor is a simple way to encrypt values which get stored somewhere
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index 87e4b1ad33..6c46b68eaf 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -1,3 +1,6 @@
+require 'active_support/base64'
+require 'active_support/core_ext/object/blank'
+
module ActiveSupport
# MessageVerifier makes it easy to generate and verify messages which are signed
# to prevent tampering.
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
index f0119f5994..6e660f8647 100644
--- a/activesupport/lib/active_support/rescuable.rb
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -1,5 +1,7 @@
require 'active_support/core_ext/class/inheritable_attributes'
require 'active_support/core_ext/proc'
+require 'active_support/core_ext/string/inflections'
+require 'active_support/core_ext/array/extract_options'
module ActiveSupport
# Rescuable module adds support for easier exception handling.
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index 66e32fa5d7..24eea1e40b 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -4,6 +4,7 @@ begin
require 'fileutils'
require 'rails/version'
require 'active_support/core_ext/class/delegating_attributes'
+ require 'active_support/core_ext/string/inflections'
module ActiveSupport
module Testing
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 8304f6c434..6b554e7158 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -1,4 +1,5 @@
require "active_support/values/time_zone"
+require 'active_support/core_ext/object/acts_like'
module ActiveSupport
# A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are
diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb
index 5c3d93c4a1..48c1cb3fe9 100644
--- a/activesupport/lib/active_support/xml_mini/jdom.rb
+++ b/activesupport/lib/active_support/xml_mini/jdom.rb
@@ -3,6 +3,8 @@ raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFO
require 'jruby'
include Java
+require 'active_support/core_ext/object/blank'
+
import javax.xml.parsers.DocumentBuilder unless defined? DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory unless defined? DocumentBuilderFactory
import java.io.StringReader unless defined? StringReader
diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb
index 0f7ba1918b..9cf187302f 100644
--- a/activesupport/lib/active_support/xml_mini/libxml.rb
+++ b/activesupport/lib/active_support/xml_mini/libxml.rb
@@ -1,4 +1,6 @@
require 'libxml'
+require 'active_support/core_ext/object/returning'
+require 'active_support/core_ext/object/blank'
# = XmlMini LibXML implementation
module ActiveSupport
@@ -12,7 +14,7 @@ module ActiveSupport
if !data.respond_to?(:read)
data = StringIO.new(data || '')
end
-
+
char = data.getc
if char.nil?
{}
@@ -34,106 +36,42 @@ module LibXML #:nodoc:
end
module Node #:nodoc:
- CONTENT_ROOT = '__content__'
- LIB_XML_LIMIT = 30000000 # Hardcoded LibXML limit
+ CONTENT_ROOT = '__content__'.freeze
# Convert XML document to hash
#
# hash::
# Hash to merge the converted element into.
def to_hash(hash={})
- if text? || cdata?
- raise LibXML::XML::Error if hash[CONTENT_ROOT].to_s.length + content.length >= LIB_XML_LIMIT
- hash[CONTENT_ROOT] = hash[CONTENT_ROOT].to_s + content
- else
- sub_hash = insert_name_into_hash(hash, name)
- attributes_to_hash(sub_hash)
- if array?
- children_array_to_hash(sub_hash)
- elsif yaml?
- children_yaml_to_hash(sub_hash)
- else
- children_to_hash(sub_hash)
- end
- end
- hash
- end
+ node_hash = {}
- protected
-
- # Insert name into hash
- #
- # hash::
- # Hash to merge the converted element into.
- # name::
- # name to to merge into hash
- def insert_name_into_hash(hash, name)
- sub_hash = {}
- if hash[name]
- if !hash[name].kind_of? Array
- hash[name] = [hash[name]]
- end
- hash[name] << sub_hash
- else
- hash[name] = sub_hash
- end
- sub_hash
+ # Insert node hash into parent hash correctly.
+ case hash[name]
+ when Array then hash[name] << node_hash
+ when Hash then hash[name] = [hash[name], node_hash]
+ when nil then hash[name] = node_hash
end
- # Insert children into hash
- #
- # hash::
- # Hash to merge the children into.
- def children_to_hash(hash={})
- each { |child| child.to_hash(hash) }
-
- if hash.length > 1 && hash[CONTENT_ROOT].blank?
- hash.delete(CONTENT_ROOT)
+ # Handle child elements
+ each_child do |c|
+ if c.element?
+ c.to_hash(node_hash)
+ elsif c.text? || c.cdata?
+ node_hash[CONTENT_ROOT] ||= ''
+ node_hash[CONTENT_ROOT] << c.content
end
-
- attributes_to_hash(hash)
- hash
end
- # Convert xml attributes to hash
- #
- # hash::
- # Hash to merge the attributes into
- def attributes_to_hash(hash={})
- each_attr { |attr| hash[attr.name] = attr.value }
- hash
+ # Remove content node if it is blank
+ if node_hash.length > 1 && node_hash[CONTENT_ROOT].blank?
+ node_hash.delete(CONTENT_ROOT)
end
- # Convert array into hash
- #
- # hash::
- # Hash to merge the array into
- def children_array_to_hash(hash={})
- hash[child.name] = map do |child|
- returning({}) { |sub_hash| child.children_to_hash(sub_hash) }
- end
- hash
- end
-
- # Convert yaml into hash
- #
- # hash::
- # Hash to merge the yaml into
- def children_yaml_to_hash(hash = {})
- hash[CONTENT_ROOT] = content unless content.blank?
- hash
- end
-
- # Check if child is of type array
- def array?
- child? && child.next? && child.name == child.next.name
- end
-
- # Check if child is of type yaml
- def yaml?
- attributes.collect{|x| x.value}.include?('yaml')
- end
+ # Handle attributes
+ each_attr { |a| node_hash[a.name] = a.value }
+ hash
+ end
end
end
end
diff --git a/activesupport/lib/active_support/xml_mini/libxmlsax.rb b/activesupport/lib/active_support/xml_mini/libxmlsax.rb
new file mode 100644
index 0000000000..d7b2f4c5be
--- /dev/null
+++ b/activesupport/lib/active_support/xml_mini/libxmlsax.rb
@@ -0,0 +1,84 @@
+require 'libxml'
+
+# = XmlMini LibXML implementation using a SAX-based parser
+module ActiveSupport
+ module XmlMini_LibXMLSAX
+ extend self
+
+ # Class that will build the hash while the XML document
+ # is being parsed using SAX events.
+ class HashBuilder
+
+ include LibXML::XML::SaxParser::Callbacks
+
+ CONTENT_KEY = '__content__'.freeze
+ HASH_SIZE_KEY = '__hash_size__'.freeze
+
+ attr_reader :hash
+
+ def current_hash
+ @hash_stack.last
+ end
+
+ def on_start_document
+ @hash = { CONTENT_KEY => '' }
+ @hash_stack = [@hash]
+ end
+
+ def on_end_document
+ @hash = @hash_stack.pop
+ @hash.delete(CONTENT_KEY)
+ end
+
+ def on_start_element(name, attrs = {})
+ new_hash = { CONTENT_KEY => '' }.merge(attrs)
+ new_hash[HASH_SIZE_KEY] = new_hash.size + 1
+
+ case current_hash[name]
+ when Array then current_hash[name] << new_hash
+ when Hash then current_hash[name] = [current_hash[name], new_hash]
+ when nil then current_hash[name] = new_hash
+ end
+
+ @hash_stack.push(new_hash)
+ end
+
+ def on_end_element(name)
+ if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == ''
+ current_hash.delete(CONTENT_KEY)
+ end
+ @hash_stack.pop
+ end
+
+ def on_characters(string)
+ current_hash[CONTENT_KEY] << string
+ end
+
+ alias_method :on_cdata_block, :on_characters
+ end
+
+ attr_accessor :document_class
+ self.document_class = HashBuilder
+
+ def parse(data)
+ if !data.respond_to?(:read)
+ data = StringIO.new(data || '')
+ end
+
+ char = data.getc
+ if char.nil?
+ {}
+ else
+ data.ungetc(char)
+
+ LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER)
+ parser = LibXML::XML::SaxParser.io(data)
+ document = self.document_class.new
+
+ parser.callbacks = document
+ parser.parse
+ document.hash
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/xml_mini/nokogiri.rb b/activesupport/lib/active_support/xml_mini/nokogiri.rb
index 17bacd8441..eb61a7fc22 100644
--- a/activesupport/lib/active_support/xml_mini/nokogiri.rb
+++ b/activesupport/lib/active_support/xml_mini/nokogiri.rb
@@ -1,4 +1,5 @@
require 'nokogiri'
+require 'active_support/core_ext/object/blank'
# = XmlMini Nokogiri implementation
module ActiveSupport
@@ -12,13 +13,13 @@ module ActiveSupport
if !data.respond_to?(:read)
data = StringIO.new(data || '')
end
-
+
char = data.getc
if char.nil?
{}
else
data.ungetc(char)
- doc = Nokogiri::XML(data) { |cfg| cfg.noblanks }
+ doc = Nokogiri::XML(data)
raise doc.errors.first if doc.errors.length > 0
doc.to_hash
end
@@ -32,39 +33,41 @@ module ActiveSupport
end
module Node #:nodoc:
- CONTENT_ROOT = '__content__'
+ CONTENT_ROOT = '__content__'.freeze
# Convert XML document to hash
#
# hash::
# Hash to merge the converted element into.
- def to_hash(hash = {})
- attributes = attributes_as_hash
- if hash[name]
- hash[name] = [hash[name]].flatten
- hash[name] << attributes
- else
- hash[name] ||= attributes
- end
+ def to_hash(hash={})
+ node_hash = {}
- children.each { |child|
- next if child.blank? && 'file' != self['type']
+ # Insert node hash into parent hash correctly.
+ case hash[name]
+ when Array then hash[name] << node_hash
+ when Hash then hash[name] = [hash[name], node_hash]
+ when nil then hash[name] = node_hash
+ end
- if child.text? || child.cdata?
- (attributes[CONTENT_ROOT] ||= '') << child.content
- next
+ # Handle child elements
+ children.each do |c|
+ if c.element?
+ c.to_hash(node_hash)
+ elsif c.text? || c.cdata?
+ node_hash[CONTENT_ROOT] ||= ''
+ node_hash[CONTENT_ROOT] << c.content
end
+ end
- child.to_hash attributes
- }
+ # Remove content node if it is blank and there are child tags
+ if node_hash.length > 1 && node_hash[CONTENT_ROOT].blank?
+ node_hash.delete(CONTENT_ROOT)
+ end
- hash
- end
+ # Handle attributes
+ attribute_nodes.each { |a| node_hash[a.node_name] = a.value }
- def attributes_as_hash
- Hash[*(attribute_nodes.map { |node|
- [node.node_name, node.value]
- }.flatten)]
+ hash
end
end
end
diff --git a/activesupport/lib/active_support/xml_mini/nokogirisax.rb b/activesupport/lib/active_support/xml_mini/nokogirisax.rb
new file mode 100644
index 0000000000..d538a9110f
--- /dev/null
+++ b/activesupport/lib/active_support/xml_mini/nokogirisax.rb
@@ -0,0 +1,82 @@
+require 'nokogiri'
+
+# = XmlMini Nokogiri implementation using a SAX-based parser
+module ActiveSupport
+ module XmlMini_NokogiriSAX
+ extend self
+
+ # Class that will build the hash while the XML document
+ # is being parsed using SAX events.
+ class HashBuilder < Nokogiri::XML::SAX::Document
+
+ CONTENT_KEY = '__content__'.freeze
+ HASH_SIZE_KEY = '__hash_size__'.freeze
+
+ attr_reader :hash
+
+ def current_hash
+ @hash_stack.last
+ end
+
+ def start_document
+ @hash = {}
+ @hash_stack = [@hash]
+ end
+
+ def end_document
+ raise "Parse stack not empty!" if @hash_stack.size > 1
+ end
+
+ def error(error_message)
+ raise error_message
+ end
+
+ def start_element(name, attrs = [])
+ new_hash = { CONTENT_KEY => '' }
+ new_hash[attrs.shift] = attrs.shift while attrs.length > 0
+ new_hash[HASH_SIZE_KEY] = new_hash.size + 1
+
+ case current_hash[name]
+ when Array then current_hash[name] << new_hash
+ when Hash then current_hash[name] = [current_hash[name], new_hash]
+ when nil then current_hash[name] = new_hash
+ end
+
+ @hash_stack.push(new_hash)
+ end
+
+ def end_element(name)
+ if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == ''
+ current_hash.delete(CONTENT_KEY)
+ end
+ @hash_stack.pop
+ end
+
+ def characters(string)
+ current_hash[CONTENT_KEY] << string
+ end
+
+ alias_method :cdata_block, :characters
+ end
+
+ attr_accessor :document_class
+ self.document_class = HashBuilder
+
+ def parse(data)
+ if !data.respond_to?(:read)
+ data = StringIO.new(data || '')
+ end
+
+ char = data.getc
+ if char.nil?
+ {}
+ else
+ data.ungetc(char)
+ document = self.document_class.new
+ parser = Nokogiri::XML::SAX::Parser.new(document)
+ parser.parse(data)
+ document.hash
+ end
+ end
+ end
+end \ No newline at end of file