json_model_rb 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +0 -0
  4. data/lib/json_model/config/options.rb +29 -0
  5. data/lib/json_model/config.rb +43 -0
  6. data/lib/json_model/errors/error.rb +7 -0
  7. data/lib/json_model/errors/invalid_ref_mode_error.rb +12 -0
  8. data/lib/json_model/errors/unknown_attribute_error.rb +13 -0
  9. data/lib/json_model/errors.rb +5 -0
  10. data/lib/json_model/properties.rb +66 -0
  11. data/lib/json_model/property.rb +54 -0
  12. data/lib/json_model/ref_mode.rb +9 -0
  13. data/lib/json_model/schema.rb +111 -0
  14. data/lib/json_model/schema_meta.rb +60 -0
  15. data/lib/json_model/type_spec/array.rb +62 -0
  16. data/lib/json_model/type_spec/composition/all_of.rb +15 -0
  17. data/lib/json_model/type_spec/composition/any_of.rb +15 -0
  18. data/lib/json_model/type_spec/composition/one_of.rb +15 -0
  19. data/lib/json_model/type_spec/composition.rb +32 -0
  20. data/lib/json_model/type_spec/enum.rb +33 -0
  21. data/lib/json_model/type_spec/object.rb +24 -0
  22. data/lib/json_model/type_spec/primitive/boolean.rb +13 -0
  23. data/lib/json_model/type_spec/primitive/integer.rb +21 -0
  24. data/lib/json_model/type_spec/primitive/null.rb +13 -0
  25. data/lib/json_model/type_spec/primitive/number.rb +14 -0
  26. data/lib/json_model/type_spec/primitive/numeric.rb +83 -0
  27. data/lib/json_model/type_spec/primitive/string.rb +150 -0
  28. data/lib/json_model/type_spec/primitive.rb +26 -0
  29. data/lib/json_model/type_spec.rb +67 -0
  30. data/lib/json_model/types/all_of.rb +26 -0
  31. data/lib/json_model/types/any_of.rb +26 -0
  32. data/lib/json_model/types/array.rb +26 -0
  33. data/lib/json_model/types/boolean.rb +7 -0
  34. data/lib/json_model/types/enum.rb +23 -0
  35. data/lib/json_model/types/one_of.rb +26 -0
  36. data/lib/json_model/types.rb +8 -0
  37. data/lib/json_model/version.rb +5 -0
  38. data/lib/json_model.rb +31 -0
  39. data/spec/config_spec.rb +106 -0
  40. data/spec/json_model_spec.rb +7 -0
  41. data/spec/properties_spec.rb +76 -0
  42. data/spec/property_spec.rb +86 -0
  43. data/spec/schema_meta_spec.rb +78 -0
  44. data/spec/schema_spec.rb +218 -0
  45. data/spec/spec_helper.rb +13 -0
  46. data/spec/type_spec/array_spec.rb +206 -0
  47. data/spec/type_spec/composition/all_of_spec.rb +20 -0
  48. data/spec/type_spec/composition/any_of_spec.rb +20 -0
  49. data/spec/type_spec/composition/one_of_spec.rb +20 -0
  50. data/spec/type_spec/composition_spec.rb +90 -0
  51. data/spec/type_spec/enum_spec.rb +93 -0
  52. data/spec/type_spec/primitive/boolean_spec.rb +12 -0
  53. data/spec/type_spec/primitive/integer_spec.rb +57 -0
  54. data/spec/type_spec/primitive/null_spec.rb +12 -0
  55. data/spec/type_spec/primitive/number_spec.rb +12 -0
  56. data/spec/type_spec/primitive/numeric_spec.rb +176 -0
  57. data/spec/type_spec/primitive/string_spec.rb +119 -0
  58. data/spec/type_spec_spec.rb +32 -0
  59. metadata +183 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6055ccf369735b5c3461df4c1e1c84fb376bbfb56db264c4b2cff411a0408f7b
