Skip to content

Commit

Permalink
Merge pull request #134 from etehtsea/refactoring
Browse files Browse the repository at this point in the history
Some subtle improvements
  • Loading branch information
dblock committed Jun 4, 2015
2 parents d207258 + a55cf24 commit 11914e8
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 82 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* [#114](https://github.com/intridea/grape-entity/pull/114): Added 'only' option that selects which attributes should be returned - [@estevaoam](https://github.com/estevaoam).
* [#115](https://github.com/intridea/grape-entity/pull/115): Allowing 'root' to be inherited from parent to child entities - [@guidoprincess](https://github.com/guidoprincess).
* [#121](https://github.com/intridea/grape-entity/pull/122): Sublcassed Entity#documentation properly handles unexposed params - [@dan-corneanu](https://github.com/dan-corneanu).
* [#134](https://github.com/intridea/grape-entity/pull/134): Subclasses no longer affected in all cases by `unexpose` in parent - [@etehtsea](https://github.com/etehtsea).
* Your contribution here.

0.4.5 (2015-03-10)
Expand Down
94 changes: 25 additions & 69 deletions lib/grape_entity/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ def entity(options = {})
end
end

class << self
# Returns exposures that have been declared for this Entity or
# ancestors. The keys are symbolized references to methods on the
# containing object, the values are the options that were passed into expose.
# @return [Hash] of exposures
attr_accessor :exposures
# Returns all formatters that are registered for this and it's ancestors
# @return [Hash] of formatters
attr_accessor :formatters
attr_accessor :nested_attribute_names
attr_accessor :nested_exposures
end

def self.inherited(subclass)
subclass.exposures = exposures.try(:dup) || {}
subclass.nested_exposures = nested_exposures.try(:dup) || {}
subclass.nested_attribute_names = nested_attribute_names.try(:dup) || {}
subclass.formatters = formatters.try(:dup) || {}
end

# This method is the primary means by which you will declare what attributes
# should be exposed by the entity.
#
Expand Down Expand Up @@ -141,14 +161,13 @@ 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
attribute = "#{@nested_attributes.last}__#{attribute}".to_sym
nested_attribute_names[attribute] = 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
nested_exposures.deep_merge!(@nested_attributes.last.to_sym => { attribute => options })
end

exposures[attribute.to_sym] = options
exposures[attribute] = options

# Nested exposures are given in a block with no parameters.
if block_given? && block.parameters.empty?
Expand Down Expand Up @@ -178,64 +197,12 @@ def self.with_options(options)
@block_options.pop
end

# Returns a hash of exposures that have been declared for this Entity or ancestors. The keys
# are symbolized references to methods on the containing object, the values are
# the options that were passed into expose.
def self.exposures
return @exposures unless @exposures.nil?

@exposures = {}

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

@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
return @nested_exposures unless @nested_exposures.nil?

@nested_exposures = {}.merge(nested_exposures_hash)

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

@nested_exposures
end
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.
def self.documentation
@documentation ||= exposures.each_with_object({}) do |(attribute, exposure_options), memo|
unless exposure_options[:documentation].nil? || exposure_options[:documentation].empty?
if exposure_options[:documentation].present?
memo[key_for(attribute)] = exposure_options[:documentation]
end
end
Expand Down Expand Up @@ -272,17 +239,6 @@ def self.format_with(name, &block)
formatters[name.to_sym] = block
end

# Returns a hash of all formatters that are registered for this and it's ancestors.
def self.formatters
@formatters ||= {}

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

@formatters
end

# This allows you to set a root element name for your representation.
#
# @param plural [String] the root key to use when representing
Expand Down
15 changes: 2 additions & 13 deletions spec/grape_entity/entity_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -296,23 +296,12 @@ class Parent < Person
expect(subject.exposures).to eq(name: {}, email: {})
end

# the following 2 behaviors are testing because it is not most intuitive and could be confusing
context 'when called from the parent class' do
it 'remove from parent and all child classes that have not locked down their attributes with an .exposures call' do
context 'when called from the parent class' do
it 'remove from parent and do not remove from child classes' do
subject.expose :name, :email
child_class = Class.new(subject)
subject.unexpose :email

expect(subject.exposures).to eq(name: {})
expect(child_class.exposures).to eq(name: {})
end

it 'remove from parent and do not remove from child classes that have locked down their attributes with an .exposures call' do
subject.expose :name, :email
child_class = Class.new(subject)
child_class.exposures
subject.unexpose :email

expect(subject.exposures).to eq(name: {})
expect(child_class.exposures).to eq(name: {}, email: {})
end
Expand Down

0 comments on commit 11914e8

Please sign in to comment.