Skip to content

Commit 4f95c65

Browse files
committed
Fixes issue with class reopening and inheriting.
Exposures and formatters should appear in inherited classes even if added after inheriting.
1 parent 079993f commit 4f95c65

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

lib/grape_entity/entity.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,16 @@ class << self
103103
# Returns all formatters that are registered for this and it's ancestors
104104
# @return [Hash] of formatters
105105
attr_accessor :formatters
106+
attr_accessor :inherited_entities
106107
end
107108

109+
@inherited_entities = []
110+
108111
def self.inherited(subclass)
109112
subclass.root_exposure = root_exposure.try(:dup) || build_root_exposure
110113
subclass.formatters = formatters.try(:dup) || {}
114+
self.inherited_entities << subclass
115+
subclass.inherited_entities = []
111116
end
112117

113118
# This method is the primary means by which you will declare what attributes
@@ -173,6 +178,10 @@ def self.expose(*args, &block)
173178
@nesting_stack.pop
174179
end
175180
end
181+
182+
inherited_entities.each do |entity|
183+
entity.expose(*args, &block)
184+
end
176185
end
177186

178187
def self.build_root_exposure
@@ -264,6 +273,10 @@ def self.documentation
264273
def self.format_with(name, &block)
265274
fail ArgumentError, 'You must pass a block for formatters' unless block_given?
266275
formatters[name.to_sym] = block
276+
277+
inherited_entities.each do |entity|
278+
entity.format_with(name, &block)
279+
end
267280
end
268281

269282
# This allows you to set a root element name for your representation.

spec/grape_entity/entity_spec.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,18 @@ class Parent < Person
272272
expect(subject.represent({ name: 'bar' }, serializable: true)).to eq(email: nil, name: 'bar')
273273
expect(child_class.represent({ name: 'bar' }, serializable: true)).to eq(email: nil, name: 'foo')
274274
end
275+
276+
it 'supports class reopening' do
277+
subject.expose :name
278+
child_class = Class.new(subject)
279+
subject.expose :email
280+
281+
object = OpenStruct.new(name: 'bar', email: 'foo@bar')
282+
expected = { name: 'bar', email: 'foo@bar' }
283+
284+
expect(subject.represent(object, serializable: true)).to eq(expected)
285+
expect(child_class.represent(object, serializable: true)).to eq(expected)
286+
end
275287
end
276288

277289
context 'register formatters' do
@@ -290,6 +302,13 @@ class Parent < Person
290302
expect(child_class.formatters).to eq subject.formatters
291303
end
292304

305+
it 'inherits formatters from ancestors with reopening' do
306+
child_class = Class.new(subject)
307+
subject.format_with :timestamp, &date_formatter
308+
309+
expect(child_class.formatters).to eq subject.formatters
310+
end
311+
293312
it 'does not allow registering a formatter without a block' do
294313
expect { subject.format_with :foo }.to raise_error ArgumentError
295314
end

0 commit comments

Comments
 (0)