deimos-ruby 1.13.2 → 1.14.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/README.md +6 -0
  4. data/deimos-ruby.gemspec +1 -0
  5. data/lib/deimos/active_record_consume/message_consumption.rb +2 -1
  6. data/lib/deimos/config/configuration.rb +4 -0
  7. data/lib/deimos/schema_backends/avro_base.rb +1 -1
  8. data/lib/deimos/schema_class/base.rb +17 -0
  9. data/lib/deimos/test_helpers.rb +1 -1
  10. data/lib/deimos/version.rb +1 -1
  11. data/lib/generators/deimos/active_record/templates/migration.rb.tt +5 -3
  12. data/lib/generators/deimos/active_record_generator.rb +1 -1
  13. data/lib/generators/deimos/schema_class/templates/schema_class.rb.tt +0 -7
  14. data/lib/generators/deimos/schema_class/templates/schema_record.rb.tt +10 -1
  15. data/lib/generators/deimos/schema_class_generator.rb +19 -7
  16. data/spec/active_record_consumer_spec.rb +21 -0
  17. data/spec/generators/active_record_generator_spec.rb +4 -2
  18. data/spec/generators/schema_class/my_schema_with_complex_types_spec.rb +37 -24
  19. data/spec/generators/schema_class_generator_spec.rb +93 -55
  20. data/spec/producer_spec.rb +1 -1
  21. data/spec/schemas/com/my-namespace/MySchemaId_key.avsc +12 -0
  22. data/spec/schemas/generated.rb +159 -0
  23. data/spec/schemas/my_nested_schema.rb +117 -0
  24. data/spec/{schema_classes → schemas}/my_schema.rb +1 -0
  25. data/spec/{schema_classes → schemas}/my_schema_key.rb +1 -0
  26. data/spec/schemas/my_schema_with_circular_reference.rb +77 -0
  27. data/spec/schemas/my_schema_with_complex_type.rb +239 -0
  28. data/spec/{schema_classes/generated.rb → snapshots/consumers-no-nest.snap} +20 -1
  29. data/spec/snapshots/consumers.snap +161 -0
  30. data/spec/snapshots/consumers_and_producers-no-nest.snap +397 -0
  31. data/spec/snapshots/consumers_and_producers.snap +377 -0
  32. data/spec/{schema_classes/my_schema_with_circular_reference.rb → snapshots/consumers_circular-no-nest.snap} +37 -26
  33. data/spec/snapshots/consumers_circular.snap +79 -0
  34. data/spec/{schema_classes/my_schema_with_complex_types.rb → snapshots/consumers_complex_types-no-nest.snap} +57 -22
  35. data/spec/snapshots/consumers_complex_types.snap +241 -0
  36. data/spec/{schema_classes/my_nested_schema.rb → snapshots/consumers_nested-no-nest.snap} +12 -1
  37. data/spec/snapshots/consumers_nested.snap +119 -0
  38. data/spec/snapshots/producers_with_key-no-nest.snap +95 -0
  39. data/spec/snapshots/producers_with_key.snap +95 -0
  40. data/spec/spec_helper.rb +4 -1
  41. metadata +54 -14
@@ -3,22 +3,27 @@
3
3
  require 'generators/deimos/schema_class_generator'
4
4
  require 'fileutils'
5
5
 
6
+ class MultiFileSerializer
7
+ def dump(value)
8
+ value.keys.sort.map { |k| "#{k}:\n#{value[k]}\n" }.join("\n")
9
+ end
10
+ end
11
+
6
12
  RSpec.describe Deimos::Generators::SchemaClassGenerator do
7
- let(:schema_class_path) { 'app/lib/schema_classes/com/my-namespace' }
8
- let(:expected_files) { Dir['spec/schema_classes/*.rb'] }
9
- let(:files) { Dir["#{schema_class_path}/*.rb"] }
13
+ let(:schema_class_path) { 'spec/app/lib/schema_classes' }
14
+ let(:files) { Dir["#{schema_class_path}/*.rb"].map { |f| [f, File.read(f)]}.to_h }
10
15
 
11
16
  before(:each) do
12
17
  Deimos.config.reset!
13
18
  Deimos.configure do
