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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -3
  3. data/.tool-versions +1 -0
  4. data/Dockerfile +1 -1
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +25 -6
  7. data/README.md +61 -93
  8. data/docs/README.md +33 -0
  9. data/docs/about.md +219 -0
  10. data/docs/builder/add.md +52 -0
  11. data/docs/builder/black_white_list.md +83 -0
  12. data/docs/builder/copy.md +48 -0
  13. data/docs/builder/explode.md +70 -0
  14. data/docs/builder/main.md +43 -0
  15. data/docs/builder/remove.md +46 -0
  16. data/docs/examples/examples.md +164 -0
  17. data/docs/export/main.md +37 -0
  18. data/docs/extract/main.md +89 -0
  19. data/docs/metadata/main.md +29 -0
  20. data/docs/query/main.md +45 -0
  21. data/docs/sources/main.md +36 -0
  22. data/docs/transform/main.md +53 -0
  23. data/docs/validate/main.md +42 -0
  24. data/exe/cure +12 -41
  25. data/exe/cure.old +59 -0
  26. data/lib/cure/builder/base_builder.rb +151 -0
  27. data/lib/cure/builder/candidate.rb +56 -0
  28. data/lib/cure/cli/command.rb +105 -0
  29. data/lib/cure/cli/generate_command.rb +54 -0
  30. data/lib/cure/cli/new_command.rb +52 -0
  31. data/lib/cure/cli/run_command.rb +19 -0
  32. data/lib/cure/cli/templates/README.md.erb +1 -0
  33. data/lib/cure/cli/templates/gemfile.erb +5 -0
  34. data/lib/cure/cli/templates/gitignore.erb +181 -0
  35. data/lib/cure/cli/templates/new_template.rb.erb +31 -0
  36. data/lib/cure/cli/templates/tool-versions.erb +1 -0
  37. data/lib/cure/config.rb +142 -18
  38. data/lib/cure/coordinator.rb +61 -25
  39. data/lib/cure/database.rb +191 -0
  40. data/lib/cure/dsl/builder.rb +26 -0
  41. data/lib/cure/dsl/exporters.rb +45 -0
  42. data/lib/cure/dsl/extraction.rb +60 -0
  43. data/lib/cure/dsl/metadata.rb +33 -0
  44. data/lib/cure/dsl/queries.rb +36 -0
  45. data/lib/cure/dsl/source_files.rb +36 -0
  46. data/lib/cure/dsl/template.rb +131 -0
  47. data/lib/cure/dsl/transformations.rb +95 -0
  48. data/lib/cure/dsl/validator.rb +22 -0
  49. data/lib/cure/export/base_processor.rb +194 -0
  50. data/lib/cure/export/manager.rb +24 -0
  51. data/lib/cure/extract/base_processor.rb +47 -0
  52. data/lib/cure/extract/csv_lookup.rb +14 -3
  53. data/lib/cure/extract/extractor.rb +41 -84
  54. data/lib/cure/extract/filter.rb +118 -0
  55. data/lib/cure/extract/named_range.rb +94 -0
  56. data/lib/cure/extract/named_range_processor.rb +128 -0
  57. data/lib/cure/extract/variable.rb +25 -0
  58. data/lib/cure/extract/variable_processor.rb +57 -0
  59. data/lib/cure/generator/base_generator.rb +14 -4
  60. data/lib/cure/generator/case_generator.rb +10 -3
  61. data/lib/cure/generator/character_generator.rb +9 -3
  62. data/lib/cure/generator/erb_generator.rb +21 -0
  63. data/lib/cure/generator/eval_generator.rb +34 -0
  64. data/lib/cure/generator/faker_generator.rb +7 -1
  65. data/lib/cure/generator/guid_generator.rb +7 -2
  66. data/lib/cure/generator/hex_generator.rb +6 -1
  67. data/lib/cure/generator/imports.rb +4 -0
  68. data/lib/cure/generator/number_generator.rb +6 -1
  69. data/lib/cure/generator/placeholder_generator.rb +7 -1
  70. data/lib/cure/generator/proc_generator.rb +21 -0
  71. data/lib/cure/generator/redact_generator.rb +9 -3
  72. data/lib/cure/generator/static_generator.rb +21 -0
  73. data/lib/cure/generator/variable_generator.rb +11 -5
  74. data/lib/cure/helpers/file_helpers.rb +12 -2
  75. data/lib/cure/helpers/object_helpers.rb +5 -17
  76. data/lib/cure/helpers/perf_helpers.rb +30 -0
  77. data/lib/cure/helpers/string.rb +54 -0
  78. data/lib/cure/launcher.rb +125 -0
  79. data/lib/cure/log.rb +7 -0
  80. data/lib/cure/planner.rb +136 -0
  81. data/lib/cure/strategy/append_strategy.rb +4 -0
  82. data/lib/cure/strategy/base_strategy.rb +19 -44
  83. data/lib/cure/strategy/contain_strategy.rb +51 -0
  84. data/lib/cure/strategy/end_with_strategy.rb +7 -1
  85. data/lib/cure/strategy/full_strategy.rb +4 -0
  86. data/lib/cure/strategy/history/history_cache.rb +82 -0
  87. data/lib/cure/strategy/imports.rb +2 -0
  88. data/lib/cure/strategy/match_strategy.rb +7 -2
  89. data/lib/cure/strategy/prepend_strategy.rb +28 -0
  90. data/lib/cure/strategy/regex_strategy.rb +7 -1
  91. data/lib/cure/strategy/split_strategy.rb +8 -3
  92. data/lib/cure/strategy/start_with_strategy.rb +7 -1
  93. data/lib/cure/transformation/candidate.rb +32 -35
  94. data/lib/cure/transformation/transform.rb +22 -56
  95. data/lib/cure/validator/base_rule.rb +78 -0
  96. data/lib/cure/validator/candidate.rb +54 -0
  97. data/lib/cure/validator/manager.rb +21 -0
  98. data/lib/cure/validators.rb +3 -3
  99. data/lib/cure/version.rb +1 -1
  100. data/lib/cure.rb +19 -11
  101. data/templates/dsl_example.rb +48 -0
  102. data/templates/empty_template.rb +31 -0
  103. metadata +132 -21
  104. data/lib/cure/export/exporter.rb +0 -74
  105. data/lib/cure/extract/builder.rb +0 -27
  106. data/lib/cure/main.rb +0 -72
  107. data/lib/cure/template/dispatch.rb +0 -30
  108. data/lib/cure/template/extraction.rb +0 -38
  109. data/lib/cure/template/template.rb +0 -28
  110. data/lib/cure/template/transformations.rb +0 -26
  111. data/templates/aws_cur_template.json +0 -145
  112. data/templates/example_template.json +0 -54
