cure 0.1.2 → 0.4.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/.rubocop.yml +13 -3
- data/.tool-versions +1 -0
- data/Dockerfile +1 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +25 -6
- data/README.md +61 -93
- data/docs/README.md +33 -0
- data/docs/about.md +219 -0
- data/docs/builder/add.md +52 -0
- data/docs/builder/black_white_list.md +83 -0
- data/docs/builder/copy.md +48 -0
- data/docs/builder/explode.md +70 -0
- data/docs/builder/main.md +43 -0
- data/docs/builder/remove.md +46 -0
- data/docs/examples/examples.md +164 -0
- data/docs/export/main.md +37 -0
- data/docs/extract/main.md +89 -0
- data/docs/metadata/main.md +29 -0
- data/docs/query/main.md +45 -0
- data/docs/sources/main.md +36 -0
- data/docs/transform/main.md +53 -0
- data/docs/validate/main.md +42 -0
- data/exe/cure +12 -41
- data/exe/cure.old +59 -0
- data/lib/cure/builder/base_builder.rb +151 -0
- data/lib/cure/builder/candidate.rb +56 -0
- data/lib/cure/cli/command.rb +105 -0
- data/lib/cure/cli/generate_command.rb +54 -0
- data/lib/cure/cli/new_command.rb +52 -0
- data/lib/cure/cli/run_command.rb +19 -0
- data/lib/cure/cli/templates/README.md.erb +1 -0
- data/lib/cure/cli/templates/gemfile.erb +5 -0
- data/lib/cure/cli/templates/gitignore.erb +181 -0
- data/lib/cure/cli/templates/new_template.rb.erb +31 -0
- data/lib/cure/cli/templates/tool-versions.erb +1 -0
- data/lib/cure/config.rb +142 -18
- data/lib/cure/coordinator.rb +61 -25
- data/lib/cure/database.rb +191 -0
- data/lib/cure/dsl/builder.rb +26 -0
- data/lib/cure/dsl/exporters.rb +45 -0
- data/lib/cure/dsl/extraction.rb +60 -0
- data/lib/cure/dsl/metadata.rb +33 -0
- data/lib/cure/dsl/queries.rb +36 -0
- data/lib/cure/dsl/source_files.rb +36 -0
- data/lib/cure/dsl/template.rb +131 -0
- data/lib/cure/dsl/transformations.rb +95 -0
- data/lib/cure/dsl/validator.rb +22 -0
- data/lib/cure/export/base_processor.rb +194 -0
- data/lib/cure/export/manager.rb +24 -0
- data/lib/cure/extract/base_processor.rb +47 -0
- data/lib/cure/extract/csv_lookup.rb +14 -3
- data/lib/cure/extract/extractor.rb +41 -84
- data/lib/cure/extract/filter.rb +118 -0
- data/lib/cure/extract/named_range.rb +94 -0
- data/lib/cure/extract/named_range_processor.rb +128 -0
- data/lib/cure/extract/variable.rb +25 -0
- data/lib/cure/extract/variable_processor.rb +57 -0
- data/lib/cure/generator/base_generator.rb +14 -4
- data/lib/cure/generator/case_generator.rb +10 -3
- data/lib/cure/generator/character_generator.rb +9 -3
- data/lib/cure/generator/erb_generator.rb +21 -0
- data/lib/cure/generator/eval_generator.rb +34 -0
- data/lib/cure/generator/faker_generator.rb +7 -1
- data/lib/cure/generator/guid_generator.rb +7 -2
- data/lib/cure/generator/hex_generator.rb +6 -1
- data/lib/cure/generator/imports.rb +4 -0
- data/lib/cure/generator/number_generator.rb +6 -1
- data/lib/cure/generator/placeholder_generator.rb +7 -1
- data/lib/cure/generator/proc_generator.rb +21 -0
- data/lib/cure/generator/redact_generator.rb +9 -3
- data/lib/cure/generator/static_generator.rb +21 -0
- data/lib/cure/generator/variable_generator.rb +11 -5
- data/lib/cure/helpers/file_helpers.rb +12 -2
- data/lib/cure/helpers/object_helpers.rb +5 -17
- data/lib/cure/helpers/perf_helpers.rb +30 -0
- data/lib/cure/helpers/string.rb +54 -0
- data/lib/cure/launcher.rb +125 -0
- data/lib/cure/log.rb +7 -0
- data/lib/cure/planner.rb +136 -0
- data/lib/cure/strategy/append_strategy.rb +4 -0
- data/lib/cure/strategy/base_strategy.rb +19 -44
- data/lib/cure/strategy/contain_strategy.rb +51 -0
- data/lib/cure/strategy/end_with_strategy.rb +7 -1
- data/lib/cure/strategy/full_strategy.rb +4 -0
- data/lib/cure/strategy/history/history_cache.rb +82 -0
- data/lib/cure/strategy/imports.rb +2 -0
- data/lib/cure/strategy/match_strategy.rb +7 -2
- data/lib/cure/strategy/prepend_strategy.rb +28 -0
- data/lib/cure/strategy/regex_strategy.rb +7 -1
- data/lib/cure/strategy/split_strategy.rb +8 -3
- data/lib/cure/strategy/start_with_strategy.rb +7 -1
- data/lib/cure/transformation/candidate.rb +32 -35
- data/lib/cure/transformation/transform.rb +22 -56
- data/lib/cure/validator/base_rule.rb +78 -0
- data/lib/cure/validator/candidate.rb +54 -0
- data/lib/cure/validator/manager.rb +21 -0
- data/lib/cure/validators.rb +3 -3
- data/lib/cure/version.rb +1 -1
- data/lib/cure.rb +19 -11
- data/templates/dsl_example.rb +48 -0
- data/templates/empty_template.rb +31 -0
- metadata +132 -21
- data/lib/cure/export/exporter.rb +0 -74
- data/lib/cure/extract/builder.rb +0 -27
- data/lib/cure/main.rb +0 -72
- data/lib/cure/template/dispatch.rb +0 -30
- data/lib/cure/template/extraction.rb +0 -38
- data/lib/cure/template/template.rb +0 -28
- data/lib/cure/template/transformations.rb +0 -26
- data/templates/aws_cur_template.json +0 -145
- data/templates/example_template.json +0 -54
@@ -0,0 +1,191 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sequel"
|
4
|
+
require "sqlite3"
|
5
|
+
require "singleton"
|
6
|
+
|
7
|
+
require "cure/config"
|
8
|
+
|
9
|
+
module Cure
|
10
|
+
module Database
|
11
|
+
def database_service
|
12
|
+
database = DatabaseSource.instance.database_service
|
13
|
+
return database if database
|
14
|
+
|
15
|
+
init_database
|
16
|
+
|
17
|
+
DatabaseSource.instance.database_service
|
18
|
+
end
|
19
|
+
|
20
|
+
def init_database
|
21
|
+
DatabaseSource.instance.init_database
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class DatabaseSource
|
26
|
+
include Singleton
|
27
|
+
|
28
|
+
attr_reader :database_service
|
29
|
+
|
30
|
+
def init_database
|
31
|
+
@database_service = DatabaseService.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class DatabaseService
|
36
|
+
include Cure::Configuration
|
37
|
+
|
38
|
+
# @return [Sequel::SQLite::Database]
|
39
|
+
attr_reader :database
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@database = init_database
|
43
|
+
setup_db
|
44
|
+
end
|
45
|
+
|
46
|
+
def setup_db
|
47
|
+
# Load this from config defined by user?
|
48
|
+
@database.execute <<-SQL
|
49
|
+
PRAGMA journal_mode = OFF;
|
50
|
+
PRAGMA synchronous = 0;
|
51
|
+
PRAGMA cache_size = 1000000;
|
52
|
+
PRAGMA locking_mode = EXCLUSIVE;
|
53
|
+
PRAGMA temp_store = MEMORY;
|
54
|
+
SQL
|
55
|
+
end
|
56
|
+
|
57
|
+
# App Service calls
|
58
|
+
def find_variable(property_name)
|
59
|
+
@database.from(:variables).where(name: property_name).get(:value)
|
60
|
+
end
|
61
|
+
|
62
|
+
def find_translation(source_value)
|
63
|
+
@database.from(:translations).where(source_value: source_value).get(:value)
|
64
|
+
end
|
65
|
+
|
66
|
+
def all_translations
|
67
|
+
@database.from(:translations).all
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param [Symbol,String] tbl_name
|
71
|
+
# @param [Array] columns
|
72
|
+
def create_table(tbl_name, columns, auto_increment: true)
|
73
|
+
tbl_name = tbl_name.to_sym if tbl_name.class != Symbol
|
74
|
+
|
75
|
+
@database.create_table tbl_name do
|
76
|
+
primary_key :_id, auto_increment: auto_increment
|
77
|
+
columns.each do |col_name|
|
78
|
+
column col_name.to_sym, String
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param [Symbol,String] tbl_name
|
84
|
+
def truncate_table(tbl_name)
|
85
|
+
@database[tbl_name.to_sym].truncate
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param [Symbol,String] tbl_name
|
89
|
+
def table_count(tbl_name)
|
90
|
+
@database[tbl_name.to_sym].count
|
91
|
+
end
|
92
|
+
|
93
|
+
def with_transaction(&block)
|
94
|
+
@database.transaction({}, &block)
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param [Symbol,String] tbl_name
|
98
|
+
# @return [TrueClass, FalseClass]
|
99
|
+
def table_exist?(tbl_name)
|
100
|
+
tbl_name = tbl_name.to_sym if tbl_name.class != Symbol
|
101
|
+
|
102
|
+
@database.table_exists?(tbl_name)
|
103
|
+
end
|
104
|
+
alias table_exists? table_exist?
|
105
|
+
|
106
|
+
# @param [Symbol,String] tbl_name
|
107
|
+
# @param [Array<String>] row
|
108
|
+
def insert_row(tbl_name, row)
|
109
|
+
@database[tbl_name.to_sym].insert(row)
|
110
|
+
end
|
111
|
+
|
112
|
+
# @param [Symbol,String] tbl_name
|
113
|
+
# @param [Array<String>] rows
|
114
|
+
def insert_batched_rows(tbl_name, rows)
|
115
|
+
@database[tbl_name.to_sym].import(@database[tbl_name.to_sym].columns, rows)
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_column(tbl_name, new_column, default: "")
|
119
|
+
tbl_name = tbl_name.to_sym if tbl_name.class != Symbol
|
120
|
+
new_column = new_column.to_sym if new_column.class != Symbol
|
121
|
+
|
122
|
+
@database.add_column(tbl_name, new_column, String, default: default)
|
123
|
+
end
|
124
|
+
|
125
|
+
def remove_column(tbl_name, remove_column)
|
126
|
+
tbl_name = tbl_name.to_sym if tbl_name.class != Symbol
|
127
|
+
remove_column = remove_column.to_sym if remove_column.class != Symbol
|
128
|
+
|
129
|
+
@database.drop_column tbl_name, remove_column
|
130
|
+
end
|
131
|
+
|
132
|
+
def list_columns(tbl_name)
|
133
|
+
@database[tbl_name.to_sym].columns
|
134
|
+
end
|
135
|
+
|
136
|
+
def rename_column(tbl_name, old_column, new_column)
|
137
|
+
tbl_name = tbl_name.to_sym if tbl_name.class != Symbol
|
138
|
+
old_column = old_column.to_sym if old_column.class != Symbol
|
139
|
+
new_column = new_column.to_sym if new_column.class != Symbol
|
140
|
+
|
141
|
+
@database.rename_column tbl_name, old_column, new_column
|
142
|
+
end
|
143
|
+
|
144
|
+
def copy_column(tbl_name, from_column, to_column)
|
145
|
+
tbl_name = tbl_name.to_sym if tbl_name.class != Symbol
|
146
|
+
from_column = from_column.to_sym if from_column.class != Symbol
|
147
|
+
to_column = to_column.to_sym if to_column.class != Symbol
|
148
|
+
|
149
|
+
add_column tbl_name, to_column
|
150
|
+
run("UPDATE #{tbl_name} SET #{to_column} = #{from_column}")
|
151
|
+
end
|
152
|
+
|
153
|
+
def run(query, opts={})
|
154
|
+
@database.run(query, opts)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Can we decouple query from named range? Probably more difficult
|
158
|
+
# than it seems. But would be nice to create two queries that doesn't
|
159
|
+
# require two tables (named ranges).
|
160
|
+
def with_paged_result(tbl_name, chunk_size: 100, &block)
|
161
|
+
raise "No block given" unless block
|
162
|
+
|
163
|
+
query = config.template.queries.find(tbl_name)
|
164
|
+
if query
|
165
|
+
@database[query.query].order(:_id).paged_each(rows_per_fetch: chunk_size, &block)
|
166
|
+
else
|
167
|
+
@database[tbl_name.to_sym].order(:_id).paged_each(rows_per_fetch: chunk_size, &block)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def list_tables
|
172
|
+
tbl_arr = @database.tables
|
173
|
+
tbl_arr.delete(:variables)
|
174
|
+
|
175
|
+
if tbl_arr.include?(:translations)
|
176
|
+
tbl_arr.delete(:translations)
|
177
|
+
tbl_arr.push(:translations)
|
178
|
+
end
|
179
|
+
|
180
|
+
tbl_arr
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def init_database
|
186
|
+
# Build from config
|
187
|
+
# This must clean the database if its not in memory
|
188
|
+
Sequel.connect("sqlite:/")
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/builder/base_builder"
|
4
|
+
require "cure/builder/candidate"
|
5
|
+
|
6
|
+
module Cure
|
7
|
+
module Dsl
|
8
|
+
class Builder
|
9
|
+
|
10
|
+
attr_reader :candidates
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@candidates = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [String,nil] column
|
17
|
+
# @param [String] named_range
|
18
|
+
# @param [Proc] block
|
19
|
+
def candidate(column: nil, named_range: "_default", &block)
|
20
|
+
candidate = Cure::Builder::Candidate.new(column, named_range)
|
21
|
+
@candidates << candidate
|
22
|
+
candidate.instance_exec(&block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/export/base_processor"
|
4
|
+
require "cure/extract/named_range"
|
5
|
+
|
6
|
+
module Cure
|
7
|
+
module Dsl
|
8
|
+
class Exporters
|
9
|
+
|
10
|
+
attr_reader :processors
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@processors = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [String,Symbol] _method_name
|
17
|
+
# @param [TrueClass,FalseClass] _include_private
|
18
|
+
# @return [TrueClass]
|
19
|
+
def respond_to_missing?(_method_name, _include_private=false)
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param [Symbol] method_name
|
24
|
+
# @return [Cure::Export::BaseBuilder]
|
25
|
+
def method_missing(method_name, **args)
|
26
|
+
klass_name = "Cure::Export::#{method_name.to_s.split("_").map(&:capitalize).join("")}Processor"
|
27
|
+
raise "#{method_name} is not valid" unless class_exists?(klass_name)
|
28
|
+
|
29
|
+
@processors << Kernel.const_get(klass_name).new(
|
30
|
+
args[:named_range] || "_default",
|
31
|
+
args || {}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [String] klass_name
|
36
|
+
# @return [TrueClass,FalseClass]
|
37
|
+
def class_exists?(klass_name)
|
38
|
+
klass = Module.const_get(klass_name)
|
39
|
+
klass.is_a?(Class)
|
40
|
+
rescue NameError
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/extract/named_range"
|
4
|
+
require "cure/extract/variable"
|
5
|
+
|
6
|
+
module Cure
|
7
|
+
module Dsl
|
8
|
+
class Extraction
|
9
|
+
|
10
|
+
attr_reader :named_ranges, :variables, :sample_rows
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@named_ranges = []
|
14
|
+
@variables = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def named_range(name:, at: -1, headers: nil, ref_name: nil, placeholder: false, &block)
|
18
|
+
named_range = Extract::NamedRange.new(name, at,
|
19
|
+
headers: headers,
|
20
|
+
ref_name: ref_name,
|
21
|
+
placeholder: placeholder
|
22
|
+
)
|
23
|
+
|
24
|
+
if block_given?
|
25
|
+
named_range.filter.instance_eval(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
@named_ranges << named_range
|
29
|
+
end
|
30
|
+
|
31
|
+
def variable(name:, at:, ref_name: nil)
|
32
|
+
@variables << Cure::Extract::Variable.new(name, at, ref_name: ref_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def sample(rows: nil)
|
36
|
+
@sample_rows = rows
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param [String] ref_name
|
40
|
+
# @return [Array]
|
41
|
+
def required_named_ranges(ref_name: "_default")
|
42
|
+
# This now needs to take support multiple files. We don't want named ranges
|
43
|
+
# for different files
|
44
|
+
return @named_ranges if ref_name == "default"
|
45
|
+
|
46
|
+
@named_ranges.select { |nr| nr.ref_name == ref_name && nr.placeholder == false }
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param [String] ref_name
|
50
|
+
# @return [Array]
|
51
|
+
def required_variables(ref_name: "_default")
|
52
|
+
# This now needs to take support multiple files. We don't want named ranges
|
53
|
+
# for different files
|
54
|
+
return @variables if ref_name == "_default"
|
55
|
+
|
56
|
+
@variables.select { |v| v.ref_name == ref_name }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cure
|
4
|
+
module Dsl
|
5
|
+
class Metadata
|
6
|
+
|
7
|
+
attr_reader :_name, :_version, :_comments, :_additional
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@_name = nil
|
11
|
+
@_version = nil
|
12
|
+
@_comments = nil
|
13
|
+
@_additional = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def name(name)
|
17
|
+
@_name = name
|
18
|
+
end
|
19
|
+
|
20
|
+
def version(version)
|
21
|
+
@_version = version
|
22
|
+
end
|
23
|
+
|
24
|
+
def comments(comments)
|
25
|
+
@_comments = comments
|
26
|
+
end
|
27
|
+
|
28
|
+
def additional(data: {})
|
29
|
+
@_additional = data
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/builder/base_builder"
|
4
|
+
require "cure/builder/candidate"
|
5
|
+
|
6
|
+
module Cure
|
7
|
+
module Dsl
|
8
|
+
class Queries
|
9
|
+
|
10
|
+
attr_reader :candidates
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@candidates = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def with(query:, named_range: "_default")
|
17
|
+
candidate = Query.new(named_range.to_sym, query)
|
18
|
+
@candidates << candidate
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(named_range)
|
22
|
+
@candidates.find { |candidate| candidate.named_range.to_sym == named_range.to_sym }
|
23
|
+
end
|
24
|
+
|
25
|
+
class Query
|
26
|
+
attr_reader :named_range, :query
|
27
|
+
|
28
|
+
def initialize(named_range, query)
|
29
|
+
@named_range = named_range
|
30
|
+
@query = query
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/builder/base_builder"
|
4
|
+
require "cure/builder/candidate"
|
5
|
+
|
6
|
+
module Cure
|
7
|
+
module Dsl
|
8
|
+
class SourceFiles
|
9
|
+
|
10
|
+
attr_reader :candidates
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@candidates = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def csv(type, value, ref_name: nil)
|
17
|
+
candidate = SourceFile.new(type, value, ref_name)
|
18
|
+
@candidates << candidate
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_candidates?
|
22
|
+
@candidates.length.positive?
|
23
|
+
end
|
24
|
+
|
25
|
+
class SourceFile
|
26
|
+
attr_accessor :type, :value, :ref_name
|
27
|
+
|
28
|
+
def initialize(type, value, ref_name)
|
29
|
+
@type = type
|
30
|
+
@value = value
|
31
|
+
@ref_name = ref_name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/log"
|
4
|
+
require "cure/dsl/extraction"
|
5
|
+
require "cure/dsl/builder"
|
6
|
+
require "cure/dsl/validator"
|
7
|
+
require "cure/dsl/transformations"
|
8
|
+
require "cure/dsl/exporters"
|
9
|
+
require "cure/dsl/queries"
|
10
|
+
require "cure/dsl/metadata"
|
11
|
+
require "cure/dsl/source_files"
|
12
|
+
|
13
|
+
module Cure
|
14
|
+
module Dsl
|
15
|
+
class DslHandler
|
16
|
+
include Log
|
17
|
+
def self.init(&block)
|
18
|
+
DslHandler.new(block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.init_from_content(dsl_source, identifier, line_number=1)
|
22
|
+
proc = Binding.get.eval(<<-SOURCE, identifier, line_number)
|
23
|
+
Proc.new do
|
24
|
+
#{dsl_source}
|
25
|
+
end
|
26
|
+
SOURCE
|
27
|
+
|
28
|
+
DslHandler.new(proc)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(proc)
|
32
|
+
@proc = proc
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate(instance_variables={})
|
36
|
+
dsl = Template.new
|
37
|
+
instance_variables.each do |name, value|
|
38
|
+
dsl.instance_variable_set("@#{name}", value)
|
39
|
+
end
|
40
|
+
|
41
|
+
dsl.instance_eval(&@proc)
|
42
|
+
dsl
|
43
|
+
|
44
|
+
rescue StandardError => e
|
45
|
+
log_error "Error parsing DSL: #{e.message}"
|
46
|
+
|
47
|
+
# Raise specific error in future.
|
48
|
+
raise e
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module Binding
|
53
|
+
# @return [Object] Empty object for binding purposes
|
54
|
+
def self.get
|
55
|
+
binding
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Template
|
60
|
+
|
61
|
+
# @return [Dsl::Extraction]
|
62
|
+
attr_reader :extraction
|
63
|
+
|
64
|
+
# @return [Dsl::Builder]
|
65
|
+
attr_reader :builder
|
66
|
+
|
67
|
+
# @return [Dsl::Validator]
|
68
|
+
attr_reader :validator
|
69
|
+
|
70
|
+
# @return [Dsl::Transformations]
|
71
|
+
attr_reader :transformations
|
72
|
+
|
73
|
+
# @return [Dsl::Exporters]
|
74
|
+
attr_reader :exporters
|
75
|
+
|
76
|
+
# @return [Dsl::Queries]
|
77
|
+
attr_reader :queries
|
78
|
+
|
79
|
+
# @return [Dsl::Metadata]
|
80
|
+
attr_reader :meta_data
|
81
|
+
|
82
|
+
# @return [Dsl::SourceFiles]
|
83
|
+
attr_reader :source_files
|
84
|
+
|
85
|
+
def initialize
|
86
|
+
@source_files = SourceFiles.new
|
87
|
+
@extraction = Extraction.new
|
88
|
+
@builder = Builder.new
|
89
|
+
@validator = Validator.new
|
90
|
+
@transformations = Transformations.new
|
91
|
+
@exporters = Exporters.new
|
92
|
+
@queries = Queries.new
|
93
|
+
@meta_data = Metadata.new
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def sources(&block)
|
99
|
+
@source_files.instance_exec(&block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def extract(&block)
|
103
|
+
@extraction.instance_exec(&block)
|
104
|
+
end
|
105
|
+
|
106
|
+
def query(&block)
|
107
|
+
@queries.instance_exec(&block)
|
108
|
+
end
|
109
|
+
|
110
|
+
def build(&block)
|
111
|
+
@builder.instance_exec(&block)
|
112
|
+
end
|
113
|
+
|
114
|
+
def validate(&block)
|
115
|
+
@validator.instance_exec(&block)
|
116
|
+
end
|
117
|
+
|
118
|
+
def transform(&block)
|
119
|
+
@transformations.instance_exec(&block)
|
120
|
+
end
|
121
|
+
|
122
|
+
def metadata(&block)
|
123
|
+
@meta_data.instance_exec(&block)
|
124
|
+
end
|
125
|
+
|
126
|
+
def export(&block)
|
127
|
+
@exporters.instance_exec(&block)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/strategy/imports"
|
4
|
+
require "cure/generator/imports"
|
5
|
+
require "cure/transformation/candidate"
|
6
|
+
|
7
|
+
module Cure
|
8
|
+
module Dsl
|
9
|
+
class Transformations
|
10
|
+
|
11
|
+
attr_reader :candidates, :placeholders
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@candidates = []
|
15
|
+
@placeholders = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def candidate(column:, named_range: "_default", options: {}, &block)
|
19
|
+
candidate = Candidate.new(column, named_range: named_range)
|
20
|
+
candidate.instance_exec(&block)
|
21
|
+
|
22
|
+
@candidates << Transformation::Candidate
|
23
|
+
.new(candidate.column, named_range: candidate.named_range, options: options)
|
24
|
+
.with_translations(candidate.translations)
|
25
|
+
.with_no_match_translation(candidate.no_match_translation)
|
26
|
+
end
|
27
|
+
|
28
|
+
def place_holders(hash)
|
29
|
+
@placeholders = hash
|
30
|
+
end
|
31
|
+
|
32
|
+
class Candidate
|
33
|
+
|
34
|
+
attr_reader :column, :named_range, :ref, :translations, :no_match_translation
|
35
|
+
|
36
|
+
def initialize(column, named_range:, ref: "_default")
|
37
|
+
@column = column
|
38
|
+
@named_range = named_range
|
39
|
+
@ref = ref
|
40
|
+
|
41
|
+
@translations = []
|
42
|
+
@no_match_translation = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_translation(&block)
|
46
|
+
translation = Translation.new
|
47
|
+
translation.instance_exec(&block)
|
48
|
+
|
49
|
+
@translations << Transformation::Translation.new(
|
50
|
+
translation.strategy,
|
51
|
+
translation.generator
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def if_no_match(&block)
|
56
|
+
no_match_translation = Translation.new
|
57
|
+
no_match_translation.instance_exec(&block)
|
58
|
+
|
59
|
+
@no_match_translation = Transformation::Translation.new(
|
60
|
+
no_match_translation.strategy,
|
61
|
+
no_match_translation.generator
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Translation
|
67
|
+
|
68
|
+
attr_reader :strategy, :generator
|
69
|
+
|
70
|
+
def replace(name, **options)
|
71
|
+
klass_name = "Cure::Strategy::#{name.to_s.capitalize}Strategy"
|
72
|
+
raise "#{name} is not valid" unless class_exists?(klass_name)
|
73
|
+
|
74
|
+
@strategy = Kernel.const_get(klass_name).new(options)
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def with(name, **options)
|
79
|
+
klass_name = "Cure::Generator::#{name.to_s.capitalize}Generator"
|
80
|
+
raise "#{name} is not valid" unless class_exists?(klass_name)
|
81
|
+
|
82
|
+
@generator = Kernel.const_get(klass_name).new(options)
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
def class_exists?(klass_name)
|
87
|
+
klass = Module.const_get(klass_name)
|
88
|
+
klass.is_a?(Class)
|
89
|
+
rescue NameError
|
90
|
+
false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cure/validator/candidate"
|
4
|
+
|
5
|
+
module Cure
|
6
|
+
module Dsl
|
7
|
+
class Validator
|
8
|
+
|
9
|
+
attr_reader :candidates
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@candidates = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def candidate(column: nil, named_range: "_default", options: {}, &block)
|
16
|
+
candidate = Cure::Validator::Candidate.new(column, named_range, options)
|
17
|
+
@candidates << candidate
|
18
|
+
candidate.instance_exec(&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|