cure 0.1.1 → 0.1.2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +16 -6
  5. data/exe/cure +7 -3
  6. data/lib/cure/config.rb +17 -3
  7. data/lib/cure/coordinator.rb +72 -0
  8. data/lib/cure/export/exporter.rb +32 -7
  9. data/lib/cure/extract/builder.rb +27 -0
  10. data/lib/cure/extract/csv_lookup.rb +32 -0
  11. data/lib/cure/extract/extractor.rb +123 -0
  12. data/lib/cure/generator/base_generator.rb +51 -0
  13. data/lib/cure/generator/case_generator.rb +25 -0
  14. data/lib/cure/generator/character_generator.rb +35 -0
  15. data/lib/cure/generator/faker_generator.rb +25 -0
  16. data/lib/cure/generator/guid_generator.rb +16 -0
  17. data/lib/cure/generator/hex_generator.rb +16 -0
  18. data/lib/cure/generator/imports.rb +12 -0
  19. data/lib/cure/generator/number_generator.rb +16 -0
  20. data/lib/cure/generator/placeholder_generator.rb +20 -0
  21. data/lib/cure/generator/redact_generator.rb +16 -0
  22. data/lib/cure/generator/variable_generator.rb +20 -0
  23. data/lib/cure/helpers/file_helpers.rb +40 -0
  24. data/lib/cure/helpers/object_helpers.rb +29 -0
  25. data/lib/cure/log.rb +3 -3
  26. data/lib/cure/main.rb +40 -31
  27. data/lib/cure/strategy/append_strategy.rb +24 -0
  28. data/lib/cure/strategy/base_strategy.rb +123 -0
  29. data/lib/cure/strategy/end_with_strategy.rb +46 -0
  30. data/lib/cure/strategy/full_strategy.rb +24 -0
  31. data/lib/cure/strategy/imports.rb +10 -0
  32. data/lib/cure/strategy/match_strategy.rb +43 -0
  33. data/lib/cure/strategy/regex_strategy.rb +49 -0
  34. data/lib/cure/strategy/split_strategy.rb +53 -0
  35. data/lib/cure/strategy/start_with_strategy.rb +47 -0
  36. data/lib/cure/template/dispatch.rb +30 -0
  37. data/lib/cure/template/extraction.rb +38 -0
  38. data/lib/cure/template/template.rb +28 -0
  39. data/lib/cure/template/transformations.rb +26 -0
  40. data/lib/cure/transformation/candidate.rb +23 -9
  41. data/lib/cure/transformation/transform.rb +33 -41
  42. data/lib/cure/validators.rb +71 -0
  43. data/lib/cure/version.rb +1 -1
  44. data/lib/cure.rb +9 -4
  45. data/templates/aws_cur_template.json +130 -128
  46. data/templates/example_template.json +46 -30
  47. metadata +36 -9
  48. data/lib/cure/csv_helpers.rb +0 -6
  49. data/lib/cure/file_helpers.rb +0 -38
  50. data/lib/cure/generator/base.rb +0 -148
  51. data/lib/cure/object_helpers.rb +0 -27
  52. data/lib/cure/strategy/base.rb +0 -223
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/generator/base_generator"
4
+ require "cure/config"
5
+
6
+ module Cure
7
+ module Generator
8
+ class PlaceholderGenerator < BaseGenerator
9
+ include Cure::Configuration
10
+
11
+ private
12
+
13
+ # @param [Object] _source_value
14
+ def _generate(_source_value)
15
+ value = config.placeholders[property_name]
16
+ value || raise("Missing placeholder value. Available candidates: [#{config.placeholders.keys.join(", ")}]")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/generator/base_generator"
4
+
5
+ module Cure
6
+ module Generator
7
+ class RedactGenerator < BaseGenerator
8
+ private
9
+
10
+ # @param [Object] source_value
11
+ def _generate(source_value)
12
+ 1.upto(length(source_value&.length || 5)).map { "X" }.join("")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/generator/base_generator"
4
+ require "cure/config"
5
+
6
+ module Cure
7
+ module Generator
8
+ class VariableGenerator < BaseGenerator
9
+ include Cure::Configuration
10
+
11
+ private
12
+
13
+ # @param [Object] _source_value
14
+ def _generate(_source_value)
15
+ value = config.variables[property_name]
16
+ value || raise("Missing placeholder value. Available candidates: [#{config.variables.keys.join(", ")}]")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Cure
6
+ module Helpers
7
+ module FileHelpers
8
+ def with_file(path, extension, &block)
9
+ dir = File.dirname(path)
10
+
11
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
12
+
13
+ path = "#{path}.#{extension}"
14
+ File.open(path, "w", &block)
15
+ end
16
+
17
+ def clean_dir(path)
18
+ dir = File.file?(path) ? File.dirname(path) : path
19
+
20
+ FileUtils.remove_dir(dir) if File.directory?(dir)
21
+ end
22
+
23
+ def read_file(file_location)
24
+ result = file_location.start_with?("/") ? file_location : File.join(File.dirname(__FILE__), file_location)
25
+
26
+ raise "No file found at [#{file_location}]" unless File.exist? result
27
+
28
+ File.read(result)
29
+ end
30
+
31
+ def with_temp_dir(temp_dir, &_block)
32
+ return unless block_given?
33
+
34
+ clean_dir(temp_dir)
35
+ yield
36
+ clean_dir(temp_dir)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure"
4
+ require "json"
5
+
6
+ module Cure
7
+ module Helpers
8
+ module ObjectHelpers
9
+ def attributes=(hash)
10
+ hash.each do |key, value|
11
+ send("#{key}=", value)
12
+ rescue NoMethodError
13
+ Cure.logger.warn("Error deserializing object: No property for #{key}")
14
+ end
15
+ end
16
+
17
+ def from_json(json)
18
+ return from_hash(json) if json.is_a?(Hash) # Just a guard in case serialisation is done
19
+
20
+ from_hash(JSON.parse(json))
21
+ end
22
+
23
+ def from_hash(hash)
24
+ self.attributes = hash
25
+ self
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/cure/log.rb CHANGED
@@ -20,10 +20,10 @@ module Cure
20
20
  end
