avro_turf 1.9.0 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cb36f9b1395a1a6210d1178ca0823636f30ad194caf57663e8fb5cc13273d68
4
- data.tar.gz: 2fb489fe330b39b88ed585d6b622936e573b525c1f4c5c4fe50704b16b11fd39
3
+ metadata.gz: 31248ad33908f238baea49fc106bc3e6292f45a1fe7fce0c0ae091dc10a9ea17
4
+ data.tar.gz: 25af934023a269b28acf004a1ec13c052380f5a664696ce881ef27efb209a7e5
5
5
  SHA512:
6
- metadata.gz: be796c4b42daf30a79dd699d23842e61c61e8f8c70b1645f269ec25e4a4f4fb1e87148b0ffd69a68b24382e9abc01048cb3ba082bd3a3dd2162be714ecdcd57b
7
- data.tar.gz: 332486d45cd611da3906247f4fb55386c7e1617043070dd44fff06b05c50c44237af6dad62f1fd087ca9c67580aadd53fc342f76509b69b67375532b60637bf9
6
+ metadata.gz: 6e0796ce28027a654fa189f561f8179567fbebf50ba6c225be9b8623999e7ef424b58b05d1282a151474aaf48057b0000ce7999f6f8aed1c5f56f53f2d1f8cab
7
+ data.tar.gz: 70fb1dc693589e71691ab8bf18cef28ebe533921efe401c6c0f7c3f1ace8ac880e5e3bd1161bd3235148f7f469c837d5224f90ea96a3867aa0fe24a16de91200
data/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v1.11.0
6
+
7
+ - Add `decode_all` and `decode_all_from_stream` methods to return all entries in a data file (#194)
8
+ - Improve the way schemas are automatically loaded (#190)
9
+ - Increment dependency on `avro` gem to v1.8.
10
+
11
+ ## v1.10.0
12
+
13
+ - Add `schema_subject_versions` to `ConfluentSchemaRegistry` to retrieve all subject versions for a schema id. (#189)
14
+ - `FakeConfluentSchemaRegistryServer` now returns same id if identical schema is created for a different subject (#188)
15
+
5
16
  ## v1.9.0
6
17
 
7
18
  - Send Accept and User-Agent headers on every request (#184)
data/avro_turf.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_dependency "avro", ">= 1.7.7", "< 1.12"
22
+ spec.add_dependency "avro", ">= 1.8.0", "< 1.12"
23
23
  spec.add_dependency "excon", "~> 0.71"
24
24
 
25
25
  spec.add_development_dependency "bundler", "~> 2.0"
@@ -17,7 +17,7 @@ class AvroTurf::CachedConfluentSchemaRegistry
17
17
  end
18
18
 
19
19
  # Delegate the following methods to the upstream
20
- %i(subjects subject_versions check compatible?
20
+ %i(subjects subject_versions schema_subject_versions check compatible?
21
21
  global_config update_global_config subject_config update_subject_config).each do |name|
22
22
  define_method(name) do |*args|
23
23
  instance_variable_get(:@upstream).send(name, *args)
@@ -68,6 +68,11 @@ class AvroTurf::ConfluentSchemaRegistry
68
68
  get("/subjects/#{subject}/versions/#{version}")
69
69
  end
70
70
 
71
+ # Get the subject and version for a schema id
72
+ def schema_subject_versions(schema_id)
73
+ get("/schemas/ids/#{schema_id}/versions")
74
+ end
75
+
71
76
  # Check if a schema exists. Returns nil if not found.
72
77
  def check(subject, schema)
73
78
  data = post("/subjects/#{subject}",
@@ -22,7 +22,7 @@ class AvroTurf::SchemaStore
22
22
  # Still need to check is the schema already loaded
23
23
  return @schemas[fullname] if @schemas.key?(fullname)
24
24
 
25
- load_schema!(fullname)
25
+ load_schema!(fullname, @schemas.dup)
26
26
  end
27
27
  end
28
28
 
@@ -70,28 +70,22 @@ class AvroTurf::SchemaStore
70
70
  @schemas[fullname] = schema
71
71
 
72
72
  schema
73
- rescue ::Avro::SchemaParseError => e
74
- # This is a hack in order to figure out exactly which type was missing. The
75
- # Avro gem ought to provide this data directly.
76
- if e.to_s =~ /"([\w\.]+)" is not a schema we know about/
77
- # Try to first resolve a referenced schema from disk.
78
- # If this is successful, the Avro gem will have mutated the
79
- # local_schemas_cache, adding all the new schemas it found.
80
- load_schema!($1, local_schemas_cache)
81
-
82
- # Attempt to re-parse the original schema now that the dependency
83
- # has been resolved and use the now-updated local_schemas_cache to
84
- # pick up where we left off.
85
- local_schemas_cache.delete(fullname)
86
- # Ensure all sub-schemas are cleaned up to avoid conflicts when re-parsing
87
- # schema.
88
- local_schemas_cache.each do |schema_name, schema|
89
- local_schemas_cache.delete(schema_name) unless File.exist?(build_schema_path(schema_name))
90
- end
91
- load_schema!(fullname, @schemas.dup)
92
- else
93
- raise
73
+ rescue ::Avro::UnknownSchemaError => e
74
+ # Try to first resolve a referenced schema from disk.
75
+ # If this is successful, the Avro gem will have mutated the
76
+ # local_schemas_cache, adding all the new schemas it found.
77
+ load_schema!(e.type_name, local_schemas_cache)
78
+
79
+ # Attempt to re-parse the original schema now that the dependency
80
+ # has been resolved and use the now-updated local_schemas_cache to
81
+ # pick up where we left off.
82
+ local_schemas_cache.delete(fullname)
83
+ # Ensure all sub-schemas are cleaned up to avoid conflicts when re-parsing
84
+ # schema.
85
+ local_schemas_cache.each_key do |schema_name|
86
+ local_schemas_cache.delete(schema_name) unless File.exist?(build_schema_path(schema_name))
94
87
  end
88
+ load_schema!(fullname, @schemas.dup)
95
89
  rescue Errno::ENOENT, Errno::ENAMETOOLONG
96
90
  raise AvroTurf::SchemaNotFoundError, "could not find Avro schema at `#{schema_path}'"
97
91
  end
@@ -35,23 +35,35 @@ class FakeConfluentSchemaRegistryServer < Sinatra::Base
35
35
 
36
36
  post "/subjects/:subject/versions" do
37
37
  schema = parse_schema
38
- ids_for_subject = SUBJECTS[params[:subject]]
39
-
40
- schemas_for_subject =
41
- SCHEMAS.select
42
- .with_index { |_, i| ids_for_subject.include?(i) }
43
-
44
- if schemas_for_subject.include?(schema)
45
- schema_id = SCHEMAS.index(schema)
46
- else
38
+ schema_id = SCHEMAS.index(schema)
39
+ if schema_id.nil?
47
40
  SCHEMAS << schema
48
41
  schema_id = SCHEMAS.size - 1
49
- SUBJECTS[params[:subject]] = SUBJECTS[params[:subject]] << schema_id
42
+ end
43
+
44
+ subject = params[:subject]
45
+ unless SUBJECTS[subject].include?(schema_id)
46
+ SUBJECTS[subject] = SUBJECTS[subject] << schema_id
50
47
  end
51
48
 
52
49
  { id: schema_id }.to_json
53
50
  end
54
51
 
52
+ get "/schemas/ids/:schema_id/versions" do
53
+ schema_id = params[:schema_id].to_i
54
+ schema = SCHEMAS.at(schema_id)
55
+ halt(404, SCHEMA_NOT_FOUND) unless schema
56
+
57
+ related_subjects = SUBJECTS.select {|_, vs| vs.include? schema_id }
58
+
59
+ related_subjects.map do |subject, versions|
60
+ {
61
+ subject: subject,
62
+ version: versions.find_index(schema_id) + 1
63
+ }
64
+ end.to_json
65
+ end
66
+
55
67
  get "/schemas/ids/:schema_id" do
56
68
  schema = SCHEMAS.at(params[:schema_id].to_i)
57
69
  halt(404, SCHEMA_NOT_FOUND) unless schema
@@ -1,3 +1,3 @@
1
1
  class AvroTurf
2
- VERSION = "1.9.0"
2
+ VERSION = "1.11.0"
3
3
  end
data/lib/avro_turf.rb CHANGED
@@ -93,24 +93,39 @@ class AvroTurf
93
93
  # namespace - The namespace of the Avro schema used to decode the data.
94
94
  #
95
95
  # Returns whatever is encoded in the data.
96
- def decode(encoded_data, schema_name: nil, namespace: @namespace)
96
+ def decode_first(encoded_data, schema_name: nil, namespace: @namespace)
97
97
  stream = StringIO.new(encoded_data)
98
98
  decode_stream(stream, schema_name: schema_name, namespace: namespace)
99
99
  end
100
100
 
101
- # Decodes Avro data from an IO stream.
101
+ alias decode decode_first
102
+
103
+ # Returns all entries encoded in the data.
104
+ def decode_all(encoded_data, schema_name: nil, namespace: @namespace)
105
+ stream = StringIO.new(encoded_data)
106
+ decode_all_from_stream(stream, schema_name: schema_name, namespace: namespace)
107
+ end
108
+
109
+ # Decodes the first entry from an IO stream containing Avro data.
102
110
  #
103
111
  # stream - An IO object containing Avro data.
104
112
  # schema_name - The String name of the schema that should be used to read
105
113
  # the data. If nil, the writer schema will be used.
106
114
  # namespace - The namespace of the Avro schema used to decode the data.
107
115
  #
108
- # Returns whatever is encoded in the stream.
109
- def decode_stream(stream, schema_name: nil, namespace: @namespace)
116
+ # Returns first entry encoded in the stream.
117
+ def decode_first_from_stream(stream, schema_name: nil, namespace: @namespace)
118
+ data = decode_all_from_stream(stream, schema_name: schema_name, namespace: namespace)
119
+ data.first
120
+ end
121
+
122
+ alias decode_stream decode_first_from_stream
123
+
124
+ # Returns all entries encoded in the stream.
125
+ def decode_all_from_stream(stream, schema_name: nil, namespace: @namespace)
110
126
  schema = schema_name && @schema_store.find(schema_name, namespace)
111
127
  reader = Avro::IO::DatumReader.new(nil, schema)
112
- dr = Avro::DataFile::Reader.new(stream, reader)
113
- dr.first
128
+ Avro::DataFile::Reader.new(stream, reader)
114
129
  end
115
130
 
116
131
  # Validates data against an Avro schema.
@@ -186,6 +186,47 @@ describe AvroTurf do
186
186
  end
187
187
  end
188
188
 
189
+ describe "#decode_all" do
190
+ context "when data contains multiple entries" do
191
+ let(:encoded_data) { "Obj\u0001\u0004\u0014avro.codec\bnull\u0016avro.schema\xB6\u0004[{\"type\": \"record\", \"name\": \"address\", \"fields\": [{\"type\": \"string\", \"name\": \"street\"}, {\"type\": \"string\", \"name\": \"city\"}]}, {\"type\": \"record\", \"name\": \"person\", \"fields\": [{\"type\": \"string\", \"name\": \"name\"}, {\"type\": \"int\", \"name\": \"age\"}, {\"type\": \"address\", \"name\": \"address\"}]}]\u0000\xF9u\x84\xA1c\u0010\x82B\xE2\xCF\xF1\x98\xF7\xF1JH\u0004\x96\u0001\u0002\u0014Python🐍\x80\u0004\u0018Green Street\u001ASan Francisco\u0002\u0010Mojo🐍\u0002\u0016Blue Street\u0014Saturn🪐\xF9u\x84\xA1c\u0010\x82B\xE2\xCF\xF1\x98\xF7\xF1JH" }
192
+
193
+ it "returns array of entries decoded using the inlined writer's schema " do
194
+ expect(avro.decode_all(encoded_data).entries).to eq(
195
+ [
196
+ {"name"=>"Python🐍", "age"=>256, "address"=>{"street"=>"Green Street", "city"=>"San Francisco"}},
197
+ {"name"=>"Mojo🐍", "age"=>1, "address"=>{"street"=>"Blue Street", "city"=>"Saturn🪐"}}
198
+ ]
199
+ )
200
+ end
201
+
202
+ it "returns array of entries decoded using the specified reader's schema " do
203
+ FileUtils.mkdir_p("spec/schemas/reader")
204
+
205
+ define_schema "reader/person.avsc", <<-AVSC
206
+ {
207
+ "name": "person",
208
+ "type": "record",
209
+ "fields": [
210
+ { "name": "fav_color", "type": "string", "default": "red🟥" },
211
+ { "name": "name", "type": "string" },
212
+ { "name": "age", "type": "int" }
213
+ ]
214
+ }
215
+ AVSC
216
+
217
+ expect(
218
+ AvroTurf.new(schemas_path: "spec/schemas/reader")
219
+ .decode_all(encoded_data, schema_name: "person").entries
220
+ ).to eq(
221
+ [
222
+ {"name"=>"Python🐍", "age"=>256, "fav_color"=>"red🟥"},
223
+ {"name"=>"Mojo🐍", "age"=>1, "fav_color"=>"red🟥"}
224
+ ]
225
+ )
226
+ end
227
+ end
228
+ end
229
+
189
230
  describe "#encode_to_stream" do
190
231
  it "writes encoded data to an existing stream" do
191
232
  define_schema "message.avsc", <<-AVSC
@@ -304,6 +345,20 @@ describe AvroTurf do
304
345
  end
305
346
  end
306
347
 
348
+ describe "#decode_all_from_stream" do
349
+ it "returns all entries when decodes Avro data from a stream containing multiple entries" do
350
+ encoded_data = "Obj\u0001\u0004\u0014avro.codec\bnull\u0016avro.schema\xB6\u0004[{\"type\": \"record\", \"name\": \"address\", \"fields\": [{\"type\": \"string\", \"name\": \"street\"}, {\"type\": \"string\", \"name\": \"city\"}]}, {\"type\": \"record\", \"name\": \"person\", \"fields\": [{\"type\": \"string\", \"name\": \"name\"}, {\"type\": \"int\", \"name\": \"age\"}, {\"type\": \"address\", \"name\": \"address\"}]}]\u0000\xF9u\x84\xA1c\u0010\x82B\xE2\xCF\xF1\x98\xF7\xF1JH\u0004\x96\u0001\u0002\u0014Python🐍\x80\u0004\u0018Green Street\u001ASan Francisco\u0002\u0010Mojo🐍\u0002\u0016Blue Street\u0014Saturn🪐\xF9u\x84\xA1c\u0010\x82B\xE2\xCF\xF1\x98\xF7\xF1JH"
351
+ stream = StringIO.new(encoded_data)
352
+
353
+ expect(avro.decode_all_from_stream(stream).entries).to eq(
354
+ [
355
+ {"name"=>"Python🐍", "age"=>256, "address"=>{"street"=>"Green Street", "city"=>"San Francisco"}},
356
+ {"name"=>"Mojo🐍", "age"=>1, "address"=>{"street"=>"Blue Street", "city"=>"Saturn🪐"}}
357
+ ]
358
+ )
359
+ end
360
+ end
361
+
307
362
  describe "#valid?" do
308
363
  before do
309
364
  define_schema "message.avsc", <<-AVSC
@@ -109,7 +109,7 @@ describe AvroTurf::Messaging do
109
109
  end
110
110
 
111
111
  it 'encodes and decodes messages' do
112
- data = avro.encode(message, schema_id: 1)
112
+ data = avro.encode(message, schema_id: 0)
113
113
  expect(avro.decode(data)).to eq message
114
114
  end
115
115
 
@@ -118,7 +118,7 @@ describe AvroTurf::Messaging do
118
118
  end
119
119
 
120
120
  it 'caches parsed schemas for decoding' do
121
- data = avro.encode(message, schema_id: 1)
121
+ data = avro.encode(message, schema_id: 0)
122
122
  avro.decode(data)
123
123
  allow(Avro::Schema).to receive(:parse).and_call_original
124
124
  expect(avro.decode(data)).to eq message
@@ -361,6 +361,49 @@ describe AvroTurf::SchemaStore do
361
361
  end
362
362
 
363
363
  describe "#load_schemas!" do
364
+ it "do not try to reload known schemas" do
365
+ define_schema "first.avsc", <<-AVSC
366
+ {
367
+ "name": "first",
368
+ "type": "record",
369
+ "fields": [
370
+ {
371
+ "type": "string",
372
+ "name": "a_value"
373
+ }
374
+ ]
375
+ }
376
+ AVSC
377
+
378
+ define_schema "second.avsc", <<-AVSC
379
+ {
380
+ "name": "second",
381
+ "type": "record",
382
+ "fields": [
383
+ {
384
+ "type": "first",
385
+ "name": "full_name"
386
+ }
387
+ ]
388
+ }
389
+ AVSC
390
+
391
+ define_schema "third.avsc", <<-AVSC
392
+ {
393
+ "name": "third",
394
+ "type": "record",
395
+ "fields": [
396
+ {
397
+ "type": "second",
398
+ "name": "embedded_first"
399
+ }
400
+ ]
401
+ }
402
+ AVSC
403
+
404
+ expect { store.load_schemas! }.not_to raise_error
405
+ end
406
+
364
407
  it "loads schemas defined in the `schemas_path` directory" do
365
408
  define_schema "person.avsc", <<-AVSC
366
409
  {
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'bundler/setup'
2
2
  require 'logger'
3
3
  require 'json_spec'
4
+ require 'pp' # Require pp before fakefs to fix TypeError: superclass mismatch for class File
4
5
  require 'fakefs/spec_helpers'
5
6
  require 'avro_turf'
6
7
 
@@ -77,6 +77,33 @@ shared_examples_for "a confluent schema registry client" do
77
77
  end
78
78
  end
79
79
 
80
+ describe "#schema_subject_versions" do
81
+ it "returns subject and version for a schema id" do
82
+ schema_id1 = registry.register(subject_name, { type: :record, name: "r1", fields: [] }.to_json)
83
+ registry.register(subject_name, { type: :record, name: "r2", fields: [] }.to_json)
84
+ schema_id2 = registry.register("other#{subject_name}", { type: :record, name: "r2", fields: [] }.to_json)
85
+ expect(registry.schema_subject_versions(schema_id1)).to eq([
86
+ 'subject' => subject_name,
87
+ 'version' => 1
88
+ ])
89
+ expect(registry.schema_subject_versions(schema_id2)).to include({
90
+ 'subject' => subject_name,
91
+ 'version' => 2
92
+ },{
93
+ 'subject' => "other#{subject_name}",
94
+ 'version' => 1
95
+ } )
96
+ end
97
+
98
+ context "when the schema does not exist" do
99
+ it "raises an error" do
100
+ expect do
101
+ registry.schema_subject_versions(-1)
102
+ end.to raise_error(Excon::Errors::NotFound)
103
+ end
104
+ end
105
+ end
106
+
80
107
  describe "#subject_versions" do
81
108
  it "lists all the versions for the subject" do
82
109
  2.times do |n|
@@ -27,14 +27,75 @@ describe FakeConfluentSchemaRegistryServer do
27
27
  expect(JSON.parse(last_response.body).fetch('id')).to eq expected_id
28
28
  end
29
29
 
30
- it 'returns a different schema ID when invoked with same schema and different subject' do
30
+ it 'returns the same schema ID when invoked with same schema and different subject' do
31
31
  post '/subjects/person/versions', { schema: schema }.to_json, 'CONTENT_TYPE' => 'application/vnd.schemaregistry+json'
32
32
 
33
33
  original_id = JSON.parse(last_response.body).fetch('id')
34
34
 
35
35
  post '/subjects/happy-person/versions', { schema: schema }.to_json, 'CONTENT_TYPE' => 'application/vnd.schemaregistry+json'
36
36
 
37
- expect(JSON.parse(last_response.body).fetch('id')).not_to eq original_id
37
+ expect(JSON.parse(last_response.body).fetch('id')).to eq original_id
38
+ end
39
+
40
+ it 'returns a different schema ID when invoked with a different schema' do
41
+ post '/subjects/person/versions', { schema: schema }.to_json, 'CONTENT_TYPE' => 'application/vnd.schemaregistry+json'
42
+
43
+ original_id = JSON.parse(last_response.body).fetch('id')
44
+
45
+ other_schema = {
46
+ type: "record",
47
+ name: "other",
48
+ fields: [
49
+ { name: "name", type: "string" }
50
+ ]
51
+ }.to_json
52
+
53
+ post '/subjects/person/versions', { schema: other_schema }.to_json, 'CONTENT_TYPE' => 'application/vnd.schemaregistry+json'
54
+
55
+ expect(JSON.parse(last_response.body).fetch('id')).to_not eq original_id
56
+ end
57
+ end
58
+
59
+ describe 'GET /schemas/ids/:id/versions' do
60
+ def schema(name:)
61
+ {
62
+ type: "record",
63
+ name: name,
64
+ fields: [
65
+ { name: "name", type: "string" },
66
+ ]
67
+ }.to_json
68
+ end
69
+
70
+ it "returns array containing subjects and versions for given schema id" do
71
+ schema1 = schema(name: "name1")
72
+ schema2 = schema(name: "name2")
73
+
74
+ post "/subjects/cats/versions", { schema: schema1 }.to_json, 'CONTENT_TYPE' => 'application/vnd.schemaregistry+json'
75
+ schema1_id = JSON.parse(last_response.body).fetch('id') # Original cats schema
76
+
77
+ post "/subjects/dogs/versions", { schema: schema2 }.to_json, 'CONTENT_TYPE' => 'application/vnd.schemaregistry+json'
78
+ post "/subjects/cats/versions", { schema: schema2 }.to_json, 'CONTENT_TYPE' => 'application/vnd.schemaregistry+json'
79
+ schema2_id = JSON.parse(last_response.body).fetch('id') # Changed cats schema == Original Dogs schema
80
+
81
+ get "/schemas/ids/#{schema1_id}/versions"
82
+ result = JSON.parse(last_response.body)
83
+
84
+ expect(result).to eq [{
85
+ 'subject' => 'cats',
86
+ 'version' => 1
87
+ }]
88
+
89
+ get "/schemas/ids/#{schema2_id}/versions"
90
+ result = JSON.parse(last_response.body)
91
+
92
+ expect(result).to include( {
93
+ 'subject' => 'cats',
94
+ 'version' => 2
95
+ }, {
96
+ 'subject' => 'dogs',
97
+ 'version' => 1
98
+ })
38
99
  end
39
100
  end
40
101
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avro_turf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schierbeck
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-06 00:00:00.000000000 Z
11
+ date: 2023-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.7.7
19
+ version: 1.8.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '1.12'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 1.7.7
29
+ version: 1.8.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '1.12'
@@ -156,7 +156,7 @@ dependencies:
156
156
  - - ">="
157
157
  - !ruby/object:Gem::Version
158
158
  version: '0'
159
- description:
159
+ description:
160
160
  email:
161
161
  - dasch@zendesk.com
162
162
  executables: []
@@ -251,8 +251,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
251
  - !ruby/object:Gem::Version
252
252
  version: '0'
253
253
  requirements: []
254
- rubygems_version: 3.0.3.1
255
- signing_key:
254
+ rubygems_version: 3.4.10
255
+ signing_key:
256
256
  specification_version: 4
257
257
  summary: A library that makes it easier to use the Avro serialization format from
258
258
  Ruby