Skip to content

Commit e6b72ca

Browse files
committed
Add serialization helpers
- Added `index` attribute type that automatically generates a link list compatible with media_types-serialization. - Added support for `collection` to automatically look up a previously defined schema when passing a view.
1 parent 11e546f commit e6b72ca

File tree

5 files changed

+61
-5
lines changed

5 files changed

+61
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- Add ability to define multiple versions using one block.
66
- Added ability to mark certain attributes as optional when validating with `loose: true` and required otherwise.
7+
- Added `index` attribute type that automatically generates a link list compatible with media_types-serialization.
8+
- Added support for `collection` to automatically look up a previously defined schema when passing a view.
79

810
## 2.1.1
911

lib/media_types/errors.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,11 @@ def initialize(mod:)
1515
super(format('Unable to change key type expectation for %<mod>s since its current expectation is already used', mod: mod.name))
1616
end
1717
end
18+
19+
class CollectionDefinitionNotFound < StandardError
20+
def initialize(current, target)
21+
super(format('Unable to use %<target>s as a collection inside %<current>s, no such schema has been defined.', current: current, target: target))
22+
end
23+
end
1824
end
1925
end

lib/media_types/scheme.rb

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,13 @@ class Scheme
9494
#
9595
# @see MissingValidation
9696
#
97-
def initialize(allow_empty: false, expected_type: ::Object, &block)
97+
def initialize(allow_empty: false, expected_type: ::Object, current_type: nil, registry: nil, &block)
9898
self.rules = Rules.new(allow_empty: allow_empty, expected_type: expected_type)
9999
self.type_attributes = {}
100100
self.fixtures = []
101101
self.asserted_sane = false
102+
@registry = registry
103+
@current_type = current_type
102104

103105
instance_exec(&block) if block_given?
104106
end
@@ -270,7 +272,7 @@ def any(scheme = nil, expected_type: ::Hash, allow_empty: false, &block)
270272
return rules.default = Attribute.new(scheme)
271273
end
272274

273-
rules.default = Scheme.new(allow_empty: allow_empty, expected_type: expected_type, &block)
275+
rules.default = Scheme.new(allow_empty: allow_empty, expected_type: expected_type, registry: @registry, current_type: @current_type, &block)
274276
end
275277

276278
##
@@ -348,10 +350,20 @@ def not_strict
348350
# MyMedia.valid?({ foo: [{ required: 'test', number: 42 }, { required: 'other', number: 0 }] })
349351
# # => true
350352
#
351-
def collection(key, scheme = nil, allow_empty: false, expected_type: ::Array, optional: false, &block)
353+
def collection(key, scheme = nil, view: nil, allow_empty: false, expected_type: ::Array, optional: false, &block)
352354
raise ConflictingTypeDefinitionError, 'You cannot apply a block to a non-hash typed collection, either remove the type or the block' if scheme != ::Hash && block_given? && !scheme.nil?
353355

354356
unless block_given?
357+
if scheme.nil?
358+
dependent_key = @current_type.as_key.dup
359+
dependent_key[1] = view
360+
361+
unless @registry.has_key? dependent_key
362+
raise Errors::CollectionDefinitionNotFound.new(@current_type.override_suffix('json').to_s, @current_type.view(view).override_suffix('json').to_s)
363+
end
364+
scheme = @registry[dependent_key]
365+
end
366+
355367
return rules.add(
356368
key,
357369
EnumerationOfType.new(
@@ -363,7 +375,16 @@ def collection(key, scheme = nil, allow_empty: false, expected_type: ::Array, op
363375
)
364376
end
365377

366-
rules.add(key, Scheme.new(allow_empty: allow_empty, expected_type: expected_type, &block), optional: optional)
378+
rules.add(key, Scheme.new(allow_empty: allow_empty, expected_type: expected_type, registry: @registry, current_type: @current_type, &block), optional: optional)
379+
end
380+
381+
##
382+
# Expect an index of links
383+
#
384+
def index(optional: false)
385+
collection(:_links, optional: optional) do
386+
link :_self
387+
end
367388
end
368389

369390
##

lib/media_types/validations.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Validations
2525
# @see Constructable
2626
# @see Scheme
2727
#
28-
def initialize(media_type, registry = {}, scheme = Scheme.new, &block)
28+
def initialize(media_type, registry = {}, scheme = Scheme.new(registry: registry, current_type: media_type), &block)
2929
self.media_type = media_type
3030
self.registry = registry.merge!(media_type.as_key => scheme)
3131
self.scheme = scheme

test/media_types/dsl/collection_test.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,33 @@ def self.organisation
305305
end
306306
end
307307

308+
309+
class IndexCollectionType
310+
include MediaTypes::Dsl
311+
312+
def self.organisation
313+
'acme'
314+
end
315+
316+
use_name 'index_test'
317+
318+
validations do
319+
version 1 do
320+
attribute :bar, Numeric
321+
end
322+
323+
view :index do
324+
version 1 do
325+
collection :_embedded
326+
end
327+
end
328+
end
329+
end
330+
331+
def test_index_collections
332+
assert IndexCollectionType.view(:index).version(1).validate!({ _embedded: [{ bar: 42 }] }), 'Expected input to be valid'
333+
end
334+
308335
end
309336
end
310337
end

0 commit comments

Comments
 (0)