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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4991d1e0e8328be48a27ab4ed1dc099cc57f0b0ebd1ae1add6763fca4908d9c3
4
- data.tar.gz: 477a17c2ba7052657d54facea23056f9ad07068b6e3596810da4ae7cfb79d51a
3
+ metadata.gz: 29e7c915346b45c1407208f6ba1810ece68004c8d7dd9ffb8eb2b5dcca903b35
4
+ data.tar.gz: c356c649bc4a902fcb347e9e16f2299f4c8a7c0db576a7fc8242d080b575920d
5
5
  SHA512:
6
- metadata.gz: ee5600adcd1052493ef5db828cc43830e5d758dfb153d849afddb1f3e7a209606036cc238d425081d3d9724ed4cb3d9ee7466dd49df6b80c37711ab25aa53172
7
- data.tar.gz: d49ccb85c6bfc5414b666f49395683ef2a751ff7af19c2f380af94aebdda835de8c8cd8bc4dbca17c426d91cb64a2254b35456b204e7327352ba8de97a232747
6
+ metadata.gz: 5999a52c084656af0a6a18ba68884aec3de825be9f84f5c67cdf771031af414789aaebf24dfc9fed52f6a76b9a9495081f0f4e1c0f872927fbe34c271fa86e62
7
+ data.tar.gz: 458962e9905380ef0e5832ef9e2ae2da1ede47f448992314bceba95c997c2af3bb4d6f2b92e1f23e906563c77ad1fbcd37d171d75732cf29c15b6b9b0e05e5bc
data/.rubocop.yml CHANGED
@@ -26,6 +26,9 @@ Metrics/ClassLength:
26
26
  Layout/SpaceAroundEqualsInParameterDefault:
27
27
  EnforcedStyle: no_space
28
28
 
29
+ Layout/EmptyLinesAroundClassBody:
30
+ Enabled: false
31
+
29
32
  # We do not need to support Ruby 1.9, so this is good to use.
30
33
  Style/SymbolArray:
31
34
  Enabled: true
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cure (0.1.1)
4
+ cure (0.1.2)
5
5
  faker
6
6
  rcsv
7
7
 
data/README.md CHANGED
@@ -1,19 +1,29 @@
1
1
  # Cure
2
2
 
