avromatic 4.1.1 → 4.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bec6621c5d35e04596185542eaa4d96d00ef67f86f24b26378c68b22ecb3b3c
4
- data.tar.gz: 1468ebd3138c5dc63a5d18d86dab5757df5c67109867628d1161b01ef70db1f3
3
+ metadata.gz: 5d9619909ed1f1301168536a2907146f30da67a08dd2bb4377d7cb0aa6cb4b6f
4
+ data.tar.gz: 3ff48eef3f8880fbd2f36eeda17008723be7bdc269a5546f432e1f5e6c09635d
5
5
  SHA512:
6
- metadata.gz: da43c835a7f56011c1ed194bba7a02e5f98a190f65a8ce025b67f8a23d9a43093e2e64f83cdaf520d847c37ecf66cfd6ed276aee7f195a9f3f2b0c248967f5bf
7
- data.tar.gz: 920048102d5947af69eca3d4e4c357adf9eefaebbd83e8d70190d29a6fb8d30c65072c97fda65613d9ebed32e127f98d9f4952e1e91e081963e61a480a002af3
6
+ metadata.gz: 61cc46b27e9544faea7b411f5f10676d206c0504fabb69f2ebf0ad00b7d6adc0610973c4c27a6716ca1e7676c6436f4be8eb1c8298978fe7b4ece5c8910fe6ae
7
+ data.tar.gz: 5ec19a93b881b723589b5f8afdaf1a0e41b15d601ca2ab840f8c627f74db3eeeab21b678c396840675caae75a3a92ccf97b872ea355cb94b2850e58d22179e12
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Avromatic
4
- VERSION = '4.1.1'
4
+ VERSION = '4.2.0'
5
5
  end
data/lib/avromatic.rb CHANGED
@@ -79,7 +79,11 @@ module Avromatic
79
79
  end
80
80
 
81
81
  def self.eager_load_models=(models)
82
- @eager_load_model_names = Array(models).map { |model| model.is_a?(Class) ? model.name : model }
82
+ @eager_load_model_names = Array(models).map { |model| model.is_a?(Class) ? model.name : model }.freeze
83
+ end
84
+
85
+ def self.eager_load_models
86
+ @eager_load_model_names
83
87
  end
84
88
 
85
89
  def self.eager_load_models!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avromatic
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Salsify Engineering
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-26 00:00:00.000000000 Z
11
+ date: 2022-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -273,30 +273,9 @@ executables: []
273
273
  extensions: []
274
274
  extra_rdoc_files: []
275
275
  files:
276
- - ".circleci/config.yml"
277
- - ".github/CODEOWNERS"
278
- - ".gitignore"
279
- - ".overcommit.yml"
280
- - ".rspec"
281
- - ".rubocop.yml"
282
- - ".ruby-gemset"
283
- - ".ruby-version"
284
- - Appraisals
285
- - CHANGELOG.md
286
- - Gemfile
287
276
  - LICENSE.txt
288
- - README.md
289
- - Rakefile
290
- - avromatic.gemspec
291
277
  - bin/console
292
278
  - bin/setup
293
- - gemfiles/.bundle/config
294
- - gemfiles/avro1_10_rails5_2.gemfile
295
- - gemfiles/avro1_10_rails6_0.gemfile
296
- - gemfiles/avro1_10_rails6_1.gemfile
297
- - gemfiles/avro1_10_rails7_0.gemfile
298
- - gemfiles/avro1_11_rails6_1.gemfile
299
- - gemfiles/avro1_11_rails7_0.gemfile
300
279
  - lib/avromatic.rb
301
280
  - lib/avromatic/io.rb
302
281
  - lib/avromatic/io/datum_reader.rb
@@ -342,7 +321,6 @@ files:
342
321
  - lib/avromatic/railtie.rb
343
322
  - lib/avromatic/rspec.rb
344
323
  - lib/avromatic/version.rb
345
- - log/.gitkeep
346
324
  homepage: https://github.com/salsify/avromatic.git
347
325
  licenses:
348
326
  - MIT
