Merge pull request #233 from SamSaffron/fix

Optimised performance for attribute extraction
This commit is contained in:
Steve Klabnik 2013-03-14 14:22:27 -07:00
commit 6408b73e3c
4 changed files with 64 additions and 12 deletions

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ spec/reports
test/tmp
test/version_tmp
tmp
*.swp

View File

@ -10,4 +10,9 @@ Rake::TestTask.new(:test) do |t|
t.verbose = true
end
desc 'Benchmark'
task :bench do
load 'bench/perf.rb'
end
task :default => :test

43
bench/perf.rb Normal file
View File

@ -0,0 +1,43 @@
require "rubygems"
require "bundler/setup"
require "active_model_serializers"
require "active_support/json"
require "benchmark"
class User < Struct.new(:id,:name,:age,:about)
include ActiveModel::SerializerSupport
def fast_hash
h = {
id: read_attribute_for_serialization(:id),
name: read_attribute_for_serialization(:name),
about: read_attribute_for_serialization(:about)
}
h[:age] = read_attribute_for_serialization(:age) if age > 18
h
end
end
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :age, :about
def include_age?
object.age > 18
end
end
u = User.new(1, "sam", 10, "about")
s = UserSerializer.new(u)
n = 100000
Benchmark.bmbm {|x|
x.report("init") { n.times { UserSerializer.new(u) } }
x.report("fast_hash") { n.times { u.fast_hash } }
x.report("attributes") { n.times { UserSerializer.new(u).attributes } }
x.report("serializable_hash") { n.times { UserSerializer.new(u).serializable_hash } }
}

View File

@ -96,6 +96,7 @@ module ActiveModel
end
define_include_method attr
end
def associate(klass, attrs) #:nodoc:
@ -284,13 +285,9 @@ module ActiveModel
# object without the root.
def serializable_hash
return nil if @object.nil?
instrument(:serialize, :serializer => self.class.name) do
@node = attributes
instrument :associations do
include_associations! if _embed
end
@node
end
@node = attributes
include_associations! if _embed
@node
end
def include_associations!
@ -381,13 +378,19 @@ module ActiveModel
# Returns a hash representation of the serializable
# object attributes.
def attributes
hash = {}
_fast_attributes
rescue NameError
method = "def _fast_attributes\n"
_attributes.each do |name,key|
hash[key] = read_attribute_for_serialization(name) if include?(name)
end
method << " h = {}\n"
hash
_attributes.each do |name,key|
method << " h[:#{key}] = read_attribute_for_serialization(:#{name}) if send #{INCLUDE_METHODS[name].inspect}\n"
end
method << " h\nend"
self.class.class_eval method
_fast_attributes
end
# Returns options[:scope]