14
19
  schema.path 'spec/schemas/'
15
- schema.generated_class_path 'app/lib/schema_classes'
20
+ schema.generated_class_path 'spec/app/lib/schema_classes'
16
21
  schema.backend :avro_local
17
22
  end
18
23
  end
19
24
 
20
25
  after(:each) do
21
- FileUtils.rm_rf(schema_class_path) if File.exist?(schema_class_path)
26
+ FileUtils.rm_rf('spec/app') if File.exist?('spec/app')
22
27
  end
23
28
 
24
29
  context 'with a Consumers Schema' do
@@ -32,19 +37,26 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
32
37
  key_config field: :a_string
33
38
  end
34
39
  end
35
- described_class.start
36
40
  end
37
41
 
38
- it 'should generate the correct number of classes' do
39
- expect(files.length).to eq(1)
42
+ context 'nested true' do
43
+ it 'should generate the correct classes' do
44
+ Deimos.with_config('schema.nest_child_schemas' => true) do
45
+ described_class.start
46
+ expect(files).to match_snapshot('consumers', snapshot_serializer: MultiFileSerializer)
47
+ end
48
+ end
40
49
  end
41
50
 
42
- it 'should generate a schema class for generated' do
43
- generated_path = files.select { |f| f =~ /generated/ }.first
44
- expected_path = expected_files.select { |f| f =~ /generated/ }.first
45
-
46
- expect(File.read(generated_path)).to eq(File.read(expected_path))
51
+ context 'nested false' do
52
+ it 'should generate the correct classes' do
53
+ Deimos.with_config('schema.nest_child_schemas' => false) do
54
+ described_class.start
55
+ expect(files).to match_snapshot('consumers-no-nest', snapshot_serializer: MultiFileSerializer)
56
+ end
57
+ end
47
58
  end
59
+
48
60
  end
49
61
 
50
62
  context 'with a Consumers Schema with Complex types' do
@@ -58,18 +70,24 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
58
70
  key_config field: :a_string
59
71
  end
60
72
  end
61
- described_class.start
62
73
  end
63
74
 
64
- it 'should generate the correct number of classes' do
65
- expect(files.length).to eq(1)
75
+ context 'nested true' do
76
+ it 'should generate the correct classes' do
77
+ Deimos.with_config('schema.nest_child_schemas' => true) do
78
+ described_class.start
79
+ expect(files).to match_snapshot('consumers_complex_types', snapshot_serializer: MultiFileSerializer)
80
+ end
81
+ end
66
82
  end
67
83
 
68
- it 'should generate a schema class for my_schema_with_complex_types' do
69
- generated_path = files.select { |f| f =~ /my_schema_with_complex_types/ }.first
70
- expected_path = expected_files.select { |f| f =~ /my_schema_with_complex_types/ }.first
71
-
72
- expect(File.read(generated_path)).to eq(File.read(expected_path))
84
+ context 'nested false' do
85
+ it 'should generate the correct classes' do
86
+ Deimos.with_config('schema.nest_child_schemas' => false) do
87
+ described_class.start
88
+ expect(files).to match_snapshot('consumers_complex_types-no-nest', snapshot_serializer: MultiFileSerializer)
89
+ end
90
+ end
73
91
  end
74
92
  end
75
93
 
@@ -84,18 +102,24 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
84
102
  key_config field: :a_string
85
103
  end
86
104
  end
87
- described_class.start
88
105
  end
89
106
 
90
- it 'should generate the correct number of classes' do
91
- expect(files.length).to eq(1)
107
+ context 'nested true' do
108
+ it 'should generate the correct classes' do
109
+ Deimos.with_config('schema.nest_child_schemas' => true) do
110
+ described_class.start
111
+ expect(files).to match_snapshot('consumers_circular', snapshot_serializer: MultiFileSerializer)
112
+ end
113
+ end
92
114
  end
93
115
 
