avro-gen-ruby 0.1.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 +7 -0
- data/.github/workflows/ci.yml +34 -0
- data/.github/workflows/release.yml +31 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.rubocop.yml +100 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +61 -0
- data/Rakefile +11 -0
- data/avro-gen-ruby.gemspec +32 -0
- data/lib/avro_gen/avro_parser.rb +64 -0
- data/lib/avro_gen/configuration.rb +60 -0
- data/lib/avro_gen/errors.rb +6 -0
- data/lib/avro_gen/generator/templates/schema_class.rb.tt +8 -0
- data/lib/avro_gen/generator/templates/schema_enum.rb.tt +13 -0
- data/lib/avro_gen/generator/templates/schema_record.rb.tt +102 -0
- data/lib/avro_gen/generator.rb +375 -0
- data/lib/avro_gen/railtie.rb +12 -0
- data/lib/avro_gen/schema_class/base.rb +62 -0
- data/lib/avro_gen/schema_class/enum.rb +48 -0
- data/lib/avro_gen/schema_class/record.rb +108 -0
- data/lib/avro_gen/schema_class.rb +62 -0
- data/lib/avro_gen/schema_field.rb +26 -0
- data/lib/avro_gen/schema_validator.rb +80 -0
- data/lib/avro_gen/upgrader.rb +43 -0
- data/lib/avro_gen/version.rb +5 -0
- data/lib/avro_gen.rb +18 -0
- data/lib/tasks/avro.rake +18 -0
- data/regenerate_test_schema_classes.rb +32 -0
- data/spec/generator_spec.rb +92 -0
- data/spec/my_schema_spec.rb +18 -0
- data/spec/my_schema_with_circular_reference_spec.rb +97 -0
- data/spec/my_schema_with_complex_types_spec.rb +235 -0
- data/spec/schema_validator_spec.rb +42 -0
- data/spec/schemas/com/my-namespace/Generated.avsc +77 -0
- data/spec/schemas/com/my-namespace/MyNestedSchema.avsc +62 -0
- data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
- data/spec/schemas/com/my-namespace/MySchemaCompound_key.avsc +18 -0
- data/spec/schemas/com/my-namespace/MySchemaId_key.avsc +12 -0
- data/spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc +18 -0
- data/spec/schemas/com/my-namespace/MySchemaWithCircularReference.avsc +39 -0
- data/spec/schemas/com/my-namespace/MySchemaWithComplexTypes.avsc +120 -0
- data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
- data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
- data/spec/schemas/com/my-namespace/MySchemaWithTitle.avsc +22 -0
- data/spec/schemas/com/my-namespace/MySchemaWithUnionType.avsc +91 -0
- data/spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc +32 -0
- data/spec/schemas/com/my-namespace/MySchema_key.avsc +13 -0
- data/spec/schemas/com/my-namespace/Wibble.avsc +43 -0
- data/spec/schemas/com/my-namespace/Widget.avsc +27 -0
- data/spec/schemas/com/my-namespace/WidgetTheSecond.avsc +27 -0
- data/spec/schemas/com/my-namespace/WidgetTheThird.avsc +27 -0
- data/spec/schemas/com/my-namespace/my-suborg/MyLongNamespaceSchema.avsc +18 -0
- data/spec/schemas/com/my-namespace/request/CreateTopic.avsc +11 -0
- data/spec/schemas/com/my-namespace/request/Index.avsc +11 -0
- data/spec/schemas/com/my-namespace/request/UpdateRequest.avsc +11 -0
- data/spec/schemas/com/my-namespace/response/CreateTopic.avsc +11 -0
- data/spec/schemas/com/my-namespace/response/Index.avsc +11 -0
- data/spec/schemas/com/my-namespace/response/UpdateResponse.avsc +11 -0
- data/spec/schemas/my_namespace/generated.rb +164 -0
- data/spec/schemas/my_namespace/my_long_namespace_schema.rb +49 -0
- data/spec/schemas/my_namespace/my_nested_schema.rb +126 -0
- data/spec/schemas/my_namespace/my_schema.rb +62 -0
- data/spec/schemas/my_namespace/my_schema_compound_key.rb +42 -0
- data/spec/schemas/my_namespace/my_schema_id_key.rb +37 -0
- data/spec/schemas/my_namespace/my_schema_key.rb +37 -0
- data/spec/schemas/my_namespace/my_schema_with_boolean.rb +42 -0
- data/spec/schemas/my_namespace/my_schema_with_circular_reference.rb +84 -0
- data/spec/schemas/my_namespace/my_schema_with_complex_type.rb +241 -0
- data/spec/schemas/my_namespace/my_schema_with_date_time.rb +57 -0
- data/spec/schemas/my_namespace/my_schema_with_id.rb +52 -0
- data/spec/schemas/my_namespace/my_schema_with_title.rb +47 -0
- data/spec/schemas/my_namespace/my_schema_with_union_type.rb +205 -0
- data/spec/schemas/my_namespace/my_schema_with_unique_id.rb +57 -0
- data/spec/schemas/my_namespace/request/create_topic.rb +37 -0
- data/spec/schemas/my_namespace/request/index.rb +37 -0
- data/spec/schemas/my_namespace/request/update_request.rb +37 -0
- data/spec/schemas/my_namespace/response/create_topic.rb +37 -0
- data/spec/schemas/my_namespace/response/index.rb +37 -0
- data/spec/schemas/my_namespace/response/update_response.rb +37 -0
- data/spec/schemas/my_namespace/wibble.rb +77 -0
- data/spec/schemas/my_namespace/widget.rb +57 -0
- data/spec/schemas/my_namespace/widget_the_second.rb +57 -0
- data/spec/schemas/my_namespace/widget_the_third.rb +57 -0
- data/spec/snapshots/consumers-no-nest.snap +1740 -0
- data/spec/snapshots/consumers.snap +1720 -0
- data/spec/snapshots/my_nested_schema.snap +121 -0
- data/spec/snapshots/my_schema_with_boolean.snap +44 -0
- data/spec/snapshots/my_schema_with_circular_reference.snap +81 -0
- data/spec/snapshots/my_schema_with_complex_type.snap +236 -0
- data/spec/snapshots/my_schema_with_date_time.snap +59 -0
- data/spec/snapshots/my_schema_with_union_type.snap +207 -0
- data/spec/snapshots/namespace_folders.snap +1800 -0
- data/spec/snapshots/namespace_map.snap +1800 -0
- data/spec/spec_helper.rb +23 -0
- metadata +265 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: ba3c25a3781ca50da7273e62f05126ffe641538096cae34178161cae558a20ff
|
|
4
|
+
data.tar.gz: b8c25703ca1cda292d6fb50e2158a75a6b3b7a7dbe7109908fb55db129ab7545
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bee416615047e91d012ceb396a9249990fb748b8e951f13d7d5296a7b4d5ba36f2ff1a748974171fc0351b3df3ae8500e4bbb5551a0c334abfebe7300beaf741
|
|
7
|
+
data.tar.gz: c4c97a2939069802696506c370b4e72582dffa5d6b97f9cc8ba2d08e2c4840fe7d572ad7ed0790b9256c8c92d071b1f3e49907ed580bf4a8ec96461564425edd
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [ main ]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
linting:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- name: Set up Ruby 3.3
|
|
14
|
+
uses: ruby/setup-ruby@v1
|
|
15
|
+
with:
|
|
16
|
+
ruby-version: 3.3
|
|
17
|
+
bundler-cache: true
|
|
18
|
+
- name: Rubocop
|
|
19
|
+
run: bundle exec rubocop --format progress
|
|
20
|
+
|
|
21
|
+
build:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
ruby: [ '3.2', '3.3', '3.4', '4.0' ]
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
- uses: ruby/setup-ruby@v1
|
|
30
|
+
with:
|
|
31
|
+
ruby-version: ${{ matrix.ruby }}
|
|
32
|
+
bundler-cache: true
|
|
33
|
+
- name: Test
|
|
34
|
+
run: bundle exec rspec
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Release Gem
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
tags:
|
|
7
|
+
- 'v*.*.*' # Matches semantic versioning tags like v1.0.0
|
|
8
|
+
workflow_dispatch: # Allows manual triggering of the workflow
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
push:
|
|
12
|
+
name: Push gem to RubyGems.org
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
|
17
|
+
contents: write # IMPORTANT: this permission is required for `rake release` to push the release tag
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
# Set up
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
- name: Set up Ruby
|
|
25
|
+
uses: ruby/setup-ruby@v1
|
|
26
|
+
with:
|
|
27
|
+
bundler-cache: true
|
|
28
|
+
ruby-version: ruby
|
|
29
|
+
|
|
30
|
+
# Release
|
|
31
|
+
- uses: rubygems/release-gem@v1
|
data/.gitignore
ADDED
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--require spec_helper --format documentation
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
plugins:
|
|
2
|
+
- rubocop-rspec
|
|
3
|
+
|
|
4
|
+
AllCops:
|
|
5
|
+
TargetRubyVersion: 3.2
|
|
6
|
+
NewCops: enable
|
|
7
|
+
SuggestExtensions: false
|
|
8
|
+
Exclude:
|
|
9
|
+
- vendor/**/*
|
|
10
|
+
- spec/app/**/*
|
|
11
|
+
- spec/schemas/**/*
|
|
12
|
+
- spec/snapshots/**/*
|
|
13
|
+
|
|
14
|
+
Gemspec/DevelopmentDependencies:
|
|
15
|
+
EnforcedStyle: gemspec
|
|
16
|
+
|
|
17
|
+
Layout/AccessModifierIndentation:
|
|
18
|
+
EnforcedStyle: outdent
|
|
19
|
+
|
|
20
|
+
Layout/DotPosition:
|
|
21
|
+
EnforcedStyle: trailing
|
|
22
|
+
|
|
23
|
+
Layout/LineLength:
|
|
24
|
+
Max: 120
|
|
25
|
+
|
|
26
|
+
Layout/MultilineMethodCallIndentation:
|
|
27
|
+
EnforcedStyle: indented
|
|
28
|
+
|
|
29
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
|
30
|
+
EnforcedStyle: no_space
|
|
31
|
+
|
|
32
|
+
Lint/UnusedBlockArgument:
|
|
33
|
+
AllowUnusedKeywordArguments: true
|
|
34
|
+
|
|
35
|
+
Lint/UnusedMethodArgument:
|
|
36
|
+
AllowUnusedKeywordArguments: true
|
|
37
|
+
|
|
38
|
+
Lint/MissingSuper:
|
|
39
|
+
Enabled: false
|
|
40
|
+
|
|
41
|
+
Metrics:
|
|
42
|
+
Enabled: false
|
|
43
|
+
|
|
44
|
+
Style/Alias:
|
|
45
|
+
EnforcedStyle: prefer_alias_method
|
|
46
|
+
|
|
47
|
+
Style/ClassAndModuleChildren:
|
|
48
|
+
Enabled: false
|
|
49
|
+
|
|
50
|
+
Style/Documentation:
|
|
51
|
+
Enabled: false
|
|
52
|
+
|
|
53
|
+
Style/EmptyMethod:
|
|
54
|
+
EnforcedStyle: expanded
|
|
55
|
+
|
|
56
|
+
Style/IfUnlessModifier:
|
|
57
|
+
Enabled: false
|
|
58
|
+
|
|
59
|
+
Style/PercentLiteralDelimiters:
|
|
60
|
+
PreferredDelimiters:
|
|
61
|
+
'%i': '()'
|
|
62
|
+
'%I': '()'
|
|
63
|
+
'%w': '()'
|
|
64
|
+
'%W': '()'
|
|
65
|
+
|
|
66
|
+
Style/RedundantSelf:
|
|
67
|
+
Enabled: false
|
|
68
|
+
|
|
69
|
+
Style/StringLiterals:
|
|
70
|
+
EnforcedStyle: single_quotes
|
|
71
|
+
|
|
72
|
+
Style/SymbolArray:
|
|
73
|
+
EnforcedStyle: percent
|
|
74
|
+
|
|
75
|
+
RSpec/ExampleWording:
|
|
76
|
+
Enabled: false
|
|
77
|
+
|
|
78
|
+
RSpec/ExampleLength:
|
|
79
|
+
Enabled: false
|
|
80
|
+
|
|
81
|
+
RSpec/MultipleExpectations:
|
|
82
|
+
Enabled: false
|
|
83
|
+
|
|
84
|
+
RSpec/MultipleMemoizedHelpers:
|
|
85
|
+
Enabled: false
|
|
86
|
+
|
|
87
|
+
RSpec/HookArgument:
|
|
88
|
+
EnforcedStyle: each
|
|
89
|
+
|
|
90
|
+
RSpec/LeakyConstantDeclaration:
|
|
91
|
+
Enabled: false
|
|
92
|
+
|
|
93
|
+
RSpec/DescribeClass:
|
|
94
|
+
Enabled: false
|
|
95
|
+
|
|
96
|
+
RSpec/NestedGroups:
|
|
97
|
+
Enabled: false
|
|
98
|
+
|
|
99
|
+
RSpec/SpecFilePathFormat:
|
|
100
|
+
Enabled: false
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 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,61 @@
|
|
|
1
|
+
# avro-gen-ruby
|
|
2
|
+
|
|
3
|
+
Generate Ruby schema classes / models from Avro schemas.
|
|
4
|
+
|
|
5
|
+
`avro-gen-ruby` (namespace `AvroGen`) takes a directory of Avro `.avsc` schema files
|
|
6
|
+
and generates plain-Ruby classes for each record and enum, giving you typed,
|
|
7
|
+
IDE-friendly objects to work with instead of raw hashes. It was extracted from
|
|
8
|
+
[deimos-ruby](https://github.com/flipp-oss/deimos), which now depends on it.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
gem 'avro-gen-ruby'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Configuration
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
AvroGen.configure do |config|
|
|
20
|
+
config.schema_path = 'avro/schemas'
|
|
21
|
+
config.generated_class_path = 'app/lib/schema_classes'
|
|
22
|
+
config.nest_child_schemas = true
|
|
23
|
+
config.use_full_namespace = false
|
|
24
|
+
config.schema_namespace_map = {}
|
|
25
|
+
config.root_module = 'Schemas'
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Setting | Default | Description |
|
|
30
|
+
|---------|---------|-------------|
|
|
31
|
+
| `schema_path` | `nil` | Local path to the directory containing your Avro `.avsc` schema files. Required for generation. |
|
|
32
|
+
| `generated_class_path` | `app/lib/schema_classes` | Local path that generated schema classes are written to. |
|
|
33
|
+
| `nest_child_schemas` | `true` | When `true`, subschemas (nested records/enums) are nested inside the generated class for the parent schema. When `false`, each subschema is generated as its own file. |
|
|
34
|
+
| `use_full_namespace` | `false` | When `true`, generate nested folders/modules matching the full Avro namespace (e.g. `com.my-org.Foo` → `Schemas::Com::MyOrg::Foo`). When `false`, all classes are generated directly under the root module. |
|
|
35
|
+
| `schema_namespace_map` | `{}` | A map of namespace prefixes to base module name(s), used to reduce nesting when `use_full_namespace` is `true`. Example: `{ 'com.mycompany.suborg' => ['SchemaClasses'] }` generates classes under `SchemaClasses::` instead of `Schemas::Com::Mycompany::Suborg::`. Has no effect unless `use_full_namespace` is `true`. |
|
|
36
|
+
| `root_module` | `'Schemas'` | The top-level module that generated classes are nested under. |
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Generate classes for every schema in `schema_path`:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
rake avro:generate
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Generated classes inherit from `AvroGen::SchemaClass::Record` / `AvroGen::SchemaClass::Enum`
|
|
47
|
+
and are namespaced under the configured `root_module` (default `Schemas`).
|
|
48
|
+
|
|
49
|
+
### Migrating from Deimos
|
|
50
|
+
|
|
51
|
+
If you previously generated classes with Deimos, they reference `Deimos::SchemaClass::*`.
|
|
52
|
+
Those still load (Deimos maps them to the AvroGen equivalents with a deprecation warning),
|
|
53
|
+
but you can rewrite them in place:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
rake avro:upgrade
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT
|
data/Rakefile
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
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 'avro_gen/version'
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = 'avro-gen-ruby'
|
|
9
|
+
spec.version = AvroGen::VERSION
|
|
10
|
+
spec.authors = ['Daniel Orner']
|
|
11
|
+
spec.email = ['daniel.orner@flipp.com']
|
|
12
|
+
spec.summary = 'Generate Ruby schema classes from Avro schemas.'
|
|
13
|
+
spec.homepage = 'https://github.com/flipp-oss/avro-gen-ruby'
|
|
14
|
+
spec.license = 'MIT'
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
17
|
+
spec.require_paths = ['lib']
|
|
18
|
+
spec.required_ruby_version = '>= 3.2'
|
|
19
|
+
|
|
20
|
+
spec.add_dependency('activesupport', '>= 6.0')
|
|
21
|
+
spec.add_dependency('avro', '~> 1.9')
|
|
22
|
+
spec.add_dependency('railties', '>= 6.0')
|
|
23
|
+
spec.add_dependency('schema_registry_client')
|
|
24
|
+
|
|
25
|
+
spec.add_development_dependency('rake', '~> 13')
|
|
26
|
+
spec.add_development_dependency('rspec', '~> 3')
|
|
27
|
+
spec.add_development_dependency('rspec-snapshot', '~> 2.0')
|
|
28
|
+
spec.add_development_dependency('rubocop', '~> 1.0')
|
|
29
|
+
spec.add_development_dependency('rubocop-rspec', '~> 3.0')
|
|
30
|
+
|
|
31
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
32
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'avro'
|
|
4
|
+
require 'active_support/core_ext/string'
|
|
5
|
+
|
|
6
|
+
module AvroGen
|
|
7
|
+
# Helper methods for interpreting Avro schema objects when generating classes.
|
|
8
|
+
module AvroParser
|
|
9
|
+
class << self
|
|
10
|
+
# @param schema [Avro::Schema::NamedSchema] A named schema
|
|
11
|
+
# @return [String]
|
|
12
|
+
def schema_classname(schema)
|
|
13
|
+
schema.name.underscore.camelize.singularize
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Converts Avro::Schema::NamedSchema's to String form for generated YARD docs.
|
|
17
|
+
# Recursively handles the typing for Arrays, Maps and Unions.
|
|
18
|
+
# @param avro_schema [Avro::Schema::NamedSchema]
|
|
19
|
+
# @return [String] A string representation of the Type of this SchemaField
|
|
20
|
+
def field_type(avro_schema)
|
|
21
|
+
case avro_schema.type_sym
|
|
22
|
+
when :string, :boolean
|
|
23
|
+
avro_schema.type_sym.to_s.titleize
|
|
24
|
+
when :int, :long
|
|
25
|
+
'Integer'
|
|
26
|
+
when :float, :double
|
|
27
|
+
'Float'
|
|
28
|
+
when :record, :enum
|
|
29
|
+
schema_classname(avro_schema)
|
|
30
|
+
when :array
|
|
31
|
+
arr_t = field_type(AvroGen::SchemaField.new('n/a', avro_schema.items).type)
|
|
32
|
+
"Array<#{arr_t}>"
|
|
33
|
+
when :map
|
|
34
|
+
map_t = field_type(AvroGen::SchemaField.new('n/a', avro_schema.values).type)
|
|
35
|
+
"Hash<String, #{map_t}>"
|
|
36
|
+
when :union
|
|
37
|
+
types = avro_schema.schemas.map do |t|
|
|
38
|
+
field_type(AvroGen::SchemaField.new('n/a', t).type)
|
|
39
|
+
end
|
|
40
|
+
types.join(', ')
|
|
41
|
+
when :null
|
|
42
|
+
'nil'
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns the base type of this schema. Decodes Arrays, Maps and Unions
|
|
47
|
+
# @param schema [Avro::Schema::NamedSchema]
|
|
48
|
+
# @return [Avro::Schema::NamedSchema]
|
|
49
|
+
def schema_base_class(schema)
|
|
50
|
+
case schema.type_sym
|
|
51
|
+
when :array
|
|
52
|
+
schema_base_class(schema.items)
|
|
53
|
+
when :map
|
|
54
|
+
schema_base_class(schema.values)
|
|
55
|
+
when :union
|
|
56
|
+
schema.schemas.map(&method(:schema_base_class)).
|
|
57
|
+
reject { |s| s.type_sym == :null }.first
|
|
58
|
+
else
|
|
59
|
+
schema
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AvroGen
|
|
4
|
+
# Configuration for schema class generation.
|
|
5
|
+
class Configuration
|
|
6
|
+
# Local path to look for Avro schemas (.avsc files) in.
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_accessor :schema_path
|
|
9
|
+
|
|
10
|
+
# Local path for schema classes to be generated in.
|
|
11
|
+
# @return [String]
|
|
12
|
+
attr_accessor :generated_class_path
|
|
13
|
+
|
|
14
|
+
# Set to false to generate child schemas as their own files.
|
|
15
|
+
# @return [Boolean]
|
|
16
|
+
attr_accessor :nest_child_schemas
|
|
17
|
+
|
|
18
|
+
# Set to true to generate folders matching the last part of the schema namespace.
|
|
19
|
+
# @return [Boolean]
|
|
20
|
+
attr_accessor :use_full_namespace
|
|
21
|
+
|
|
22
|
+
# Use this option to reduce nesting when using use_full_namespace.
|
|
23
|
+
# For example: { 'com.mycompany.suborg' => 'SchemaClasses' }
|
|
24
|
+
# would replace a prefix matching the given key with the module name SchemaClasses.
|
|
25
|
+
# @return [Hash]
|
|
26
|
+
attr_accessor :schema_namespace_map
|
|
27
|
+
|
|
28
|
+
# The top-level module that generated classes are nested under.
|
|
29
|
+
# @return [String]
|
|
30
|
+
attr_accessor :root_module
|
|
31
|
+
|
|
32
|
+
def initialize
|
|
33
|
+
reset!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Restore all settings to their defaults.
|
|
37
|
+
# @return [void]
|
|
38
|
+
def reset!
|
|
39
|
+
@schema_path = nil
|
|
40
|
+
@generated_class_path = 'app/lib/schema_classes'
|
|
41
|
+
@nest_child_schemas = true
|
|
42
|
+
@use_full_namespace = false
|
|
43
|
+
@schema_namespace_map = {}
|
|
44
|
+
@root_module = 'Schemas'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class << self
|
|
49
|
+
# @return [AvroGen::Configuration]
|
|
50
|
+
def config
|
|
51
|
+
@config ||= Configuration.new
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @yieldparam [AvroGen::Configuration]
|
|
55
|
+
# @return [void]
|
|
56
|
+
def configure
|
|
57
|
+
yield config if block_given?
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Autogenerated Schema for Enum at <%= @current_schema.namespace %>.<%= @current_schema.name %>
|
|
2
|
+
class <%= AvroGen::AvroParser.schema_classname(@current_schema) %> < AvroGen::SchemaClass::Enum
|
|
3
|
+
# @override
|
|
4
|
+
def symbols
|
|
5
|
+
%w(<%= @current_schema.symbols.join(' ') %>)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
<% @current_schema.symbols.each do |symbol| %>
|
|
9
|
+
def <%= symbol.underscore %>?
|
|
10
|
+
@value == '<%= symbol %>'
|
|
11
|
+
end
|
|
12
|
+
<% end %>
|
|
13
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Autogenerated Schema for Record at <%= @current_schema.namespace %>.<%= @current_schema.name %>
|
|
2
|
+
class <%= AvroGen::AvroParser.schema_classname(@current_schema) %> < AvroGen::SchemaClass::Record
|
|
3
|
+
<% if @sub_schema_templates.present? -%>
|
|
4
|
+
|
|
5
|
+
### Secondary Schema Classes ###
|
|
6
|
+
<%- @sub_schema_templates.each do |schema_template| -%>
|
|
7
|
+
<%=- schema_template.gsub(/^/, " ") %>
|
|
8
|
+
|
|
9
|
+
<%- end -%>
|
|
10
|
+
<% end -%>
|
|
11
|
+
|
|
12
|
+
<%- if @field_assignments.select{ |h| h[:is_schema_class] }.any? -%>
|
|
13
|
+
### Attribute Readers ###
|
|
14
|
+
<%- @field_assignments.select{ |h| h[:is_schema_class] }.each do |method_definition| -%>
|
|
15
|
+
# @return [<%= method_definition[:deimos_type] %>]
|
|
16
|
+
attr_reader :<%= method_definition[:field].name %>
|
|
17
|
+
<%- end -%>
|
|
18
|
+
|
|
19
|
+
<% end -%>
|
|
20
|
+
<%- if @field_assignments.select{ |h| !h[:is_schema_class] }.any? -%>
|
|
21
|
+
### Attribute Accessors ###
|
|
22
|
+
<%- @field_assignments.select{ |h| !h[:is_schema_class] }.each do |method_definition| -%>
|
|
23
|
+
# @return [<%= method_definition[:deimos_type] %>]
|
|
24
|
+
attr_accessor :<%= method_definition[:field].name %>
|
|
25
|
+
<%- end -%>
|
|
26
|
+
|
|
27
|
+
<% end -%>
|
|
28
|
+
<%- if @field_assignments.select{ |h| h[:is_schema_class] }.any? -%>
|
|
29
|
+
### Attribute Writers ###
|
|
30
|
+
<%- @field_assignments.select{ |h| h[:is_schema_class] }.each do |method_definition| -%>
|
|
31
|
+
# @return [<%= method_definition[:deimos_type] %>]
|
|
32
|
+
def <%= method_definition[:field].name %>=(<%= method_definition[:method_argument] %>)
|
|
33
|
+
<%- if method_definition[:field_type] == :array -%>
|
|
34
|
+
@<%= method_definition[:field].name %> = values&.map do |value|
|
|
35
|
+
<%= method_definition[:field_initialization] %>
|
|
36
|
+
end
|
|
37
|
+
<%- elsif method_definition[:field_type] == :map -%>
|
|
38
|
+
@<%= method_definition[:field].name %> = values&.transform_values do |value|
|
|
39
|
+
<%= method_definition[:field_initialization] %>
|
|
40
|
+
end
|
|
41
|
+
<%- else -%>
|
|
42
|
+
@<%= method_definition[:field].name %> = <%= method_definition[:field_initialization] %>
|
|
43
|
+
<%- end -%>
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
<%- end -%>
|
|
47
|
+
<% end -%>
|
|
48
|
+
<%- if @field_assignments.select{ |h| h[:is_complex_union] }.any? -%>
|
|
49
|
+
<%- @field_assignments.select{ |h| h[:is_complex_union] }.each do |method_definition| -%>
|
|
50
|
+
# Helper method to determine which schema type to use for <%= method_definition[:field].name %>
|
|
51
|
+
# @param value [Hash, nil]
|
|
52
|
+
# @param from_message [Boolean] whether this was initialized from a real Avro message
|
|
53
|
+
# @return [Object, nil]
|
|
54
|
+
def initialize_<%= method_definition[:field].name %>_type(value, from_message: false)
|
|
55
|
+
return nil if value.nil?
|
|
56
|
+
|
|
57
|
+
klass = [<%= method_definition[:field].type.schemas.reject { |s| s.type_sym == :null }.select { |s| s.type_sym == :record }.map { |s| AvroGen::AvroParser.schema_classname(s) }.join(', ') %>].find do |candidate|
|
|
58
|
+
fields = candidate.new.as_json.keys
|
|
59
|
+
(value.keys - fields).empty?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
klass.initialize_from_value(value, from_message: self._from_message)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
<%- end -%>
|
|
66
|
+
<% end -%>
|
|
67
|
+
# @override
|
|
68
|
+
<%= @initialization_definition %>
|
|
69
|
+
@_from_message = _from_message
|
|
70
|
+
super
|
|
71
|
+
<%- @fields.each do |field| -%>
|
|
72
|
+
self.<%= field.name %> = <%= field.name %>
|
|
73
|
+
<% end -%>
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @override
|
|
77
|
+
def schema
|
|
78
|
+
'<%= @current_schema.name %>'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @override
|
|
82
|
+
def namespace
|
|
83
|
+
'<%= @current_schema.namespace %>'
|
|
84
|
+
end
|
|
85
|
+
<%- if @tombstone_assignment %>
|
|
86
|
+
def self.tombstone(key)
|
|
87
|
+
record = self.allocate
|
|
88
|
+
<%- if @tombstone_assignment.present? -%>
|
|
89
|
+
<%= @tombstone_assignment %>
|
|
90
|
+
<%- end -%>
|
|
91
|
+
record
|
|
92
|
+
end
|
|
93
|
+
<%- end %>
|
|
94
|
+
# @override
|
|
95
|
+
def as_json(_opts={})
|
|
96
|
+
{
|
|
97
|
+
<%- @fields.each do |field| -%>
|
|
98
|
+
<%= field_as_json(field) %>
|
|
99
|
+
<% end -%>
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
end
|