21
21
 
22
22
  # @param [String] message
23
- # @param [Exception/Nil] ex
24
- def log_error(message, ex=nil)
23
+ # @param [Exception/Nil] exception
24
+ def log_error(message, exception=nil)
25
25
  Cure.logger.error(message)
26
- Cure.logger.error(ex.backtrace.join("\n")) unless ex.nil?
26
+ Cure.logger.error(exception.backtrace.join("\n")) unless exception.nil?
27
27
  end
28
28
  end
29
29
  end
data/lib/cure/main.rb CHANGED
@@ -1,63 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cure"
4
- require "json"
3
+ require "cure/template/template"
5
4
  require "cure/transformation/candidate"
6
5
  require "cure/transformation/transform"
7
6
  require "cure/export/exporter"
7
+ require "cure/coordinator"
8
8
 
9
- module Cure
9
+ require "cure"
10
+ require "json"
10
11
 
12
+ module Cure
11
13
  class Main
12
14
  include Configuration
13
- include FileHelpers
15
+ include Helpers::FileHelpers
14
16
 
17
+ # @param [String] template_file_loc
18
+ # @param [String] csv_file_loc
19
+ # @param [String] output_dir
15
20
  # @return [Cure::Main]
16
- def self.init(template_file, csv_file, output_dir)
21
+ def self.init_from_file(template_file_loc, csv_file_loc, output_dir)
17
22
  # Run all init stuff here.
23
+ # Run validator?
24
+
18
25
  main = Main.new
19
- main.setup(template_file, csv_file, output_dir)
26
+ template_hash = JSON.parse(main.read_file(template_file_loc))
27
+ template = Template.from_hash(template_hash)
28
+ main.setup(csv_file_loc, template, output_dir)
29
+ main
30
+ end
20
31
 
32
+ # @param [Hash] template_hash
33
+ # @param [String] csv_file_loc
34
+ # @param [String] output_dir
35
+ # @return [Cure::Main]
36
+ def self.init_from_hash(template_hash, csv_file_loc, output_dir)
37
+ # Run all init stuff here.
38
+ # Run validator?
39
+
40
+ main = Main.new
41
+ template = Template.from_hash(template_hash)
42
+ main.setup(csv_file_loc, template, output_dir)
21
43
  main