94
- it 'should generate a schema class for my_schema_with_circular_reference' do
95
- generated_path = files.select { |f| f =~ /my_schema_with_circular_reference/ }.first
96
- expected_path = expected_files.select { |f| f =~ /my_schema_with_circular_reference/ }.first
97
-
98
- expect(File.read(generated_path)).to eq(File.read(expected_path))
116
+ context 'nested false' do
117
+ it 'should generate the correct classes' do
118
+ Deimos.with_config('schema.nest_child_schemas' => false) do
119
+ described_class.start
120
+ expect(files).to match_snapshot('consumers_circular-no-nest', snapshot_serializer: MultiFileSerializer)
121
+ end
122
+ end
99
123
  end
100
124
  end
101
125
 
@@ -110,19 +134,23 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
110
134
  key_config schema: 'MySchema_key'
111
135
  end
112
136
  end
113
- described_class.start
114
137
  end
115
138
 
116
- it 'should generate the correct number of classes' do
117
- expect(files.length).to eq(2)
139
+ context 'nested true' do
140
+ it 'should generate the correct classes' do
141
+ Deimos.with_config('schema.nest_child_schemas' => true) do
142
+ described_class.start
143
+ expect(files).to match_snapshot('producers_with_key', snapshot_serializer: MultiFileSerializer)
144
+ end
145
+ end
118
146
  end
119
147
 