data/.circleci/config.yml DELETED
@@ -1,88 +0,0 @@
1
- version: 2.1
2
- jobs:
3
- lint:
4
- docker:
5
- - image: salsify/ruby_ci:2.7.4
6
- working_directory: ~/avromatic
7
- steps:
8
- - checkout
9
- - restore_cache:
10
- keys:
11
- - v2-gems-ruby-2.7.4-{{ checksum "avromatic.gemspec" }}-{{ checksum "Gemfile" }}
12
- - v2-gems-ruby-2.7.4-
13
- - run:
14
- name: Install Gems
15
- command: |
16
- if ! bundle check --path=vendor/bundle; then
17
- bundle install --path=vendor/bundle --jobs=4 --retry=3
18
- bundle clean
19
- fi
20
- - save_cache:
21
- key: v2-gems-ruby-2.7.4-{{ checksum "avromatic.gemspec" }}-{{ checksum "Gemfile" }}
22
- paths:
23
- - "vendor/bundle"
24
- - "gemfiles/vendor/bundle"
25
- - run:
26
- name: Run Rubocop
27
- command: bundle exec rubocop
28
- test:
29
- parameters:
30
- gemfile:
31
- type: string
32
- ruby-version:
33
- type: string
34
- docker:
35
- - image: salsify/ruby_ci:<< parameters.ruby-version >>
36
- environment:
37
- CIRCLE_TEST_REPORTS: "test-results"
38
- BUNDLE_GEMFILE: << parameters.gemfile >>
39
- working_directory: ~/avromatic
40
- steps:
41
- - checkout
42
- - restore_cache:
43
- keys:
44
- - v2-gems-ruby-<< parameters.ruby-version >>-{{ checksum "avromatic.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
45
- - v2-gems-ruby-<< parameters.ruby-version >>-
46
- - run:
47
- name: Install Gems
48
- command: |
49
- if ! bundle check --path=vendor/bundle; then
50
- bundle install --path=vendor/bundle --jobs=4 --retry=3
51
- bundle clean
52
- fi
53
- - save_cache:
54
- key: v2-gems-ruby-<< parameters.ruby-version >>-{{ checksum "avromatic.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
55
- paths:
56
- - "vendor/bundle"
57
- - "gemfiles/vendor/bundle"
58
- - run:
59
- name: Run Tests
60
- command: |
61
- bundle exec rspec --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/rspec/junit.xml --format progress spec
62
- - store_test_results:
63
- path: "test-results"
64
- workflows:
65
- build:
66
- jobs:
67
- - lint
68
- - test:
69
- matrix:
70
- parameters:
71
- gemfile:
72
- - "gemfiles/avro1_10_rails5_2.gemfile"
73
- - "gemfiles/avro1_10_rails6_0.gemfile"
74
- - "gemfiles/avro1_10_rails6_1.gemfile"
75
- - "gemfiles/avro1_10_rails7_0.gemfile"
76
- - "gemfiles/avro1_11_rails7_0.gemfile"
77
- ruby-version:
78
- - "2.7.4"
79
- - test:
80
- matrix:
81
- parameters:
82
- gemfile:
83
- - "gemfiles/avro1_10_rails6_1.gemfile"
84
- - "gemfiles/avro1_10_rails7_0.gemfile"
85
- - "gemfiles/avro1_11_rails7_0.gemfile"
86
- ruby-version:
87
- - "3.0.3"
88
- - "3.1.0"
data/.github/CODEOWNERS DELETED
@@ -1 +0,0 @@
1
- * @jturkel @tjwp @salsify/infrastructure-services
data/.gitignore DELETED
@@ -1,14 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- /gemfiles/*.lock
11
- /log/*
12
-
13
- *.iml
14
- .idea
data/.overcommit.yml DELETED
@@ -1,14 +0,0 @@
1
- PreCommit:
2
- RuboCop:
3
- enabled: true
4
- required: false
5
- on_warn: fail
6
-
7
- HardTabs:
8
- enabled: true
9
- required: false
10
-
11
- CommitMsg:
12
- TrailingPeriod:
13
- enabled: false
14
-
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,17 +0,0 @@
1
- inherit_gem:
2
- salsify_rubocop: conf/rubocop.yml
3
-
4
- AllCops:
5
- TargetRubyVersion: 2.7
6
- Exclude:
7
- - 'vendor/**/*'
8
- - 'gemfiles/**/*'
9
-
10
- Style/MultilineBlockChain:
11
- Enabled: false
12
-
13
- Style/NumericPredicate:
14
- Enabled: false
15
-
16
- Style/FrozenStringLiteralComment:
17
- Enabled: true
data/.ruby-gemset DELETED
@@ -1 +0,0 @@
1
- avromatic
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.7.4
data/Appraisals DELETED
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- appraise 'avro1_10-rails5_2' do
4
- gem 'avro', '~> 1.10.0'
5
- gem 'activesupport', '~> 5.2.0'
6
- gem 'activemodel', '~> 5.2.0'
7
- end
8
-
9
- appraise 'avro1_10-rails6_0' do
10
- gem 'avro', '~> 1.10.0'
11
- gem 'activesupport', '~> 6.0.0'
12
- gem 'activemodel', '~> 6.0.0'
13
- end
14
-
15
- appraise 'avro1_10-rails6_1' do
16
- gem 'avro', '~> 1.10.0'
17
- gem 'activesupport', '~> 6.1.0'
18
- gem 'activemodel', '~> 6.1.0'
19
- end
20
-
21
- appraise 'avro1_10-rails7_0' do
22
- gem 'avro', '~> 1.10.0'
23
- gem 'activesupport', '~> 7.0.0'
24
- gem 'activemodel', '~> 7.0.0'
25
- end
26
-
27
- appraise 'avro1_11-rails6_1' do
28
- gem 'avro', '~> 1.11.0'
29
- gem 'activesupport', '~> 6.1.0'
30
- gem 'activemodel', '~> 6.1.0'
31
- end
32
-
33
- appraise 'avro1_11-rails7_0' do
34
- gem 'avro', '~> 1.11.0'
35
- gem 'activesupport', '~> 7.0.0'
36
- gem 'activemodel', '~> 7.0.0'
37
- end
data/CHANGELOG.md DELETED
@@ -1,275 +0,0 @@
1
- # avromatic changelog
2
-
3
- ## 4.1.1
4
- - Fix eager loading of nested models when using the Zeitwerk classloader with Rails.
5
-
6
- ## 4.1.0
7
- - Add support for specifying a subject for the avro schema when building an Avromatic model
8
-
9
- ## 4.0.0
10
- - Drop support for Ruby 2.6.
11
- - Drop support for Avro 1.9.
12
- - Add support for Avro 1.11.
13
- - Add support for Rails 7.0.
14
-
15
- ## 3.0.2
16
- - Reset the schema registry client between RSpec tests to ensure any cached values are
17
- consistent with the fake schema registry.
18
-
19
- ## 3.0.1
20
- - Raise an error when registering a nested model that has already been auto-generated.
21
- This avoids hard to troubleshoot coercion errors when instantiating models and fixes
22
- a regression introduced in Avromatic 2.2.2.
23
-
24
- ## 3.0.0
25
- - Drop support for Ruby 2.4.
26
- - Add support for Ruby 3.0.
27
- - Drop support for Avro < 1.9.
28
- - Drop support for Rails < 5.2.
29
- - Fix decoding of unions containing false boolean values.
30
-
31
- ## v2.4.0
32
- - Ignore the `validate` argument and always validate during serialization. This
33
- argument will be removed in Avromatic 3.0.
34
- - Optimize model validation during serialization.
35
- - Don't cache immutable model validation results or serialized Avro attributes if a model has mutable children.
36
-
37
- ## v2.3.0
38
- - Add support for Rails 6.1.
39
- - Optimize nested model serialization.
40
-
41
- ## v2.2.6
42
- - Optimize memory usage when serializing models.
43
-
44
- ## v2.2.5
45
- - Optimize memory usage when serializing, deserializing and instantiating models.
46
-
47
- ## v2.2.4
48
- - Compatibility with Avro v1.10.x.
49
-
50
- ## v2.2.3
51
- - Fix bug where method `#referenced_model_classes` was declared as private instead of public.
52
-
53
- ## v2.2.2
54
- - Fix missing models in the model registry when in development by loading the nested models of eager loaded models.
55
- - Fake schema registry support for stubbing URLs with usernames and passwords.
56
-
57
- ## v2.2.1
58
- - Avoid allocating default empty hash in `Avromatic::IO::DatumReader.read_data`
59
-
60
- ## v2.2.0
61
- - Add support for Rails 6.0.
62
- - Drop support for Ruby < 2.4.
63
-
64
- ## v2.1.0
65
- - Add `key_schema_name` and `value_schema_name` attributes to `UnexpectedKeyError`.
66
-
67
- ## v2.0.2
68
- - Optimize model initialization and decoding
69
-
70
- ## v2.0.1
71
- - Allow generated model attribute accessors to be overridden. This was a regression in Avromatic 2.0.0.
72
- - Ensure that timestamp-millis are coerced when the number of microseconds is divisible by 1,000 but the
73
- number of nanoseconds is not divisible by 1,000,000.
74
-
75
- ## v2.0.0
76
- - Remove [virtus](https://github.com/solnic/virtus) dependency resulting in a 3x performance improvement in model instantation and 1.4x - 2.0x performance improvement in Avro serialization and Avromatic code simplification.
77
- - Raise `Avromatic::Model::CoercionError` when attribute values can't be coerced to the target type in model constructors and attribute setters. Previously coercion errors weren't detected until Avro serialization or an explicit call to `valid?`.
78
- - Prevent model instances from being constructed with unknown attributes. Previously unknown attributes were ignored.
79
- This can be disabled by setting `Avromatic.allow_unknown_attributes` to `true`.
80
- WARNING: Setting `Avromatic.allow_unknown_attributes` to `true` will result in incorrect union member coercions
81
- if an earlier union member is satisfied by a subset of the latter union member's attributes.
82
- - Validate required attributes are present when serializing to Avro for better error messages. Explicit
83
- validation can still be done by calling the `valid?` or `invalid?` methods from the
84
- [ActiveModel::Validations](https://edgeapi.rubyonrails.org/classes/ActiveModel/Validations.html) interface
85
- but errors will now appear under the `:base` key. Previously these errors were detected late in the Avro serialization process resulting in hard to understand error messages.
86
- - Support for custom types in unions with more than one non-null type.
87
- - Drop support for Ruby < 2.3 and Rails < 5.0.
88
- - Call `super()` in model constructor making it easier to define class/module hierarchies for models.
89
-
90
- ## v1.0.0
91
- - No changes.
92
-
93
- ## v0.33.0
94
- - Fix compatibility with avro-patches v0.4.0.
95
-
96
- ## v0.32.0
97
- - Improve partial assignment using a hash for records outside of unions.
98
- - Prevent invalid types from being assigned to primitives in unions.
99
- - Add validation that primitive attributes have the expected type.
100
-
101
- ## v0.31.0
102
- - Add support for Rails 5.2.
103
-
104
- ## v0.30.0
105
- - Add `Avromatic::Model::MessageDecoder#model` method to return the Avromatic
106
- model class for a message.
107
-
108
- ## v0.29.1
109
- - Add `Avromatic.build_messaging!` to `avromatic/rspec`.
110
-
111
- ## v0.29.0
112
- - Add new public methods `#avro_key_datum` and `#avro_value_datum` on an
113
- Avromatic model instance that return the attributes of the model suitable for
114
- Avro encoding without any customizations.
115
-
116
- ## v0.28.1
117
- - Fix a bug that raised an error when encoding a cached model containing optional
118
- field(s). With this change, immutable model caching now enabled only when
119
- `avro-patches` is present.
120
-
121
- ## v0.28.0
122
- - Add support for caching avro encodings for immutable models
123
-
124
- ## v0.27.0
125
- - Patches avromatic model classes to cache `Virtus::ValueObject::AllowedWriterMethods#allowed_writer_methods`
126
- - Support Rails 5.1
127
-
128
- ## v0.26.0
129
- - Caches result of Avromatic::Model::RawSerialization#value_attributes_for_avro for immutable models
130
-
131
- ## v0.25.0
132
- - Disallow optional fields in schemas used for keys by default.
133
-
134
- ## v0.24.0
135
- - Add `Avromatic::IO::DatumWriter` to optimize the encoding of Avro unions
136
- from Avromatic models.
137
- - Expose the `#key_attributes_for_avro` method on models.
138
-
139
- ## v0.23.0
140
- - Add mutable option when defining a model.
141
-
142
- ## v0.22.0
143
- - Require `avro_schema_registry_client` v0.3.0 or later to avoid
144
- using `avro-salsify-fork`.
145
-
146
- ## v0.21.1
147
- - Fix a bug in the optimization of optional union decoding.
148
-
149
- ## v0.21.0
150
- - Remove monkey-patches for `AvroTurf::ConfluentSchemaRegistry` and
151
- `FakeConfluentSchemaRegistryServer` and depend on `avro_schema_registry-client`
152
- instead.
153
- - Rename the configuration option `use_cacheable_schema_registration` to
154
- `use_schema_fingerprint_lookup`.
155
-
156
- ## v0.20.0
157
- - Support schema stores with a `#clear_schemas` method.
158
-
159
- ## v0.19.0
160
- - Use a fingerprint based on `avro-resolution_canonical_form`.
161
-
162
- ## v0.18.1
163
- - Replace another reference to `avromatic/test/fake_schema_registry_server`.
164
-
165
- ## v0.18.0
166
- - Compatibility with `avro_turf` v0.8.0. `avromatic/test/fake_schema_registry_server`
167
- is now deprecated and will be removed in a future release.
168
- Use `avromatic/test/fake_confluent_schema_registry_server` instead.
169
-
170
- ## v0.17.1
171
- - Correctly namespace Avro errors raised by `Avromatic::IO::DatumReader`.
172
-
173
- ## v0.17.0
174
- - Add `.register_schemas!` method to generated models to register the associated
175
- schemas in a schema registry.
176
-
177
- ## v0.16.0
178
- - Add `#lookup_subject_schema` method to `AvroTurf::SchemaRegistry` patch to
179
- directly support looking up existing schema ids by fingerprint.
180
-
181
- ## v0.15.1
182
- - Add `Avromatic.use_cacheable_schema_registration` option to control the lookup
183
- of existing schema ids by fingerprint.
184
-
185
- ## v0.15.0
186
- - Add patch to `AvroTurf::SchemaRegistry` to lookup existing schema ids using
187
- `GET /subjects/:subject/fingerprints/:fingerprint` from `#register`.
188
- This endpoint is supported in the avro-schema-registry.
189
- - Add patch to the `FakeSchemaRegistryServer` from `AvroTurf` to support the
190
- fingerprint endpoint.
191
-
192
- ## v0.14.0
193
- - Add `Avromatic::Messaging` and `Avromatic::IO::DatumReader` classes to
194
- optimize the decoding of Avro unions to Avromatic models.
195
-
196
- ## v0.13.0
197
- - Add interfaces to deserialize as a hash of attributes instead of a model.
198
-
199
- ## v0.12.0
200
- - Clear the schema store, if it supports it, prior to code reloading in Rails
201
- applications. This allows schema changes to be picked up during code
202
- reloading.
203
-
204
- ## v0.11.2
205
- - Fix for models containing optional array and map fields.
206
-
207
- ## v0.11.1
208
- - Another fix for Rails initialization and reloading. Do not clear the nested
209
- models registry the first time that the `to_prepare` hook is called.
210
-
211
- ## v0.11.0
212
- - Replace `Avromatic.on_initialize` proc with `Avromatic.eager_load_models`
213
- array. The models listed by this configuration are added to the registry
214
- at the end of `.configure` and prior to code reloading in Rails applications.
215
- This is a compatibility breaking change.
216
-
217
- ## v0.10.0
218
- - Add `Avromatic.on_initialize` proc that is called at the end of `.configure`
219
- and on code reloading in Rails applications.
220
-
221
- ## v0.9.0
222
- - Experimental: Add support for more than one non-null type in a union.
223
- - Allow nested models to be referenced and reused.
224
- - Fix the serialization of nested complex types.
225
- - Add support for recursive models.
226
- - Allow required array and map fields to be empty. Only nil values for required
227
- array and map fields are now considered invalid.
228
- - Validate nested models. This includes models embedded within other complex
229
- types (array, map, and union).
230
- - Truncate values for timestamps to the precision supported by the logical type.
231
-
232
- ## v0.8.0
233
- - Add support for logical types. Currently this requires using the
234
- `avro-salsify-fork` gem for logical types support with Ruby.
235
-
236
- ## v0.7.1
237
- - Raise a more descriptive error when attempting to generate a model for a
238
- non-record Avro type.
239
-
240
- ## v0.7.0
241
- - Add RSpec `FakeSchemaRegistryServer` test helper.
242
-
243
- ## v0.6.2
244
- - Remove dependency on `Hash#transform_values` from `ActiveSupport` v4.2.
245
-
246
- ## v0.6.1
247
- - Fix serialization of array and map types that contain nested models.
248
-
249
- ## v0.6.0
250
- - Require `avro_turf` v0.7.0 or later.
251
-
252
- ## v0.5.0
253
- - Rename `Avromatic::Model::Decoder` to `MessageDecoder`.
254
- - Rename `.deserialize` on generated models to `.avro_message_decode`.
255
- - Add `#avro_raw_key`, `#avro_raw_value` and `.avro_raw_decode` methods to
256
- generated models to support encoding and decoding without a schema registry.
257
-
258
- ## v0.4.0
259
- - Allow the specification of a custom type, including conversion to/from Avro,
260
- for named types.
261
-
262
- ## v0.3.0
263
- - Remove dependency on the `private_attr` gem.
264
-
265
- ## v0.2.0
266
- - Allow a module level schema registry to be configured.
267
-
268
- ## v0.1.2
269
- - Do not build an `AvroTurf::Messaging` object for each model class.
270
-
271
- ## v0.1.1
272
- - Fix Railtie.
273
-
274
- ## v0.1.0
275
- - Initial release
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in avromatic.gemspec
6
- gemspec
data/README.md DELETED
@@ -1,477 +0,0 @@
1
- # Avromatic
2
-
3
- [![Build Status](https://circleci.com/gh/salsify/avromatic.svg?style=svg)][circleci]
4
- [![Gem Version](https://badge.fury.io/rb/avromatic.svg)](https://badge.fury.io/rb/avromatic)
5
-
6
- [circleci]: https://circleci.com/gh/salsify/avromatic
7
-
8
- `Avromatic` generates Ruby models from [Avro](http://avro.apache.org/) schemas
9
- and provides utilities to encode and decode them.
10
-
11
- **This README reflects Avromatic 2.0. Please see the
12
- [1-0-stable](https://github.com/salsify/avromatic/blob/1-0-stable/README.md) branch for Avromatic 1.0.**
13
-
14
- ## Installation
15
-
16
- Add this line to your application's Gemfile:
17
-
18
- ```ruby
19
- gem 'avromatic'
20
- ```
21
-
22
- And then execute:
23
-
24
- $ bundle
25
-
26
- Or install it yourself as:
27
-
28
- $ gem install avromatic
29
-
30
- See the [Logical Types](#logical-types) section below for details on using
31
- Avromatic with unreleased Avro features.
32
-
33
- ## Usage
34
-
35
- ### Configuration
36
-
37
- `Avromatic` supports the following configuration:
38
-
39
- #### Model Generation
40
-
41
- * **schema_store**: A schema store is required to load Avro schemas from the filesystem.
42
- It should be an object that responds to `find(name, namespace = nil)` and
43
- returns an `Avro::Schema` object. An `AvroTurf::SchemaStore` can be used.
44
- The `schema_store` is unnecessary if models are generated directly from
45
- `Avro::Schema` objects. See [Models](#models).
46
- * **nested_models**: An optional [ModelRegistry](https://github.com/salsify/avromatic/blob/master/lib/avromatic/model_registry.rb)
47
- that is used to store, by full schema name, the generated models that are
48
- embedded within top-level models. By default a new `Avromatic::ModelRegistry`
49
- is created.
50
- * **eager_load_models**: An optional array of models, or strings with class
51
- names for models, that are added to `nested_models` at the end of
52
- `Avromatic.configure` and during code reloading in Rails applications. This
53
- option is useful for defining models that will be extended when the load order
54
- is important.
55
- * **allow_unknown_attributes**: Optionally allow model constructors to silently
56
- ignore unknown attributes. Defaults to `false`. WARNING: Setting this to `true`
57
- will result in incorrect union member coercions if an earlier union member is
58
- satisfied by a subset of the latter union member's attributes.
59
-
60
- #### Custom Types
61
-
62
- See the section below on configuring [Custom Types](#custom-type-configuration).
63
-
64
- #### Using a Schema Registry/Messaging API
65
-
66
- The configuration options below are required when using a schema registry
67
- (see [Confluent Schema Registry](http://docs.confluent.io/2.0.1/schema-registry/docs/intro.html))
68
- and the [Messaging API](#messaging-api).
69
-
70
- * **schema_registry**: An `AvroSchemaRegistry::Client` or
71
- `AvroTurf::ConfluentSchemaRegistry` object used to store Avro schemas
72
- so that they can be referenced by id. Either `schema_registry` or
73
- `registry_url` must be configured.
74
- * **registry_url**: URL for the schema registry. Either `schema_registry` or
75
- `registry_url` must be configured. The `build_schema_registry!` method may
76
- be used to create a caching schema registry client instance based on other
77
- configuration values.
78
- * **use_schema_fingerprint_lookup**: Avromatic supports a Schema Registry
79
- [extension](https://github.com/salsify/avro-schema-registry#extensions) that
80
- provides an endpoint to lookup existing schema ids by fingerprint.
81
- A successful response from this GET request can be cached indefinitely.
82
- The use of this additional endpoint can be disabled by setting this option to
83
- `false` and this is recommended if using a Schema Registry that does not support
84
- the endpoint.
85
- * **messaging**: An `AvroTurf::Messaging` object to be shared by all generated models
86
- The `build_messaging!` method may be used to create a `Avromatic::Messaging`
87
- instance based on the other configuration values.
88
- * **logger**: The logger to use for the schema registry client.
89
-
90
- Example using a schema registry:
91
-
92
- ```ruby
93
- Avromatic.configure do |config|
94
- config.schema_store = AvroTurf::SchemaStore.new(path: 'avro/schemas')
95
- config.registry_url = Rails.configuration.x.avro_schema_registry_url
96
- config.build_schema_registry!
97
- config.build_messaging!
98
- end
99
- ```
100
-
101
- #### Decoding
102
-
103
- * **use_custom_datum_reader**: `Avromatic` includes a modified subclass of
104
- `Avro::IO::DatumReader`. This subclass returns additional information about
105
- the index of union members when decoding Avro messages. This information is
106
- used to optimize model creation when decoding. By default this information
107
- is included in the hash returned by the `DatumReader` but can be omitted by
108
- setting this option to `false`.
109
-
110
- #### Encoding
111
- * **use_custom_datum_writer**: `Avromatic` includes a modified subclass of
112
- `Avro::IO::DatumWriter`. This subclass supports caching avro encodings for
113
- immutable models and uses additional information about the index of union
114
- members to optimize the encoding of Avro messages. By default this
115
- information is included in the hash passed to the encoder but can be omitted
116
- by setting this option to `false`.
117
-
118
-
119
- ### Models
120
-
121
- Models are defined based on an Avro schema for a record.
122
-
123
- The Avro schema can be specified by name and loaded using the schema store:
124
-
125
- ```ruby
126
- class MyModel
127
- include Avromatic::Model.build(schema_name: :my_model)
128
- end
129
-
130
- # Construct instances by passing in a hash of attributes
131
- instance = MyModel.new(id: 123, name: 'Tesla Model 3', enabled: true)
132
-
133
- # Access attribute values with readers
134
- instance.name # => "Tesla Model 3"
135
-
136
- # Models are immutable by default
137
- instance.name = 'Tesla Model X' # => NoMethodError (private method `name=' called for #<MyModel:0x00007ff711e64e60>)
138
-
139
- # Booleans can also be accessed by '?' readers that coerce nil to false
140
- instance.enabled? # => true
141
-
142
- # Models implement ===, eql? and hash
143
- instance == MyModel.new(id: 123, name: 'Tesla Model 3', enabled: true) # => true
144
- instance.eql?(MyModel.new(id: 123, name: 'Tesla Model 3', enabled: true)) # => true
145
- instance.hash # => -1279155042741869898
146
-
147
- # Retrieve a hash of the model's attributes via to_h, to_hash or attributes
148
- instance.to_h # => {:id=>123, :name=>"Tesla Model 3", :enabled=>true}
149
- ```
150
-
151
- Or an `Avro::Schema` object can be specified directly:
152
-
153
- ```ruby
154
- class MyModel
155
- include Avromatic::Model.build(schema: schema_object)
156
- end
157
- ```
158
-
159
- A specific subject name can be associated with the schema:
160
- ```ruby
161
- class MyModel
162
- include Avromatic::Model.build(schema_name: 'my_model',
163
- schema_subject: 'my_model-value')
164
- end
165
- ```
166
-
167
- Models are generated as immutable value
168
- objects by default, but can optionally be defined as mutable:
169
-
170
- ```ruby
171
- class MyModel
172
- include Avromatic::Model.build(schema_name: :my_model, mutable: true)
173
- end
174
- ```
175
-
176
- Generated models include attributes for each field in the Avro schema
177
- including any default values defined in the schema.
178
-
179
- A model may be defined with both a key and a value schema:
180
-
181
- ```ruby
182
- class MyTopic
183
- include Avromatic::Model.build(value_schema_name: :topic_value,
184
- key_schema_name: :topic_key)
185
- end
186
- ```
187
-
188
- When key and value schemas are both specified, attributes are added to the model
189
- for the union of the fields in the two schemas.
190
-
191
- By default, optional fields are not allowed in key schemas since their values may
192
- be accidentally omitted leading to problems if data is partitioned based on the
193
- key values.
194
-
195
- This behavior can be overridden by specifying the `:allow_optional_key_fields`
196
- option for the model:
197
-
198
- ```ruby
199
- class MyTopic
200
- include Avromatic::Model.build(value_schema_name: :topic_value,
201
- key_schema_name: :topic_key,
202
- allow_optional_key_fields: true)
203
- end
204
- ```
205
-
206
- A specific subject name can be associated with both the value and key schemas:
207
- ```ruby
208
- class MyTopic
209
- include Avromatic::Model.build(value_schema_name: :topic_value,
210
- value_schema_subject: 'topic_value-value',
211
- key_schema_name: :topic_key,
212
- key_schema_subject: 'topic_key-value')
213
- end
214
- ```
215
-
216
- A model can also be generated as an anonymous class that can be assigned to a
217
- constant:
218
-
219
- ```ruby
220
- MyModel = Avromatic::Model.model(schema_name :my_model)
221
- ```
222
-
223
- #### Experimental: Union Support
224
-
225
- Avromatic contains experimental support for unions containing more than one
226
- non-null member type. This feature is experimental because Avromatic
227
- may attempt to coerce between types too aggressively.
228
-
229
- For now, if a union contains [nested models](#nested-models) then it is
230
- recommended that you assign model instances.
231
-
232
- Some combination of the ordering of member types in the union and relying on
233
- model validation may be required so that the correct member is selected,
234
- especially when deserializing from Avro.
235
-
236
- In the future, the type coercion used in the gem will be enhanced to better
237
- support the union use case.
238
-
239
- #### Nested Models
240
-
241
- Nested models are models that are embedded within top-level models generated
242
- using Avromatic. Normally these nested models are automatically generated.
243
-
244
- By default, nested models are stored in `Avromatic.nested_models`. This is an
245
- `Avromatic::ModelRegistry` instance that provides access to previously generated
246
- nested models by the full name of their Avro schema.
247
-
248
- ```ruby
249
- Avromatic.nested_models['com.my_company.test.example']
250
- #=> <model class>
251
- ```
252
-
253
- The `ModelRegistry` can be customized to remove a namespace prefix:
254
-
255
- ```ruby
256
- Avromatic.nested_models =
257
- Avromatic::ModelRegistry.new(remove_namespace_prefix: 'com.my_company')
258
- ```
259
-
260
- The `:remove_namespace_prefix` value can be a string or a regexp.
261
-
262
- By default, top-level generated models reuse `Avromatic.nested_models`. This
263
- allows nested models to be shared across different generated models.
264
- A `:nested_models` option can be specified when generating a model. This allows
265
- the reuse of nested models to be scoped:
266
-
267
- ```ruby
268
- Avromatic::Model.model(schema_name, :my_model
269
- nested_models: ModelRegistry.new)
270
- ```
271
-
272
- Only models without a key schema can be used as nested models. When a model is
273
- generated with just a value schema then it is automatically registered so that
274
- it can be used as a nested model.
275
-
276
- To extend a model that will be used as a nested model, you must ensure that it
277
- is defined, which will register it, prior it being referenced by another model.
278
-
279
- Using the `Avromatic.eager_load_models` option allows models that are extended
280
- and will be used as nested models to be defined at the end of the `.configure`
281
- block. In Rails applications, these models are also re-registered after
282
- `nested_models` is cleared when code reloads to ensure that classes load in the
283
- correct order:
284
-
285
- ```ruby
286
- Avromatic.configure do |config|
287
- config.eager_load_models = [
288
- # reference any extended models that should be defined first
289
- 'MyNestedModel'
290
- ]
291
- end
292
- ```
293
-
294
- #### Custom Type Configuration
295
-
296
- Custom types can be configured for fields of named types (record, enum, fixed).
297
- These customizations are registered on the `Avromatic` module. Once a custom type
298
- is registered, it is used for all models with a schema that references that type.
299
- It is recommended to register types within a block passed to `Avromatic.configure`:
300
-
301
- ```ruby
302
- Avromatic.configure do |config|
303
- config.register_type('com.example.my_string', MyString)
304
- end
305
- ```
306
-
307
- The full name of the type and an optional class may be specified. When a class is
308
- provided then values for attributes of that type are defined using the specified
309
- class.
310
-
311
- If the provided class responds to the class methods `from_avro` and `to_avro`
312
- then those methods are used to convert values when assigning to the model and
313
- before encoding using Avro respectively.
314
-
315
- `from_avro` and `to_avro` methods may be also be specified as Procs when
316
- registering the type:
317
-
318
- ```ruby
319
- Avromatic.configure do |config|
320
- config.register_type('com.example.updown_string') do |type|
321
- type.from_avro = ->(value) { value.upcase }
322
- type.to_avro = ->(value) { value.downcase }
323
- end
324
- end
325
- ```
326
-
327
- Nil handling is not required as the conversion methods are not be called if the
328
- inbound or outbound value is nil.
329
-
330
- If a custom type is registered for a record-type field, then any `to_avro`
331
- method/Proc should return a Hash with string keys for encoding using Avro.
332
-
333
- ### Encoding and Decoding
334
-
335
- `Avromatic` provides two different interfaces for encoding the key (optional)
336
- and value associated with a model.
337
-
338
- #### Manually Managed Schemas
339
-
340
- The attributes for the value schema used to define a model can be encoded using:
341
-
342
- ```ruby
343
- encoded_value = model.avro_raw_value
344
- ```
345
-
346
- In order to decode this data, a copy of the value schema is required.
347
-
348
- If a model also has an Avro schema for a key, then the key attributes can be
349
- encoded using:
350
-
351
- ```ruby
352
- encoded_key = model.avro_raw_key
353
- ```
354
-
355
- If attributes were encoded using the same schema(s) used to define a model, then
356
- the data can be decoded to create a new model instance:
357
-
358
- ```ruby
359
- MyModel.avro_raw_decode(key: encoded_key, value: encoded_value)
360
- ```
361
-
362
- If the attributes where encoded using a different version of the model's schemas,
363
- then a new model instance can be created by also providing the schemas used to
364
- encode the data:
365
-
366
- ```ruby
367
- MyModel.avro_raw_decode(key: encoded_key,
368
- key_schema: writers_key_schema,
369
- value: encoded_value,
370
- value_schema: writers_value_schema)
371
- ```
372
-
373
- #### Messaging API
374
-
375
- The other interface for encoding and decoding attributes uses the
376
- `AvroTurf::Messaging` API. This interface leverages a schema registry and
377
- prefixes the encoded data with an id to identify the schema. In this approach,
378
- a schema registry is used to ensure that the correct schemas are available during
379
- decoding.
380
-
381
- The attributes for the value schema can be encoded with a schema id prefix using:
382
-
383
- ```ruby
384
- message_value = model.avro_message_value
385
- ```
386
-
387
- If a model has an Avro schema for a key, then those attributes can also be encoded
388
- prefixed with a schema id:
389
-
390
- ```ruby
391
- message_key = model.avro_message_key
392
- ```
393
-
394
- A model instance can be created from a key and value encoded in this manner:
395
-
396
- ```ruby
397
- MyTopic.avro_message_decode(message_key, message_value)
398
- ```
399
-
400
- Or just a value if only one schema is used:
401
-
402
- ```ruby
403
- MyValue.avro_message_decode(message_value)
404
- ```
405
-
406
- The schemas associated with a model can also be added to a schema registry without
407
- encoding a message:
408
-
409
- ```ruby
410
- MyTopic.register_schemas!
411
- ```
412
-
413
- #### Avromatic::Model::MessageDecoder
414
-
415
- A stream of messages encoded from various models using the messaging approach
416
- can be decoded using `Avromatic::Model::MessageDecoder`. The decoder must be
417
- initialized with the list of models to decode:
418
-
419
- ```ruby
420
- decoder = Avromatic::Model::MessageDecoder.new(MyModel1, MyModel2)
421
-
422
- decoder.decode(model1_messge_key, model1_message_value)
423
- # => instance of MyModel1
424
- decoder.decode(model2_message_value)
425
- # => instance of MyModel2
426
- ```
427
-
428
- ### Validations and Coercions
429
-
430
- An exception will be thrown if an attribute value cannot be coerced to the corresponding Avro schema field's type.
431
- The following coercions are supported:
432
-
433
- | Ruby Type | Avro Type |
434
- | --------- | --------- |
435
- | String, Symbol | string |
436
- | Array | array |
437
- | Hash | map |
438
- | Integer, Float | int |
439
- | Integer | long |
440
- | Float | float |
441
- | Float | double |
442
- | String | bytes |
443
- | Date, Time, DateTime | date |
444
- | Time, DateTime | timestamp-millis |
445
- | Time, DateTime | timestamp-micros |
446
- | TrueClass, FalseClass | boolean |
447
- | NilClass | null |
448
- | Hash | record |
449
-
450
- Validation of required fields is done automatically when serializing a model to Avro. It can also be done
451
- explicitly by calling the `valid?` or `invalid?` methods from the
452
- [ActiveModel::Validations](https://edgeapi.rubyonrails.org/classes/ActiveModel/Validations.html) interface.
453
-
454
- ### RSpec Support
455
-
456
- This gem also includes an `"avromatic/rspec"` file that can be required to support
457
- using Avromatic with a fake schema registry during tests.
458
-
459
- Requiring this file configures a RSpec before hook that directs any schema
460
- registry requests to a fake, in-memory schema registry and rebuilds the
461
- `Avromatic::Messaging` object for each example.
462
-
463
- ## Development
464
-
465
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
466
-
467
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
468
-
469
- ## Contributing
470
-
471
- Bug reports and pull requests are welcome on GitHub at https://github.com/salsify/avromatic.
472
-
473
-
474
- ## License
475
-
476
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
477
-
data/Rakefile DELETED
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
- require 'appraisal/task'
6
- require 'avro/builder'
7
-
8
- RSpec::Core::RakeTask.new(:default_spec)
9
-
10
- Appraisal::Task.new
11
-
12
- if !ENV['APPRAISAL_INITIALIZED']
13
- task default: :appraisal
14
- task spec: :appraisal
15
- else
16
- task default: :default_spec
17
- end
18
-
19
- namespace :avro do
20
- desc 'Generate Avro schema files used by specs'
21
- task :generate_spec do
22
- root = 'spec/avro/dsl'
23
- Avro::Builder.add_load_path(root)
24
- Dir["#{root}/**/*.rb"].each do |dsl_file|
25
- puts "Generating Avro schema from #{dsl_file}"
26
- output_file = dsl_file.sub('/dsl/', '/schema/').sub(/\.rb$/, '.avsc')
27
- schema = Avro::Builder.build(File.read(dsl_file))
28
- FileUtils.mkdir_p(File.dirname(output_file))
29
- File.write(output_file, schema.end_with?("\n") ? schema : schema << "\n")
30
- end
31
- end
32
- end
data/avromatic.gemspec DELETED
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- lib = File.expand_path('lib', __dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'avromatic/version'
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = 'avromatic'
9
- spec.version = Avromatic::VERSION
10
- spec.authors = ['Salsify Engineering']
11
- spec.email = ['engineering@salsify.com']
12
-
13
- spec.summary = 'Generate Ruby models from Avro schemas'
14
- spec.description = spec.summary
15
- spec.homepage = 'https://github.com/salsify/avromatic.git'
16
- spec.license = 'MIT'
17
-
18
- if spec.respond_to?(:metadata)
19
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
- spec.metadata['rubygems_mfa_required'] = 'true'
21
- else
22
- raise 'RubyGems 2.0 or newer is required to set allowed_push_host.'
23
- end
24
-
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
- spec.bindir = 'exe'
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ['lib']
29
-
30
- spec.metadata['rubygems_mfa_required'] = 'true'
31
-
32
- spec.required_ruby_version = '>= 2.7'
33
-
34
- spec.add_runtime_dependency 'activemodel', '>= 5.2', '< 7.1'
35
- spec.add_runtime_dependency 'activesupport', '>= 5.2', '< 7.1'
36
- spec.add_runtime_dependency 'avro', '>= 1.10.0', '< 1.12'
37
- spec.add_runtime_dependency 'avro_schema_registry-client', '>= 0.4.0'
38
- spec.add_runtime_dependency 'avro_turf'
39
- spec.add_runtime_dependency 'ice_nine'
40
-
41
- spec.add_development_dependency 'appraisal'
42
- spec.add_development_dependency 'avro-builder', '>= 0.12.0'
43
- spec.add_development_dependency 'bundler', '~> 2.0'
44
- spec.add_development_dependency 'overcommit', '0.35.0'
45
- spec.add_development_dependency 'rake', '~> 13.0'
46
- spec.add_development_dependency 'rspec', '~> 3.8'
47
- spec.add_development_dependency 'rspec_junit_formatter'
48
- spec.add_development_dependency 'salsify_rubocop', '~> 1.27.1'
49
- spec.add_development_dependency 'simplecov'
50
- spec.add_development_dependency 'webmock'
51
- # For AvroSchemaRegistry::FakeServer
52
- spec.add_development_dependency 'sinatra'
53
- end
@@ -1,2 +0,0 @@
1
- ---
2
- BUNDLE_RETRY: "1"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 5.2.0"
7
- gem "activemodel", "~> 5.2.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 6.0.0"
7
- gem "activemodel", "~> 6.0.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 6.1.0"
7
- gem "activemodel", "~> 6.1.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 7.0.0"
7
- gem "activemodel", "~> 7.0.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.11.0"
6
- gem "activesupport", "~> 6.1.0"
7
- gem "activemodel", "~> 6.1.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.11.0"
6
- gem "activesupport", "~> 7.0.0"
7
- gem "activemodel", "~> 7.0.0"
8
-
9
- gemspec path: "../"
data/log/.gitkeep DELETED
File without changes