4
+ data.tar.gz: 269014c71581e5fa7053b00e37cd0e9faa854b2af11b243aab322da3673cc758
5
+ SHA512:
6
+ metadata.gz: 9e9145acb6866d32cd0a34a507bf9b30658c7197e5098e630f679bd874697639d66cf17c60fd9b8534418c6f01c7470508193077e260d935845b6275ee5f9636
7
+ data.tar.gz: 1d5c2c8cd76cb864be16eb30787a53349ccc5c28f08d159f6e1984e87264c91dea759184ed7f67ff61720bf912e92deeaa1a014c560338ca86694ab5288585c4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 gillesbergerp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
File without changes
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module Config
5
+ module Options
6
+ # @return [Hash]
7
+ def defaults
8
+ @defaults ||= {}
9
+ end
10
+
11
+ # @return [Hash]
12
+ def settings
13
+ @settings ||= {}
14
+ end
15
+
16
+ def option(name, default: nil, &transformation)
17
+ define_method(name) { settings[name] }
18
+ define_method("#{name}=") do |value|
19
+ settings[name] = transformation.present? ? transformation.call(value) : value
20
+ end
21
+ module_function(name)
22
+ module_function("#{name}=")
23
+
24
+ defaults[name] = transformation.present? ? transformation.call(default) : default
25
+ settings[name] = defaults[name]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('active_support/core_ext/string')
4
+ require_relative('config/options')
5
+
6
+ module JsonModel
7
+ module Config
8
+ extend(JsonModel::Config::Options)
9
+
10
+ PROPERTY_NAMING_STRATEGIES = {
11
+ identity: lambda(&:to_sym),
12
+ camel_case: ->(property_name) { property_name.to_s.tr('-', '_').camelize(:lower) },
13
+ pascal_case: ->(property_name) { property_name.to_s.tr('-', '_').camelize },
14
+ }.freeze
15
+
16
+ SCHEMA_ID_NAMING_STRATEGIES = {
17
+ class_name: ->(klass) { klass.name.demodulize },
18
+ kebab_case_class_name: ->(klass) { klass.name.demodulize.underscore.tr('_', '-') },
19
+ none: ->(_) {},
20
+ snake_case_class_name: ->(klass) { klass.name.demodulize.underscore },
21
+ }.freeze
22
+
23
+ option(:property_naming_strategy, default: :identity) do |value|
24
+ if value.is_a?(Proc)
25
+ value
26
+ else
27
+ PROPERTY_NAMING_STRATEGIES[value]
28
+ end
29
+ end
30
+
31
+ option(:schema_id_base_uri, default: nil)
32
+
33
+ option(:schema_id_naming_strategy, default: :none) do |value|
34
+ if value.is_a?(Proc)
35
+ value
36
+ else
37
+ SCHEMA_ID_NAMING_STRATEGIES[value]
38
+ end
39
+ end
40
+
41
+ option(:validate_after_instantiation, default: true)
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module Errors
5
+ class Error < StandardError; end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module Errors
5
+ class InvalidRefModeError < Error
6
+ # @param [Symbol] ref_mode
7
+ def initialize(ref_mode)
8
+ super("Invalid ref_mode: #{ref_mode}.")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module Errors
5
+ class UnknownAttributeError < Error
6
+ # @param [Class] klass
7
+ # @param [Symbol] name
8
+ def initialize(klass, name)
9
+ super("Unknown attribute '#{name}' for '#{klass}'.")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative('errors/error')
4
+ require_relative('errors/invalid_ref_mode_error')
5
+ require_relative('errors/unknown_attribute_error')
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module Properties
5
+ extend(ActiveSupport::Concern)
6
+
7
+ included do
8
+ extend(ActiveSupport::DescendantsTracker)
9
+ include(ActiveModel::Validations)
10
+
11
+ class_attribute(:attributes, instance_writer: false, default: {})
12
+ class_attribute(:properties, instance_writer: false, default: {})
13
+ end
14
+
15
+ class_methods do
16
+ # @param [Symbol] name
17
+ # @param [Object] type
18
+ # @param [Hash] options
19
+ def property(name, type:, **options)
20
+ property_options = options.slice(:default, :optional, :ref_mode)
21
+ resolved_type = TypeSpec.resolve(type, **options.except(:default, :optional, :ref_mode))
22
+ add_property(name, type: resolved_type, **property_options)
23
+ descendants.each { |subclass| subclass.add_property(name, type: resolved_type, **property_options) }
24
+ end
25
+
26
+ protected
27
+
28
+ # @param [Symbol] name
29
+ # @param [TypeSpec] type
30
+ # @param [Hash] options
31
+ def add_property(name, type:, **options)
32
+ property = Property.new(name, type: type, **options)
33
+ properties[name] = property
34
+ define_accessors(property)
35
+ define_validations(property)
36
+ end
37
+
38
+ # @param [Property] property
39
+ def define_accessors(property)
40
+ define_getter(property)
41
+ define_setter(property)
42
+ end
43
+
44
+ # @param [Property] property
45
+ def define_getter(property)
46
+ define_method(property.name) do
47
+ if attributes.key?(property.name)
48
+ attributes[property.name]
49
+ else
50
+ property.default
51
+ end
52
+ end
53
+ end
54
+
55
+ # @param [Property] property
56
+ def define_setter(property)
57
+ define_method("#{property.name}=") { |value| attributes[property.name] = value }
58
+ end
59
+
60
+ # @param [Property] property
61
+ def define_validations(property)
62
+ property.register_validations(self)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class Property
5
+ attr_reader(:name, :default, :type, :optional, :alias)
6
+
7
+ # @param [Symbol] name
8
+ # @param [TypeSpec] type
9
+ # @param [Object, nil] default
10
+ # @param [Boolean] optional
11
+ # @param [Symbol] ref_mode
12
+ # @param [Symbol, nil] as
13
+ def initialize(name, type:, default: nil, optional: false, ref_mode: RefMode::INLINE, as: nil)
14
+ @name = name
15
+ @type = type
16
+ @default = default
17
+ @optional = optional
18
+ @ref_mode = ref_mode
19
+ @alias = as || JsonModel.config.property_naming_strategy.call(name).to_sym
20
+ end
21
+
22
+ # @param [Hash] options
23
+ # @return [Hash]
24
+ def as_schema(**options)
25
+ {
26
+ self.alias => type
27
+ .as_schema(**options, ref_mode: @ref_mode)
28
+ .merge({ default: default }.compact),
29
+ }
30
+ end
31
+
32
+ # @param [ActiveModel::Validations]
33
+ def register_validations(klass)
34
+ if required?
35
+ klass.validates(name, presence: true)
36
+ end
37
+ type.register_validations(name, klass)
38
+ end
39
+
40
+ # @return [Boolean]
41
+ def required?
42
+ !optional
43
+ end
44
+
45
+ # @return [Array]
46
+ def referenced_schemas
47
+ if @ref_mode == RefMode::LOCAL
48
+ type.referenced_schemas
49
+ else
50
+ []
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module RefMode
5
+ EXTERNAL = :external
6
+ INLINE = :inline
7
+ LOCAL = :local
8
+ end
9
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module Schema
5
+ extend(ActiveSupport::Concern)
6
+ include(Properties)
7
+ include(SchemaMeta)
8
+
9
+ # @param [Hash, nil] attributes
10
+ def initialize(attributes = nil)
11
+ return unless attributes
12
+
13
+ assign_attributes(attributes)
14
+
15
+ if JsonModel.config.validate_after_instantiation
16
+ validate!
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ # @param [Hash, nil] attributes
23
+ def assign_attributes(attributes)
24
+ attributes.each { |name, value| assign_attribute(name, value) }
25
+ end
26
+
27
+ # @param [Symbol] name
28
+ # @param [Object] value
29
+ def assign_attribute(name, value)
30
+ if respond_to?("#{name}=")
31
+ send("#{name}=", value)
32
+ elsif !self.class.additional_properties && JsonModel.config.validate_after_instantiation
33
+ raise(Errors::UnknownAttributeError.new(self.class, name))
34
+ end
35
+ end
36
+
37
+ class_methods do
38
+ # @param [Symbol] ref_mode
39
+ # @param [Hash] _options
40
+ # @return [Hash]
41
+ def as_schema(ref_mode: RefMode::INLINE, **_options)
42
+ case ref_mode
43
+ when RefMode::INLINE
44
+ meta_attributes
45
+ .merge(
46
+ properties: properties_as_schema,
47
+ required: required_properties_as_schema,
48
+ '$defs': defs_as_schema,
49
+ )
50
+ .merge(type: 'object')
51
+ .compact
52
+ when RefMode::LOCAL
53
+ { '$ref': "#/$defs/#{name}" }
54
+ when RefMode::EXTERNAL
55
+ { '$ref': schema_id }
56
+ else
57
+ raise(Errors::InvalidRefModeError, ref_mode)
58
+ end
59
+ end
60
+
61
+ # @return [Hash, nil]
62
+ def properties_as_schema
63
+ if local_properties.any?
64
+ local_properties
65
+ .sort_by { |key, _property| key }
66
+ .map { |_key, property| property.as_schema }
67
+ .inject({}, &:merge)
68
+ end
69
+ end
70
+
71
+ # @return [Array, nil]
72
+ def required_properties_as_schema
73
+ if local_properties.any?
74
+ local_properties
75
+ .values
76
+ .select(&:required?)
77
+ .map(&:alias)
78
+ .sort
79
+ end
80
+ end
81
+
82
+ def defs_as_schema
83
+ referenced_schemas = local_properties
84
+ .values
85
+ .flat_map(&:referenced_schemas)
86
+ .uniq
87
+
88
+ if referenced_schemas.any?
89
+ referenced_schemas.to_h { |type| [type.name.to_sym, type.as_schema] }
90
+ end
91
+ end
92
+
93
+ # @return [Array<Class>]
94
+ def parent_schemas
95
+ @parent_schemas ||= ancestors.select { |klass| klass != self && klass < Schema }
96
+ end
97
+
98
+ # @return [Hash]
99
+ def local_properties
100
+ if !defined?(@local_properties)
101
+ ancestor_properties = parent_schemas.flat_map { |property| property.properties.values }
102
+ @local_properties = properties.select do |_key, property|
103
+ ancestor_properties.none? { |ancestor_property| ancestor_property == property }
104
+ end
105
+ end
106
+
107
+ @local_properties
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ module SchemaMeta
5
+ extend(ActiveSupport::Concern)
6
+
7
+ SCHEMA_VERSIONS = {
8
+ draft4: 'http://json-schema.org/draft-04/schema#',
9
+ draft6: 'http://json-schema.org/draft-06/schema#',
10
+ draft7: 'http://json-schema.org/draft-07/schema#',
11
+ draft201909: 'https://json-schema.org/draft/2019-09/schema',
12
+ draft202012: 'https://json-schema.org/draft/2020-12/schema',
13
+ }.freeze
14
+
15
+ included do
16
+ class_attribute(:meta_attributes, instance_writer: false, default: {})
17
+ class_attribute(:ref_schema, instance_writer: false)
18
+
19
+ # @param [Class] subclass
20
+ def self.inherited(subclass)
21
+ super
22
+ subclass.meta_attributes[:$ref] = schema_id
23
+ end
24
+
25
+ schema_id(name)
26
+ end
27
+
28
+ class_methods do
29
+ # @param [String, nil] id
30
+ # @return [String, nil]
31
+ def schema_id(id = nil)
32
+ if id
33
+ meta_attributes[:$id] = URI.parse("#{JsonModel.config.schema_id_base_uri}#{id}").to_s
34
+ else
35
+ meta_attributes[:$id]
36
+ end
37
+ end
38
+
39
+ # @param [Boolean, nil] value
40
+ # @return [Boolean]
41
+ def additional_properties(value = nil)
42
+ if value.nil?
43
+ meta_attributes[:additionalProperties] || false
44
+ else
45
+ meta_attributes[:additionalProperties] = value
46
+ end
47
+ end
48
+
49
+ # @param [Symbol, nil] version
50
+ # @return [Boolean]
51
+ def schema_version(version = nil)
52
+ if version.nil?
53
+ meta_attributes[:$schema]
54
+ else
55
+ meta_attributes[:$schema] = SCHEMA_VERSIONS[version]
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Array < TypeSpec
6
+ # @param [TypeSpec] type
7
+ # @param [Integer, nil] min_items
8
+ # @param [Integer, nil] max_items
9
+ # @param [Boolean, nil] unique_items
10
+ def initialize(type, min_items: nil, max_items: nil, unique_items: nil)
11
+ super()
12
+ @type = type
13
+ @min_items = min_items
14
+ @max_items = max_items
15
+ @unique_items = unique_items
16
+ end
17
+
18
+ # @param [Hash] options
19
+ # @return [Hash]
20
+ def as_schema(**options)
21
+ {
22
+ type: 'array',
23
+ items: @type.as_schema(**options),
24
+ minItems: @min_items,
25
+ maxItems: @max_items,
26
+ uniqueItems: @unique_items,
27
+ }.compact
28
+ end
29
+
30
+ # @param [Symbol] name
31
+ # @param [ActiveModel::Validations] klass
32
+ def register_validations(name, klass)
33
+ super
34
+
35
+ if @min_items || @max_items
36
+ klass.validates(name, length: { minimum: @min_items, maximum: @max_items }.compact, allow_nil: true)
37
+ end
38
+ if @unique_items
39
+ register_uniqueness_validation(name, klass)
40
+ end
41
+ end
42
+
43
+ # @return [Array<TypeSpec>]
44
+ def referenced_schemas
45
+ @type.referenced_schemas
46
+ end
47
+
48
+ private
49
+
50
+ # @param [Symbol] name
51
+ # @param [ActiveModel::Validations] klass
52
+ def register_uniqueness_validation(name, klass)
53
+ klass.validate do |record|
54
+ duplicates = record.send(name)&.group_by(&:itself)&.select { |_k, v| v.size > 1 }&.keys
55
+ if !duplicates.nil? && duplicates.any?
56
+ record.errors.add(:tags, :uniqueness, message: "contains duplicates: #{duplicates.join(', ')}")
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Composition
6
+ class AllOf < Composition
7
+ # @param [TypeSpec] types
8
+ # @param [Hash] options
9
+ def initialize(*types, **options)
10
+ super(:allOf, *types, **options)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Composition
6
+ class AnyOf < Composition
7
+ # @param [TypeSpec] types
8
+ # @param [Hash] options
9
+ def initialize(*types, **options)
10
+ super(:anyOf, *types, **options)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Composition
6
+ class OneOf < Composition
7
+ # @param [TypeSpec] types
8
+ # @param [Hash] options
9
+ def initialize(*types, **options)
10
+ super(:oneOf, *types, **options)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Composition < TypeSpec
6
+ # @param [Symbol] modifier
7
+ # @param [TypeSpec] types
8
+ def initialize(modifier, *types)
9
+ super()
10
+ @types = types
11
+ @modifier = modifier
12
+ end
13
+
14
+ # @param [Hash] options
15
+ # @return [Hash]
16
+ def as_schema(**options)
17
+ {
18
+ @modifier => @types.map { |type| type.as_schema(**options) },
19
+ }
20
+ end
21
+
22
+ # @return [Array<TypeSpec>]
23
+ def referenced_schemas
24
+ @types.flat_map(&:referenced_schemas)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ require_relative('composition/all_of')
31
+ require_relative('composition/any_of')
32
+ require_relative('composition/one_of')
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Enum < TypeSpec
6
+ # @param [Array<Object, nil>] values
7
+ def initialize(*values)
8
+ super()
9
+ @values = values
10
+
11
+ if @values.blank?
12
+ raise(ArgumentError, 'Enum type spec requires a non-empty enum array')
13
+ end
14
+ end
15
+
16
+ # @param [Hash] _options
17
+ # @return [Hash]
18
+ def as_schema(**_options)
19
+ {
20
+ enum: @values,
21
+ }.compact
22
+ end
23
+
24
+ # @param [Symbol] name
25
+ # @param [ActiveModel::Validations] klass
26
+ def register_validations(name, klass)
27
+ super
28
+
29
+ klass.validates(name, inclusion: { in: @values })
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Object < TypeSpec
6
+ # @param [Schema] type
7
+ def initialize(type)
8
+ super()
9
+ @type = type
10
+ end
11
+
12
+ # @param [Hash] options
13
+ # @return [Hash]
14
+ def as_schema(**options)
15
+ @type.as_schema(**options)
16
+ end
17
+
18
+ # @return [Array<TypeSpec>]
19
+ def referenced_schemas
20
+ [@type]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonModel
4
+ class TypeSpec
5
+ class Primitive
6
+ class Boolean < Primitive
7
+ def initialize
8
+ super('boolean')
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end