120
- %w(my_schema my_schema_key).each do |klass|
121
- it "should generate a schema class for #{klass}" do
122
- generated_path = files.select { |f| f =~ /#{klass}\.rb/ }.first
123
- expected_path = expected_files.select { |f| f =~ /#{klass}\.rb/ }.first
124
-
125
- expect(File.read(generated_path)).to eq(File.read(expected_path))
148
+ context 'nested false' do
149
+ it 'should generate the correct classes' do
150
+ Deimos.with_config('schema.nest_child_schemas' => false) do
151
+ described_class.start
152
+ expect(files).to match_snapshot('producers_with_key-no-nest', snapshot_serializer: MultiFileSerializer)
153
+ end
126
154
  end
127
155
  end
128
156
  end
@@ -138,18 +166,24 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
138
166
  key_config field: :test_id
139
167
  end
140
168
  end
141
- described_class.start
142
169
  end
143
170
 
144
- it 'should generate the correct number of classes' do
145
- expect(files.length).to eq(1)
171
+ context 'nested true' do
172
+ it 'should generate the correct classes' do
173
+ Deimos.with_config('schema.nest_child_schemas' => true) do
174
+ described_class.start
175
+ expect(files).to match_snapshot('consumers_nested', snapshot_serializer: MultiFileSerializer)
176
+ end
177
+ end
146
178
  end
147
179
 
148
- it 'should generate a schema class for my_nested_schema' do
149
- generated_path = files.select { |f| f =~ /my_nested_schema/ }.first
150
- expected_path = expected_files.select { |f| f =~ /my_nested_schema/ }.first
151
-
152
- expect(File.read(generated_path)).to eq(File.read(expected_path))
180
+ context 'nested false' do
181
+ it 'should generate the correct classes' do
182
+ Deimos.with_config('schema.nest_child_schemas' => false) do
183
+ described_class.start
184
+ expect(files).to match_snapshot('consumers_nested-no-nest', snapshot_serializer: MultiFileSerializer)
185
+ end
186
+ end
153
187
  end
154
188
  end
155
189
 
@@ -180,19 +214,23 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
180
214
  key_config field: :test_id
181
215
  end
182
216
  end
183
- described_class.start
184
217
  end
185
218
 
186
- it 'should generate the correct number of classes' do
187
- expect(files.length).to eq(4)
219
+ context 'nested true' do
220
+ it 'should generate the correct classes' do
221
+ Deimos.with_config('schema.nest_child_schemas' => true) do
222
+ described_class.start
223
+ expect(files).to match_snapshot('consumers_and_producers', snapshot_serializer: MultiFileSerializer)
224
+ end
225
+ end
188
226
  end
189
227
 
190
- %w(generated my_schema my_schema_key my_nested_schema).each do |klass|
191
- it "should generate a schema class for #{klass}" do
192
- generated_path = files.select { |f| f =~ /#{klass}\.rb/ }.first
193
- expected_path = expected_files.select { |f| f =~ /#{klass}\.rb/ }.first
194
-
195
- expect(File.read(generated_path)).to eq(File.read(expected_path))
228
+ context 'nested false' do
229
+ it 'should generate the correct classes' do
230
+ Deimos.with_config('schema.nest_child_schemas' => false) do
231
+ described_class.start
232
+ expect(files).to match_snapshot('consumers_and_producers-no-nest', snapshot_serializer: MultiFileSerializer)
233
+ end
196
234
  end
197
235
  end
198
236
  end
@@ -476,7 +476,7 @@ module ProducerTest
476
476
  test_id: 'foo',
477
477
  test_float: BigDecimal('123.456'),
478
478
  test_array: ['1'],
479
- some_nested_record: Schemas::MyNestedRecord.new(
479
+ some_nested_record: Schemas::MyNestedSchema::MyNestedRecord.new(
480
480
  some_int: 123,
481
481
  some_float: BigDecimal('456.789'),
482
482
  some_string: '123',
@@ -0,0 +1,12 @@
1
+ {
2
+ "namespace": "com.my-namespace",
3
+ "name": "MySchemaId_key",
4
+ "type": "record",
5
+ "doc": "Test schema",
6
+ "fields": [
7
+ {
8
+ "name": "id",
9
+ "type": "integer"
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is autogenerated by Deimos, Do NOT modify
4
+ module Schemas
5
+ ### Primary Schema Class ###
6
+ # Autogenerated Schema for Record at com.my-namespace.Generated
7
+ class Generated < Deimos::SchemaClass::Record
8
+
9
+ ### Secondary Schema Classes ###
10
+ # Autogenerated Schema for Record at com.my-namespace.ARecord
11
+ class ARecord < Deimos::SchemaClass::Record
12
+
13
+ ### Attribute Accessors ###
14
+ # @param value [String]
15
+ attr_accessor :a_record_field
16
+
17
+ # @override
18
+ def initialize(a_record_field: nil)
19
+ super
20
+ self.a_record_field = a_record_field
21
+ end
22
+
23
+ # @override
24
+ def schema
25
+ 'ARecord'
26
+ end
27
+
28
+ # @override
29
+ def namespace
30
+ 'com.my-namespace'
31
+ end
32
+
33
+ # @override
34
+ def to_h
35
+ {
36
+ 'a_record_field' => @a_record_field
37
+ }
38
+ end
39
+ end
40
+
41
+ # Autogenerated Schema for Enum at com.my-namespace.AnEnum
42
+ class AnEnum < Deimos::SchemaClass::Enum
43
+ # @return ['sym1', 'sym2']
44
+ attr_accessor :an_enum
45
+
46
+ # :nodoc:
47
+ def initialize(an_enum)
48
+ super
49
+ self.an_enum = an_enum
50
+ end
51
+
52
+ # @override
53
+ def symbols
54
+ %w(sym1 sym2)
55
+ end
56
+
57
+ # @override
58
+ def to_h
59
+ @an_enum
60
+ end
61
+ end
62
+
63
+
64
+ ### Attribute Readers ###
65
+ # @return [AnEnum]
66
+ attr_reader :an_enum
67
+ # @return [ARecord]
68
+ attr_reader :a_record
69
+
70
+ ### Attribute Accessors ###
71
+ # @param value [String]
72
+ attr_accessor :a_string
73
+ # @param value [Integer]
74
+ attr_accessor :a_int
75
+ # @param value [Integer]
76
+ attr_accessor :a_long
77
+ # @param value [Float]
78
+ attr_accessor :a_float
79
+ # @param value [Float]
80
+ attr_accessor :a_double
81
+ # @param value [nil, Integer]
82
+ attr_accessor :an_optional_int
83
+ # @param values [Array<Integer>]
84
+ attr_accessor :an_array
85
+ # @param values [Hash<String, String>]
86
+ attr_accessor :a_map
87
+ # @param value [String]
88
+ attr_accessor :timestamp
89
+ # @param value [String]
90
+ attr_accessor :message_id
91
+
92
+ ### Attribute Writers ###
93
+ # @param value [AnEnum]
94
+ def an_enum=(value)
95
+ @an_enum = AnEnum.initialize_from_value(value)
96
+ end
97
+
98
+ # @param value [ARecord]
99
+ def a_record=(value)
100
+ @a_record = ARecord.initialize_from_value(value)
101
+ end
102
+
103
+ # @override
104
+ def initialize(a_string: nil,
105
+ a_int: nil,
106
+ a_long: nil,
107
+ a_float: nil,
108
+ a_double: nil,
109
+ an_optional_int: nil,
110
+ an_enum: nil,
111
+ an_array: nil,
112
+ a_map: nil,
113
+ timestamp: nil,
114
+ message_id: nil,
115
+ a_record: nil)
116
+ super
117
+ self.a_string = a_string
118
+ self.a_int = a_int
119
+ self.a_long = a_long
120
+ self.a_float = a_float
121
+ self.a_double = a_double
122
+ self.an_optional_int = an_optional_int
123
+ self.an_enum = an_enum
124
+ self.an_array = an_array
125
+ self.a_map = a_map
126
+ self.timestamp = timestamp
127
+ self.message_id = message_id
128
+ self.a_record = a_record
129
+ end
130
+
131
+ # @override
132
+ def schema
133
+ 'Generated'
134
+ end
135
+
136
+ # @override
137
+ def namespace
138
+ 'com.my-namespace'
139
+ end
140
+
141
+ # @override
142
+ def to_h
143
+ {
144
+ 'a_string' => @a_string,
145
+ 'a_int' => @a_int,
146
+ 'a_long' => @a_long,
147
+ 'a_float' => @a_float,
148
+ 'a_double' => @a_double,
149
+ 'an_optional_int' => @an_optional_int,
150
+ 'an_enum' => @an_enum&.to_h,
151
+ 'an_array' => @an_array,
152
+ 'a_map' => @a_map,
153
+ 'timestamp' => @timestamp,
154
+ 'message_id' => @message_id,
155
+ 'a_record' => @a_record&.to_h
156
+ }
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is autogenerated by Deimos, Do NOT modify
4
+ module Schemas
5
+ ### Primary Schema Class ###
6
+ # Autogenerated Schema for Record at com.my-namespace.MyNestedSchema
7
+ class MyNestedSchema < Deimos::SchemaClass::Record
8
+
9
+ ### Secondary Schema Classes ###
10
+ # Autogenerated Schema for Record at com.my-namespace.MyNestedRecord
11
+ class MyNestedRecord < Deimos::SchemaClass::Record
12
+
13
+ ### Attribute Accessors ###
14
+ # @param value [Integer]
15
+ attr_accessor :some_int
16
+ # @param value [Float]
17
+ attr_accessor :some_float
18
+ # @param value [String]
19
+ attr_accessor :some_string
20
+ # @param value [nil, Integer]
21
+ attr_accessor :some_optional_int
22
+
23
+ # @override
24
+ def initialize(some_int: nil,
25
+ some_float: nil,
26
+ some_string: nil,
27
+ some_optional_int: nil)
28
+ super
29
+ self.some_int = some_int
30
+ self.some_float = some_float
31
+ self.some_string = some_string
32
+ self.some_optional_int = some_optional_int
33
+ end
34
+
35
+ # @override
36
+ def schema
37
+ 'MyNestedRecord'
38
+ end
39
+
40
+ # @override
41
+ def namespace
42
+ 'com.my-namespace'
43
+ end
44
+
45
+ # @override
46
+ def to_h
47
+ {
48
+ 'some_int' => @some_int,
49
+ 'some_float' => @some_float,
50
+ 'some_string' => @some_string,
51
+ 'some_optional_int' => @some_optional_int
52
+ }
53
+ end
54
+ end
55
+
56
+
57
+ ### Attribute Readers ###
58
+ # @return [MyNestedRecord]
59
+ attr_reader :some_nested_record
60
+ # @return [nil, MyNestedRecord]
61
+ attr_reader :some_optional_record
62
+
63
+ ### Attribute Accessors ###
64
+ # @param value [String]
65
+ attr_accessor :test_id
66
+ # @param value [Float]
67
+ attr_accessor :test_float
68
+ # @param values [Array<String>]
69
+ attr_accessor :test_array
70
+
71
+ ### Attribute Writers ###
72
+ # @param value [MyNestedRecord]
73
+ def some_nested_record=(value)
74
+ @some_nested_record = MyNestedRecord.initialize_from_value(value)
75
+ end
76
+
77
+ # @param value [nil, MyNestedRecord]
78
+ def some_optional_record=(value)
79
+ @some_optional_record = MyNestedRecord.initialize_from_value(value)
80
+ end
81
+
82
+ # @override
83
+ def initialize(test_id: nil,
84
+ test_float: nil,
85
+ test_array: nil,
86
+ some_nested_record: nil,
87
+ some_optional_record: nil)
88
+ super
89
+ self.test_id = test_id
90
+ self.test_float = test_float
91
+ self.test_array = test_array
92
+ self.some_nested_record = some_nested_record
93
+ self.some_optional_record = some_optional_record
94
+ end
95
+
96
+ # @override
97
+ def schema
98
+ 'MyNestedSchema'
99
+ end
100
+
101
+ # @override
102
+ def namespace
103
+ 'com.my-namespace'
104
+ end
105
+
106
+ # @override
107
+ def to_h
108
+ {
109
+ 'test_id' => @test_id,
110
+ 'test_float' => @test_float,
111
+ 'test_array' => @test_array,
112
+ 'some_nested_record' => @some_nested_record&.to_h,
113
+ 'some_optional_record' => @some_optional_record&.to_h
114
+ }
115
+ end
116
+ end
117
+ end
@@ -5,6 +5,7 @@ module Schemas
5
5
  ### Primary Schema Class ###
6
6
  # Autogenerated Schema for Record at com.my-namespace.MySchema
7
7
  class MySchema < Deimos::SchemaClass::Record
8
+
8
9
  ### Attribute Readers ###
9
10
  # @return [MySchemaKey]
10
11
  attr_reader :payload_key
@@ -5,6 +5,7 @@ module Schemas
5
5
  ### Primary Schema Class ###
6
6
  # Autogenerated Schema for Record at com.my-namespace.MySchema_key
7
7
  class MySchemaKey < Deimos::SchemaClass::Record
8
+
8
9
  ### Attribute Accessors ###
9
10
  # @param value [String]
10
11
  attr_accessor :test_id
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is autogenerated by Deimos, Do NOT modify
4
+ module Schemas
5
+ ### Primary Schema Class ###
6
+ # Autogenerated Schema for Record at com.my-namespace.MySchemaWithCircularReference
7
+ class MySchemaWithCircularReference < Deimos::SchemaClass::Record
8
+
9
+ ### Secondary Schema Classes ###
10
+ # Autogenerated Schema for Record at com.my-namespace.Property
11
+ class Property < Deimos::SchemaClass::Record
12
+
13
+ ### Attribute Accessors ###
14
+ # @param value [Boolean, Integer, Integer, Float, Float, String, Array<Property>, Hash<String, Property>]
15
+ attr_accessor :property
16
+
17
+ # @override
18
+ def initialize(property: nil)
19
+ super
20
+ self.property = property
21
+ end
22
+
23
+ # @override
24
+ def schema
25
+ 'Property'
26
+ end
27
+
28
+ # @override
29
+ def namespace
30
+ 'com.my-namespace'
31
+ end
32
+
33
+ # @override
34
+ def to_h
35
+ {
36
+ 'property' => @property
37
+ }
38
+ end
39
+ end
40
+
41
+
42
+ ### Attribute Readers ###
43
+ # @return [Hash<String, Property>]
44
+ attr_reader :properties
45
+
46
+ ### Attribute Writers ###
47
+ # @param values [Hash<String, Property>]
48
+ def properties=(values)
49
+ @properties = values.transform_values do |value|
50
+ Property.initialize_from_value(value)
51
+ end
52
+ end
53
+
54
+ # @override
55
+ def initialize(properties: {})
56
+ super
57
+ self.properties = properties
58
+ end
59
+
60
+ # @override
61
+ def schema
62
+ 'MySchemaWithCircularReference'
63
+ end
64
+
65
+ # @override
66
+ def namespace
67
+ 'com.my-namespace'
68
+ end
69
+
70
+ # @override
71
+ def to_h
72
+ {
73
+ 'properties' => @properties.transform_values { |v| v&.to_h }
74
+ }
75
+ end
76
+ end
77
+ end