Skip to content

Commit

Permalink
Speed up xml serializer by computing values just once and remove unec…
Browse files Browse the repository at this point in the history
…essary code duplication.
  • Loading branch information
josevalim committed Apr 22, 2010
1 parent 81fb742 commit 9476daa
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 29 deletions.
35 changes: 17 additions & 18 deletions activemodel/lib/active_model/serializers/xml.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/hash/conversions'
require 'active_support/core_ext/hash/slice'

module ActiveModel
module Serializers
Expand All @@ -12,8 +13,10 @@ class Serializer #:nodoc:
class Attribute #:nodoc:
attr_reader :name, :value, :type

def initialize(name, serializable)
def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
@raw_value = raw_value || @serializable.send(name)

@type = compute_type
@value = compute_value
end
Expand Down Expand Up @@ -51,28 +54,25 @@ def decorations(include_types = true)

protected
def compute_type
value = @serializable.send(name)
type = Hash::XML_TYPE_NAMES[value.class.name]
type ||= :string if value.respond_to?(:to_str)
type = Hash::XML_TYPE_NAMES[@raw_value.class.name]
type ||= :string if @raw_value.respond_to?(:to_str)
type ||= :yaml
type
end

def compute_value
value = @serializable.send(name)

if formatter = Hash::XML_FORMATTING[type.to_s]
value ? formatter.call(value) : nil
@raw_value ? formatter.call(@raw_value) : nil
else
value
@raw_value
end
end
end

class MethodAttribute < Attribute #:nodoc:
protected
def compute_type
Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
Hash::XML_TYPE_NAMES[@raw_value.class.name] || :string
end
end

Expand All @@ -92,25 +92,24 @@ def initialize(serializable, options = nil)
# then because <tt>:except</tt> is set to a default value, the second
# level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
# <tt>:only</tt> is set, always delete <tt>:except</tt>.
def serializable_attribute_names
attribute_names = @serializable.attributes.keys.sort

def serializable_attributes_hash
attributes = @serializable.attributes
if options[:only].any?
attribute_names &= options[:only]
attributes.slice(*options[:only])
elsif options[:except].any?
attribute_names -= options[:except]
attributes.except(*options[:except])
else
attributes
end

attribute_names
end

def serializable_attributes
serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
serializable_attributes_hash.map { |name, value| self.class::Attribute.new(name, @serializable, value) }
end

def serializable_method_attributes
Array.wrap(options[:methods]).inject([]) do |methods, name|
methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
methods << self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
methods
end
end
Expand Down
11 changes: 0 additions & 11 deletions activerecord/lib/active_record/serializers/xml_serializer.rb
Expand Up @@ -182,17 +182,6 @@ def initialize(*args)
options[:except] |= Array.wrap(@serializable.class.inheritance_column)
end

def serializable_attributes
serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
end

def serializable_method_attributes
Array.wrap(options[:methods]).inject([]) do |method_attributes, name|
method_attributes << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
method_attributes
end
end

def add_associations(association, records, opts)
if records.is_a?(Enumerable)
tag = reformat_name(association.to_s)
Expand Down

0 comments on commit 9476daa

Please sign in to comment.