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,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code is by Ivan Black - available here:
4
+ # https://stackoverflow.com/questions/1489183/how-can-i-use-ruby-to-colorize-the-text-output-to-a-terminal
5
+
6
+ class String
7
+ def black
8
+ "\e[30m#{self}\e[0m"
9
+ end
10
+
11
+ def red
12
+ "\e[31m#{self}\e[0m"
13
+ end
14
+
15
+ def green
16
+ "\e[32m#{self}\e[0m"
17
+ end
18
+
19
+ def brown
20
+ "\e[33m#{self}\e[0m"
21
+ end
22
+
23
+ def blue
24
+ "\e[34m#{self}\e[0m"
25
+ end
26
+
27
+ def magenta
28
+ "\e[35m#{self}\e[0m"
29
+ end
30
+
31
+ def cyan
32
+ "\e[36m#{self}\e[0m"
33
+ end
34
+
35
+ def gray
36
+ "\e[37m#{self}\e[0m"
37
+ end
38
+
39
+ def bold
40
+ "\e[1m#{self}\e[22m"
41
+ end
42
+
43
+ def italic
44
+ "\e[3m#{self}\e[23m"
45
+ end
46
+
47
+ def underline
48
+ "\e[4m#{self}\e[24m"
49
+ end
50
+
51
+ def blink
52
+ "\e[5m#{self}\e[25m"
53
+ end
54
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/transformation/candidate"
4
+ require "cure/transformation/transform"
5
+ require "cure/coordinator"
6
+ require "cure/database"
7
+ require "cure/planner"
8
+ require "cure/config"
9
+
10
+ require "json"
11
+
12
+ module Cure
13
+ class Launcher
14
+ include Database
15
+ include Configuration
16
+ include Helpers::FileHelpers
17
+
18
+ # @return [Cure::Coordinator]
19
+ attr_accessor :coordinator
20
+
21
+ def initialize(coordinator: Coordinator.new, planner: Planner.new)
22
+ @coordinator = coordinator
23
+ @planner = planner
24
+ @validated = false
25
+ @csv_files = []
26
+ end
27
+
28
+ # This will only support single file CSV processing, and is deprecated now
29
+ #
30
+ # @param [Symbol] type
31
+ # @param [Object] obj
32
+ # @param [TrueClass,FalseClass] print_query_plan
33
+ # @return [void]
34
+ # @deprecated
35
+ def process(type, obj, print_query_plan: true)
36
+ @csv_files << Cure::Configuration::CsvFileProxy.load_file(type, obj, "_default")
37
+ run_export(print_query_plan: print_query_plan)
38
+ end
39
+
40
+ def run_export(print_query_plan: true)
41
+ setup
42
+
43
+ raise "Not initialized" unless @validated
44
+
45
+ query_plan if print_query_plan
46
+ @coordinator.process
47
+ end
48
+
49
+ # -- Builder opts start
50
+
51
+ # @param [Symbol] type
52
+ # @param [Object] obj
53
+ # @return [Cure::Main]
54
+ def with_csv_file(type, obj, ref_name: nil)
55
+ if ref_name.nil?
56
+ ref_name = @csv_files.length.zero? ? "_default" : "_default_#{@csv_files.length}"
57
+ end
58
+
59
+ @csv_files << Cure::Configuration::CsvFileProxy.load_file(type, obj, ref_name)
60
+ self
61
+ end
62
+
63
+ # @return [Cure::Main]
64
+ def with_config(&block)
65
+ raise "No block given to config" unless block
66
+
67
+ dsl = Dsl::DslHandler.init(&block)
68
+ @template = dsl.generate
69
+
70
+ load_csv_from_config
71
+
72
+ self
73
+ end
74
+
75
+ # @return [Cure::Main]
76
+ def with_config_file(file_location)
77
+ contents = read_file(file_location.to_s)
78
+
79
+ dsl = Dsl::DslHandler.init_from_content(contents, "cure")
80
+ @template = dsl.generate
81
+
82
+ load_csv_from_config
83
+
84
+ self
85
+ end
86
+
87
+ # -- Builder end
88
+
89
+ # @return [Cure::Main]
90
+ def setup
91
+ raise "CSV File(s) are required" if @csv_files.empty?
92
+ raise "Template is required" unless @template
93
+
94
+ config = create_config(@csv_files, @template)
95
+ register_config(config)
96
+
97
+ init_database
98
+ init_history
99
+
100
+ @validated = true
101
+ self
102
+ end
103
+
104
+ # @return [void]
105
+ def query_plan
106
+ raise "Not initialized" unless @validated
107
+
108
+ @planner.process
109
+ end
110
+
111
+ private
112
+
113
+ def load_csv_from_config
114
+ return unless @template.source_files.has_candidates?
115
+
116
+ @template.source_files.candidates.each do |source|
117
+ with_csv_file(source.type, source.value, ref_name: source.ref_name)
118
+ end
119
+ end
120
+
121
+ def init_history
122
+ Cure::History::HistoryCache.instance.reset
123
+ end
124
+ end
125
+ end
data/lib/cure/log.rb CHANGED
@@ -4,6 +4,13 @@ require "cure"
4
4
 