22
44
  end
23
45
 
24
- # @return [Cure::Transformation::Transform]
25
- attr_accessor :transformer
46
+ # @return [Cure::Coordinator]
47
+ attr_accessor :coordinator
26
48
 
27
49
  # @return [Boolean]
28
50
  attr_reader :is_initialised
29
51
 
30
52
  def initialize
31
53
  @is_initialised = false
54
+ @coordinator = Coordinator.new
32
55
  end
33
56
 
34
- def run
35
- raise "Not init" unless @transformer
36
-
37
- ctx = build_ctx
38
- export(ctx)
39
- end
40
-
41
- # @return [Cure::Transform::TransformContext]
42
- def build_ctx
43
- @transformer.extract_from_file(config.source_file_location)
57
+ def run_export
58
+ @coordinator.process
44
59
  end
45
60
 
46
- def setup(template_file, csv_file, output_dir)
47
- config = create_config(csv_file, JSON.parse(read_file(template_file)), output_dir)
61
+ # @param [String] csv_file_location
62
+ # @param [Cure::Template] template
63
+ # @param [String] output_dir
64
+ # @return [Cure::Main]
65
+ def setup(csv_file_location, template, output_dir)
66
+ config = create_config(csv_file_location, template, output_dir)
48
67
  register_config(config)
49
68
 
50
- candidates = config.template["candidates"].map { |c| Cure::Transformation::Candidate.new.from_json(c) }
51
-
52
- @transformer = Cure::Transformation::Transform.new(candidates)
53
- @is_initialised = true
54
- end
55
-
56
- private
57
-
58
- # @param [Cure::Transform::TransformContext] ctx
59
- def export(ctx)
60
- Cure::Export::Exporter.export_ctx(ctx, config.output_dir, "csv_file")
69
+ self
61
70
  end
62
71
  end
