dbml 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8979759a1d1b3dc026d99323199313a0e35fca4fc0cf865a7ed256b1bf61054c
4
+ data.tar.gz: 93f4d97a7c07c9d94e9412cc781c0312007b7dd42c225ffc9fd64aec3fc9eb1f
5
+ SHA512:
6
+ metadata.gz: 03d021e161615e622a88bac15a21c8fd633f60bed64b081d0479ee47df29478e5d9eb0465365269bf214c8f160bfb452de81e2e78114d033a60bf6d23131c087
7
+ data.tar.gz: 32bb14bc1df49cebf682b7b65aa5670e45130f182f6397d3df45ec26744fe4e394aa7050ffe0071e86b0e389dd1f6370b39ee6ab9c48238d37cea4985ecd890b
@@ -0,0 +1,32 @@
1
+ name: Run tests
2
+
3
+ on: [pull_request, push]
4
+
5
+ jobs:
6
+ unit_tests:
7
+ name: Run unit tests
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - name: Check out repository
11
+ uses: actions/checkout@v2
12
+
13
+ - name: Set up Ruby
14
+ uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: 2.6
17
+
18
+ - name: Restore gems from cache
19
+ uses: actions/cache@v2
20
+ env:
21
+ cache-name: ruby-gems-cache
22
+ with:
23
+ path: ./.gems
24
+ key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/dbml.gemspec') }}
25
+ restore-keys: |
26
+ ${{ runner.os }}-${{ env.cache-name }}-
27
+
28
+ - name: Install gems
29
+ run: bundle install --path=./.gems --jobs=4
30
+
31
+ - name: Run tests
32
+ run: bundle exec rake test
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in dbml.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Simon Worthington
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.
@@ -0,0 +1,47 @@
1
+ # DBML
2
+
3
+ Ruby library for [Database Markup Language (DBML)](https://www.dbml.org/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'dbml'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install dbml
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'dbml'
25
+ project = DBML::Parser.parse """
26
+ Table users {
27
+ id int64 [pk, unique]
28
+ name varchar [unique]
29
+ Note: 'add some more things in here!'
30
+ }"""
31
+ puts project.tables.first.name
32
+ # => "users"
33
+ ```
34
+
35
+ ## Development
36
+
37
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests.
38
+
39
+ 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).
40
+
41
+ ## Contributing
42
+
43
+ Bug reports and pull requests are welcome on GitHub at https://github.com/simonwo/dbml-ruby.
44
+
45
+ ## License
46
+
47
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,29 @@
1
+
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dbml/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'dbml'
8
+ spec.version = DBML::VERSION
9
+ spec.authors = ['Simon Worthington']
10
+ spec.email = ['simon@simonwo.net']
11
+
12
+ spec.summary = %q{Parser for Database Markup Language (DBML).}
13
+ spec.homepage = 'https://github.com/simonwo/dbml-ruby'
14
+ spec.license = 'MIT'
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_dependency 'rsec', '~> 1.0'
26
+ spec.add_development_dependency 'bundler'
27
+ spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'minitest', '~> 5.0'
29
+ end
@@ -0,0 +1,244 @@
1
+ require 'rsec'
2
+ include Rsec::Helpers
3
+
4
+ module DBML
5
+ Column = Struct.new :name, :type, :settings
6
+ Table = Struct.new :name, :alias, :notes, :columns, :indexes
7
+ Index = Struct.new :fields, :settings
8
+ Expression = Struct.new :text
9
+ Enum = Struct.new :name, :choices
10
+ EnumChoice = Struct.new :name, :settings
11
+ TableGroup = Struct.new :name, :tables
12
+ Project = Struct.new :name, :notes, :settings, :tables, :enums, :table_groups
13
+ ProjectDef = Struct.new :name, :notes, :settings
14
+
15
+ module Parser
16
+ def self.long_or_short p
17
+ (':'.r >> p) | ('{'.r >> p << '}'.r)
18
+ end
19
+
20
+ def self.unwrap p, *_
21
+ if p.empty? then nil else p.first end
22
+ end
23
+
24
+ def self.comma_separated p
25
+ p.join(/, */.r.map {|_| nil}).star.map {|v| v.first.reject(&:nil?) }
26
+ end
27
+
28
+ def self.space_surrounded p
29
+ /\s*/.r >> p << /\s*/.r
30
+ end
31
+
32
+ def self.block type, name_parser, content_parser, &block
33
+ seq_(type.r >> name_parser, '{'.r >> space_surrounded(content_parser).star.map {|a| a.flatten(1) } << '}'.r, &block)
34
+ end
35
+
36
+ # ATOM parses true: 'true' => true
37
+ # ATOM parses false: 'false' => false
38
+ # ATOM parses null: 'null' => nil
39
+ # ATOM parses numbers: '123.45678' => 123.45678
40
+ # ATOM parses strings: "'string'" => "string"
41
+ # ATOM parses multilines: "'''long\nstring'''" => "long\nstring"
42
+ # ATOM parses expressions: '`now()`' => DBML::Expression.new('now()')
43
+ BOOLEAN = 'true'.r.map {|_| true } | 'false'.r.map {|_| false }
44
+ NULL = 'null'.r.map {|_| nil }
45
+ NUMBER = prim(:double)
46
+ EXPRESSION = seq('`'.r, /[^`]+/.r, '`'.r)[1].map {|str| Expression.new str}
47
+ SINGLE_LING_STRING = seq("'".r, /[^']+/.r, "'".r)[1]
48
+ MULTI_LINE_STRING = seq("'''".r, /([^']|'[^']|''[^'])+/m.r, "'''".r)[1].map do |string|
49
+ # MULTI_LINE_STRING ignores indentation on the first line: "''' long\n string'''" => "long\n string"
50
+ # MULTI_LINE_STRING allows apostrophes: "'''it's a string with '' bunny ears'''" => "it's a string with '' bunny ears"
51
+ indent = string.match(/^\s*/m)[0].size
52
+ string.lines.map do |line|
53
+ raise "Indentation does not match" unless line =~ /\s{#{indent}}/
54
+ line[indent..]
55
+ end.join
56
+ end
57
+ STRING = SINGLE_LING_STRING | MULTI_LINE_STRING
58
+ ATOM = BOOLEAN | NULL | NUMBER | EXPRESSION | STRING
59
+
60
+ # Each setting item can take in 2 forms: Key: Value or keyword, similar to that of Python function parameters.
61
+ # Settings are all defined within square brackets: [setting1: value1, setting2: value2, setting3, setting4]
62
+ #
63
+ # SETTINGS parses key value settings: '[default: 123]' => {'default' => 123}
64
+ # SETTINGS parses keyword settings: '[not null]' => {'not null' => nil}
65
+ # SETTINGS parses many settings: "[some setting: 'value', primary key]" => {'some setting' => 'value', 'primary key' => nil}
66
+ SETTING = seq_(/[^,:\[\]\{\}\s][^,:\[\]]+/.r, (':'.r >> ATOM).maybe(&method(:unwrap))) {|(key, value)| {key => value} }
67
+ SETTINGS = ('['.r >> comma_separated(SETTING) << ']'.r).map {|values| values.reduce({}, &:update) }
68
+
69
+ # NOTE parses short notes: "Note: 'this is cool'" => 'this is cool'
70
+ # NOTE parses block notes: "Note {\n'still a single line of note'\n}" => 'still a single line of note'
71
+ # NOTE can use multilines: "Note: '''this is\nnot reassuring'''" => "this is\nnot reassuring"
72
+ NOTE = 'Note'.r >> (long_or_short STRING)
73
+
74
+ # Index Definition
75
+ #
76
+ # Indexes allow users to quickly locate and access the data. Users can define single or multi-column indexes.
77
+ #
78
+ # Table bookings {
79
+ # id integer
80
+ # country varchar
81
+ # booking_date date
82
+ # created_at timestamp
83
+ #
84
+ # indexes {
85
+ # (id, country) [pk] // composite primary key
86
+ # created_at [note: 'Date']
87
+ # booking_date
88
+ # (country, booking_date) [unique]
89
+ # booking_date [type: hash]
90
+ # (`id*2`)
91
+ # (`id*3`,`getdate()`)
92
+ # (`id*3`,id)
93
+ # }
94
+ # }
95
+ #
96
+ # There are 3 types of index definitions:
97
+ #
98
+ # # Index with single field (with index name): CREATE INDEX on users (created_at)
99
+ # # Index with multiple fields (composite index): CREATE INDEX on users (created_at, country)
100
+ # # Index with an expression: CREATE INDEX ON films ( first_name + last_name )
101
+ # # (bonus) Composite index with expression: CREATE INDEX ON users ( country, (lower(name)) )
102
+ #
103
+ # INDEX parses single fields: 'id' => DBML::Index.new(['id'], {})
104
+ # INDEX parses composite fields: '(id, country)' => DBML::Index.new(['id', 'country'], {})
105
+ # INDEX parses expressions: '(`id*2`)' => DBML::Index.new([DBML::Expression.new('id*2')], {})
106
+ # INDEX parses settings: '(country, booking_date) [unique]' => DBML::Index.new(['country', 'booking_date'], {'unique' => nil})
107
+
108
+ INDEX_SINGLE = /[^\(\)\,\{\}\s]+/.r
109
+ INDEX_COMPOSITE = seq_('('.r, comma_separated(EXPRESSION | INDEX_SINGLE), ')'.r).inner.map {|v| unwrap(v) }
110
+ INDEX = seq_(INDEX_SINGLE.map {|field| [field] } | INDEX_COMPOSITE, SETTINGS.maybe).map do |(fields, settings)|
111
+ Index.new fields, unwrap(settings) || {}
112
+ end
113
+ INDEXES = block 'indexes', ''.r, INDEX do |(_, indexes)| indexes end
114
+
115
+ # Enum Definition
116
+ # ---------------
117
+ #
118
+ # Enum allows users to define different values of a particular column.
119
+ #
120
+ # enum job_status {
121
+ # created [note: 'Waiting to be processed']
122
+ # running
123
+ # done
124
+ # failure
125
+ # }
126
+ #
127
+ # ENUM parses empty blocks: "enum empty {\n}" => DBML::Enum.new('empty', [])
128
+ # ENUM parses settings: "enum setting {\none [note: 'something']\n}" => DBML::Enum.new('setting', [DBML::EnumChoice.new('one', {'note' => 'something'})])
129
+ # ENUM parses filled blocks: "enum filled {\none\ntwo}" =? DBML::Enum.new('filled', [DBML::EnumChoice.new('one', {}), DBML::EnumChoice.new('two', {})])
130
+
131
+ ENUM_CHOICE = seq_(/[^\{\}\s]+/.r, SETTINGS.maybe).map {|(name, settings)| EnumChoice.new name, unwrap(settings) }
132
+ ENUM = block 'enum', /\S+/.r, ENUM_CHOICE do |(name, choices)|
133
+ Enum.new name, choices
134
+ end
135
+
136
+ # Column Definition
137
+ # =================
138
+ # * name of the column is listed as column_name
139
+ # * type of the data in the column listed as column_type
140
+ # * supports all data types, as long as it is a single word (remove all spaces in the data type). Example, JSON, JSONB, decimal(1,2), etc.
141
+ # * column_name can be stated in just plain text, or wrapped in a double quote as "column name"
142
+ #
143
+ # Column Settings
144
+ # ---------------
145
+ # Each column can take have optional settings, defined in square brackets like:
146
+ #
147
+ # Table buildings {
148
+ # //...
149
+ # address varchar(255) [unique, not null, note: 'to include unit number']
150
+ # id integer [ pk, unique, default: 123, note: 'Number' ]
151
+ # }
152
+ #
153
+ # COLUMN parses naked identifiers as names: 'column_name type' => DBML::Column.new('column_name', 'type', {})
154
+ # COLUMN parses quoted identifiers as names: '"column name" type' => DBML::Column.new('column name', 'type', {})
155
+ # COLUMN parses types: 'name string' => DBML::Column.new('name', 'string', {})
156
+ # COLUMN parses settings: 'name string [pk]' => DBML::Column.new('name', 'string', {'pk' => nil})
157
+
158
+ QUOTED_COLUMN_NAME = '"'.r >> /[^"]+/.r << '"'.r
159
+ UNQUOTED_COLUMN_NAME = /[^\{\}\s]+/.r
160
+ COLUMN_TYPE = /\S+/.r
161
+ COLUMN = seq_(
162
+ QUOTED_COLUMN_NAME | UNQUOTED_COLUMN_NAME,
163
+ COLUMN_TYPE,
164
+ SETTINGS.maybe
165
+ ) {|(name, type, settings)| Column.new name, type, unwrap(settings) || {} }
166
+
167
+ # Table Definition
168
+ #
169
+ # Table table_name {
170
+ # column_name column_type [column_settings]
171
+ # }
172
+ #
173
+ # * title of database table is listed as table_name
174
+ # * list is wrapped in curly brackets {}, for indexes, constraints and table definitions.
175
+ # * string value is be wrapped in a single quote as 'string'
176
+ #
177
+ # TABLE_NAME parses identifiers: 'table_name' => ['table_name', nil]
178
+ # TABLE_NAME parses aliases: 'table_name as thingy' => ['table_name', 'thingy']
179
+ # TABLE parses empty tables: 'Table empty {}' => DBML::Table.new('empty', nil, [], [], [])
180
+ # TABLE parses notes: "Table with_notes {\nNote: 'this is a note'\n}" => DBML::Table.new('with_notes', nil, ['this is a note'], [], [])
181
+
182
+ TABLE_NAME = seq_(/[^\{\}\s]+/.r, ('as'.r >> /\S+/.r).maybe {|v| unwrap(v) })
183
+ TABLE = block 'Table', TABLE_NAME, (INDEXES | NOTE | COLUMN) do |((name, aliaz), objects)|
184
+ Table.new name, aliaz,
185
+ objects.select {|o| o.is_a? String },
186
+ objects.select {|o| o.is_a? Column },
187
+ objects.select {|o| (o.is_a? Array) && (o.all? {|e| e.is_a? Index })}.flatten
188
+ end
189
+
190
+ # TableGroup
191
+ # ==========
192
+ #
193
+ # TableGroup allows users to group the related or associated tables together.
194
+ #
195
+ # TableGroup tablegroup_name { // tablegroup is case-insensitive.
196
+ # table1
197
+ # table2
198
+ # table3
199
+ # }
200
+ #
201
+ # TABLE_GROUP parses names: 'TableGroup group1 { }' => DBML::TableGroup.new('group1', [])
202
+ # TABLE_GROUP parses tables: "TableGroup group2 {\ntable1\ntable2\n}" => DBML::TableGroup.new('group2', ['table1', 'table2'])
203
+ TABLE_GROUP = block 'TableGroup', /\S+/.r, /[^\{\}\s]+/.r do |(name, tables)|
204
+ TableGroup.new name, tables
205
+ end
206
+
207
+ # Project Definition
208
+ # ==================
209
+ # You can give overall description of the project.
210
+ #
211
+ # Project project_name {
212
+ # database_type: 'PostgreSQL'
213
+ # Note: 'Description of the project'
214
+ # }
215
+ #
216
+ # PROJECT_DEFINITION parses names: 'Project my_proj { }' => DBML::ProjectDef.new('my_proj', [], {})
217
+ # PROJECT_DEFINITION parses notes: "Project my_porg { Note: 'porgs are cool!' }" => DBML::ProjectDef.new('my_porg', ['porgs are cool!'], {})
218
+ # PROJECT_DEFINITION parses settings: "Project my_cool {\ndatabase_type: 'PostgreSQL'\n}" => DBML::ProjectDef.new('my_cool', [], {'database_type' => 'PostgreSQL'})
219
+ PROJECT_DEFINITION = block 'Project', /\S+/.r, (NOTE | SETTING).star do |(name, objects)|
220
+ ProjectDef.new name,
221
+ objects.select {|o| o.is_a? String },
222
+ objects.select {|o| o.is_a? Hash }.reduce({}, &:update)
223
+ end
224
+
225
+ # PROJECT can be empty: "" => DBML::Project.new(nil, [], {}, [], [], [])
226
+ # PROJECT includes definition info: "Project p { Note: 'hello' }" => DBML::Project.new('p', ['hello'], {}, [], [], [])
227
+ # PROJECT includes tables: "Table t { }" => DBML::Project.new(nil, [], {}, [DBML::Table.new('t', nil, [], [], [])], [], [])
228
+ # PROJECT includes enums: "enum E { }" => DBML::Project.new(nil, [], {}, [], [DBML::Enum.new('E', [])], [])
229
+ # PROJECT includes table groups: "TableGroup TG { }" => DBML::Project.new(nil, [], {}, [], [], [DBML::TableGroup.new('TG', [])])
230
+ PROJECT = space_surrounded(PROJECT_DEFINITION | TABLE | TABLE_GROUP | ENUM).star do |objects|
231
+ definition = objects.find {|o| o.is_a? ProjectDef }
232
+ Project.new definition.nil? ? nil : definition.name,
233
+ definition.nil? ? [] : definition.notes,
234
+ definition.nil? ? {} : definition.settings,
235
+ objects.select {|o| o.is_a? Table },
236
+ objects.select {|o| o.is_a? Enum },
237
+ objects.select {|o| o.is_a? TableGroup }
238
+ end
239
+
240
+ def self.parse str
241
+ PROJECT.eof.parse! str.gsub(/\/{2}.*$/, '')
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,3 @@
1
+ module DBML
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dbml
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Worthington
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-09-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rsec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.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.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: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ description:
70
+ email:
71
+ - simon@simonwo.net
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".github/workflows/test.yml"
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - dbml.gemspec
83
+ - lib/dbml.rb
84
+ - lib/dbml/version.rb
85
+ homepage: https://github.com/simonwo/dbml-ruby
86
+ licenses:
87
+ - MIT
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubygems_version: 3.0.3
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Parser for Database Markup Language (DBML).
108
+ test_files: []