5
5
  module Cure
6
6
  module Log
7
+ # @param [String] _message
8
+ def log_trace(_message)
9
+ # Ruby default logger doesnt have trace, so my version
10
+ # is to just uncomment it when you need it for now.
11
+ # Cure.logger.trace(message)
12
+ end
13
+
7
14
  # @param [String] message
8
15
  def log_debug(message)
9
16
  Cure.logger.debug(message)
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/log"
4
+ require "cure/config"
5
+ require "cure/helpers/string"
6
+
7
+ require "artii"
8
+
9
+ module Cure
10
+ class Planner
11
+ include Configuration
12
+ include Log
13
+
14
+ def process
15
+ print_starter
16
+ print_extract_plan
17
+ print_build_plan
18
+ print_transformations_plan
19
+ print_ender
20
+ end
21
+
22
+ def print_starter # rubocop:disable Metrics/AbcSize
23
+ a = Artii::Base.new({font: "isometric1"})
24
+ puts a.asciify("C u r e")
25
+ puts "\nIf you require assistance, please read:"
26
+ puts "https://github.com/williamthom-as/cure/tree/main/docs\n"
27
+ puts ""
28
+ log_info "_______________________________________________"
29
+ print_spacer
30
+ log_info "Cure Execution Plan".bold.underline
31
+ log_info ""
32
+ log_info "Source file location: #{config.source_files.map(&:description).join(",")}"
33
+ log_info "Template file descriptor below"
34
+
35
+ print_spacer
36
+ end
37
+
38
+ def print_ender
39
+ log_info "_______________________________________________"
40
+ print_spacer
41
+ end
42
+
43
+ def print_extract_plan # rubocop:disable Metrics/AbcSize
44
+ print_title "Extract"
45
+ named_ranges = config.template.extraction.named_ranges
46
+ variables = config.template.extraction.variables
47
+
48
+ if named_ranges.empty?
49
+ print_empty(named_ranges, "If you wanted to add a named range, please read docs/extraction.md")
50
+ else
51
+ log_info("[#{named_ranges.length}] named ranges specified")
52
+ named_ranges.each do |nr|
53
+ log_info "-- #{nr.name} will extract values from #{nr.section}"
54
+ end
55
+ end
56
+
57
+ print_spacer
58
+
59
+ if variables.empty?
60
+ print_empty("variables")
61
+ else
62
+ log_info("[#{variables.length}] variables specified")
63
+ variables.each do |v|
64
+ log_info "-- #{v.name} will extract from #{v.location}"
65
+ end
66
+ end
67
+
68
+ print_spacer
69
+ end
70
+
71
+ def print_build_plan
72
+ print_title "Build"
73
+ candidates = config.template.builder.candidates
74
+
75
+ if candidates.empty?
76
+ print_empty("Build")
77
+ else
78
+ candidates.each do |c|
79
+ log_info "-- #{c.column || "Multiple columns>"} from #{c.named_range} will be changed with #{c.action}"
80
+ end
81
+ end
82
+
83
+ print_spacer
84
+ end
85
+
86
+ def print_transformations_plan # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity
87
+ print_title "Transforms"
88
+ candidates = config.template.transformations.candidates
89
+ placeholders = config.template.transformations.placeholders
90
+
91
+ if candidates.empty?
92
+ print_empty("Transforms")
93
+ else
94
+ candidates.each do |c|
95
+ log_info "-- #{c.column} from #{c.named_range} will be changed with #{c.translations.size} translation"
96
+ c.translations.each do |tr|
97
+ log_info "\t\t> #{"Replacement".bold} [#{tr.strategy.class}]: #{tr.strategy.describe}"
98
+ log_info "\t\t> #{"Generator".bold} [#{tr.generator.class}]: #{tr.generator.describe}"
99
+ end
100
+ end
101
+ end
102
+
103
+ print_spacer
104
+
105
+ if placeholders.nil? || placeholders.empty?
106
+ print_empty("Placeholders")
107
+ else
108
+ log_info "-- Variables"
109
+ placeholders.each do |k, v|
110
+ log_info "\t\t> #{k} => #{v}"
111
+ end
112
+ end
113
+
114
+ print_spacer
115
+ end
116
+
117
+ private
118
+
119
+ # @param [String] title
120
+ def print_title(title)
121
+ log_info title.bold.underline
122
+ print_spacer
123
+ end
124
+
125
+ # @param [String] descriptor
126
+ # @param [String,nil] remedy
127
+ def print_empty(descriptor, remedy=nil)
128
+ log_info "No #{descriptor} specified.".italic
129
+ log_info "[Remedy: #{remedy}]" unless remedy.nil?
130
+ end
131
+
132
+ def print_spacer
133
+ log_info ""
134
+ end
135
+ end
136
+ end
@@ -19,6 +19,10 @@ module Cure
19
19
  def _replace_value(source_value, generated_value)