3
3
  ![run tests](https://github.com/williamthom-as/cure/actions/workflows/rspec.yml/badge.svg)
4
+ [![Gem Version](https://badge.fury.io/rb/cure.svg)](https://badge.fury.io/rb/cure)
4
5
 
5
- Cure is a simple tool to **remove/redact/anonymize** and **replace** private information in a spreadsheet.
6
- It has been written to anonymize private cloud billing data for use in public demo environments.
6
+ Cure is a simple tool to **extract/clean/transform/remove/redact/anonymize** and **replace** information in a spreadsheet.
7
+ It has been written to anonymize private cloud billing data for use in public demo environments. Since then, it has grown to
8
+ additional processing capabilities that can take a CSV from junk to workable data.
7
9
 
8
10
  It has several key features:
9
- - Define either full or regex match groups replacements.
10
- - Choose from many strategies to replace anonymous data - random number sequences, GUIDs, placeholders, multipliers amongst many others.
11
- - **Existing generated values are stored and recalled** so once a replacement is defined, it is kept around for other columns to use.
12
- - For example, once a replacement **Account Number** is generated, any further use of that number sequence is other columns will be used, keeping data real(ish) and functional in a relational sense.
11
+ - Operate on your data to build what you need.
12
+ - Files are taken through an `Extract -> Build -> Transform -> Export` pipeline.
13
+ - Extract parts of your file into named ranges to remove junk.
14
+ - Build (Add/Remove/Explode) columns - handy for files that may have JSON as a column value.
15
+ - Transform values:
16
+ - Define either full or regex match groups replacements.
17
+ - Choose from many strategies to replace anonymous data - random number sequences, GUIDs, placeholders, multipliers amongst many others.
18
+ - **Existing generated values are stored and recalled** so once a replacement is defined, it is kept around for other columns to use.
19
+ - For example, once a replacement **Account Number** is generated, any further use of that number sequence is other columns will be used, keeping data real(ish) and functional in a relational sense.
20
+ - Export into one (or many) files, in a selection of chosen formats (CSV at the moment, coming soon with JSON, Parquet).
13
21
 
14
22
  ## Use Cases
15
23
 
16
24
  - Strip out personal data from a CSV that may be used for public demo.
25
+ - Extract specific parts of a CSV file and junk the rest.
26
+ - Explode JSON values into individual columns per key.
17
27
 
18
28
  ## Usage
19
29
 
data/exe/cure CHANGED
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ # rubocop:disable Style/MixinUsage
5
+ # rubocop:disable Style/MethodCalledOnDoEndBlock
6
+
4
7
  require "cure"
5
8
  require "optparse"
6
9
 
@@ -34,9 +37,10 @@ OptionParser.new do |opts|
34
37
  end.parse!
35
38
 
36
39
  log_info "Config loaded successfully, initialising environment ..."
37
- main = Cure::Main.init(conf[:template_file_location], conf[:source_file_location], conf[:output_dir])
40
+ main = Cure::Main.init_from_file(conf[:template_file_location], conf[:source_file_location], conf[:output_dir])
38
41
 
39
42
  log_info "... set up complete. Beginning process"
40
- main.process
41
-
43
+ main.run_export
42
44
 
45
+ # rubocop:enable Style/MixinUsage
46
+ # rubocop:enable Style/MethodCalledOnDoEndBlock
data/lib/cure/config.rb CHANGED
@@ -19,16 +19,30 @@ module Cure
19
19
  ConfigurationSource.instance.load_config(request_config)
20
20
  end
21
21
 
22
+ # @param [String] source_file_location
23
+ # @param [Cure::Template] template
24
+ # @param [String] output_dir
22
25
  # @return [Config]
23
26
  def create_config(source_file_location, template, output_dir)
24
27
  Config.new(source_file_location, template, output_dir)
25
28
  end
26
29
 
30
+ # If we are overloading here as a "data store" and "config store", we
31
+ # could break out variables and placeholders into their own singleton.
32
+ #
33
+ # This should be a kind of instance cache, which loads once per run,
34
+ # and junk can be jammed in there?
27
35
  class Config
28
- attr_accessor :source_file_location, :template, :output_dir
36
+ attr_accessor :source_file_location, :output_dir
37
+
38
+ # @return [Cure::Template] template
39
+ attr_accessor :template
40
+
41
+ # @return [Hash] variables
42
+ attr_accessor :variables
29
43
 
30
44
  # @param [String] source_file_location
31
- # @param [Hash] template
45
+ # @param [Cure::Template] template
32
46
  # @param [String] output_dir
33
47
  def initialize(source_file_location, template, output_dir)
34
48
  @source_file_location = source_file_location
@@ -37,7 +51,7 @@ module Cure
37
51
  end
38
52
 
39
53
  def placeholders
40
- @template["placeholders"] || []
54
+ @template.transformations.placeholders || {}
41
55
  end
42
56
  end
43
57
 
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/log"
4
+ require "cure/config"
5
+ require "cure/helpers/file_helpers"
6
+
7
+ require "cure/extract/extractor"
8
+ require "cure/transformation/transform"
9
+ require "cure/export/exporter"
10
+
11
+ require "rcsv"
12
+
13
+ module Cure
14
+ # Coordinates the entire process:
15
+ # Extract -> Build -> Transform -> Export
16
+ class Coordinator
17
+ include Configuration
18
+ include Log
19
+
20
+ def process
21
+ # need to check config is init'd
22
+
23
+ extracted_csv = extract
24
+ built_csv = build(extracted_csv)
25
+ transformed_csv = transform(built_csv)
26
+ export(transformed_csv)
27
+ end
28
+
29
+ private
30
+
31
+ # @return [Cure::Extract::WrappedCSV]
32
+ def extract
33
+ log_info "Beginning the extraction process..."
34
+
35
+ extractor = Extract::Extractor.new({})
36
+ result = extractor.extract_from_file(config.source_file_location)
37
+
38
+ log_debug "Setting extracted variables to global conf for access downstream"
39
+ config.variables = result.variables
40
+
41
+ log_info "...extraction complete"
42
+ result
43
+ end
44
+
45
+ # @param [Cure::Extract::WrappedCSV] wrapped_csv
46
+ def build(wrapped_csv)
47
+ log_info "Beginning the building process..."
48
+ log_info "... building complete"
49
+ wrapped_csv
50
+ end
51
+
52
+ # @return [Hash<String,Cure::Transformation::TransformResult>]
53
+ # @param [Cure::Extract::WrappedCSV] parsed_csv
54
+ def transform(parsed_csv)
55
+ log_info "Beginning the transformation process..."
56
+ transformer = Cure::Transformation::Transform.new(config.template.transformations.candidates)
57
+ content = transformer.transform_content(parsed_csv)
58
+
59
+ log_info "...transform complete"
60
+ content
61
+ end
62
+
63
+ # @return [Hash<String,Cure::Transformation::TransformResult>]
64
+ def export(transformed_result)
65
+ log_info "Beginning export process..."
66
+ Cure::Export::Exporter.export_result(transformed_result, config.output_dir)
67
+ log_info "... export complete."
68
+
69
+ transformed_result
70
+ end
71
+ end
72
+ end
@@ -1,24 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cure/log"
4
- require "cure/file_helpers"
4
+ require "cure/config"
5
+ require "cure/helpers/file_helpers"
5
6
 
6
7
  module Cure
7
8
  module Export
8
9
  class Exporter
9
- include Cure::FileHelpers
10
+ include Helpers::FileHelpers
11
+ include Configuration
10
12
  include Log
11
13
 
12
- def self.export_ctx(ctx, output_dir, file_name)
13
- column_headers = ctx.column_headers.keys
14
+ # @param [Array<Cure::Transform::TransformResult>] result
15
+ def self.export_result(results, output_dir)
16
+ exporter = Exporter.new(output_dir)
17
+ exporter.export_results(results)
18
+ end
19
+
20
+ attr_reader :output_dir
21
+
22
+ def initialize(output_dir)
23
+ @output_dir = output_dir
24
+ end
14
25
 
15
- exporter = Exporter.new
16
- exporter.export(output_dir, file_name, ctx.transformed_rows, column_headers)
26
+ # @param [Array<Cure::Transform::TransformResult>] result
27
+ def export_results(result)
28
+ export_ranges = config.template.dispatch.named_ranges
29
+
30
+ export_ranges.each do |range|
31
+ named_range = range["named_range"]
32
+ unless result.has_key?(named_range)
33
+ raise "Missing named range - #{range} from candidates [#{result.keys.join(", ")}]"
34
+ end
35
+
36
+ data = result[named_range]
37
+ column_headers = data.column_headers.keys
38
+ export(@output_dir, range["file_name"], data.transformed_rows, column_headers)
39
+ end
17
40
  end
18
41
 
19
42
  # @param [Array] rows
20
43
  # @param [Array] columns
21
44
  def export(output_dir, file_name, rows, columns)
45
+ file_name = "#{file_name}-#{Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S%-z")}"
46
+
22
47
  log_info("Exporting file to [#{output_dir}/#{file_name}] with #{rows.length} rows")
23
48
 
24
49
  file_contents = []
@@ -37,7 +62,7 @@ module Cure
37
62
  # @param [String] contents
38
63
  # @param [String] file_extension
39
64
  def write_to_file(file_path, file_name, file_extension, contents)
40
- file_location = "#{file_path}/#{file_name || Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S%-z")}"
65
+ file_location = "#{file_path}/#{file_name}"
41
66
  clean_dir(file_path)
