proto_turf 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 748636abfd68b4fbf48cb1786c3d2617ae0b48400c23e14c9ff03786601a4dd8
4
+ data.tar.gz: 9b3e76306ecefa2cfe6ca7b097b366d8145ec4c3a2c1dbe59b05625b1d1b37e7
5
+ SHA512:
6
+ metadata.gz: 58e153ed45709e81d7b1d6d2b35523282d866a20f925e549ace5930daf29d1f2afafadcdd48b383bc7f27e662e401aa72cabc7cbd9e4a3d5bc3abad3f121f0d2
7
+ data.tar.gz: 5715d4b57c35db06292f30ec6228a19d4e089e65558cf0e2c0c698ec930fc471541a1b92d9743344a173a6b7b67ba2c8593bbe198bca5eb58841112d8f5339ce
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Flipp
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
@@ -0,0 +1,48 @@
1
+ # proto_turf
2
+
3
+ `proto_turf` is a library to interact with the Confluent Schema Registry using Google Protobuf. It is inspired by and based off of [avro_turf](https://github.com/dasch/avro_turf).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'proto_turf'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install proto_turf
20
+
21
+ ## Usage
22
+
23
+ ProtoTurf interacts with the Confluent Schema Registry, and caches all results. When you first encode a message, it will register the message and all dependencies with the Schema Registry. When decoding, it will look up the schema in the Schema Registry and use the associated local generated code to decode the message.
24
+
25
+ Example usage:
26
+
27
+ ```ruby
28
+ require 'proto_turf'
29
+
30
+ proto_turf = ProtoTurf.new(registry_url: 'http://localhost:8081')
31
+ message = MyProto::MyMessage.new(field1: 'value1', field2: 42)
32
+ encoded = proto_turf.encode(message, subject: 'my-subject')
33
+
34
+ # Decoding
35
+
36
+ decoded_proto_message = proto_turf.decode(encoded_string)
37
+ ```
38
+
39
+ If you're using [buf](https://buf.build/) to manage your Protobuf definitions, you should run `buf export` before using `proto_turf` to ensure that all the dependencies are available as `.proto` files in your project. The actual proto text is needed when registering the schema with the Schema Registry.
40
+
41
+ ## Notes about usage
42
+
43
+ * For now, this library only supports a single message per `.proto` file that is registered with the Schema Registry. You can reference as many other files and messages as you like from that message, but keeping it to one message per file simplifies the workflow significantly.
44
+ * When decoding, this library does *not* attempt to fully parse the Proto definition stored on the schema registry and generate dynamic classes. Instead, it simply parses out the package and message and assumes that the reader has the message available in the descriptor pool. Any compatibility issues should be detected through normal means, i.e. just by instantiating the message and seeing if any errors are raised.
45
+
46
+ ## TODO
47
+
48
+ * Support multi-message proto files
@@ -0,0 +1,51 @@
1
+ class ProtoTurf::CachedConfluentSchemaRegistry
2
+
3
+ # @param upstream [ProtoTurf::ConfluentSchemaRegistry]
4
+ def initialize(upstream)
5
+ @upstream = upstream
6
+ @schemas_by_id = {}
7
+ @ids_by_schema = {}
8
+ @versions_by_subject_and_id = {}
9
+ end
10
+
11
+ # Delegate the following methods to the upstream
12
+ %i(subject_versions schema_subject_versions).each do |name|
13
+ define_method(name) do |*args|
14
+ instance_variable_get(:@upstream).send(name, *args)
15
+ end
16
+ end
17
+
18
+ # @param id [Integer] the schema ID to fetch
19
+ # @return [String] the schema string stored in the registry for the given id
20
+ def fetch(id)
21
+ @schemas_by_id[id] ||= @upstream.fetch(id)
22
+ end
23
+
24
+ # @param id [Integer] the schema ID to fetch
25
+ # @param subject [String] the subject to fetch the version for
26
+ # @return [Integer, nil] the version of the schema for the given subject and id, or nil if not found
27
+ def fetch_version(id, subject)
28
+ key = [subject, id]
29
+ return @versions_by_subject_and_id[key] if @versions_by_subject_and_id[key]
30
+
31
+ results = @upstream.schema_subject_versions(id)
32
+ @versions_by_subject_and_id[key] = results&.find { |r| r['subject'] == subject }&.dig('version')
33
+ end
34
+
35
+ # @param subject [String] the subject to check
36
+ # @param schema [String] the schema text to check
37
+ # @return [Boolean] true if we know the schema has been registered for that subject.
38
+ def registered?(subject, schema)
39
+ @ids_by_schema[[subject, schema]].present?
40
+ end
41
+
42
+ # @param subject [String] the subject to register the schema under
43
+ # @param schema [String] the schema text to register
44
+ # @param references [Array<Hash>] optional references to other schemas
45
+ def register(subject, schema, references: [])
46
+ key = [subject, schema]
47
+
48
+ @ids_by_schema[key] ||= @upstream.register(subject, schema, references: references)
49
+ end
50
+
51
+ end
@@ -0,0 +1,118 @@
1
+ require 'excon'
2
+
3
+ class ProtoTurf
4
+ class ConfluentSchemaRegistry
5
+
6
+ CONTENT_TYPE = "application/vnd.schemaregistry.v1+json".freeze
7
+
8
+ def initialize(
9
+ url,
10
+ schema_context: nil,
11
+ logger: Logger.new($stdout),
12
+ proxy: nil,
13
+ user: nil,
14
+ password: nil,
15
+ ssl_ca_file: nil,
16
+ client_cert: nil,
17
+ client_key: nil,
18
+ client_key_pass: nil,
19
+ client_cert_data: nil,
20
+ client_key_data: nil,
21
+ path_prefix: nil,
22
+ connect_timeout: nil,
23
+ resolv_resolver: nil,
24
+ retry_limit: nil
25
+ )
26
+ @path_prefix = path_prefix
27
+ @schema_context_prefix = schema_context.nil? ? '' : ":.#{schema_context}:"
28
+ @schema_context_options = schema_context.nil? ? {} : {query: {subject: @schema_context_prefix}}
29
+ @logger = logger
30
+ headers = Excon.defaults[:headers].merge(
31
+ "Content-Type" => CONTENT_TYPE
32
+ )
33
+ params = {
34
+ headers: headers,
35
+ user: user,
36
+ password: password,
37
+ proxy: proxy,
38
+ ssl_ca_file: ssl_ca_file,
39
+ client_cert: client_cert,
40
+ client_key: client_key,
41
+ client_key_pass: client_key_pass,
42
+ client_cert_data: client_cert_data,
43
+ client_key_data: client_key_data,
44
+ resolv_resolver: resolv_resolver,
45
+ connect_timeout: connect_timeout,
46
+ retry_limit: retry_limit
47
+ }
48
+ # Remove nil params to allow Excon to use its default values
49
+ params.reject! { |_, v| v.nil? }
50
+ @connection = Excon.new(
51
+ url,
52
+ params
53
+ )
54
+ end
55
+
56
+ # @param id [Integer] the schema ID to fetch
57
+ # @return [String] the schema string stored in the registry for the given id
58
+ def fetch(id)
59
+ @logger.info "Fetching schema with id #{id}"
60
+ data = get("/schemas/ids/#{id}", idempotent: true, **@schema_context_options, )
61
+ data.fetch("schema")
62
+ end
63
+
64
+ # @param schema_id [Integer] the schema ID to fetch versions for
65
+ # @return [Array<Hash>] an array of versions for the given schema ID
66
+ def schema_subject_versions(schema_id)
67
+ get("/schemas/ids/#{schema_id}/versions", idempotent: true, **@schema_context_options)
68
+ end
69
+
70
+ # @param subject [String] the subject to check
71
+ # @param schema [String] the schema text to check
72
+ # @param references [Array<Hash>] optional references to other schemas
73
+ # @return [Integer] the ID of the registered schema
74
+ def register(subject, schema, references: [])
75
+ data = post("/subjects/#{@schema_context_prefix}#{CGI.escapeURIComponent(subject)}/versions",
76
+ body: { schemaType: 'PROTOBUF',
77
+ references: references,
78
+ schema: schema.to_s }.to_json)
79
+
80
+ id = data.fetch("id")
81
+
82
+ @logger.info "Registered schema for subject `#{@schema_context_prefix}#{subject}`; id = #{id}"
83
+
84
+ id
85
+ end
86
+
87
+ # @param subject [String]
88
+ # @return [Array<Hash>] an array of versions for the given subject
89
+ def subject_versions(subject)
90
+ get("/subjects/#{@schema_context_prefix}#{CGI.escapeURIComponent(subject)}/versions", idempotent: true)
91
+ end
92
+
93
+ private
94
+
95
+ def get(path, **options)
96
+ request(path, method: :get, **options)
97
+ end
98
+
99
+ def put(path, **options)
100
+ request(path, method: :put, **options)
101
+ end
102
+
103
+ def post(path, **options)
104
+ request(path, method: :post, **options)
105
+ end
106
+
107
+ def request(path, **options)
108
+ options = { expects: 200 }.merge!(options)
109
+ path = File.join(@path_prefix, path) unless @path_prefix.nil?
110
+ response = @connection.request(path: path, **options)
111
+ JSON.parse(response.body)
112
+ rescue Excon::Error => e
113
+ @logger.error("Error while requesting #{path}: #{e.response.body}")
114
+ raise
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,3 @@
1
+ class ProtoTurf
2
+ VERSION = "0.0.1"
3
+ end
data/lib/proto_turf.rb ADDED
@@ -0,0 +1,229 @@
1
+ require 'logger'
2
+ require 'proto_turf/confluent_schema_registry'
3
+ require 'proto_turf/cached_confluent_schema_registry'
4
+
5
+ class ProtoTurf
6
+ # Provides a way to encode and decode messages without having to embed schemas
7
+ # in the encoded data. Confluent's Schema Registry[1] is used to register
8
+ # a schema when encoding a message -- the registry will issue a schema id that
9
+ # will be included in the encoded data alongside the actual message. When
10
+ # decoding the data, the schema id will be used to look up the writer's schema
11
+ # from the registry.
12
+ #
13
+ # 1: https://github.com/confluentinc/schema-registry
14
+ # https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/serdes-protobuf.html
15
+ # https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/index.html#wire-format
16
+ MAGIC_BYTE = [0].pack("C").freeze
17
+
18
+
19
+ # Instantiate a new ProtoTurf instance with the given configuration.
20
+ #
21
+ # registry - A schema registry object that responds to all methods in the
22
+ # ProtoTurf::ConfluentSchemaRegistry interface.
23
+ # registry_url - The String URL of the schema registry that should be used.
24
+ # schema_context - Schema registry context name (optional)
25
+ # schemas_path - The String file system path where local schemas are stored.
26
+ # registry_path_prefix - The String URL path prefix used to namespace schema registry requests (optional).
27
+ # logger - The Logger that should be used to log information (optional).
28
+ # proxy - Forward the request via proxy (optional).
29
+ # user - User for basic auth (optional).
30
+ # password - Password for basic auth (optional).
31
+ # ssl_ca_file - Name of file containing CA certificate (optional).
32
+ # client_cert - Name of file containing client certificate (optional).
33
+ # client_key - Name of file containing client private key to go with client_cert (optional).
34
+ # client_key_pass - Password to go with client_key (optional).
35
+ # client_cert_data - In-memory client certificate (optional).
36
+ # client_key_data - In-memory client private key to go with client_cert_data (optional).
37
+ # connect_timeout - Timeout to use in the connection with the schema registry (optional).
38
+ # resolv_resolver - Custom domain name resolver (optional).
39
+ def initialize(
40
+ registry: nil,
41
+ registry_url: nil,
42
+ schema_context: nil,
43
+ schemas_path: nil,
44
+ registry_path_prefix: nil,
45
+ logger: nil,
46
+ proxy: nil,
47
+ user: nil,
48
+ password: nil,
49
+ ssl_ca_file: nil,
50
+ client_cert: nil,
51
+ client_key: nil,
52
+ client_key_pass: nil,
53
+ client_cert_data: nil,
54
+ client_key_data: nil,
55
+ connect_timeout: nil,
56
+ resolv_resolver: nil,
57
+ retry_limit: nil
58
+ )
59
+ @logger = logger || Logger.new($stderr)
60
+ @path = schemas_path
61
+ @registry = registry || ProtoTurf::CachedConfluentSchemaRegistry.new(
62
+ ProtoTurf::ConfluentSchemaRegistry.new(
63
+ registry_url,
64
+ schema_context: schema_context,
65
+ logger: @logger,
66
+ proxy: proxy,
67
+ user: user,
68
+ password: password,
69
+ ssl_ca_file: ssl_ca_file,
70
+ client_cert: client_cert,
71
+ client_key: client_key,
72
+ client_key_pass: client_key_pass,
73
+ client_cert_data: client_cert_data,
74
+ client_key_data: client_key_data,
75
+ path_prefix: registry_path_prefix,
76
+ connect_timeout: connect_timeout,
77
+ resolv_resolver: resolv_resolver
78
+ )
79
+ )
80
+ @all_schemas = {}
81
+ end
82
+
83
+ # Encodes a message using the specified schema.
84
+ #
85
+ # message - The message that should be encoded. Must be compatible with
86
+ # the schema.
87
+ # subject - The subject name the schema should be registered under in
88
+ # the schema registry (optional).
89
+ # Returns the encoded data as a String.
90
+ def encode(message, subject: nil)
91
+ load_schemas! if @all_schemas.empty?
92
+
93
+ id = register_schema(message.class.descriptor.file_descriptor, subject: subject)
94
+
95
+ stream = StringIO.new
96
+ # Always start with the magic byte.
97
+ stream.write(MAGIC_BYTE)
98
+
99
+ # The schema id is encoded as a 4-byte big-endian integer.
100
+ stream.write([id].pack("N"))
101
+
102
+ # For now, we're only going to support a single message per schema. See
103
+ # https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/index.html#wire-format
104
+ write_int(stream, 0)
105
+
106
+ # Now we write the actual message.
107
+ stream.write(message.to_proto)
108
+
109
+ stream.string
110
+ rescue Excon::Error::NotFound
111
+ if schema_id
112
+ raise SchemaNotFoundError.new("Schema with id: #{schema_id} is not found on registry")
113
+ else
114
+ raise SchemaNotFoundError.new("Schema with subject: `#{subject}` version: `#{version}` is not found on registry")
115
+ end
116
+ end
117
+
118
+ # Decodes data into the original message.
119
+ #
120
+ # data - A String containing encoded data.
121
+ #
122
+ # Returns a Protobuf AbstractMessage object instantiated with the decoded data.
123
+ def decode(data)
124
+ stream = StringIO.new(data)
125
+
126
+ # The first byte is MAGIC!!!
127
+ magic_byte = stream.read(1)
128
+
129
+ if magic_byte != MAGIC_BYTE
130
+ raise "Expected data to begin with a magic byte, got `#{magic_byte.inspect}`"
131
+ end
132
+
133
+ # The schema id is a 4-byte big-endian integer.
134
+ schema_id = stream.read(4).unpack("N").first
135
+
136
+ # For now, we're only going to support a single message per schema. See
137
+ # https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/index.html#wire-format
138
+ read_int(stream)
139
+
140
+ schema = @registry.fetch(schema_id)
141
+ encoded = stream.read
142
+ decode_protobuf(schema, encoded)
143
+ rescue Excon::Error::NotFound
144
+ raise SchemaNotFoundError.new("Schema with id: #{schema_id} is not found on registry")
145
+ end
146
+
147
+ private
148
+
149
+ # Write an int with zig-zag encoding. Copied from Avro.
150
+ def write_int(stream, n)
151
+ n = (n << 1) ^ (n >> 63)
152
+ while (n & ~0x7F) != 0
153
+ stream.write(((n & 0x7f) | 0x80).chr)
154
+ n >>= 7
155
+ end
156
+ stream.write(n.chr)
157
+ end
158
+
159
+ # Read an int with zig-zag encoding. Copied from Avro.
160
+ def read_int(stream)
161
+ b = stream.readbyte
162
+ n = b & 0x7F
163
+ shift = 7
164
+ while (b & 0x80) != 0
165
+ b = stream.readbyte
166
+ n |= (b & 0x7F) << shift
167
+ shift += 7
168
+ end
169
+ (n >> 1) ^ -(n & 1)
170
+ end
171
+
172
+ def decode_protobuf(schema, encoded)
173
+ # get the package
174
+ package = schema.match(/package (\S+);/)[1]
175
+ # get the first message in the protobuf text
176
+ # TODO - get the correct message based on schema index
177
+ message_name = schema.match(/message (\w+) {/)[1]
178
+ # look up the descriptor
179
+ full_name = "#{package}.#{message_name}"
180
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(full_name)
181
+ unless descriptor
182
+ raise "Could not find schema for #{full_name}. Make sure the corresponding .proto file has been compiled and loaded."
183
+ end
184
+ descriptor.msgclass.decode(encoded)
185
+ end
186
+
187
+ def register_schema(file_descriptor, subject: nil)
188
+ subject ||= file_descriptor.name
189
+ return if @registry.registered?(file_descriptor.name, subject)
190
+
191
+ # register dependencies first
192
+ dependencies = file_descriptor.to_proto.dependency.to_a.reject { |d| d.start_with?('google/protobuf/') }
193
+ versions = dependencies.map do |dependency|
194
+ dependency_descriptor = @all_schemas[dependency]
195
+ result = register_schema(dependency_descriptor, subject: dependency_descriptor.name)
196
+ @registry.fetch_version(result, dependency_descriptor.name)
197
+ end
198
+
199
+ @registry.register(subject,
200
+ schema_text(file_descriptor),
201
+ references: dependencies.map.with_index do |dependency, i|
202
+ {
203
+ name: dependency,
204
+ subject: dependency,
205
+ version: versions[i]
206
+ }
207
+ end
208
+ )
209
+ end
210
+
211
+ def schema_text(file_descriptor)
212
+ filename = "#{@path}/#{file_descriptor.name}"
213
+ File.exist?(filename) ? File.read(filename) : ""
214
+ end
215
+
216
+ def load_schemas!
217
+ all_messages = ObjectSpace.each_object(Class).select do |o|
218
+ o < Google::Protobuf.const_get(:AbstractMessage)
219
+ end.to_a
220
+ all_messages.each do |m|
221
+ file_desc = m.descriptor.file_descriptor
222
+ file_path = file_desc.name
223
+ next if file_path.start_with?('google/protobuf/') # skip built-in protos
224
+
225
+ @all_schemas[file_path] = file_desc
226
+ end
227
+ end
228
+
229
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'proto_turf/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "proto_turf"
8
+ spec.version = ProtoTurf::VERSION
9
+ spec.authors = ["Daniel Orner"]
10
+ spec.email = ["daniel.orner@flipp.com"]
11
+ spec.summary = "Support for Protobuf files in Confluent Schema Registry"
12
+ spec.homepage = "https://github.com/flipp-oss/proto_turf"
13
+ spec.license = "MIT"
14
+
15
+ spec.metadata["rubygems_mfa_required"] = "true"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "google-protobuf"
23
+
24
+ spec.add_development_dependency "bundler", "~> 2.0"
25
+ spec.add_development_dependency "rake", "~> 13.0"
26
+ spec.add_development_dependency "rspec", "~> 3.2"
27
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: proto_turf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Orner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-08-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: google-protobuf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.2'
69
+ description:
70
+ email:
71
+ - daniel.orner@flipp.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - LICENSE
77
+ - README.md
78
+ - lib/proto_turf.rb
79
+ - lib/proto_turf/cached_confluent_schema_registry.rb
80
+ - lib/proto_turf/confluent_schema_registry.rb
81
+ - lib/proto_turf/version.rb
82
+ - proto_turf.gemspec
83
+ homepage: https://github.com/flipp-oss/proto_turf
84
+ licenses:
85
+ - MIT
86
+ metadata:
87
+ rubygems_mfa_required: 'true'
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubygems_version: 3.4.10
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Support for Protobuf files in Confluent Schema Registry
107
+ test_files: []