lkml 0.1.0 → 0.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 +4 -4
- data/.github/workflows/ci.yml +28 -0
- data/.gitignore +57 -0
- data/.rubocop.yml +25 -0
- data/.ruby-version +1 -0
- data/CONTRIBUTING.md +56 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +76 -0
- data/LICENSE.md +1 -2
- data/README.md +81 -7
- data/Rakefile +12 -0
- data/bin/lkml +6 -0
- data/lib/lkml/cli.rb +44 -0
- data/lib/lkml/keys.rb +64 -114
- data/lib/lkml/lexer.rb +45 -68
- data/lib/lkml/parser.rb +296 -191
- data/lib/lkml/simple.rb +244 -238
- data/lib/lkml/tokens.rb +44 -129
- data/lib/lkml/tree.rb +362 -236
- data/lib/lkml/utils.rb +32 -0
- data/lib/lkml/version.rb +1 -1
- data/lib/lkml/visitors.rb +69 -64
- data/lib/lkml.rb +49 -14
- data/lkml.gemspec +35 -0
- data/script/benchmark.rb +36 -0
- data/script/download_lookml.rb +70 -0
- metadata +88 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 947467843616af2d9823cae9e566dd7c7125f7d5eed824b00f23593d05c9874b
|
|
4
|
+
data.tar.gz: 17aca72ede33a42f05be5ce902db30a755842bb19eb51dddc6ef0cb7bbf19016
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10ac65ed0b899f40360bf307b92fb7521d41cb53eeeac34f5b2b9293b91cd07c950251a1288f21c76b0aa6a5d6cb19cbc1b69d9b78a54fd7713e72533124d733
|
|
7
|
+
data.tar.gz: 48de5ca911b5344afd31d31d6c469e7b333b269b572b88a0a740d27133f35f26f93523866a6f912e2728a88969cf1383b08fc0ac88d1e2a6b23e01b90f87db41
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
ruby: [ "3.3", "3.4", "4.0" ]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- uses: ruby/setup-ruby@v1
|
|
18
|
+
with:
|
|
19
|
+
ruby-version: ${{ matrix.ruby }}
|
|
20
|
+
bundler-cache: true
|
|
21
|
+
|
|
22
|
+
- name: Lint with RuboCop
|
|
23
|
+
run: bundle exec rubocop
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: bundle exec rake test
|
|
27
|
+
env:
|
|
28
|
+
LKML_RUN_GITHUB_TESTS: 1
|
data/.gitignore
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
.rspec_status
|
|
13
|
+
|
|
14
|
+
# Used by dotenv library to load environment variables.
|
|
15
|
+
.env
|
|
16
|
+
|
|
17
|
+
# Ignore Byebug command history file.
|
|
18
|
+
.byebug_history
|
|
19
|
+
|
|
20
|
+
## Specific to RubyMotion:
|
|
21
|
+
.dat*
|
|
22
|
+
.repl_history
|
|
23
|
+
build/
|
|
24
|
+
*.bridgesupport
|
|
25
|
+
build-iPhoneOS/
|
|
26
|
+
build-iPhoneSimulator/
|
|
27
|
+
|
|
28
|
+
## Specific to RubyMotion (use of CocoaPods):
|
|
29
|
+
#
|
|
30
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
|
31
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
|
32
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
33
|
+
#
|
|
34
|
+
# vendor/Pods/
|
|
35
|
+
|
|
36
|
+
## Documentation cache and generated files:
|
|
37
|
+
/.yardoc/
|
|
38
|
+
/_yardoc/
|
|
39
|
+
/doc/
|
|
40
|
+
/rdoc/
|
|
41
|
+
/docs/api/
|
|
42
|
+
|
|
43
|
+
## Environment normalization:
|
|
44
|
+
/.bundle/
|
|
45
|
+
/vendor/bundle
|
|
46
|
+
/lib/bundler/man/
|
|
47
|
+
|
|
48
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
49
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
50
|
+
Gemfile.lock
|
|
51
|
+
gemfiles/*.lock
|
|
52
|
+
# .ruby-version
|
|
53
|
+
# .ruby-gemset
|
|
54
|
+
|
|
55
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
56
|
+
.rvmrc
|
|
57
|
+
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
NewCops: enable
|
|
3
|
+
TargetRubyVersion: 3.3
|
|
4
|
+
SuggestExtensions: false
|
|
5
|
+
|
|
6
|
+
# Library code does not use RDoc-style class/module comments.
|
|
7
|
+
Style/Documentation:
|
|
8
|
+
Enabled: false
|
|
9
|
+
|
|
10
|
+
# Annotated format tokens add noise for debug logging and printf-style benchmarks.
|
|
11
|
+
Style/FormatStringToken:
|
|
12
|
+
Enabled: false
|
|
13
|
+
|
|
14
|
+
# Dev dependencies are declared in the gemspec for this gem.
|
|
15
|
+
Gemspec/DevelopmentDependencies:
|
|
16
|
+
Enabled: false
|
|
17
|
+
|
|
18
|
+
Style/StringLiterals:
|
|
19
|
+
EnforcedStyle: double_quotes
|
|
20
|
+
|
|
21
|
+
Layout/LineLength:
|
|
22
|
+
Max: 120
|
|
23
|
+
|
|
24
|
+
Metrics:
|
|
25
|
+
Enabled: false
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.3.6
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Contributing to lkml
|
|
2
|
+
|
|
3
|
+
## Local setup
|
|
4
|
+
|
|
5
|
+
- Fork the repository and clone your fork
|
|
6
|
+
- Create a branch from the default branch (e.g. `feature/your-change`)
|
|
7
|
+
- Install dependencies:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bundle install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Tests
|
|
14
|
+
|
|
15
|
+
Run the full suite:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bundle exec rake test
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Add or update tests under `test/` using Minitest (`test/test_*.rb`). Keep fixtures in `test/resources/` as needed.
|
|
22
|
+
|
|
23
|
+
### GitHub sample acceptance tests
|
|
24
|
+
|
|
25
|
+
A large set of LookML files lives under `test/resources/github/`. Tests in `test/test_github.rb` are **skipped by default**. Enable them with:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
LKML_RUN_GITHUB_TESTS=1 bundle exec ruby -Itest test/test_github.rb
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Downloading fresh samples from GitHub
|
|
32
|
+
|
|
33
|
+
`script/download_lookml.rb` queries the GitHub API. Set:
|
|
34
|
+
|
|
35
|
+
- `GITHUB_USERNAME`
|
|
36
|
+
- `GITHUB_PERSONAL_ACCESS_TOKEN`
|
|
37
|
+
|
|
38
|
+
Then:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ruby script/download_lookml.rb
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Files are written to `test/resources/github/`.
|
|
45
|
+
|
|
46
|
+
## Style
|
|
47
|
+
|
|
48
|
+
RuboCop is configured for this repo:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
bundle exec rubocop
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Pull requests
|
|
55
|
+
|
|
56
|
+
Open a PR against the main repository’s default branch. Reference related issues; use closing keywords (e.g. `Closes #19`) when appropriate.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
lkml (1.2.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
ast (2.4.3)
|
|
10
|
+
json (2.19.4)
|
|
11
|
+
language_server-protocol (3.17.0.5)
|
|
12
|
+
lint_roller (1.1.0)
|
|
13
|
+
logger (1.7.0)
|
|
14
|
+
minitest (5.27.0)
|
|
15
|
+
parallel (2.0.1)
|
|
16
|
+
parser (3.3.11.1)
|
|
17
|
+
ast (~> 2.4.1)
|
|
18
|
+
racc
|
|
19
|
+
prism (1.9.0)
|
|
20
|
+
racc (1.8.1)
|
|
21
|
+
rainbow (3.1.1)
|
|
22
|
+
rake (13.4.2)
|
|
23
|
+
regexp_parser (2.12.0)
|
|
24
|
+
rubocop (1.86.1)
|
|
25
|
+
json (~> 2.3)
|
|
26
|
+
language_server-protocol (~> 3.17.0.2)
|
|
27
|
+
lint_roller (~> 1.1.0)
|
|
28
|
+
parallel (>= 1.10)
|
|
29
|
+
parser (>= 3.3.0.2)
|
|
30
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
31
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
32
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
33
|
+
ruby-progressbar (~> 1.7)
|
|
34
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
35
|
+
rubocop-ast (1.49.1)
|
|
36
|
+
parser (>= 3.3.7.2)
|
|
37
|
+
prism (~> 1.7)
|
|
38
|
+
ruby-progressbar (1.13.0)
|
|
39
|
+
unicode-display_width (3.2.0)
|
|
40
|
+
unicode-emoji (~> 4.1)
|
|
41
|
+
unicode-emoji (4.2.0)
|
|
42
|
+
|
|
43
|
+
PLATFORMS
|
|
44
|
+
arm64-darwin-25
|
|
45
|
+
ruby
|
|
46
|
+
|
|
47
|
+
DEPENDENCIES
|
|
48
|
+
lkml!
|
|
49
|
+
logger
|
|
50
|
+
minitest (~> 5.25)
|
|
51
|
+
rake (~> 13.2)
|
|
52
|
+
rubocop (~> 1.69)
|
|
53
|
+
|
|
54
|
+
CHECKSUMS
|
|
55
|
+
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
56
|
+
json (2.19.4) sha256=670a7d333fb3b18ca5b29cb255eb7bef099e40d88c02c80bd42a3f30fe5239ac
|
|
57
|
+
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
58
|
+
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
59
|
+
lkml (1.2.0)
|
|
60
|
+
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
61
|
+
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
|
62
|
+
parallel (2.0.1) sha256=337782d3e39f4121e67563bf91dd8ece67f48923d90698614773a0ec9a5b2c7d
|
|
63
|
+
parser (3.3.11.1) sha256=d17ace7aabe3e72c3cc94043714be27cc6f852f104d81aa284c2281aecc65d54
|
|
64
|
+
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
65
|
+
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
|
66
|
+
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
|
|
67
|
+
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
|
68
|
+
regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
|
|
69
|
+
rubocop (1.86.1) sha256=44415f3f01d01a21e01132248d2fd0867572475b566ca188a0a42133a08d4531
|
|
70
|
+
rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
|
|
71
|
+
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
72
|
+
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
73
|
+
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
74
|
+
|
|
75
|
+
BUNDLED WITH
|
|
76
|
+
4.0.7
|
data/LICENSE.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2019 Josh Temple
|
|
4
|
-
Copyright (c) 2025 Sylvain Utard
|
|
3
|
+
Copyright (c) 2019 Josh Temple, 2026 Altertable
|
|
5
4
|
|
|
6
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
6
|
|
data/README.md
CHANGED
|
@@ -1,11 +1,85 @@
|
|
|
1
|
-
#
|
|
1
|
+
# lkml
|
|
2
2
|
|
|
3
|
-
A LookML parser and serializer implemented in pure Ruby.
|
|
3
|
+
A fast LookML parser and serializer implemented in **pure Ruby** (stdlib only).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`Lkml.load` parses LookML text into Ruby hashes (with string keys, suitable for JSON). `Lkml.dump` / `Lkml.generate` serialize hashes back to LookML.
|
|
6
6
|
|
|
7
|
-
Why
|
|
7
|
+
Why use **lkml**?
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
9
|
+
- Exercised on a large corpus of real-world LookML (including bundled GitHub samples)
|
|
10
|
+
- Parses typical view/model files in a few milliseconds (CPU time, excluding I/O)
|
|
11
|
+
- No runtime gem dependencies
|
|
12
|
+
- Full Minitest suite including lexer, parser, round-trip, and CLI checks
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
gem install lkml
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or add to your `Gemfile`:
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
gem "lkml"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Requires Ruby **3.3+**.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
require "lkml"
|
|
32
|
+
|
|
33
|
+
hash = Lkml.load('view: orders { sql_table_name: public.orders ;; }')
|
|
34
|
+
# => {"views"=>[{"name"=>"orders", "sql_table_name"=>"public.orders"}]}
|
|
35
|
+
|
|
36
|
+
lookml = Lkml.dump(hash)
|
|
37
|
+
# or
|
|
38
|
+
lookml = Lkml.generate(hash)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Parse to the concrete syntax tree instead of a hash:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
tree = Lkml.parse("view: x { dimension: id { type: number sql: ${TABLE}.id ;; } }")
|
|
45
|
+
tree.to_s # round-trip string
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### CLI
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
lkml path/to/file.view.lkml
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Pretty-prints JSON.
|
|
55
|
+
|
|
56
|
+
Options:
|
|
57
|
+
|
|
58
|
+
- `-v` / `--verbose` — debug logging on stderr
|
|
59
|
+
|
|
60
|
+
## Development
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
bundle install
|
|
64
|
+
bundle exec rake test
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Optional acceptance run over bundled GitHub samples (slow):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
LKML_RUN_GITHUB_TESTS=1 bundle exec ruby -Itest test/test_github.rb
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Benchmark (CPU time over `test/resources/github/*.lkml`):
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
ruby script/benchmark.rb
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Contributing
|
|
80
|
+
|
|
81
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT — see [LICENSE.md](LICENSE.md).
|
data/Rakefile
ADDED
data/bin/lkml
ADDED
data/lib/lkml/cli.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "logger"
|
|
5
|
+
require "optparse"
|
|
6
|
+
|
|
7
|
+
require_relative "../lkml"
|
|
8
|
+
|
|
9
|
+
module Lkml
|
|
10
|
+
module CLI
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def parse_args(argv)
|
|
14
|
+
options = { log_level: Logger::WARN }
|
|
15
|
+
parser = OptionParser.new do |opts|
|
|
16
|
+
opts.banner = "usage: lkml [-v|--verbose] FILE"
|
|
17
|
+
|
|
18
|
+
opts.on("-v", "--verbose", "Increase logging verbosity to debug") do
|
|
19
|
+
options[:log_level] = Logger::DEBUG
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
parser.parse!(argv)
|
|
23
|
+
|
|
24
|
+
raise OptionParser::MissingArgument, "FILE is required" if argv.empty?
|
|
25
|
+
|
|
26
|
+
options[:file_path] = argv[0]
|
|
27
|
+
options
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def run(argv = ARGV)
|
|
31
|
+
logger = Logger.new($stderr)
|
|
32
|
+
logger.level = Logger::WARN
|
|
33
|
+
|
|
34
|
+
opts = parse_args(argv.dup)
|
|
35
|
+
|
|
36
|
+
logger.level = opts[:log_level]
|
|
37
|
+
|
|
38
|
+
File.open(opts[:file_path], "r:UTF-8") do |file|
|
|
39
|
+
result = Lkml.load(file)
|
|
40
|
+
puts JSON.pretty_generate(result)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/lkml/keys.rb
CHANGED
|
@@ -1,125 +1,75 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# These are repeatable keys in LookML that the parser should collapse into a single
|
|
6
|
-
# Ruby hash key. For example, LookML can have multiple dimensions, so the parser
|
|
7
|
-
# will combine those dimensions into an array of hashes with a top-level key,
|
|
8
|
-
# `dimensions`.
|
|
3
|
+
require_relative "tokens"
|
|
9
4
|
|
|
10
5
|
module Lkml
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
explore
|
|
27
|
-
extends
|
|
28
|
-
filter
|
|
29
|
-
filters
|
|
30
|
-
form_param
|
|
31
|
-
include
|
|
32
|
-
join
|
|
33
|
-
link
|
|
34
|
-
map_layer
|
|
35
|
-
measure
|
|
36
|
-
named_value_format
|
|
37
|
-
option
|
|
38
|
-
override_constant
|
|
39
|
-
param
|
|
40
|
-
parameter
|
|
41
|
-
query
|
|
42
|
-
set
|
|
43
|
-
sql_step
|
|
44
|
-
test
|
|
45
|
-
user_attribute_param
|
|
46
|
-
view
|
|
47
|
-
when
|
|
48
|
-
].freeze
|
|
6
|
+
module Keys
|
|
7
|
+
PLURAL_KEYS = %w[
|
|
8
|
+
access_filter access_grant action aggregate_table allowed_value assert bind_filters
|
|
9
|
+
column constant datagroup remote_dependency local_dependency derived_column dimension
|
|
10
|
+
dimension_group explore extends filter filters form_param include join link map_layer
|
|
11
|
+
measure named_value_format option override_constant param parameter query set sql_step
|
|
12
|
+
test user_attribute_param view when
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
EXPR_BLOCK_KEYS = %w[
|
|
16
|
+
expression_custom_filter expression html sql_trigger_value sql_table_name
|
|
17
|
+
sql_distinct_key sql_start sql_always_having sql_always_where sql_trigger
|
|
18
|
+
sql_foreign_key sql_where sql_end sql_create sql_latitude sql_longitude sql_step
|
|
19
|
+
sql_on sql sql_preamble
|
|
20
|
+
].freeze
|
|
49
21
|
|
|
50
|
-
|
|
22
|
+
QUOTED_LITERAL_KEYS = %w[
|
|
23
|
+
label view_label group_label group_item_label suggest_persist_for default_value
|
|
24
|
+
direction value_format name url icon_url form_url default tags value description
|
|
25
|
+
sortkeys indexes partition_keys connection include max_cache_age allowed_values
|
|
26
|
+
timezone persist_for cluster_keys distribution extents_json_url feature_key file
|
|
27
|
+
property_key property_label_key else interval_trigger
|
|
28
|
+
].freeze
|
|
51
29
|
|
|
52
|
-
|
|
53
|
-
expression_custom_filter
|
|
54
|
-
expression
|
|
55
|
-
html
|
|
56
|
-
sql_trigger_value
|
|
57
|
-
sql_table_name
|
|
58
|
-
sql_distinct_key
|
|
59
|
-
sql_start
|
|
60
|
-
sql_always_having
|
|
61
|
-
sql_always_where
|
|
62
|
-
sql_trigger
|
|
63
|
-
sql_foreign_key
|
|
64
|
-
sql_where
|
|
65
|
-
sql_end
|
|
66
|
-
sql_create
|
|
67
|
-
sql_latitude
|
|
68
|
-
sql_longitude
|
|
69
|
-
sql_step
|
|
70
|
-
sql_on
|
|
71
|
-
sql
|
|
72
|
-
sql_preamble
|
|
73
|
-
].freeze
|
|
30
|
+
KEYS_WITH_NAME_FIELDS = %w[user_attribute_param param form_param option].freeze
|
|
74
31
|
|
|
75
|
-
|
|
76
|
-
|
|
32
|
+
CHARACTER_TO_TOKEN = {
|
|
33
|
+
"\0" => Tokens::StreamEndToken,
|
|
34
|
+
"{" => Tokens::BlockStartToken,
|
|
35
|
+
"}" => Tokens::BlockEndToken,
|
|
36
|
+
"[" => Tokens::ListStartToken,
|
|
37
|
+
"]" => Tokens::ListEndToken,
|
|
38
|
+
"," => Tokens::CommaToken,
|
|
39
|
+
":" => Tokens::ValueToken,
|
|
40
|
+
";" => Tokens::ExpressionBlockEndToken
|
|
41
|
+
}.freeze
|
|
77
42
|
|
|
78
|
-
|
|
79
|
-
label
|
|
80
|
-
view_label
|
|
81
|
-
group_label
|
|
82
|
-
group_item_label
|
|
83
|
-
suggest_persist_for
|
|
84
|
-
default_value
|
|
85
|
-
direction
|
|
86
|
-
value_format
|
|
87
|
-
name
|
|
88
|
-
url
|
|
89
|
-
icon_url
|
|
90
|
-
form_url
|
|
91
|
-
default
|
|
92
|
-
tags
|
|
93
|
-
value
|
|
94
|
-
description
|
|
95
|
-
sortkeys
|
|
96
|
-
indexes
|
|
97
|
-
partition_keys
|
|
98
|
-
connection
|
|
99
|
-
include
|
|
100
|
-
max_cache_age
|
|
101
|
-
allowed_values
|
|
102
|
-
timezone
|
|
103
|
-
persist_for
|
|
104
|
-
cluster_keys
|
|
105
|
-
distribution
|
|
106
|
-
extents_json_url
|
|
107
|
-
feature_key
|
|
108
|
-
file
|
|
109
|
-
property_key
|
|
110
|
-
property_label_key
|
|
111
|
-
else
|
|
112
|
-
interval_trigger
|
|
113
|
-
].freeze
|
|
43
|
+
module_function
|
|
114
44
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
45
|
+
def pluralize(key)
|
|
46
|
+
case key
|
|
47
|
+
when "filters", "bind_filters", "extends"
|
|
48
|
+
"#{key}__all"
|
|
49
|
+
when "query"
|
|
50
|
+
"queries"
|
|
51
|
+
when "remote_dependency"
|
|
52
|
+
"remote_dependencies"
|
|
53
|
+
when "local_dependency"
|
|
54
|
+
"local_dependencies"
|
|
55
|
+
else
|
|
56
|
+
"#{key}s"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
118
59
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
60
|
+
def singularize(key)
|
|
61
|
+
case key
|
|
62
|
+
when "queries"
|
|
63
|
+
"query"
|
|
64
|
+
when "remote_dependencies"
|
|
65
|
+
"remote_dependency"
|
|
66
|
+
when "local_dependencies"
|
|
67
|
+
"local_dependency"
|
|
68
|
+
when /__all\z/
|
|
69
|
+
key[0..-6]
|
|
70
|
+
else
|
|
71
|
+
key.end_with?("s") ? key.sub(/s+\z/, "") : key
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
125
75
|
end
|