avro-builder 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/.gitignore +9 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +156 -0
- data/Rakefile +6 -0
- data/avro-builder.gemspec +29 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/avro/builder/dsl.rb +124 -0
- data/lib/avro/builder/dsl_attributes.rb +59 -0
- data/lib/avro/builder/field.rb +78 -0
- data/lib/avro/builder/file_handler.rb +39 -0
- data/lib/avro/builder/namespaceable.rb +12 -0
- data/lib/avro/builder/record.rb +84 -0
- data/lib/avro/builder/schema_serializer_reference_state.rb +27 -0
- data/lib/avro/builder/type_factory.rb +33 -0
- data/lib/avro/builder/types/array_type.rb +29 -0
- data/lib/avro/builder/types/configurable_type.rb +16 -0
- data/lib/avro/builder/types/enum_type.rb +33 -0
- data/lib/avro/builder/types/fixed_type.rb +24 -0
- data/lib/avro/builder/types/map_type.rb +29 -0
- data/lib/avro/builder/types/named_type.rb +48 -0
- data/lib/avro/builder/types/specific_type.rb +31 -0
- data/lib/avro/builder/types/type.rb +31 -0
- data/lib/avro/builder/types/type_referencer.rb +21 -0
- data/lib/avro/builder/types.rb +7 -0
- data/lib/avro/builder/version.rb +5 -0
- data/lib/avro/builder.rb +22 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fc0e206e5b0cfe57f356bcc17de31819fc2db7ea
|
4
|
+
data.tar.gz: c7ebe9cd48e6ea8a55762d71d1349405e78d022a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b02e6bf7877bb667d2602c871aceda94b5943adbbe356ca80b7479044dab2dbdaa05d130d9f4732dee2314aa87484159195a845c1af354db0855105259fe2e06
|
7
|
+
data.tar.gz: b22b39dae5253d9b021fe4deabd8b50ef3757dff483cf0a10ef28612045c32f8ed149db761b68427eb191c8df7751bdabf5e8e98dce88e0b2ccac5180ad9d2a4
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Salsify, Inc
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
# Avro::Builder
|
2
|
+
|
3
|
+
`Avro::Builder` provides a Ruby DSL to create [Apache Avro](https://avro.apache.org/docs/current/) Schemas.
|
4
|
+
|
5
|
+
This DSL was created because:
|
6
|
+
* The [Avro IDL](https://avro.apache.org/docs/current/idl.html) is not supported in Ruby.
|
7
|
+
* The Avro IDL can only be used to define Protocols.
|
8
|
+
* Schemas can be extracted as JSON from an IDL Protocol but support
|
9
|
+
for imports is still limited.
|
10
|
+
|
11
|
+
## Features
|
12
|
+
* The syntax is designed for ease-of-use.
|
13
|
+
* Definitions can be imported by name. This includes auto-loading from a configured
|
14
|
+
set of paths. This allows definitions to split across files and even reused
|
15
|
+
between projects.
|
16
|
+
* Record definitions can inherit from other record definitions.
|
17
|
+
|
18
|
+
## Limitations
|
19
|
+
|
20
|
+
* Only Avro Schemas, not Protocols are supported.
|
21
|
+
* See [Issues](https://github.com/salsify/avro-builder/issues) for functionality
|
22
|
+
that has yet to be implemented.
|
23
|
+
* This is alpha quality code. There may be breaking changes until version 1.0 is
|
24
|
+
released.
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Add this line to your application's Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
gem 'avro-builder'
|
32
|
+
```
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install avro-builder
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
To use `Avro::Builder` define a schema:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
namespace 'com.example'
|
48
|
+
|
49
|
+
fixed :password, 8
|
50
|
+
|
51
|
+
enum :user_type, :ADMIN, :REGULAR
|
52
|
+
|
53
|
+
record :user do
|
54
|
+
required :id, :long
|
55
|
+
required :user_name, :string
|
56
|
+
required :type, :user_type, default: :REGULAR
|
57
|
+
required :pw, :password
|
58
|
+
optional :full_name, :string
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
The schema definition may be passed as a string or a block to
|
63
|
+
`Avro::Builder.build`.
|
64
|
+
|
65
|
+
This generates the following Avro JSON schema:
|
66
|
+
```json
|
67
|
+
{
|
68
|
+
"type": "record",
|
69
|
+
"name": "user",
|
70
|
+
"namespace": "com.example",
|
71
|
+
"fields": [
|
72
|
+
{
|
73
|
+
"name": "id",
|
74
|
+
"type": "long"
|
75
|
+
},
|
76
|
+
{
|
77
|
+
"name": "user_name",
|
78
|
+
"type": "string"
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"name": "type",
|
82
|
+
"type": {
|
83
|
+
"name": "user_type",
|
84
|
+
"type": "enum",
|
85
|
+
"symbols": [
|
86
|
+
"ADMIN",
|
87
|
+
"REGULAR"
|
88
|
+
],
|
89
|
+
"namespace": "com.example"
|
90
|
+
},
|
91
|
+
"default": "REGULAR"
|
92
|
+
},
|
93
|
+
{
|
94
|
+
"name": "pw",
|
95
|
+
"type": {
|
96
|
+
"name": "password",
|
97
|
+
"type": "fixed",
|
98
|
+
"size": 8,
|
99
|
+
"namespace": "com.example"
|
100
|
+
}
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"name": "full_name",
|
104
|
+
"type": [
|
105
|
+
"null",
|
106
|
+
"string"
|
107
|
+
]
|
108
|
+
}
|
109
|
+
]
|
110
|
+
}
|
111
|
+
```
|
112
|
+
|
113
|
+
### Required and Optional
|
114
|
+
|
115
|
+
Fields for a record a specified as `required` or `optional`. Optional fields are
|
116
|
+
implemented as a union in Avro, where `null` is the first type in the union.
|
117
|
+
|
118
|
+
### Named Types
|
119
|
+
|
120
|
+
`fixed` and `enum` fields may be specified inline as part of a record
|
121
|
+
or as standalone named types.
|
122
|
+
|
123
|
+
### Auto-loading and Imports
|
124
|
+
|
125
|
+
Specify paths to search for definitions:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Avro::Builder.add_load_path('/path/to/dsl/files')
|
129
|
+
```
|
130
|
+
|
131
|
+
Undefined references are automatically loaded from a file with the same name.
|
132
|
+
The load paths are searched for `.rb` file with a matching name.
|
133
|
+
|
134
|
+
Files may also be explicitly imported using `import <filename>`.
|
135
|
+
|
136
|
+
### Extends
|
137
|
+
|
138
|
+
A previously defined record may be referenced in the definition of another
|
139
|
+
record using `extends <record_name>`. This adds all of the fields from
|
140
|
+
the referenced record to the current record. The current record may override
|
141
|
+
fields in the record that it extends.
|
142
|
+
|
143
|
+
## Development
|
144
|
+
|
145
|
+
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.
|
146
|
+
|
147
|
+
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).
|
148
|
+
|
149
|
+
## Contributing
|
150
|
+
|
151
|
+
Issues and pull requests are welcome on GitHub at https://github.com/salsify/avro-builder.
|
152
|
+
|
153
|
+
## License
|
154
|
+
|
155
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
156
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'avro/builder/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "avro-builder"
|
8
|
+
spec.version = Avro::Builder::VERSION
|
9
|
+
spec.authors = ["Salsify Engineering"]
|
10
|
+
spec.email = ["engineering@salsify.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Ruby DSL to create Avro schemas}
|
13
|
+
spec.description = spec.summary
|
14
|
+
spec.homepage = "https://github.com/salsify/avro-builder.git"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "avro", ">= 1.7.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
spec.add_development_dependency "json_spec"
|
28
|
+
spec.add_development_dependency "simplecov"
|
29
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "avro/builder"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'avro'
|
2
|
+
require 'avro/builder/dsl_attributes'
|
3
|
+
require 'avro/builder/namespaceable'
|
4
|
+
require 'avro/builder/type_factory'
|
5
|
+
require 'avro/builder/types'
|
6
|
+
require 'avro/builder/field'
|
7
|
+
require 'avro/builder/record'
|
8
|
+
require 'avro/builder/file_handler'
|
9
|
+
require 'avro/builder/schema_serializer_reference_state'
|
10
|
+
|
11
|
+
module Avro
|
12
|
+
module Builder
|
13
|
+
# This class is used to construct Avro schemas (not protocols) using a ruby
|
14
|
+
# DSL
|
15
|
+
class DSL
|
16
|
+
include Avro::Builder::DslAttributes
|
17
|
+
include Avro::Builder::FileHandler
|
18
|
+
include Avro::Builder::TypeFactory
|
19
|
+
|
20
|
+
dsl_attribute :namespace
|
21
|
+
|
22
|
+
# An instance of the DSL is initialized with a string or a block to
|
23
|
+
# evaluate to define Avro schema objects.
|
24
|
+
def initialize(str = nil, &block)
|
25
|
+
str ? instance_eval(str) : instance_eval(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Define an Avro schema record
|
29
|
+
def record(name, options = {}, &block)
|
30
|
+
add_schema_object(build_record(name, options, &block))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Imports from the file with specified name fragment.
|
34
|
+
def import(name)
|
35
|
+
previous_namespace = namespace
|
36
|
+
eval_file(name)
|
37
|
+
namespace(previous_namespace)
|
38
|
+
end
|
39
|
+
|
40
|
+
## DSL methods for Types
|
41
|
+
|
42
|
+
def enum(name, *symbols, **options, &block)
|
43
|
+
type(name, :enum, { symbols: symbols }.merge(options), &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def fixed(name, size = nil, options = {}, &block)
|
47
|
+
type(name, :fixed, { size: size }.merge(options), &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def type(name, type_name, options = {}, &block)
|
51
|
+
build_type(type_name,
|
52
|
+
builder: self,
|
53
|
+
internal: { name: name, namespace: namespace },
|
54
|
+
options: options,
|
55
|
+
&block).tap do |type|
|
56
|
+
add_schema_object(type)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Lookup an Avro schema object by name, possibly fully qualified by namespace.
|
61
|
+
def lookup(key, required: true)
|
62
|
+
key_str = key.to_s
|
63
|
+
object = schema_objects[key_str]
|
64
|
+
|
65
|
+
unless object
|
66
|
+
import(key)
|
67
|
+
object = schema_objects[key_str]
|
68
|
+
end
|
69
|
+
|
70
|
+
raise "Schema object #{key} not found" if required && !object
|
71
|
+
object
|
72
|
+
rescue
|
73
|
+
raise if required
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return the last schema object processed as a Hash representing
|
78
|
+
# the Avro schema.
|
79
|
+
def to_h
|
80
|
+
@last_object.to_h(SchemaSerializerReferenceState.new)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return the last schema object processed as an Avro JSON schema
|
84
|
+
def to_json(validate: true, pretty: true)
|
85
|
+
hash = to_h
|
86
|
+
(pretty ? JSON.pretty_generate(hash) : hash.to_json).tap do |json|
|
87
|
+
# Parse the schema to validate before returning
|
88
|
+
::Avro::Schema.parse(json) if validate
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def as_schema
|
93
|
+
Avro::Schema.parse(to_json(validate: false))
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def builder
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def schema_objects
|
103
|
+
@schema_objects ||= {}
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_schema_object(object)
|
107
|
+
@last_object = object
|
108
|
+
schema_objects[object.name.to_s] = object
|
109
|
+
schema_objects[object.fullname] = object if object.namespace
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_record(name, options, &block)
|
113
|
+
Record.new(name, options.merge(namespace: namespace)).tap do |record|
|
114
|
+
record.builder = builder
|
115
|
+
record.instance_eval(&block)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def eval_file(name)
|
120
|
+
instance_eval(read_file(name))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
|
4
|
+
# This module provides methods for defining attributes that can be
|
5
|
+
# set via the DSL on various objects.
|
6
|
+
#
|
7
|
+
# The methods generated for DSL attributes are combined getter/setters
|
8
|
+
# of the form:
|
9
|
+
#
|
10
|
+
# attribute(value = nil)
|
11
|
+
#
|
12
|
+
# When value is provided the attribute is set, and when it is nil the
|
13
|
+
# current value is returned.
|
14
|
+
#
|
15
|
+
# When a DSL attribute is defined, the class also keeps track of the
|
16
|
+
# attribute names.
|
17
|
+
module DslAttributes
|
18
|
+
def self.included(base)
|
19
|
+
base.extend ClassMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_dsl_attribute?(name)
|
23
|
+
self.class.dsl_attribute_names.include?(name.to_sym)
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
def dsl_attributes(*names)
|
28
|
+
names.each do |name|
|
29
|
+
dsl_attribute_names << name
|
30
|
+
ivar = :"@#{name}"
|
31
|
+
define_method(name) do |value = nil|
|
32
|
+
value ? instance_variable_set(ivar, value) : instance_variable_get(ivar)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# If a block is specified then it is used to define the
|
38
|
+
# combined getter/setter method for the DSL attribute.
|
39
|
+
def dsl_attribute(name, &block)
|
40
|
+
if block_given?
|
41
|
+
dsl_attribute_names << name
|
42
|
+
define_method(name, &block)
|
43
|
+
else
|
44
|
+
dsl_attributes(name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def dsl_attribute_names
|
49
|
+
@dsl_attribute_names ||=
|
50
|
+
if superclass.respond_to?(:dsl_attribute_names)
|
51
|
+
superclass.dsl_attribute_names.dup
|
52
|
+
else
|
53
|
+
Set.new
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'avro/builder/type_factory'
|
2
|
+
|
3
|
+
module Avro
|
4
|
+
module Builder
|
5
|
+
|
6
|
+
# This class represents a field in a record.
|
7
|
+
# A field must be initialized with a type.
|
8
|
+
class Field
|
9
|
+
include Avro::Builder::DslAttributes
|
10
|
+
include Avro::Builder::Namespaceable
|
11
|
+
include Avro::Builder::TypeFactory
|
12
|
+
|
13
|
+
INTERNAL_ATTRIBUTES = Set.new(%i(optional)).freeze
|
14
|
+
|
15
|
+
attr_accessor :type, :optional, :builder
|
16
|
+
|
17
|
+
# These attributes may be set as options or via a block in the DSL
|
18
|
+
dsl_attributes :doc, :aliases, :default, :order
|
19
|
+
|
20
|
+
def initialize(name:, type_name:, builder:, internal: {}, options: {}, &block)
|
21
|
+
@builder = builder
|
22
|
+
@name = name.to_s
|
23
|
+
|
24
|
+
internal.each do |key, value|
|
25
|
+
send("#{key}=", value) if INTERNAL_ATTRIBUTES.include?(key)
|
26
|
+
end
|
27
|
+
|
28
|
+
options.each do |key, value|
|
29
|
+
send(key, value) if has_dsl_attribute?(key)
|
30
|
+
end
|
31
|
+
|
32
|
+
@type = builder.lookup(type_name, required: false) ||
|
33
|
+
build_type(type_name, field: self, internal: internal, options: options)
|
34
|
+
|
35
|
+
# DSL calls must be evaluated after the type has been constructed
|
36
|
+
instance_eval(&block) if block_given?
|
37
|
+
end
|
38
|
+
|
39
|
+
## Delegate additional DSL calls to the type
|
40
|
+
|
41
|
+
def respond_to_missing?(id, include_all = false)
|
42
|
+
super || type.respond_to?(id, include_all)
|
43
|
+
end
|
44
|
+
|
45
|
+
def method_missing(id, *args)
|
46
|
+
type.respond_to?(id) ? type.send(id, *args) : super
|
47
|
+
end
|
48
|
+
|
49
|
+
# Delegate setting name explicitly via DSL to type
|
50
|
+
def name(value = nil)
|
51
|
+
if value
|
52
|
+
type.name(value)
|
53
|
+
else
|
54
|
+
# Return the name of the field
|
55
|
+
@name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def serialize(reference_state)
|
60
|
+
{
|
61
|
+
name: name,
|
62
|
+
type: serialized_type(reference_state),
|
63
|
+
doc: doc,
|
64
|
+
default: default,
|
65
|
+
aliases: aliases
|
66
|
+
}.reject { |_, v| v.nil? }
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# Optional types must be serialized as an array.
|
72
|
+
def serialized_type(reference_state)
|
73
|
+
result = type.serialize(reference_state)
|
74
|
+
optional ? [:null, result] : result
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
# TODO: eventually this should be refactored into something standalone
|
4
|
+
# instead of a module that is included to provide the file handling methods.
|
5
|
+
module FileHandler
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Load paths are used to search for imports and extends.
|
9
|
+
def load_paths
|
10
|
+
@load_paths ||= Set.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
base.extend ClassMethods
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_file(name)
|
19
|
+
File.read(find_file(name))
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def find_file(name)
|
25
|
+
file_name = "#{name.to_s.sub(/\.rb$/, '')}.rb"
|
26
|
+
matches = self.class.load_paths.flat_map do |load_path|
|
27
|
+
Dir["#{load_path}/**/*.rb"].select do |file_path|
|
28
|
+
file_path.end_with?(file_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
raise "Multiple matches: #{matches}" if matches.size > 1
|
32
|
+
raise "File not found #{name}" if matches.empty?
|
33
|
+
|
34
|
+
matches.first
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
# This class represents a record in an Avro schema.
|
4
|
+
class Record
|
5
|
+
include Avro::Builder::DslAttributes
|
6
|
+
include Avro::Builder::Namespaceable
|
7
|
+
|
8
|
+
attr_accessor :builder
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
dsl_attributes :doc, :aliases, :namespace
|
12
|
+
|
13
|
+
def initialize(name, options = {})
|
14
|
+
@name = name
|
15
|
+
options.each do |key, value|
|
16
|
+
send(key, value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add a required field to the record
|
21
|
+
def required(name, type_name, options = {}, &block)
|
22
|
+
new_field = Avro::Builder::Field.new(name: name,
|
23
|
+
type_name: type_name,
|
24
|
+
builder: builder,
|
25
|
+
internal: { namespace: namespace },
|
26
|
+
options: options,
|
27
|
+
&block)
|
28
|
+
add_field(new_field)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Add an optional field to the record. In Avro this is represented
|
32
|
+
# as a union of null and the type specified here.
|
33
|
+
def optional(name, type_name, options = {}, &block)
|
34
|
+
new_field = Avro::Builder::Field.new(name: name,
|
35
|
+
type_name: type_name,
|
36
|
+
builder: builder,
|
37
|
+
internal: { namespace: namespace,
|
38
|
+
optional: true },
|
39
|
+
options: options,
|
40
|
+
&block)
|
41
|
+
add_field(new_field)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Adds fields from the record with the specified name to the current
|
45
|
+
# record.
|
46
|
+
def extends(name)
|
47
|
+
fields.merge!(builder.lookup(name).duplicated_fields)
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_h(reference_state = SchemaSerializerReferenceState.new)
|
51
|
+
reference_state.definition_or_reference(fullname) do
|
52
|
+
{
|
53
|
+
type: :record,
|
54
|
+
name: name,
|
55
|
+
namespace: namespace,
|
56
|
+
doc: doc,
|
57
|
+
aliases: aliases,
|
58
|
+
fields: fields.values.map { |field| field.serialize(reference_state) }
|
59
|
+
}.reject { |_, v| v.nil? }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def duplicated_fields
|
66
|
+
fields.each_with_object(Hash.new) do |(name, field), result|
|
67
|
+
field_copy = field.dup
|
68
|
+
result[name] = field_copy
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Add field, replacing any existing field with the same name.
|
75
|
+
def add_field(field)
|
76
|
+
fields[field.name] = field
|
77
|
+
end
|
78
|
+
|
79
|
+
def fields
|
80
|
+
@fields ||= {}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
|
4
|
+
# This class is used to keep track of references to each named type while
|
5
|
+
# generating an Avro JSON schema. Only the first reference to the type
|
6
|
+
# can include all of details of the definition. All subsequent references
|
7
|
+
# must use the full name for the type.
|
8
|
+
class SchemaSerializerReferenceState
|
9
|
+
|
10
|
+
attr_reader :references
|
11
|
+
private :references
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@references = Set.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def definition_or_reference(fullname)
|
18
|
+
if references.include?(fullname)
|
19
|
+
fullname
|
20
|
+
else
|
21
|
+
references << fullname
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
|
4
|
+
# This concern is used by classes that create new Type instances.
|
5
|
+
module TypeFactory
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
# Return a new Type instance
|
10
|
+
def create_type(type_name)
|
11
|
+
case
|
12
|
+
when Avro::Schema::PRIMITIVE_TYPES_SYM.include?(type_name.to_sym)
|
13
|
+
Avro::Builder::Types::Type.new(type_name)
|
14
|
+
else
|
15
|
+
type_class_name = "#{type_name.to_s.capitalize}Type"
|
16
|
+
Avro::Builder::Types.const_get(type_class_name).new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return a new Type instance, including propagating internal state
|
21
|
+
# and setting attributes via the DSL
|
22
|
+
def build_type(type_name, field: nil, builder: nil, internal: {}, options: {}, &block)
|
23
|
+
create_type(type_name).tap do |type|
|
24
|
+
type.field = field
|
25
|
+
type.builder = builder
|
26
|
+
type.configure_options(internal.merge(options))
|
27
|
+
type.instance_eval(&block) if block_given?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'avro/builder/types/configurable_type'
|
2
|
+
require 'avro/builder/types/type_referencer'
|
3
|
+
|
4
|
+
module Avro
|
5
|
+
module Builder
|
6
|
+
module Types
|
7
|
+
class ArrayType < Type
|
8
|
+
include Avro::Builder::Types::SpecificType
|
9
|
+
include Avro::Builder::Types::ConfigurableType
|
10
|
+
include Avro::Builder::Types::TypeReferencer
|
11
|
+
|
12
|
+
dsl_attribute :items do |items_type = nil|
|
13
|
+
if items_type
|
14
|
+
@items = find_or_create_type(items_type)
|
15
|
+
else
|
16
|
+
@items
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def serialize(referenced_state)
|
21
|
+
{
|
22
|
+
type: type_name,
|
23
|
+
items: items.serialize(referenced_state)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
module Types
|
4
|
+
|
5
|
+
# This concern is used by Types that can be configured using DSL
|
6
|
+
# attributes.
|
7
|
+
module ConfigurableType
|
8
|
+
def configure_options(options = {})
|
9
|
+
options.each do |key, value|
|
10
|
+
send(key, value) if has_dsl_attribute?(key)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
module Types
|
4
|
+
class EnumType < NamedType
|
5
|
+
|
6
|
+
dsl_attribute :doc
|
7
|
+
|
8
|
+
dsl_attribute :symbols do |*values|
|
9
|
+
# Define symbols explicitly to support values as a splat or single array
|
10
|
+
if !values.empty?
|
11
|
+
@symbols = values.flatten
|
12
|
+
else
|
13
|
+
@symbols
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def serialize(reference_state)
|
18
|
+
super(reference_state, overrides: serialized_attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_h(reference_state)
|
22
|
+
super(reference_state, overrides: serialized_attributes)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def serialized_attributes
|
28
|
+
{ symbols: symbols, doc: doc }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
module Types
|
4
|
+
class FixedType < NamedType
|
5
|
+
|
6
|
+
dsl_attribute :size
|
7
|
+
|
8
|
+
def serialize(reference_state)
|
9
|
+
super(reference_state, overrides: serialized_attributes)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h(reference_state)
|
13
|
+
super(reference_state, overrides: serialized_attributes)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def serialized_attributes
|
19
|
+
{ size: size }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'avro/builder/types/configurable_type'
|
2
|
+
require 'avro/builder/types/type_referencer'
|
3
|
+
|
4
|
+
module Avro
|
5
|
+
module Builder
|
6
|
+
module Types
|
7
|
+
class MapType < Type
|
8
|
+
include Avro::Builder::Types::SpecificType
|
9
|
+
include Avro::Builder::Types::ConfigurableType
|
10
|
+
include Avro::Builder::Types::TypeReferencer
|
11
|
+
|
12
|
+
dsl_attribute :values do |value_type = nil|
|
13
|
+
if value_type
|
14
|
+
@values = find_or_create_type(value_type)
|
15
|
+
else
|
16
|
+
@values
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def serialize(referenced_state)
|
21
|
+
{
|
22
|
+
type: type_name,
|
23
|
+
values: values.serialize(referenced_state)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'avro/builder/types/configurable_type'
|
2
|
+
require 'avro/builder/namespaceable'
|
3
|
+
|
4
|
+
module Avro
|
5
|
+
module Builder
|
6
|
+
module Types
|
7
|
+
|
8
|
+
# This is an abstract class that represents a type that can be defined
|
9
|
+
# with a name, outside a record.
|
10
|
+
class NamedType < Type
|
11
|
+
include Avro::Builder::Types::SpecificType
|
12
|
+
include Avro::Builder::Namespaceable
|
13
|
+
include Avro::Builder::Types::ConfigurableType
|
14
|
+
|
15
|
+
dsl_attributes :name, :namespace, :aliases
|
16
|
+
|
17
|
+
def generated_name
|
18
|
+
name || "__#{field.name}_#{type_name}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# As a type for a field
|
22
|
+
# Subclasses may call super with additional overrides to be added
|
23
|
+
# to the serialized value.
|
24
|
+
def serialize(reference_state, overrides: {})
|
25
|
+
reference_state.definition_or_reference(fullname) do
|
26
|
+
{
|
27
|
+
name: generated_name,
|
28
|
+
type: type_name,
|
29
|
+
namespace: namespace
|
30
|
+
}.merge(overrides).reject { |_, v| v.nil? }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# As a top-level, named type
|
35
|
+
# Subclasses may call super with additional overrides to be added
|
36
|
+
# to the hash representation.
|
37
|
+
def to_h(_reference_state, overrides: {})
|
38
|
+
{
|
39
|
+
name: name,
|
40
|
+
type: type_name,
|
41
|
+
namespace: namespace,
|
42
|
+
aliases: aliases
|
43
|
+
}.merge(overrides).reject { |_, v| v.nil? }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
module Types
|
4
|
+
|
5
|
+
# This module provides common functionality for Types with a specific
|
6
|
+
# type name vs the generic Type class.
|
7
|
+
module SpecificType
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.extend ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
# Override initialize so that type name is not required
|
14
|
+
def initialize
|
15
|
+
end
|
16
|
+
|
17
|
+
def type_name
|
18
|
+
self.class.type_name
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
|
23
|
+
# Infer type_name based on class
|
24
|
+
def type_name
|
25
|
+
@type_name ||= name.split('::').last.sub('Type', '').downcase.to_sym
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Avro
|
2
|
+
module Builder
|
3
|
+
module Types
|
4
|
+
# Base class for simple types. The type name is specified when the
|
5
|
+
# type is constructed. The type has no additional attributes, and
|
6
|
+
# the type is serialized as just the type name.
|
7
|
+
class Type
|
8
|
+
include Avro::Builder::DslAttributes
|
9
|
+
|
10
|
+
attr_reader :type_name
|
11
|
+
attr_accessor :field, :builder
|
12
|
+
|
13
|
+
def initialize(type_name)
|
14
|
+
@type_name = type_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def serialize(_reference_state)
|
18
|
+
type_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def namespace
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def configure_options(_options = {})
|
26
|
+
# No-op
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'avro/builder/type_factory'
|
2
|
+
|
3
|
+
module Avro
|
4
|
+
module Builder
|
5
|
+
module Types
|
6
|
+
|
7
|
+
# This concern is used by Types that reference other types.
|
8
|
+
module TypeReferencer
|
9
|
+
include Avro::Builder::TypeFactory
|
10
|
+
|
11
|
+
def builder
|
12
|
+
(!field.nil? && field.builder) || super
|
13
|
+
end
|
14
|
+
|
15
|
+
def find_or_create_type(type_name)
|
16
|
+
builder.lookup(type_name, required: false) || create_type(type_name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'avro/builder/types/type'
|
2
|
+
require 'avro/builder/types/specific_type'
|
3
|
+
require 'avro/builder/types/named_type'
|
4
|
+
require 'avro/builder/types/enum_type'
|
5
|
+
require 'avro/builder/types/fixed_type'
|
6
|
+
require 'avro/builder/types/array_type'
|
7
|
+
require 'avro/builder/types/map_type'
|
data/lib/avro/builder.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'avro/builder/version'
|
2
|
+
require 'avro/builder/dsl'
|
3
|
+
|
4
|
+
module Avro
|
5
|
+
module Builder
|
6
|
+
|
7
|
+
# Accepts a string or block to eval to define a JSON schema
|
8
|
+
def self.build(str = nil, &block)
|
9
|
+
Avro::Builder::DSL.new(str, &block).to_json
|
10
|
+
end
|
11
|
+
|
12
|
+
# Accepts a string or block to eval and returns an Avro::Schema
|
13
|
+
def self.build_schema(str = nil, &block)
|
14
|
+
Avro::Builder::DSL.new(str, &block).as_schema
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add paths that will be searched for definitions
|
18
|
+
def self.add_load_path(*paths)
|
19
|
+
Avro::Builder::DSL.load_paths.merge(paths)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: avro-builder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Salsify Engineering
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: avro
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.7.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.7.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: '1.11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.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.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: json_spec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Ruby DSL to create Avro schemas
|
98
|
+
email:
|
99
|
+
- engineering@salsify.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".travis.yml"
|
106
|
+
- CHANGELOG.md
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE.txt
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- avro-builder.gemspec
|
112
|
+
- bin/console
|
113
|
+
- bin/setup
|
114
|
+
- lib/avro/builder.rb
|
115
|
+
- lib/avro/builder/dsl.rb
|
116
|
+
- lib/avro/builder/dsl_attributes.rb
|
117
|
+
- lib/avro/builder/field.rb
|
118
|
+
- lib/avro/builder/file_handler.rb
|
119
|
+
- lib/avro/builder/namespaceable.rb
|
120
|
+
- lib/avro/builder/record.rb
|
121
|
+
- lib/avro/builder/schema_serializer_reference_state.rb
|
122
|
+
- lib/avro/builder/type_factory.rb
|
123
|
+
- lib/avro/builder/types.rb
|
124
|
+
- lib/avro/builder/types/array_type.rb
|
125
|
+
- lib/avro/builder/types/configurable_type.rb
|
126
|
+
- lib/avro/builder/types/enum_type.rb
|
127
|
+
- lib/avro/builder/types/fixed_type.rb
|
128
|
+
- lib/avro/builder/types/map_type.rb
|
129
|
+
- lib/avro/builder/types/named_type.rb
|
130
|
+
- lib/avro/builder/types/specific_type.rb
|
131
|
+
- lib/avro/builder/types/type.rb
|
132
|
+
- lib/avro/builder/types/type_referencer.rb
|
133
|
+
- lib/avro/builder/version.rb
|
134
|
+
homepage: https://github.com/salsify/avro-builder.git
|
135
|
+
licenses:
|
136
|
+
- MIT
|
137
|
+
metadata: {}
|
138
|
+
post_install_message:
|
139
|
+
rdoc_options: []
|
140
|
+
require_paths:
|
141
|
+
- lib
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
requirements: []
|
153
|
+
rubyforge_project:
|
154
|
+
rubygems_version: 2.4.8
|
155
|
+
signing_key:
|
156
|
+
specification_version: 4
|
157
|
+
summary: Ruby DSL to create Avro schemas
|
158
|
+
test_files: []
|