From e6b72caa880e8c95fd1b9cce21f2db8f8c303e23 Mon Sep 17 00:00:00 2001 From: Max Maton Date: Sun, 6 Aug 2023 15:34:49 +0000 Subject: [PATCH 1/2] 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. --- CHANGELOG.md | 2 ++ lib/media_types/errors.rb | 6 +++++ lib/media_types/scheme.rb | 29 +++++++++++++++++++++---- lib/media_types/validations.rb | 2 +- test/media_types/dsl/collection_test.rb | 27 +++++++++++++++++++++++ 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21ed0d96..0d0a9b35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - Add ability to define multiple versions using one block. - Added ability to mark certain attributes as optional when validating with `loose: true` and required otherwise. + - 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. ## 2.1.1 diff --git a/lib/media_types/errors.rb b/lib/media_types/errors.rb index e53f14be..d09c0a86 100644 --- a/lib/media_types/errors.rb +++ b/lib/media_types/errors.rb @@ -15,5 +15,11 @@ def initialize(mod:) super(format('Unable to change key type expectation for %s since its current expectation is already used', mod: mod.name)) end end + + class CollectionDefinitionNotFound < StandardError + def initialize(current, target) + super(format('Unable to use %s as a collection inside %s, no such schema has been defined.', current: current, target: target)) + end + end end end diff --git a/lib/media_types/scheme.rb b/lib/media_types/scheme.rb index 073770fc..4ba548d9 100644 --- a/lib/media_types/scheme.rb +++ b/lib/media_types/scheme.rb @@ -94,11 +94,13 @@ class Scheme # # @see MissingValidation # - def initialize(allow_empty: false, expected_type: ::Object, &block) + def initialize(allow_empty: false, expected_type: ::Object, current_type: nil, registry: nil, &block) self.rules = Rules.new(allow_empty: allow_empty, expected_type: expected_type) self.type_attributes = {} self.fixtures = [] self.asserted_sane = false + @registry = registry + @current_type = current_type instance_exec(&block) if block_given? end @@ -270,7 +272,7 @@ def any(scheme = nil, expected_type: ::Hash, allow_empty: false, &block) return rules.default = Attribute.new(scheme) end - rules.default = Scheme.new(allow_empty: allow_empty, expected_type: expected_type, &block) + rules.default = Scheme.new(allow_empty: allow_empty, expected_type: expected_type, registry: @registry, current_type: @current_type, &block) end ## @@ -348,10 +350,20 @@ def not_strict # MyMedia.valid?({ foo: [{ required: 'test', number: 42 }, { required: 'other', number: 0 }] }) # # => true # - def collection(key, scheme = nil, allow_empty: false, expected_type: ::Array, optional: false, &block) + def collection(key, scheme = nil, view: nil, allow_empty: false, expected_type: ::Array, optional: false, &block) 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? unless block_given? + if scheme.nil? + dependent_key = @current_type.as_key.dup + dependent_key[1] = view + + unless @registry.has_key? dependent_key + raise Errors::CollectionDefinitionNotFound.new(@current_type.override_suffix('json').to_s, @current_type.view(view).override_suffix('json').to_s) + end + scheme = @registry[dependent_key] + end + return rules.add( key, EnumerationOfType.new( @@ -363,7 +375,16 @@ def collection(key, scheme = nil, allow_empty: false, expected_type: ::Array, op ) end - rules.add(key, Scheme.new(allow_empty: allow_empty, expected_type: expected_type, &block), optional: optional) + rules.add(key, Scheme.new(allow_empty: allow_empty, expected_type: expected_type, registry: @registry, current_type: @current_type, &block), optional: optional) + end + + ## + # Expect an index of links + # + def index(optional: false) + collection(:_links, optional: optional) do + link :_self + end end ## diff --git a/lib/media_types/validations.rb b/lib/media_types/validations.rb index efa608cc..b003141d 100644 --- a/lib/media_types/validations.rb +++ b/lib/media_types/validations.rb @@ -25,7 +25,7 @@ class Validations # @see Constructable # @see Scheme # - def initialize(media_type, registry = {}, scheme = Scheme.new, &block) + def initialize(media_type, registry = {}, scheme = Scheme.new(registry: registry, current_type: media_type), &block) self.media_type = media_type self.registry = registry.merge!(media_type.as_key => scheme) self.scheme = scheme diff --git a/test/media_types/dsl/collection_test.rb b/test/media_types/dsl/collection_test.rb index 01a88ff1..dd498c40 100644 --- a/test/media_types/dsl/collection_test.rb +++ b/test/media_types/dsl/collection_test.rb @@ -305,6 +305,33 @@ def self.organisation end end + + class IndexCollectionType + include MediaTypes::Dsl + + def self.organisation + 'acme' + end + + use_name 'index_test' + + validations do + version 1 do + attribute :bar, Numeric + end + + view :index do + version 1 do + collection :_embedded + end + end + end + end + + def test_index_collections + assert IndexCollectionType.view(:index).version(1).validate!({ _embedded: [{ bar: 42 }] }), 'Expected input to be valid' + end + end end end From 82fd765539b31603fa42588eb1c4a28e3149321e Mon Sep 17 00:00:00 2001 From: Max Maton Date: Sun, 6 Aug 2023 15:39:48 +0000 Subject: [PATCH 2/2] Add debian package to gitignore --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 7f64dfb1..8348b105 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,11 @@ .idea/ /media_types-*.gem +/media-types-*.tar.gz +/ruby-media-types-* +/ruby-media-types_*.deb +/ruby-media-types_*.buildinfo +/ruby-media-types_*.changes +/ruby-media-types_*.debian.tar.xz +/ruby-media-types_*.dsc +/ruby-media-types_*.orig.tar.gz