deimos-ruby 1.13.2 → 1.14.1

Sign up to get free protection for your applications and to get access to all the features.
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