42
67
 
43
68
  with_file(file_location, file_extension) do |file|
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/extract/csv_lookup"
4
+
5
+ module Cure
6
+ module Extract
7
+ class Builder
8
+
9
+ # @param [Hash] opts
10
+ attr_reader :opts
11
+
12
+ # @param [Hash] opts
13
+ def initialize(opts)
14
+ @opts = opts
15
+ end
16
+
17
+ # @param [Array<Array>] _sheet
18
+ # @param [Hash<String, Integer>] _column_headers
19
+ # @return [Array]
20
+ #
21
+ # This returns changed column headers and sheets
22
+ def handle(_sheet, _column_headers)
23
+ []
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cure
4
+ module Extract
5
+ class CsvLookup
6
+
7
+ # @param [String] position - [Ex A1:B1, A1:B1,A2:B2]
8
+ # @return [Array] [column_start_idx, column_end_idx, row_start_idx, row_end_idx]
9
+ def self.array_position_lookup(position)
10
+ return [0, -1, 0, -1] if position.is_a?(Integer) && position == -1 # Whole sheet
11
+
12
+ start, finish, *_excess = position.split(":")
13
+ raise "Invalid format" unless start || finish
14
+
15
+ [
16
+ position_for_letter(start),
17
+ position_for_letter(finish),
18
+ position_for_digit(start),
19
+ position_for_digit(finish)
20
+ ]
21
+ end
22
+
23
+ def self.position_for_letter(range)
24
+ range.upcase.scan(/[A-Z]+/).first.ord - 65 # A (65) - 65 = 0 idx
25
+ end
26
+
27
+ def self.position_for_digit(range)
28
+ range.upcase.scan(/\d+/).first.to_i - 1
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/log"
4
+ require "cure/config"
5
+ require "cure/extract/csv_lookup"
6
+ require "cure/helpers/file_helpers"
7
+
8
+ module Cure
9
+ module Extract
10
+ class Extractor
11
+ include Log
12
+ include Configuration
13
+ include Helpers::FileHelpers
14
+
15
+ # @param [Hash] opts
16
+ attr_reader :opts
17
+
18
+ # @param [Hash] opts
19
+ def initialize(opts)
20
+ @opts = opts
21
+ end
22
+
23
+ # @param [String] csv_file_location
24
+ # @return [WrappedCSV]
25
+ def extract_from_file(csv_file_location)
26
+ file_contents = read_file(csv_file_location)
27
+ extract_from_contents(file_contents)
28
+ end
29
+
30
+ # @param [String] file_contents
31
+ # @return [WrappedCSV]
32
+ def extract_from_contents(file_contents)
33
+ parsed_content = parse_csv(file_contents, header: :none)
34
+ log_info("Parsed CSV into #{parsed_content.content.length} sections.")
35
+ parsed_content
36
+ end
37
+
38
+ # private
39
+
40
+ # @param [String] file_contents
41
+ # @param [Hash] opts
42
+ # @return [WrappedCSV]
43
+ def parse_csv(file_contents, opts={})
44
+ csv_rows = []
45
+
46
+ Rcsv.parse(file_contents, opts) { |row| csv_rows << row }
47
+
48
+ result = WrappedCSV.new
49
+ result.content = extract_named_ranges(csv_rows)
50
+ result.variables = extract_variables(csv_rows)
51
+
52
+ result
53
+ end
54
+
55
+ # @param [Array<Array>] csv_rows
56
+ # @return [Array<Hash>]
57
+ def extract_named_ranges(csv_rows)
58
+ # Use only the NR's that are defined from the candidates list
59
+ candidates = config.template.transformations.candidates
60
+ candidate_nrs = config.template.extraction.required_named_ranges(candidates.map(&:named_range).uniq)
61
+ candidate_nrs.map do |nr|
62
+ {
63
+ "rows" => extract_from_rows(csv_rows, nr["section"]),
64
+ "name" => nr["name"]
65
+ }
66
+ end
67
+ end
68
+
69
+ # @param [Array<Array>] csv_rows
70
+ # @return [Hash]
71
+ def extract_variables(csv_rows)
72
+ config.template.extraction.variables.each_with_object({}) do |variable, hash|
73
+ hash[variable["name"]] = lookup_location(csv_rows, variable["location"])
74
+ end
75
+ end
76
+
77
+ # @param [Array<Array>] rows
78
+ def extract_from_rows(rows, named_range)
79
+ psx = CsvLookup.array_position_lookup(named_range)
80
+
81
+ ret_val = []
82
+ rows.each_with_index do |row, idx|
83
+ # If the position of the end row is -1, we need all,
84
+ # otherwise if its between/equal to start/finish
85
+ ret_val << row[psx[0]..psx[1]] if psx[3] == -1 || (idx >= psx[2] && idx <= psx[3])
86
+ end
87
+
88
+ ret_val
89
+ end
90
+
91
+ # @param [Array<Array>] rows
92
+ # @param [String] variable_location
93
+ def lookup_location(rows, variable_location)
94
+ psx = [CsvLookup.position_for_letter(variable_location),
95
+ CsvLookup.position_for_digit(variable_location)]
96
+ rows[psx[1]][psx[0]]
97
+ end
98
+
99
+ # @param [Integer] row_idx
100
+ # @param [Array] row
101
+ # @param [Array] psx
102
+ # @return [Array, nil]
103
+ def handle_row(row_idx, row, psx)
104
+ return nil unless psx[3] == -1 || (row_idx >= psx[2] && row_idx <= psx[3])
105
+
106
+ row[psx[0]..psx[1]]
107
+ end
108
+ end
109
+
110
+ class WrappedCSV
111
+ # @return [Array<Hash>]
112
+ attr_accessor :content
113
+
114
+ # @return [Hash]
115
+ attr_accessor :variables
116
+
117
+ def initialize
118
+ @content = []
119
+ @variables = {}
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cure
4
+ module Generator
5
+ class BaseGenerator
6
+ # @return [Hash]
7
+ attr_accessor :options
8
+
9
+ def initialize(options={})
10
+ @options = options
11
+ end
12
+
13
+ # @param [Object/Nil] source_value
14
+ # @return [String]
15
+ def generate(source_value=nil)
16
+ translated = _generate(source_value)
17
+ translated = "#{prefix}#{translated}" if prefix
18
+ translated = "#{translated}#{suffix}" if suffix
19
+ translated
20
+ end
21
+
22
+ private
23
+
24
+ # @param [Object/Nil] _source_value
25
+ # @return [String]
26
+ def _generate(_source_value)
27
+ raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
28
+ end
29
+
30
+ def prefix(default=nil)
31
+ extract_property("prefix", default)
32
+ end
33
+
34
+ def suffix(default=nil)
35
+ extract_property("suffix", default)
36
+ end
37
+
38
+ def length(default=nil)
39
+ extract_property("length", default)
40
+ end
41
+
42
+ def property_name(default=nil)
43
+ extract_property("name", default)
44
+ end
45
+
46
+ def extract_property(property, default_val)
47
+ @options.fetch(property, default_val)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/generator/base_generator"
4
+
5
+ module Cure
6
+ module Generator
7
+ class CaseGenerator < BaseGenerator
8
+ private
9
+
10
+ # @param [Object] source_value
11
+ def _generate(source_value)
12
+ result = case_options.fetch("switch").find { |opts| opts["case"] == source_value }&.fetch("return_value", nil)
13
+
14
+ return result if result
15
+
16
+ case_options.fetch("else", {}).fetch("return_value", nil)
17
+ end
18
+
19
+ # @return [Hash]
20
+ def case_options
21
+ @case_options ||= extract_property("statement", nil)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/generator/base_generator"
4
+
5
+ module Cure
6
+ module Generator
7
+ class CharacterGenerator < BaseGenerator
8
+
9
+ def initialize(options=nil)
10
+ super(options)
11
+ end
12
+
13
+ private
14
+
15
+ # @param [Object] source_value
16
+ def _generate(source_value)
17
+ arr = build_options.map(&:to_a).flatten
18
+ (0...length(source_value&.length || 5)).map { arr[rand(arr.length)] }.join
19
+ end
20
+
21
+ def build_options
22
+ return [("a".."z"), ("A".."Z"), (0..9)] unless @options.key?("types")
23
+
24
+ type_array = @options["types"]
25
+
26
+ arr = []
27
+ arr << ("a".."z") if type_array.include? "lowercase"
28
+ arr << ("A".."Z") if type_array.include? "uppercase"
29
+ arr << (0..9) if type_array.include? "number"
30
+ arr << ("!".."+") if type_array.include? "symbol"
31
+ arr
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/generator/base_generator"
4
+ require "faker"
5
+
6
+ module Cure
7
+ module Generator
8
+ class FakerGenerator < BaseGenerator
9
+ private
10
+
11
+ # @param [Object] _source_value
12
+ def _generate(_source_value)
13
+ mod_code = extract_property("module", nil)
14
+ mod = Faker.const_get(mod_code)
15
+
16
+ raise "No Faker module found for [#{mod_code}]" unless mod
17
+
18
+ meth_code = extract_property("method", nil)&.to_sym
19
+ raise "No Faker module found for [#{meth_code}]" unless mod.methods.include?(meth_code)
20
+
21
+ mod.send(meth_code)
22
+ end
23
+ end
24
+ end
25
+ 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 GuidGenerator < BaseGenerator
8
+ private
9
+
10
+ # @param [Object] _source_value
11
+ def _generate(_source_value)
12
+ SecureRandom.uuid.to_s
13
+ end
14
+ end
15
+ end
16
+ 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 HexGenerator < BaseGenerator
8
+ private
9
+
10
+ # @param [Object] _source_value
11
+ def _generate(_source_value)
12
+ 1.upto(length(rand(0..9))).map { rand(0..15).to_s(16) }.join("")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cure/generator/base_generator"
4
+ require "cure/generator/hex_generator"
5
+ require "cure/generator/case_generator"
6
+ require "cure/generator/character_generator"
7
+ require "cure/generator/faker_generator"
8
+ require "cure/generator/guid_generator"
9
+ require "cure/generator/number_generator"
10
+ require "cure/generator/placeholder_generator"
11
+ require "cure/generator/redact_generator"
12
+ require "cure/generator/variable_generator"
@@ -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 NumberGenerator < BaseGenerator
8
+ private
9
+
10
+ # @param [Object] _source_value
11
+ def _generate(_source_value)
12
+ 1.upto(length(rand(0..9))).map { rand(1..9) }.join("").to_i
13
+ end
14
+ end
15
+ end
16
+ end