Skip to content

Commit

Permalink
Merge pull request #76 from justfalter/improve_performance
Browse files Browse the repository at this point in the history
Improve performance for serialization of entities
  • Loading branch information
dblock committed Jun 11, 2014
2 parents d1f20a1 + 026c2d8 commit 5daa2c9
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Next Release

* Your contribution here.
* [#77](https://github.com/intridea/grape-entity/pull/77): Fix compatibility with Rspec 3 - [@justfalter](https://github.com/justfalter).
* [#76](https://github.com/intridea/grape-entity/pull/76): Improve performance of entity serialization - [@justfalter](https://github.com/justfalter)

0.4.2 (2014-04-03)
==================
Expand Down
98 changes: 98 additions & 0 deletions bench/serializing.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'grape-entity'
require 'benchmark'

module Models
class School
attr_reader :classrooms
def initialize
@classrooms = []
end
end

class ClassRoom
attr_reader :students
attr_accessor :teacher
def initialize(opts = {})
@teacher = opts[:teacher]
@students = []
end
end

class Person
attr_accessor :name
def initialize(opts = {})
@name = opts[:name]
end
end

class Teacher < Models::Person
attr_accessor :tenure
def initialize(opts = {})
super(opts)
@tenure = opts[:tenure]
end
end

class Student < Models::Person
attr_reader :grade
def initialize(opts = {})
super(opts)
@grade = opts[:grade]
end
end
end

module Entities
class School < Grape::Entity
expose :classrooms, using: 'Entities::ClassRoom'
end

class ClassRoom < Grape::Entity
expose :teacher, using: 'Entities::Teacher'
expose :students, using: 'Entities::Student'
expose :size do |model, _opts|
model.students.count
end
end

class Person < Grape::Entity
expose :name
end

class Student < Entities::Person
expose :grade
expose :failing do |model, _opts|
model.grade == 'F'
end
end

class Teacher < Entities::Person
expose :tenure
end
end

teacher1 = Models::Teacher.new(name: 'John Smith', tenure: 2)
classroom1 = Models::ClassRoom.new(teacher: teacher1)
classroom1.students << Models::Student.new(name: 'Bobby', grade: 'A')
classroom1.students << Models::Student.new(name: 'Billy', grade: 'B')

teacher2 = Models::Teacher.new(name: 'Lisa Barns')
classroom2 = Models::ClassRoom.new(teacher: teacher2, tenure: 15)
classroom2.students << Models::Student.new(name: 'Eric', grade: 'A')
classroom2.students << Models::Student.new(name: 'Eddie', grade: 'C')
classroom2.students << Models::Student.new(name: 'Arnie', grade: 'C')
classroom2.students << Models::Student.new(name: 'Alvin', grade: 'F')
school = Models::School.new
school.classrooms << classroom1
school.classrooms << classroom2

iters = 5000

Benchmark.bm do |bm|
bm.report('serializing') do
iters.times do
Entities::School.represent(school, serializable: true)
end
end
end
44 changes: 37 additions & 7 deletions lib/grape_entity/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ def self.expose(*args, &block)

args.each do |attribute|
unless @nested_attributes.empty?
orig_attribute = attribute.to_sym
attribute = "#{@nested_attributes.last}__#{attribute}"
nested_attribute_names_hash[attribute.to_sym] = orig_attribute
options[:nested] = true
nested_exposures_hash[@nested_attributes.last.to_sym] ||= {}
nested_exposures_hash[@nested_attributes.last.to_sym][attribute.to_sym] = options
Expand Down Expand Up @@ -175,7 +177,9 @@ def self.with_options(options)
# are symbolized references to methods on the containing object, the values are
# the options that were passed into expose.
def self.exposures
@exposures ||= {}
return @exposures unless @exposures.nil?

@exposures = {}

if superclass.respond_to? :exposures
@exposures = superclass.exposures.merge(@exposures)
Expand All @@ -185,20 +189,39 @@ def self.exposures
end

class << self
attr_accessor :_nested_attribute_names_hash
attr_accessor :_nested_exposures_hash

def nested_attribute_names_hash
self._nested_attribute_names_hash ||= {}
end

def nested_exposures_hash
self._nested_exposures_hash ||= {}
end

def nested_attribute_names
return @nested_attribute_names unless @nested_attribute_names.nil?

@nested_attribute_names = {}.merge(nested_attribute_names_hash)

if superclass.respond_to? :nested_attribute_names
@nested_attribute_names = superclass.nested_attribute_names.deep_merge(@nested_attribute_names)
end

@nested_attribute_names
end

def nested_exposures
value = nested_exposures_hash
return @nested_exposures unless @nested_exposures.nil?

@nested_exposures = {}.merge(nested_exposures_hash)

if superclass.respond_to? :nested_exposures
value = superclass.nested_exposures.deep_merge(value)
@nested_exposures = superclass.nested_exposures.deep_merge(@nested_exposures)
end

value
@nested_exposures
end
end

Expand Down Expand Up @@ -404,7 +427,8 @@ def to_xml(options = {})
protected

def self.name_for(attribute)
attribute.to_s.split('__').last.to_sym
attribute = attribute.to_sym
nested_attribute_names[attribute] || attribute
end

def self.key_for(attribute)
Expand Down Expand Up @@ -475,7 +499,10 @@ def valid_exposure?(attribute, exposure_options)
end

def conditions_met?(exposure_options, options)
if_conditions = (exposure_options[:if_extras] || []).dup
if_conditions = []
unless exposure_options[:if_extras].nil?
if_conditions.concat(exposure_options[:if_extras])
end
if_conditions << exposure_options[:if] unless exposure_options[:if].nil?

if_conditions.each do |if_condition|
Expand All @@ -486,7 +513,10 @@ def conditions_met?(exposure_options, options)
end
end

unless_conditions = (exposure_options[:unless_extras] || []).dup
unless_conditions = []
unless exposure_options[:unless_extras].nil?
unless_conditions.concat(exposure_options[:unless_extras])
end
unless_conditions << exposure_options[:unless] unless exposure_options[:unless].nil?

unless_conditions.each do |unless_condition|
Expand Down

0 comments on commit 5daa2c9

Please sign in to comment.