20
20
  source_value + generated_value
21
21
  end
22
+
23
+ def _describe
24
+ "Append generated value to the end of source value"
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -2,47 +2,10 @@
2
2
 
3
3
  require "singleton"
4
4
  require "cure/validators"
5
+ require "cure/strategy/history/history_cache"
5
6
 
6
7
  module Cure
7
8
  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
9
  class BaseStrategy
47
10
  include History
48
11
 
@@ -57,17 +20,18 @@ module Cure
57
20
  end
58
21
 
59
22
  # @param [String] source_value
23
+ # @param [Transformation::RowCtx,nil] row_ctx
60
24
  # @param [Generator::BaseGenerator] generator
61
25
  # @return [String]
62
26
  #
63
27
  # This will retrieve the (partial) value, then generate a new replacement.
64
- def extract(source_value, generator)
28
+ def extract(source_value, row_ctx, generator)
65
29
  extracted_value = _retrieve_value(source_value)
66
-
67
30
  existing = retrieve_history(extracted_value)
68
- return _replace_value(source_value, existing) if existing
69
31
 
70
- generated_value = generator.generate(source_value)&.to_s
32
+ return _replace_value(source_value, existing) if existing && !@params.force_replace
33
+
34
+ generated_value = generator.generate(source_value, row_ctx)&.to_s
71
35
  value = _replace_value(source_value, generated_value)
72
36
 
73
37
  store_history(extracted_value, generated_value)
@@ -75,6 +39,10 @@ module Cure
75
39
  value
76
40
  end
77
41
 
42
+ def describe
43
+ _describe
44
+ end
45
+
78
46
  private
79
47
 
80
48
  def replace_partial_record
@@ -99,6 +67,10 @@ module Cure
99
67
  def _replace_value(_source_value, _generated_value)
100
68
  raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
101
69
  end
70
+
71
+ def _describe
72
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
73
+ end
102
74
  end
103
75
 
104
76
  class BaseStrategyParams
@@ -108,11 +80,14 @@ module Cure
108
80
  # Additional details needed to make substitution.
109
81
  # @return [Hash]
110
82
  attr_accessor :options
111
- attr_accessor :replace_partial
83
+ attr_accessor :replace_partial, :force_replace
112
84
 
113
85
  def initialize(options={})
114
- @replace_partial = options["replace_partial"] || "false"
86
+ @replace_partial = options[:replace_partial] || false
87
+ @force_replace = options[:force_replace] || false
115
88
  @options = options
89
+
90
+ validate_params
116
91
  end
117
92
 
118
93
  def validate_params
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class ContainStrategy < BaseStrategy
8
+ # Additional details needed to make substitution.
9
+ # @return [ContainStrategyParams]
10
+ attr_accessor :params
11
+
12
+ def initialize(options)
13
+ super(ContainStrategyParams.new(options))
14
+ end
15
+
16
+ # @param [String] source_value
17
+ def _retrieve_value(source_value)
18
+ return unless source_value.include?(@params.match)
19
+
20
+ @params.match
21
+ end
22
+
23
+ # @param [String] source_value
24
+ # @param [String] generated_value
25
+ # @return [String]
26
+ def _replace_value(source_value, generated_value)
27
+ return unless source_value.include?(@params.match)
28
+
29
+ source_value.gsub(@params.match, generated_value)
30
+ end
31
+
32
+ def _describe
33
+ "Replacing matched value on '#{@params.match}') " \
34
+ "[Note: If the value does not include '#{@params.match}', no substitution is made.]"
35
+ end
36
+ end
37
+
38
+ class ContainStrategyParams < BaseStrategyParams
39
+ attr_reader :match
40
+
41
+ validates :match, validator: :presence
42
+
43
+ def initialize(options=nil)
44
+ @match = options[:match]
45
+ # valid?
46
+
47
+ super(options)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -30,6 +30,12 @@ module Cure
30
30
  generated_value + @params.match
31
31
  # generated_value + source_value.reverse.chomp(@options["match"].reverse).reverse
32
32
  end
33
+
34
+ def _describe
35
+ "End with replacement will look for '#{@params.match}'. " \
36
+ "It will do a #{replace_partial_record ? "partial" : "full"} replacement. " \
37
+ "[Note: If the value does not include '#{@params.match}', no substitution is made.]"
38
+ end
33
39
  end
