Skip to content

Commit

Permalink
Improved nested exposures performance, nested exposures doubling fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
AMar4enko committed Feb 28, 2014
1 parent b8c4fe4 commit bec5d81
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ Next Release
============

* Your contribution here.
* [#60] (https://github.com/intridea/grape-entity/issues/59) Performance issues introduced by nested exposures - [@AlexYankee](https://github.com/AlexYankee).
* [#60] (https://github.com/intridea/grape-entity/issues/57) Nested exposure double-exposes a field - [@AlexYankee](https://github.com/AlexYankee).

0.4.1 (2014-02-13)
==================
Expand Down
18 changes: 16 additions & 2 deletions lib/grape_entity/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,13 @@ def self.expose(*args, &block)
options[:proc] = block if block_given? && block.parameters.any?

@nested_attributes ||= []

args.each do |attribute|
unless @nested_attributes.empty?
attribute = "#{@nested_attributes.last}__#{attribute}"
options[:nested] = true
nested_exposures[@nested_attributes.last.to_sym] ||= {}
nested_exposures[@nested_attributes.last.to_sym][attribute.to_sym] = options
end

exposures[attribute.to_sym] = options
Expand Down Expand Up @@ -180,6 +184,16 @@ def self.exposures
@exposures
end

def self.nested_exposures
@nested_exposures ||= {}

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

@nested_exposures
end

# Returns a hash, the keys are symbolized references to fields in the entity,
# the values are document keys in the entity's documentation key. When calling
# #docmentation, any exposure without a documentation key will be ignored.
Expand Down Expand Up @@ -324,7 +338,7 @@ def exposures
end

def valid_exposures
exposures.select do |attribute, exposure_options|
exposures.reject { |a, options| options[:nested] }.select do |attribute, exposure_options|
valid_exposure?(attribute, exposure_options)
end
end
Expand Down Expand Up @@ -390,7 +404,7 @@ def self.key_for(attribute)
end

def self.nested_exposures_for(attribute)
exposures.select { |a, _| a.to_s =~ /^#{attribute}__/ }
nested_exposures[attribute] || {}
end

def value_for(attribute, options = {})
Expand Down
27 changes: 24 additions & 3 deletions spec/grape_entity/entity_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ class BogusEntity < Grape::Entity

subject.exposures.should == {
awesome: {},
awesome__nested: {},
awesome__nested__moar_nested: { as: 'weee' },
awesome__another_nested: { using: 'Awesome' }
awesome__nested: { nested: true },
awesome__nested__moar_nested: { as: 'weee', nested: true },
awesome__another_nested: { using: 'Awesome', nested: true }
}
end

Expand All @@ -110,6 +110,26 @@ class BogusEntity < Grape::Entity
}
end

it 'does not represent attributes, declared inside nested exposure, outside of it' do
subject.expose :awesome do
subject.expose(:nested) { |_| "value" }
subject.expose(:another_nested) { |_| "value" }
subject.expose :second_level_nested do
subject.expose(:deeply_exposed_attr) { |_| "value" }
end
end

subject.represent({}).serializable_hash.should == {
awesome: {
nested: "value",
another_nested: "value",
second_level_nested: {
deeply_exposed_attr: "value"
}
}
}
end

it 'is safe if its nested exposures are safe' do
subject.with_options safe: true do
subject.expose :awesome do
Expand All @@ -121,6 +141,7 @@ class BogusEntity < Grape::Entity
end

valid_keys = subject.represent({}).valid_exposures.keys

valid_keys.include?(:awesome).should == true && \
valid_keys.include?(:not_awesome).should == false
end
Expand Down

0 comments on commit bec5d81

Please sign in to comment.