@@ -0,0 +1,181 @@
1
+ # Created by https://www.toptal.com/developers/gitignore/api/rubymine,ruby
2
+ # Edit at https://www.toptal.com/developers/gitignore?templates=rubymine,ruby
3
+
4
+ .idea
5
+
6
+ /sandpit
7
+
8
+ /.bundle/
9
+ /.yardoc
10
+ /_yardoc/
11
+ /coverage/
12
+ /doc/
13
+ /pkg/
14
+ /spec/reports/
15
+ /tmp/
16
+
17
+ # rspec failure tracking
18
+ .rspec_status
19
+
20
+ ### Ruby ###
21
+ *.gem
22
+ *.rbc
23
+ /.config
24
+ /InstalledFiles
25
+ /spec/examples.txt
26
+ /test/tmp/
27
+ /test/version_tmp/
28
+
29
+ # Used by dotenv library to load environment variables.
30
+ # .env
31
+
32
+ # Ignore Byebug command history file.
33
+ .byebug_history
34
+
35
+ ## Specific to RubyMotion:
36
+ .dat*
37
+ .repl_history
38
+ build/
39
+ *.bridgesupport
40
+ build-iPhoneOS/
41
+ build-iPhoneSimulator/
42
+
43
+ ## Specific to RubyMotion (use of CocoaPods):
44
+ #
45
+ # We recommend against adding the Pods directory to your .gitignore. However
46
+ # you should judge for yourself, the pros and cons are mentioned at:
47
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48
+ # vendor/Pods/
49
+
50
+ ## Documentation cache and generated files:
51
+ /.yardoc/
52
+ /rdoc/
53
+
54
+ ## Environment normalization:
55
+ /vendor/bundle
56
+ /lib/bundler/man/
57
+
58
+ # for a library or gem, you might want to ignore these files since the code is
59
+ # intended to run in multiple environments; otherwise, check them in:
60
+ # Gemfile.lock
61
+ # .ruby-version
62
+ # .ruby-gemset
63
+
64
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
65
+ .rvmrc
66
+
67
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
68
+ # .rubocop-https?--*
69
+
70
+ ### RubyMine ###
71
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
72
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
73
+
74
+ # User-specific stuff
75
+ .idea/**/workspace.xml
76
+ .idea/**/tasks.xml
77
+ .idea/**/usage.statistics.xml
78
+ .idea/**/dictionaries
79
+ .idea/**/shelf
80
+
81
+ # AWS User-specific
82
+ .idea/**/aws.xml
83
+
84
+ # Generated files
85
+ .idea/**/contentModel.xml
86
+
87
+ # Sensitive or high-churn files
88
+ .idea/**/dataSources/
89
+ .idea/**/dataSources.ids
90
+ .idea/**/dataSources.local.xml
91
+ .idea/**/sqlDataSources.xml
92
+ .idea/**/dynamic.xml
93
+ .idea/**/uiDesigner.xml
94
+ .idea/**/dbnavigator.xml
95
+
96
+ # Gradle
97
+ .idea/**/gradle.xml
98
+ .idea/**/libraries
99
+
100
+ # Gradle and Maven with auto-import
101
+ # When using Gradle or Maven with auto-import, you should exclude module files,
102
+ # since they will be recreated, and may cause churn. Uncomment if using
103
+ # auto-import.
104
+ # .idea/artifacts
105
+ # .idea/compiler.xml
106
+ # .idea/jarRepositories.xml
107
+ # .idea/modules.xml
108
+ # .idea/*.iml
109
+ # .idea/modules
110
+ # *.iml
111
+ # *.ipr
112
+
113
+ # CMake
114
+ cmake-build-*/
115
+
116
+ # Mongo Explorer plugin
117
+ .idea/**/mongoSettings.xml
118
+
119
+ # File-based project format
120
+ *.iws
121
+
122
+ # IntelliJ
123
+ out/
124
+
125
+ # mpeltonen/sbt-idea plugin
126
+ .idea_modules/
127
+
128
+ # JIRA plugin
129
+ atlassian-ide-plugin.xml
130
+
131
+ # Cursive Clojure plugin
132
+ .idea/replstate.xml
133
+
134
+ # Crashlytics plugin (for Android Studio and IntelliJ)
135
+ com_crashlytics_export_strings.xml
136
+ crashlytics.properties
137
+ crashlytics-build.properties
138
+ fabric.properties
139
+
140
+ # Editor-based Rest Client
141
+ .idea/httpRequests
142
+
143
+ # Android studio 3.1+ serialized cache file
144
+ .idea/caches/build_file_checksums.ser
145
+
146
+ ### RubyMine Patch ###
147
+ # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
148
+
149
+ # *.iml
150
+ # modules.xml
151
+ # .idea/misc.xml
152
+ # *.ipr
153
+
154
+ # Sonarlint plugin
155
+ # https://plugins.jetbrains.com/plugin/7973-sonarlint
156
+ .idea/**/sonarlint/
157
+
158
+ # SonarQube Plugin
159
+ # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
160
+ .idea/**/sonarIssues.xml
161
+
162
+ # Markdown Navigator plugin
163
+ # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
164
+ .idea/**/markdown-navigator.xml
165
+ .idea/**/markdown-navigator-enh.xml
166
+ .idea/**/markdown-navigator/
167
+
168
+ # Cache file creation bug
169
+ # See https://youtrack.jetbrains.com/issue/JBR-2257
170
+ .idea/$CACHE_FILE$
171
+
172
+ # CodeStream plugin
173
+ # https://plugins.jetbrains.com/plugin/12206-codestream
174
+ .idea/codestream.xml
175
+
176
+ # End of https://www.toptal.com/developers/gitignore/api/rubymine,ruby
177
+
178
+ /input/*
179
+ !/input/.gitkeep
180
+ /output/*
181
+ !/output/.gitkeep
@@ -0,0 +1,31 @@
1
+ ## Empty template, uncomment the sections that you need!
2
+ #
3
+ # metadata do
4
+ # name ""
5
+ # version ""
6
+ # comments ""
7
+ # additional data: {
8
+ # # Any additional data can go here. For example:
9
+ # key: "value"
10
+ # }
11
+ # end
12
+ #
13
+ # extract do
14
+ # # ...
15
+ # end
16
+ #
17
+ # build do
18
+ # # ...
19
+ # end
20
+ #
21
+ # query do
22
+ # # ...
23
+ # end
24
+ #
25
+ # transform do
26
+ # # ...
27
+ # end
28
+ #
29
+ # export do
30
+ # # ...
31
+ # end
@@ -0,0 +1 @@
1
+ ruby 3.2.1
data/lib/cure/config.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "cure"
4
4
  require "json"
5
5
  require "singleton"
6
+ require "tempfile"
6
7
 
7
8
  module Cure
8
9
  module Configuration
@@ -14,45 +15,47 @@ module Cure
14
15
  conf
15
16
  end
16
17
 
18
+ # @param [Array<Cure::Configuration::CsvFileProxy>] source_files
19
+ # @param [Cure::Template] template
20
+ # @return [Config]
21
+ def create_config(source_files, template)
22
+ Config.new(source_files, template)
23
+ end
24
+
17
25
  # @param [Config] request_config
18
26
  def register_config(request_config)
19
27
  ConfigurationSource.instance.load_config(request_config)
20
28
  end
21
29
 
22
- # @param [String] source_file_location
23
- # @param [Cure::Template] template
24
- # @param [String] output_dir
25
- # @return [Config]
26
- def create_config(source_file_location, template, output_dir)
27
- Config.new(source_file_location, template, output_dir)
28
- end
29
-
30
30
  # If we are overloading here as a "data store" and "config store", we
31
31
  # could break out variables and placeholders into their own singleton.
32
32
  #
33
33
  # This should be a kind of instance cache, which loads once per run,
34
34
  # and junk can be jammed in there?
35
35
  class Config
36
- attr_accessor :source_file_location, :output_dir
37
36
 
38
- # @return [Cure::Template] template
39
- attr_accessor :template
37
+ # @return Array<Cure::Configuration::CsvFileProxy>
38
+ attr_accessor :source_files
40
39
 
41
- # @return [Hash] variables
42
- attr_accessor :variables
40
+ # @return [Cure::Template]
41
+ attr_accessor :template
43
42
 
44
- # @param [String] source_file_location
43
+ # @param [Array<Cure::Configuration::CsvFileProxy>] source_files
45
44
  # @param [Cure::Template] template
46
- # @param [String] output_dir
47
- def initialize(source_file_location, template, output_dir)
48
- @source_file_location = source_file_location
45
+ def initialize(source_files, template)
46
+ @source_files = source_files
49
47
  @template = template
50
- @output_dir = output_dir
51
48
  end
52
49
 
53
50
  def placeholders
54
51
  @template.transformations.placeholders || {}
55
52
  end
53
+
54
+ def with_source_file(&block)
55
+ @source_files.each_with_index do |file, _idx|
56
+ file.with_file(&block)
57
+ end
58
+ end
56
59
  end
57
60
 
58
61
  class ConfigurationSource
@@ -66,5 +69,126 @@ module Cure
66
69
  @config = config
67
70
  end
68
71
  end
72
+
73
+ class CsvFileProxy
74
+
75
+ # @return [TrueClass,FalseClass]
76
+ attr_reader :valid
77
+ # @return [DefaultFileHandler]
78
+ attr_reader :csv_handler
79
+
80
+ # @return [CsvFileProxy]
81
+ def self.load_file(type, obj, ref_name)
82
+ handler =
83
+ case type
84
+ when :file
85
+ FileHandler.new(obj, ref_name)
86
+ when :file_contents
87
+ FileContentsHandler.new(obj, ref_name)
88
+ when :path, :pathname
89
+ PathnameHandler.new(obj, ref_name)
90
+ else
91
+ raise "Invalid file type handler [#{type}]. Supported: [:file, :file_contents, :path, :pathname]"
92
+ end
93
+
94
+ new(handler)
95
+ end
96
+
97
+ # @return [DefaultFileHandler]
98
+ def initialize(csv_handler)
99
+ @csv_handler = csv_handler
100
+ end
101
+
102
+ def description
103
+ @csv_handler.description
104
+ end
105
+
106
+ def with_file(&block)
107
+ @csv_handler.with_file(&block)
108
+ end
109
+ end
110
+
111
+ class DefaultFileHandler
112
+ attr_reader :type, :ref_name
113
+
114
+ def initialize(type, ref_name)
115
+ @type = type
116
+ @ref_name = ref_name
117
+ end
118
+
119
+ def with_file(&_block)
120
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
121
+ end
122
+
123
+ def description
124
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
125
+ end
126
+ end
127
+
128
+ class PathnameHandler < DefaultFileHandler
129
+ attr_accessor :pathname
130
+
131
+ # @param [Pathname] pathname
132
+ def initialize(pathname, ref_name)
133
+ super(:pathname, ref_name)
134
+ @pathname = pathname
135
+ end
136
+
137
+ def with_file(&_block)
138
+ yield @pathname, @ref_name
139
+ end
140
+
141
+ def description
142
+ @pathname.to_s
143
+ end
144
+ end
145
+
146
+ class FileHandler < DefaultFileHandler
147
+ # @return [File]
148
+ attr_accessor :file
149
+
150
+ # @param [File] file
151
+ def initialize(file, ref_name)
152
+ super(:file, ref_name)
153
+ @file = file
154
+ end
155
+
156
+ def with_file(&_block)
157
+ yield @file, @ref_name
158
+
159
+ ensure
160
+ @file&.close
161
+ end
162
+
163
+ def description
164
+ File.basename(file)
165
+ end
166
+ end
167
+
168
+ class FileContentsHandler < DefaultFileHandler
169
+ # @return [String]
170
+ attr_accessor :file_contents
171
+
172
+ # @param [String] file_contents
173
+ def initialize(file_contents, ref_name)
174
+ super(:file_contents, ref_name)
175
+ @file_contents = file_contents
176
+ end
177
+
178
+ def with_file(&_block)
179
+ tmp_file = Tempfile.new('cure-temp')
180
+ tmp_file.write(@file_contents)
181
+ tmp_file.open
182
+
183
+ yield tmp_file, @ref_name
184
+
185
+ ensure
186
+ tmp_file.unlink
187
+ end
188
+
189
+ def description
190
+ "<content provided>"
191
+ end
192
+ end
69
193
  end
70
194
  end
@@ -2,11 +2,13 @@
2
2
 
3
3
  require "cure/log"
4
4
  require "cure/config"
5
+ require "cure/database"
5
6
  require "cure/helpers/file_helpers"
7
+ require "cure/helpers/perf_helpers"
6
8
 
7
9
  require "cure/extract/extractor"
8
10
  require "cure/transformation/transform"
9
- require "cure/export/exporter"
11
+ require "cure/export/manager"
10
12
 
11
13
  require "rcsv"
12
14
 
@@ -14,59 +16,93 @@ module Cure
14
16
  # Coordinates the entire process:
15
17
  # Extract -> Build -> Transform -> Export
16
18
  class Coordinator
17
- include Configuration
18
19
  include Log
20
+ include Database
21
+ include Configuration
22
+ include Helpers::PerfHelpers
19
23
 
20
24
  def process
21
25
  # need to check config is init'd
26
+ result = nil
27
+ print_memory_usage do
28
+ print_time_spent do
29
+ # 1. Extract into SQLite
30
+ extract
31
+ # 2. Manipulate SQLite columns
32
+ build
33
+ # 3. Validate columns
34
+
35
+ # 4. Transform each row
36
+ with_tables.each do |table|
37
+ with_transformer(table) do |transformer|
38
+ with_exporters(table) do |exporters|
39
+ database_service.with_paged_result(table) do |row|
40
+ transformed_row = transformer.transform(row)
41
+ exporters.each do |exporter|
42
+ # 4. Export
43
+ exporter.process_row(transformed_row)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
22
51
 
23
- extracted_csv = extract
24
- built_csv = build(extracted_csv)
25
- transformed_csv = transform(built_csv)
26
- export(transformed_csv)
52
+ result
27
53
  end
28
54
 
29
55
  private
30
56
 
31
- # @return [Cure::Extract::WrappedCSV]
32
57
  def extract
33
58
  log_info "Beginning the extraction process..."
34
59
 
35
60
  extractor = Extract::Extractor.new({})
36
- result = extractor.extract_from_file(config.source_file_location)
37
61
 
38
- log_debug "Setting extracted variables to global conf for access downstream"
39
- config.variables = result.variables
62
+ file_count = 0
63
+ config.with_source_file do |file, ref_name|
64
+ extractor.parse_csv(file, ref_name: ref_name)
65
+ file_count += 1
66
+ end
40
67
 
41
68
  log_info "...extraction complete"
42
- result
43
69
  end
44
70
 
45
- # @param [Cure::Extract::WrappedCSV] wrapped_csv
46
- def build(wrapped_csv)
71
+ def build
47
72
  log_info "Beginning the building process..."
73
+ candidates = config.template.builder.candidates
74
+ candidates.each(&:perform)
75
+
48
76
  log_info "... building complete"
49
- wrapped_csv
50
77
  end
51
78
 
52
- # @return [Hash<String,Cure::Transformation::TransformResult>]
53
- # @param [Cure::Extract::WrappedCSV] parsed_csv
54
- def transform(parsed_csv)
79
+ # @yieldreturn [Cure::Transformation::Transform]
80
+ def with_transformer(named_range, &block)
81
+ raise "No block passed" unless block
82
+
55
83
  log_info "Beginning the transformation process..."
56
- transformer = Cure::Transformation::Transform.new(config.template.transformations.candidates)
57
- content = transformer.transform_content(parsed_csv)
84
+ candidates = config.template.transformations.candidates.select { |c| c.named_range == named_range.to_s }
85
+ transformer = Cure::Transformation::Transform.new(candidates)
86
+ yield transformer
58
87
 
59
88
  log_info "...transform complete"
60
- content
61
89
  end
62
90
 
63
- # @return [Hash<String,Cure::Transformation::TransformResult>]
64
- def export(transformed_result)
91
+ # @yieldreturn [Cure::Export::Section]
92
+ def with_exporters(named_range, &block)
93
+ raise "No block passed" unless block
94
+
65
95
  log_info "Beginning export process..."
66
- Cure::Export::Exporter.export_result(transformed_result, config.output_dir)
67
- log_info "... export complete."
96
+ processors = config.template.exporters.processors.select { |c| c.named_range.to_s == named_range.to_s }
97
+ manager = Cure::Export::Manager.new(named_range, processors)
98
+
99
+ manager.with_processors(&block)
100
+
101
+ log_info "...export complete"
102
+ end
68
103
 
69
- transformed_result
104
+ def with_tables
105
+ config.template.exporters.processors.map { |e| e.named_range.to_sym }.uniq
70
106
  end
71
107
  end
72
108
  end