34
40
 
35
41
  class EndWithStrategyParams < BaseStrategyParams
@@ -38,7 +44,7 @@ module Cure
38
44
  validates :match
39
45
 
40
46
  def initialize(options=nil)
41
- @match = options["match"]
47
+ @match = options[:match]
42
48
  super(options)
43
49
  end
44
50
  end
@@ -19,6 +19,10 @@ module Cure
19
19
  def _replace_value(_source_value, generated_value)
20
20
  generated_value
21
21
  end
22
+
23
+ def _describe
24
+ "Full replacement of source value with generated value."
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/database"
4
+
5
+ # Singleton Strategy for storing data across all processes
6
+
7
+ module Cure
8
+ module History
9
+
10
+ # @return [HistoryCache]
11
+ def history
12
+ HistoryCache.instance
13
+ end
14
+
15
+ # @return [String]
16
+ def retrieve_history(source_value)
17
+ history.search(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
+ unless source_value.nil? || source_value == ""
24
+ history.insert(source_value, value)
25
+ end
26
+ end
27
+
28
+ def reset_history
29
+ history.reset
30
+ end
31
+ alias clear_history reset_history
32
+
33
+ class HistoryCache
34
+ include Database
35
+ include Singleton
36
+
37
+ attr_accessor :count
38
+
39
+ def initialize
40
+ @count = 0
41
+
42
+ init_cache
43
+ end
44
+
45
+ # @return [String]
46
+ def search(source_value, _named_range: nil, _column: nil)
47
+ database_service.find_translation(source_value)
48
+ end
49
+
50
+ def insert(source_value, value, named_range: nil, column: nil)
51
+ @count += 1
52
+
53
+ database_service.insert_row(:translations, [
54
+ @count, source_value, value, named_range, column
55
+ ])
56
+ end
57
+
58
+ def all_values
59
+ database_service.all_translations
60
+ end
61
+
62
+ def reset
63
+ @count = 0
64
+ if database_service.table_exist?(:translations)
65
+ database_service.truncate_table(:translations)
66
+ else
67
+ init_cache
68
+ end
69
+ end
70
+
71
+ def table_count
72
+ database_service.table_count(:translations)
73
+ end
74
+
75
+ def init_cache
76
+ return if database_service.table_exist?(:translations)
77
+
78
+ database_service.create_table(:translations, %w[source_value value named_range column])
79
+ end
80
+ end
81
+ end
82
+ end
@@ -8,3 +8,5 @@ require "cure/strategy/regex_strategy"
8
8
  require "cure/strategy/split_strategy"
9
9
  require "cure/strategy/start_with_strategy"
10
10
  require "cure/strategy/append_strategy"
11
+ require "cure/strategy/prepend_strategy"
12
+ require "cure/strategy/contain_strategy"
@@ -23,10 +23,15 @@ module Cure
23
23
  # @param [String] generated_value
24
24
  # @return [String]
25
25
  def _replace_value(source_value, generated_value)
26
- return unless source_value.include? @params.match
26
+ return source_value unless source_value.include? @params.match
27
27
 
28
28
  source_value.gsub(@params.match, generated_value)
29
29
  end
30
+
31
+ def _describe
32
+ "Match replacement will look for the presence of '#{@params.match}', and replace that value. " \
33
+ "[Note: If the value does not include '#{@params.match}', no substitution is made.]"
34
+ end
30
35
  end
31
36
 
32
37
  class MatchStrategyParams < BaseStrategyParams
@@ -35,7 +40,7 @@ module Cure
35
40
  validates :match
36
41
 
37
42
  def initialize(options=nil)
38
- @match = options["match"]
43
+ @match = options[:match]
39
44
  super(options)
40
45
  end
41
46
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/strategy/base_strategy"
4
+
5
+ module Cure
6
+ module Strategy
7
+ class PrependStrategy < 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 + source_value
21
+ end
22
+
23
+ def _describe
24
+ "Prepend generated value to the end of source value"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -33,6 +33,12 @@ module Cure
33
33
 
34
34
  source_value.gsub(m[1], generated_value)
35
35
  end
36
+
37
+ def _describe
38
+ "Matching on '#{@params.regex_cg}'. " \
39
+ "[Note: If the regex does not match, or has no capture group, no substitution is made.]"
40
+ end
41
+
36
42
  end
37
43
 
38
44
  class RegexStrategyParams < BaseStrategyParams
@@ -41,7 +47,7 @@ module Cure
41
47
  validates :regex_cg
42
48
 
43
49
  def initialize(options=nil)
44
- @regex_cg = options["regex_cg"]
50
+ @regex_cg = options[:regex_cg]
45
51
  super(options)
46
52
  end
47
53
  end