63
72
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class AppendStrategy < BaseStrategy
8
+ private
9
+
10
+ # @param [String] source_value
11
+ # @return [String]
12
+ def _retrieve_value(source_value)
13
+ source_value
14
+ end
15
+
16
+ # @param [String] source_value
17
+ # @param [String] generated_value
18
+ # @return [String]
19
+ def _replace_value(source_value, generated_value)
20
+ source_value + generated_value
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+ require "cure/validators"
5
+
6
+ module Cure
7
+ module Strategy
8
+ # Singleton Strategy for storing data across all processes
9
+ module History
10
+ # @return [Hash]
11
+ def history
12
+ HistoryCache.instance.history_cache
13
+ end
14
+
15
+ # @return [String]
16
+ def retrieve_history(source_value)
17
+ history[source_value] unless source_value.nil? || source_value == ""
18
+ end
19
+
20
+ # @param [String] source_value
21
+ # @param [String] value
22
+ def store_history(source_value, value)
23
+ history[source_value] = value unless source_value.nil? || source_value == ""
24
+ end
25
+
26
+ def reset_history
27
+ HistoryCache.instance.reset
28
+ end
29
+ alias clear_history reset_history
30
+
31
+ class HistoryCache
32
+ include Singleton
33
+
34
+ attr_reader :history_cache
35
+
36
+ def initialize
37
+ @history_cache = {}
38
+ end
39
+
40
+ def reset
41
+ @history_cache = {}
42
+ end
43
+ end
44
+ end
45
+
46
+ class BaseStrategy
47
+ include History
48
+
49
+ # Additional details needed to make substitution.
50
+ # @return [BaseStrategyParams]
51
+ attr_accessor :params
52
+
53
+ def initialize(params)
54
+ # Is there a better way to do this? If its a base, we take a {}, if super
55
+ # defines it, we just use that instance.
56
+ @params = params.is_a?(Hash) ? BaseStrategyParams.new(params) : params
57
+ end
58
+
59
+ # @param [String] source_value
60
+ # @param [Generator::BaseGenerator] generator
61
+ # @return [String]
62
+ #
63
+ # This will retrieve the (partial) value, then generate a new replacement.
64
+ def extract(source_value, generator)
65
+ extracted_value = _retrieve_value(source_value)
66
+
67
+ existing = retrieve_history(extracted_value)
68
+ return _replace_value(source_value, existing) if existing
69
+
70
+ generated_value = generator.generate(source_value)&.to_s
71
+ value = _replace_value(source_value, generated_value)
72
+
73
+ store_history(extracted_value, generated_value)
74
+
75
+ value
76
+ end
77
+
78
+ private
79
+
80
+ def replace_partial_record
81
+ replace_partial = @params.replace_partial
82
+ return replace_partial || false unless replace_partial.instance_of?(String)
83
+
84
+ (replace_partial || "true").to_s == "true"
85
+ end
86
+
87
+ def value?(value)
88
+ !value.nil? && value != ""
89
+ end
90
+
91
+ # @param [String] _source_value
92
+ def _retrieve_value(_source_value)
93
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
94
+ end
95
+
96
+ # @param [String] _source_value
97
+ # @param [String] _generated_value
98
+ # @return [String]
99
+ def _replace_value(_source_value, _generated_value)
100
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
101
+ end
102
+ end
103
+
104
+ class BaseStrategyParams
105
+ include Validators::Helpers
106
+ extend Validators
107
+
108
+ # Additional details needed to make substitution.
109
+ # @return [Hash]
110
+ attr_accessor :options
111
+ attr_accessor :replace_partial
112
+
113
+ def initialize(options={})
114
+ @replace_partial = options["replace_partial"] || "false"
115
+ @options = options
116
+ end
117
+
118
+ def validate_params
119
+ valid?
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class EndWithStrategy < BaseStrategy
8
+ # Additional details needed to make substitution.
9
+ # @return [EndWithStrategyParams]
10
+ attr_accessor :params
11
+
12
+ def initialize(options)
13
+ super(EndWithStrategyParams.new(options))
14
+ end
15
+
16
+ # gsub catchment group
17
+ # @param [String] source_value
18
+ def _retrieve_value(source_value)
19
+ @params.match || nil if source_value.end_with? @params.match
20
+ end
21
+
22
+ # @param [String] source_value
23
+ # @param [String] generated_value
24
+ # @return [String]
25
+ def _replace_value(source_value, generated_value)
26
+ return unless source_value.end_with? @params.match
27
+
28
+ return generated_value unless replace_partial_record
29
+
30
+ generated_value + @params.match
31
+ # generated_value + source_value.reverse.chomp(@options["match"].reverse).reverse
32
+ end
33
+ end
34
+
35
+ class EndWithStrategyParams < BaseStrategyParams
36
+ attr_reader :match
37
+
38
+ validates :match
39
+
40
+ def initialize(options=nil)
41
+ @match = options["match"]
42
+ super(options)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class FullStrategy < BaseStrategy
8
+ private
9
+
10
+ # @param [String] source_value
11
+ # @return [String]
12
+ def _retrieve_value(source_value)
13
+ source_value
14
+ end
15
+
16
+ # @param [String] _source_value
17
+ # @param [String] generated_value
18
+ # @return [String]
19
+ def _replace_value(_source_value, generated_value)
20
+ generated_value
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+ require "cure/strategy/end_with_strategy"
5
+ require "cure/strategy/full_strategy"
6
+ require "cure/strategy/match_strategy"
7
+ require "cure/strategy/regex_strategy"
8
+ require "cure/strategy/split_strategy"
9
+ require "cure/strategy/start_with_strategy"
10
+ require "cure/strategy/append_strategy"
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class MatchStrategy < BaseStrategy
8
+ # Additional details needed to make substitution.
9
+ # @return [MatchStrategyParams]
10
+ attr_accessor :params
11
+
12
+ def initialize(options)
13
+ super(MatchStrategyParams.new(options))
14
+ end
15
+
16
+ # gsub catchment group
17
+ # @param [String] source_value
18
+ def _retrieve_value(source_value)
19
+ @params.match || nil if source_value.include? @params.match
20
+ end
21
+
22
+ # @param [String] source_value
23
+ # @param [String] generated_value
24
+ # @return [String]
25
+ def _replace_value(source_value, generated_value)
26
+ return unless source_value.include? @params.match
27
+
28
+ source_value.gsub(@params.match, generated_value)
29
+ end
30
+ end
31
+
32
+ class MatchStrategyParams < BaseStrategyParams
33
+ attr_reader :match
34
+
35
+ validates :match
36
+
37
+ def initialize(options=nil)
38
+ @match = options["match"]
39
+ super(options)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class RegexStrategy < BaseStrategy
8
+ # Additional details needed to make substitution.
9
+ # @return [RegexStrategyParams]
10
+ attr_accessor :params
11
+
12
+ def initialize(options)
13
+ super(RegexStrategyParams.new(options))
14
+ end
15
+
16
+ # gsub catchment group
17
+ # @param [String] source_value
18
+ def _retrieve_value(source_value)
19
+ m = /#{@params.regex_cg}/.match(source_value)
20
+ return unless m.instance_of?(MatchData) && (!m[1].nil? && m[1] != "")
21
+
22
+ m[1]
23
+ end
24
+
25
+ # @param [String] source_value
26
+ # @param [String] generated_value
27
+ # @return [String]
28
+ def _replace_value(source_value, generated_value)
29
+ m = /#{@params.regex_cg}/.match(source_value)
30
+ return unless m.instance_of?(MatchData) && (!m[1].nil? && m[1] != "")
31
+
32
+ generated_value unless replace_partial_record
33
+
34
+ source_value.gsub(m[1], generated_value)
35
+ end
36
+ end
37
+
38
+ class RegexStrategyParams < BaseStrategyParams
39
+ attr_reader :regex_cg
40
+
41
+ validates :regex_cg
42
+
43
+ def initialize(options=nil)
44
+ @regex_cg = options["regex_cg"]
45
+ super(options)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class SplitStrategy < BaseStrategy
8
+ # Additional details needed to make substitution.
9
+ # @return [SplitStrategyParams]
10
+ attr_accessor :params
11
+
12
+ def initialize(options)
13
+ super(SplitStrategyParams.new(options))
14
+ end
15
+
16
+ # @param [String] source_value
17
+ def _retrieve_value(source_value)
18
+ return unless source_value.include?(@params.token)
19
+
20
+ result_arr = source_value.split(@params.token)
21
+ result_arr[@params.index]
22
+ end
23
+
24
+ # @param [String] source_value
25
+ # @param [String] generated_value
26
+ # @return [String]
27
+ def _replace_value(source_value, generated_value)
28
+ split_token = @params.token
29
+
30
+ return unless source_value.include?(split_token)
31
+
32
+ result_arr = source_value.split(split_token)
33
+ result_arr[@params.index] = generated_value if value?(result_arr[@params.index])
34
+ result_arr.join(split_token)
35
+ end
36
+ end
37
+
38
+ class SplitStrategyParams < BaseStrategyParams
39
+ attr_reader :token, :index
40
+
41
+ validates :token, validator: :presence
42
+ validates :index, validator: :presence
43
+
44
+ def initialize(options=nil)
45
+ @token = options["token"]
46
+ @index = options["index"]
47
+ valid?
48
+
49
+ super(options)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class StartWithStrategy < BaseStrategy
8
+ # validates :match
9
+
10
+ # Additional details needed to make substitution.
11
+ # @return [StartWithStrategyParams]
12
+ attr_accessor :params
13
+
14
+ def initialize(options)
15
+ super(StartWithStrategyParams.new(options))
16
+ end
17
+
18
+ # gsub catchment group
19
+ # @param [String] source_value
20
+ def _retrieve_value(source_value)
21
+ @params.match || nil if source_value.start_with? @params.match
22
+ end
23
+
24
+ # @param [String] source_value
25
+ # @param [String] generated_value
26
+ # @return [String]
27
+ def _replace_value(source_value, generated_value)
28
+ return unless source_value.start_with? @params.match
29
+
30
+ return generated_value unless replace_partial_record
31
+
32
+ @params.match + generated_value
33
+ end
34
+ end
35
+
36
+ class StartWithStrategyParams < BaseStrategyParams
37
+ attr_reader :match
38
+
39
+ validates :match
40
+
41
+ def initialize(options=nil)
42
+ @match = options["match"]
43
+ super(options)
44
+ end
45
+ end
46
+ end
47
+ end