csvops 0.8.0.alpha → 1.0.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -6
  3. data/docs/architecture.md +3 -0
  4. data/docs/cli-output-conventions.md +49 -0
  5. data/docs/release-v0.9.0-alpha.md +80 -0
  6. data/docs/release-v1.0.0.md +80 -0
  7. data/lib/csvtool/cli.rb +132 -12
  8. data/lib/csvtool/interface/cli/menu_loop.rb +6 -5
  9. data/lib/csvtool/interface/cli/output/color_policy.rb +25 -0
  10. data/lib/csvtool/interface/cli/output/colorizer.rb +27 -0
  11. data/lib/csvtool/interface/cli/output/formatters/csv_row_formatter.rb +19 -0
  12. data/lib/csvtool/interface/cli/output/formatters/stats_formatter.rb +57 -0
  13. data/lib/csvtool/interface/cli/output/streams.rb +22 -0
  14. data/lib/csvtool/interface/cli/output/table_renderer.rb +70 -0
  15. data/lib/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter.rb +17 -5
  16. data/lib/csvtool/interface/cli/workflows/presenters/csv_parity_presenter.rb +15 -4
  17. data/lib/csvtool/interface/cli/workflows/presenters/csv_split_presenter.rb +15 -6
  18. data/lib/csvtool/interface/cli/workflows/presenters/csv_stats_presenter.rb +18 -9
  19. data/lib/csvtool/interface/cli/workflows/presenters/row_extraction_presenter.rb +5 -4
  20. data/lib/csvtool/interface/cli/workflows/presenters/row_randomization_presenter.rb +5 -4
  21. data/lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb +9 -8
  22. data/lib/csvtool/interface/cli/workflows/run_csv_parity_workflow.rb +6 -5
  23. data/lib/csvtool/interface/cli/workflows/run_csv_split_workflow.rb +11 -10
  24. data/lib/csvtool/interface/cli/workflows/run_csv_stats_workflow.rb +7 -6
  25. data/lib/csvtool/interface/cli/workflows/run_extraction_workflow.rb +9 -8
  26. data/lib/csvtool/interface/cli/workflows/run_row_extraction_workflow.rb +7 -6
  27. data/lib/csvtool/interface/cli/workflows/run_row_randomization_workflow.rb +8 -7
  28. data/lib/csvtool/version.rb +1 -1
  29. data/test/csvtool/cli_test.rb +289 -44
  30. data/test/csvtool/cli_unit_test.rb +5 -5
  31. data/test/csvtool/interface/cli/output/color_policy_test.rb +40 -0
  32. data/test/csvtool/interface/cli/output/colorizer_test.rb +28 -0
  33. data/test/csvtool/interface/cli/output/formatters/csv_row_formatter_test.rb +22 -0
  34. data/test/csvtool/interface/cli/output/formatters/stats_formatter_test.rb +51 -0
  35. data/test/csvtool/interface/cli/output/streams_test.rb +25 -0
  36. data/test/csvtool/interface/cli/output/table_renderer_test.rb +36 -0
  37. data/test/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter_test.rb +4 -1
  38. data/test/csvtool/interface/cli/workflows/presenters/csv_parity_presenter_test.rb +5 -1
  39. data/test/csvtool/interface/cli/workflows/presenters/csv_split_presenter_test.rb +22 -4
  40. data/test/csvtool/interface/cli/workflows/presenters/csv_stats_presenter_test.rb +7 -5
  41. data/test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb +10 -7
  42. data/test/csvtool/interface/cli/workflows/run_csv_parity_workflow_test.rb +3 -1
  43. data/test/csvtool/interface/cli/workflows/run_csv_split_workflow_test.rb +5 -3
  44. data/test/csvtool/interface/cli/workflows/run_csv_stats_workflow_test.rb +23 -18
  45. metadata +16 -1
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Csvtool
4
+ module Interface
5
+ module CLI
6
+ module Output
7
+ class Streams
8
+ attr_reader :data, :ui
9
+
10
+ def self.build(data:, ui: data)
11
+ new(data: data, ui: ui)
12
+ end
13
+
14
+ def initialize(data:, ui:)
15
+ @data = data
16
+ @ui = ui
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Csvtool
4
+ module Interface
5
+ module CLI
6
+ module Output
7
+ class TableRenderer
8
+ MIN_COLUMN_WIDTH = 4
9
+
10
+ def render(headers:, rows:, max_width: 80)
11
+ widths = compute_widths(headers, rows)
12
+ widths = fit_widths(widths, max_width)
13
+
14
+ lines = []
15
+ lines << format_row(headers, widths)
16
+ lines << separator(widths)
17
+ rows.each { |row| lines << format_row(row, widths) }
18
+ lines.join("\n")
19
+ end
20
+
21
+ private
22
+
23
+ def compute_widths(headers, rows)
24
+ widths = headers.map { |header| header.to_s.length }
25
+ rows.each do |row|
26
+ row.each_with_index do |cell, index|
27
+ widths[index] = [widths[index], cell.to_s.length].max
28
+ end
29
+ end
30
+ widths
31
+ end
32
+
33
+ def fit_widths(widths, max_width)
34
+ return widths if total_width(widths) <= max_width
35
+
36
+ adjusted = widths.dup
37
+ while total_width(adjusted) > max_width
38
+ index = adjusted.each_with_index.max_by { |width, _i| width }[1]
39
+ break if adjusted[index] <= MIN_COLUMN_WIDTH
40
+
41
+ adjusted[index] -= 1
42
+ end
43
+ adjusted
44
+ end
45
+
46
+ def total_width(widths)
47
+ widths.sum + (3 * (widths.length - 1))
48
+ end
49
+
50
+ def separator(widths)
51
+ widths.map { |width| "-" * width }.join("-+-")
52
+ end
53
+
54
+ def format_row(row, widths)
55
+ row.each_with_index.map do |cell, index|
56
+ truncate(cell.to_s, widths[index]).ljust(widths[index])
57
+ end.join(" | ")
58
+ end
59
+
60
+ def truncate(text, width)
61
+ return text if text.length <= width
62
+ return text[0, width] if width < MIN_COLUMN_WIDTH
63
+
64
+ "#{text[0, width - 3]}..."
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "csv"
3
+ require "csvtool/interface/cli/output/formatters/csv_row_formatter"
4
+ require "csvtool/interface/cli/output/colorizer"
5
+ require "csvtool/interface/cli/output/table_renderer"
4
6
 
5
7
  module Csvtool
6
8
  module Interface
@@ -8,18 +10,22 @@ module Csvtool
8
10
  module Workflows
9
11
  module Presenters
10
12
  class CrossCsvDedupePresenter
11
- def initialize(stdout:, col_sep:)
13
+ def initialize(stdout:, col_sep:, row_formatter: Output::Formatters::CsvRowFormatter.new, colorizer: Output::Colorizer.auto(io: stdout), table_renderer: Output::TableRenderer.new, max_width: 80)
12
14
  @stdout = stdout
13
15
  @col_sep = col_sep
16
+ @row_formatter = row_formatter
17
+ @colorizer = colorizer
18
+ @table_renderer = table_renderer
19
+ @max_width = max_width
14
20
  end
15
21
 
16
22
  def print_header(headers)
17
23
  @stdout.puts
18
- @stdout.puts ::CSV.generate_line(headers, row_sep: "", col_sep: @col_sep).chomp
24
+ @stdout.puts @row_formatter.call(fields: headers, col_sep: @col_sep)
19
25
  end
20
26
 
21
27
  def print_row(fields)
22
- @stdout.puts ::CSV.generate_line(fields, row_sep: "", col_sep: @col_sep).chomp
28
+ @stdout.puts @row_formatter.call(fields: fields, col_sep: @col_sep)
23
29
  end
24
30
 
25
31
  def print_file_written(path)
@@ -27,7 +33,13 @@ module Csvtool
27
33
  end
28
34
 
29
35
  def print_summary(stats)
30
- @stdout.puts "Summary: source_rows=#{stats[:source_rows]} removed_rows=#{stats[:removed_rows]} kept_rows=#{stats[:kept_rows_count]}"
36
+ rows = [
37
+ ["Source rows", stats[:source_rows].to_s],
38
+ ["Removed rows", stats[:removed_rows].to_s],
39
+ ["Kept rows", stats[:kept_rows_count].to_s]
40
+ ]
41
+ @stdout.puts @colorizer.call("Summary", code: "1")
42
+ @stdout.puts @table_renderer.render(headers: ["Metric", "Value"], rows: rows, max_width: @max_width)
31
43
  @stdout.puts "No rows removed; no matching keys found." if stats[:removed_rows].zero?
32
44
  @stdout.puts "All source rows were removed by dedupe." if stats[:source_rows].positive? && stats[:kept_rows_count].zero?
33
45
  end
@@ -1,19 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "csvtool/interface/cli/output/colorizer"
4
+ require "csvtool/interface/cli/output/table_renderer"
5
+
3
6
  module Csvtool
4
7
  module Interface
5
8
  module CLI
6
9
  module Workflows
7
10
  module Presenters
8
11
  class CsvParityPresenter
9
- def initialize(stdout:)
12
+ def initialize(stdout:, colorizer: Output::Colorizer.auto(io: stdout), table_renderer: Output::TableRenderer.new, max_width: 80)
10
13
  @stdout = stdout
14
+ @colorizer = colorizer
15
+ @table_renderer = table_renderer
16
+ @max_width = max_width
11
17
  end
12
18
 
13
19
  def print_summary(data)
14
- @stdout.puts(data[:match] ? "MATCH" : "MISMATCH")
15
- @stdout.puts "Summary: left_rows=#{data[:left_rows]} right_rows=#{data[:right_rows]} " \
16
- "left_only=#{data[:left_only_count]} right_only=#{data[:right_only_count]}"
20
+ @stdout.puts(data[:match] ? @colorizer.call("MATCH", code: "32") : @colorizer.call("MISMATCH", code: "31"))
21
+ rows = [
22
+ ["Left rows", data[:left_rows].to_s],
23
+ ["Right rows", data[:right_rows].to_s],
24
+ ["Left only", data[:left_only_count].to_s],
25
+ ["Right only", data[:right_only_count].to_s]
26
+ ]
27
+ @stdout.puts @table_renderer.render(headers: ["Metric", "Value"], rows: rows, max_width: @max_width)
17
28
  return if data[:match]
18
29
 
19
30
  print_examples("Left-only examples", data[:left_only_examples])
@@ -1,21 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "csvtool/interface/cli/output/colorizer"
4
+ require "csvtool/interface/cli/output/table_renderer"
5
+
3
6
  module Csvtool
4
7
  module Interface
5
8
  module CLI
6
9
  module Workflows
7
10
  module Presenters
8
11
  class CsvSplitPresenter
9
- def initialize(stdout:)
12
+ def initialize(stdout:, colorizer: Output::Colorizer.auto(io: stdout), table_renderer: Output::TableRenderer.new, max_width: 80)
10
13
  @stdout = stdout
14
+ @colorizer = colorizer
15
+ @table_renderer = table_renderer
16
+ @max_width = max_width
11
17
  end
12
18
 
13
19
  def print_summary(data)
14
- @stdout.puts "Split complete."
15
- @stdout.puts "Chunk size: #{data[:chunk_size]}"
16
- @stdout.puts "Data rows: #{data[:data_rows]}"
17
- @stdout.puts "Chunks written: #{data[:chunk_count]}"
18
- @stdout.puts "Manifest: #{data[:manifest_path]}" if data[:manifest_path]
20
+ @stdout.puts @colorizer.call("Split complete.", code: "1;36")
21
+ rows = [
22
+ ["Chunk size", data[:chunk_size].to_s],
23
+ ["Data rows", data[:data_rows].to_s],
24
+ ["Chunks written", data[:chunk_count].to_s]
25
+ ]
26
+ rows << ["Manifest", data[:manifest_path]] if data[:manifest_path]
27
+ @stdout.puts @table_renderer.render(headers: ["Metric", "Value"], rows: rows, max_width: @max_width)
19
28
  data[:chunk_paths].each { |path| @stdout.puts path }
20
29
  end
21
30
  end
@@ -1,26 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "csvtool/interface/cli/output/colorizer"
4
+ require "csvtool/interface/cli/output/table_renderer"
5
+
3
6
  module Csvtool
4
7
  module Interface
5
8
  module CLI
6
9
  module Workflows
7
10
  module Presenters
8
11
  class CsvStatsPresenter
9
- def initialize(stdout:)
12
+ def initialize(stdout:, colorizer: Output::Colorizer.auto(io: stdout), table_renderer: Output::TableRenderer.new, max_width: 80)
10
13
  @stdout = stdout
14
+ @colorizer = colorizer
15
+ @table_renderer = table_renderer
16
+ @max_width = max_width
11
17
  end
12
18
 
13
19
  def print_summary(data)
14
- @stdout.puts "CSV Stats Summary"
15
- @stdout.puts "Rows: #{data[:row_count]}"
16
- @stdout.puts "Columns: #{data[:column_count]}"
17
- @stdout.puts "Headers: #{data[:headers].join(', ')}" unless data[:headers].nil? || data[:headers].empty?
20
+ @stdout.puts @colorizer.call("CSV Stats Summary", code: "1;36")
21
+ rows = [
22
+ ["Rows", data[:row_count].to_s],
23
+ ["Columns", data[:column_count].to_s]
24
+ ]
25
+ rows << ["Headers", data[:headers].join(", ")] unless data[:headers].nil? || data[:headers].empty?
26
+ @stdout.puts @table_renderer.render(headers: ["Metric", "Value"], rows: rows, max_width: @max_width)
18
27
  return if data[:column_stats].nil? || data[:column_stats].empty?
19
28
 
20
- @stdout.puts "Column completeness:"
21
- data[:column_stats].each do |stats|
22
- @stdout.puts " #{stats[:name]}: non_blank=#{stats[:non_blank_count]} blank=#{stats[:blank_count]}"
23
- end
29
+ @stdout.puts
30
+ @stdout.puts @colorizer.call("Column completeness:", code: "1")
31
+ stat_rows = data[:column_stats].map { |stats| [stats[:name], stats[:non_blank_count].to_s, stats[:blank_count].to_s] }
32
+ @stdout.puts @table_renderer.render(headers: ["Column", "Non-blank", "Blank"], rows: stat_rows, max_width: @max_width)
24
33
  end
25
34
 
26
35
  def print_file_written(path)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "csv"
3
+ require "csvtool/interface/cli/output/formatters/csv_row_formatter"
4
4
 
5
5
  module Csvtool
6
6
  module Interface
@@ -8,19 +8,20 @@ module Csvtool
8
8
  module Workflows
9
9
  module Presenters
10
10
  class RowExtractionPresenter
11
- def initialize(stdout:, headers:, col_sep:)
11
+ def initialize(stdout:, headers:, col_sep:, row_formatter: Output::Formatters::CsvRowFormatter.new)
12
12
  @stdout = stdout
13
13
  @headers = headers
14
14
  @col_sep = col_sep
15
+ @row_formatter = row_formatter
15
16
  @printed_header = false
16
17
  end
17
18
 
18
19
  def print_row(fields)
19
20
  unless @printed_header
20
- @stdout.puts ::CSV.generate_line(@headers, row_sep: "", col_sep: @col_sep).chomp
21
+ @stdout.puts @row_formatter.call(fields: @headers, col_sep: @col_sep)
21
22
  @printed_header = true
22
23
  end
23
- @stdout.puts ::CSV.generate_line(fields, row_sep: "", col_sep: @col_sep).chomp
24
+ @stdout.puts @row_formatter.call(fields: fields, col_sep: @col_sep)
24
25
  end
25
26
 
26
27
  def print_file_written(path)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "csv"
3
+ require "csvtool/interface/cli/output/formatters/csv_row_formatter"
4
4
 
5
5
  module Csvtool
6
6
  module Interface
@@ -8,19 +8,20 @@ module Csvtool
8
8
  module Workflows
9
9
  module Presenters
10
10
  class RowRandomizationPresenter
11
- def initialize(stdout:, headers:, col_sep:)
11
+ def initialize(stdout:, headers:, col_sep:, row_formatter: Output::Formatters::CsvRowFormatter.new)
12
12
  @stdout = stdout
13
13
  @headers = headers
14
14
  @col_sep = col_sep
15
+ @row_formatter = row_formatter
15
16
  end
16
17
 
17
18
  def print_console_start
18
19
  @stdout.puts
19
- @stdout.puts ::CSV.generate_line(@headers, row_sep: "", col_sep: @col_sep).chomp if @headers
20
+ @stdout.puts @row_formatter.call(fields: @headers, col_sep: @col_sep) if @headers
20
21
  end
21
22
 
22
23
  def print_row(fields)
23
- @stdout.puts ::CSV.generate_line(fields, row_sep: "", col_sep: @col_sep).chomp
24
+ @stdout.puts @row_formatter.call(fields: fields, col_sep: @col_sep)
24
25
  end
25
26
 
26
27
  def print_file_written(path)
@@ -23,11 +23,12 @@ module Csvtool
23
23
  module CLI
24
24
  module Workflows
25
25
  class RunCrossCsvDedupeWorkflow
26
- def initialize(stdin:, stdout:, use_case: Application::UseCases::RunCrossCsvDedupe.new)
26
+ def initialize(stdin:, stdout:, stderr: stdout, use_case: Application::UseCases::RunCrossCsvDedupe.new)
27
27
  @stdin = stdin
28
28
  @stdout = stdout
29
+ @stderr = stderr
29
30
  @use_case = use_case
30
- @errors = Interface::CLI::Errors::Presenter.new(stdout: stdout)
31
+ @errors = Interface::CLI::Errors::Presenter.new(stdout: @stderr)
31
32
  @session_builder = Builders::CrossCsvDedupeSessionBuilder.new
32
33
  @output_destination_mapper = Support::OutputDestinationMapper.new
33
34
  @result_error_handler = Support::ResultErrorHandler.new(errors: @errors)
@@ -44,17 +45,17 @@ module Csvtool
44
45
 
45
46
  pipeline = Steps::WorkflowStepPipeline.new(steps: [
46
47
  Steps::CrossCsvDedupe::CollectProfilesStep.new(
47
- file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stdout),
48
- separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors),
49
- headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stdout),
48
+ file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stderr),
49
+ separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors),
50
+ headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stderr),
50
51
  errors: @errors
51
52
  ),
52
53
  Steps::CrossCsvDedupe::CollectOptionsStep.new(
53
- selector_prompt: Interface::CLI::Prompts::DedupeKeySelectorPrompt.new(stdin: @stdin, stdout: @stdout),
54
- yes_no_prompt: Interface::CLI::Prompts::YesNoPrompt.new(stdin: @stdin, stdout: @stdout),
54
+ selector_prompt: Interface::CLI::Prompts::DedupeKeySelectorPrompt.new(stdin: @stdin, stdout: @stderr),
55
+ yes_no_prompt: Interface::CLI::Prompts::YesNoPrompt.new(stdin: @stdin, stdout: @stderr),
55
56
  output_destination_prompt: Interface::CLI::Prompts::OutputDestinationPrompt.new(
56
57
  stdin: @stdin,
57
- stdout: @stdout,
58
+ stdout: @stderr,
58
59
  errors: @errors
59
60
  ),
60
61
  errors: @errors
@@ -18,11 +18,12 @@ module Csvtool
18
18
  module CLI
19
19
  module Workflows
20
20
  class RunCsvParityWorkflow
21
- def initialize(stdin:, stdout:, use_case: Application::UseCases::RunCsvParity.new)
21
+ def initialize(stdin:, stdout:, stderr: stdout, use_case: Application::UseCases::RunCsvParity.new)
22
22
  @stdin = stdin
23
23
  @stdout = stdout
24
+ @stderr = stderr
24
25
  @use_case = use_case
25
- @errors = Interface::CLI::Errors::Presenter.new(stdout: stdout)
26
+ @errors = Interface::CLI::Errors::Presenter.new(stdout: @stderr)
26
27
  @session_builder = Builders::CsvParitySessionBuilder.new
27
28
  @presenter = Presenters::CsvParityPresenter.new(stdout: stdout)
28
29
  @result_error_handler = Support::ResultErrorHandler.new(errors: @errors)
@@ -37,9 +38,9 @@ module Csvtool
37
38
  }
38
39
  pipeline = Steps::WorkflowStepPipeline.new(steps: [
39
40
  Steps::Parity::CollectInputsStep.new(
40
- file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stdout),
41
- separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors),
42
- headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stdout)
41
+ file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stderr),
42
+ separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors),
43
+ headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stderr)
43
44
  ),
44
45
  Steps::Parity::BuildSessionStep.new,
45
46
  Steps::Parity::ExecuteStep.new
@@ -24,11 +24,12 @@ module Csvtool
24
24
  module CLI
25
25
  module Workflows
26
26
  class RunCsvSplitWorkflow
27
- def initialize(stdin:, stdout:, use_case: Application::UseCases::RunCsvSplit.new)
27
+ def initialize(stdin:, stdout:, stderr: stdout, use_case: Application::UseCases::RunCsvSplit.new)
28
28
  @stdin = stdin
29
29
  @stdout = stdout
30
+ @stderr = stderr
30
31
  @use_case = use_case
31
- @errors = Interface::CLI::Errors::Presenter.new(stdout: stdout)
32
+ @errors = Interface::CLI::Errors::Presenter.new(stdout: @stderr)
32
33
  @session_builder = Builders::CsvSplitSessionBuilder.new
33
34
  @presenter = Presenters::CsvSplitPresenter.new(stdout: stdout)
34
35
  @result_error_handler = Support::ResultErrorHandler.new(errors: @errors)
@@ -43,24 +44,24 @@ module Csvtool
43
44
  }
44
45
  pipeline = Steps::WorkflowStepPipeline.new(steps: [
45
46
  Steps::CsvSplit::CollectInputsStep.new(
46
- file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stdout),
47
- separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors),
48
- headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stdout),
49
- chunk_size_prompt: Interface::CLI::Prompts::ChunkSizePrompt.new(stdin: @stdin, stdout: @stdout),
47
+ file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stderr),
48
+ separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors),
49
+ headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stderr),
50
+ chunk_size_prompt: Interface::CLI::Prompts::ChunkSizePrompt.new(stdin: @stdin, stdout: @stderr),
50
51
  errors: @errors
51
52
  ),
52
53
  Steps::CsvSplit::CollectOutputStep.new(
53
54
  split_output_prompt: Interface::CLI::Prompts::SplitOutputPrompt.new(
54
55
  stdin: @stdin,
55
- stdout: @stdout,
56
- yes_no_prompt: Interface::CLI::Prompts::YesNoPrompt.new(stdin: @stdin, stdout: @stdout)
56
+ stdout: @stderr,
57
+ yes_no_prompt: Interface::CLI::Prompts::YesNoPrompt.new(stdin: @stdin, stdout: @stderr)
57
58
  )
58
59
  ),
59
60
  Steps::CsvSplit::CollectManifestStep.new(
60
61
  split_manifest_prompt: Interface::CLI::Prompts::SplitManifestPrompt.new(
61
62
  stdin: @stdin,
62
- stdout: @stdout,
63
- yes_no_prompt: Interface::CLI::Prompts::YesNoPrompt.new(stdin: @stdin, stdout: @stdout)
63
+ stdout: @stderr,
64
+ yes_no_prompt: Interface::CLI::Prompts::YesNoPrompt.new(stdin: @stdin, stdout: @stderr)
64
65
  )
65
66
  ),
66
67
  Steps::CsvSplit::BuildSessionStep.new,
@@ -21,11 +21,12 @@ module Csvtool
21
21
  module CLI
22
22
  module Workflows
23
23
  class RunCsvStatsWorkflow
24
- def initialize(stdin:, stdout:, use_case: Application::UseCases::RunCsvStats.new)
24
+ def initialize(stdin:, stdout:, stderr: stdout, use_case: Application::UseCases::RunCsvStats.new)
25
25
  @stdin = stdin
26
26
  @stdout = stdout
27
+ @stderr = stderr
27
28
  @use_case = use_case
28
- @errors = Interface::CLI::Errors::Presenter.new(stdout: stdout)
29
+ @errors = Interface::CLI::Errors::Presenter.new(stdout: @stderr)
29
30
  @session_builder = Builders::CsvStatsSessionBuilder.new
30
31
  @presenter = Presenters::CsvStatsPresenter.new(stdout: stdout)
31
32
  @output_destination_mapper = Support::OutputDestinationMapper.new
@@ -42,14 +43,14 @@ module Csvtool
42
43
  }
43
44
  pipeline = Steps::WorkflowStepPipeline.new(steps: [
44
45
  Steps::CsvStats::CollectInputsStep.new(
45
- file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stdout),
46
- separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors),
47
- headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stdout)
46
+ file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stderr),
47
+ separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors),
48
+ headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stderr)
48
49
  ),
49
50
  Steps::CsvStats::CollectDestinationStep.new(
50
51
  output_destination_prompt: Interface::CLI::Prompts::OutputDestinationPrompt.new(
51
52
  stdin: @stdin,
52
- stdout: @stdout,
53
+ stdout: @stderr,
53
54
  errors: @errors
54
55
  )
55
56
  ),
@@ -23,11 +23,12 @@ module Csvtool
23
23
  module CLI
24
24
  module Workflows
25
25
  class RunExtractionWorkflow
26
- def initialize(stdin:, stdout:, use_case: Application::UseCases::RunExtraction.new)
26
+ def initialize(stdin:, stdout:, stderr: stdout, use_case: Application::UseCases::RunExtraction.new)
27
27
  @stdin = stdin
28
28
  @stdout = stdout
29
+ @stderr = stderr
29
30
  @use_case = use_case
30
- @errors = Interface::CLI::Errors::Presenter.new(stdout: stdout)
31
+ @errors = Interface::CLI::Errors::Presenter.new(stdout: @stderr)
31
32
  @session_builder = Builders::ColumnSessionBuilder.new
32
33
  @presenter = Presenters::ColumnExtractionPresenter.new(stdout: @stdout)
33
34
  @output_destination_mapper = Support::OutputDestinationMapper.new
@@ -45,18 +46,18 @@ module Csvtool
45
46
 
46
47
  pipeline = Steps::WorkflowStepPipeline.new(steps: [
47
48
  Steps::Extraction::CollectInputsStep.new(
48
- file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stdout),
49
- separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors),
50
- column_selector_prompt: Interface::CLI::Prompts::ColumnSelectorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors),
51
- skip_blanks_prompt: Interface::CLI::Prompts::SkipBlanksPrompt.new(stdin: @stdin, stdout: @stdout)
49
+ file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stderr),
50
+ separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors),
51
+ column_selector_prompt: Interface::CLI::Prompts::ColumnSelectorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors),
52
+ skip_blanks_prompt: Interface::CLI::Prompts::SkipBlanksPrompt.new(stdin: @stdin, stdout: @stderr)
52
53
  ),
53
54
  Steps::Extraction::BuildPreviewStep.new(
54
- confirm_prompt: Interface::CLI::Prompts::ConfirmPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors)
55
+ confirm_prompt: Interface::CLI::Prompts::ConfirmPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors)
55
56
  ),
56
57
  Steps::Extraction::CollectDestinationStep.new(
57
58
  output_destination_prompt: Interface::CLI::Prompts::OutputDestinationPrompt.new(
58
59
  stdin: @stdin,
59
- stdout: @stdout,
60
+ stdout: @stderr,
60
61
  errors: @errors
61
62
  )
62
63
  ),
@@ -21,11 +21,12 @@ module Csvtool
21
21
  module CLI
22
22
  module Workflows
23
23
  class RunRowExtractionWorkflow
24
- def initialize(stdin:, stdout:, use_case: Application::UseCases::RunRowExtraction.new)
24
+ def initialize(stdin:, stdout:, stderr: stdout, use_case: Application::UseCases::RunRowExtraction.new)
25
25
  @stdin = stdin
26
26
  @stdout = stdout
27
+ @stderr = stderr
27
28
  @use_case = use_case
28
- @errors = Interface::CLI::Errors::Presenter.new(stdout: stdout)
29
+ @errors = Interface::CLI::Errors::Presenter.new(stdout: @stderr)
29
30
  @session_builder = Builders::RowExtractionSessionBuilder.new
30
31
  @output_destination_mapper = Support::OutputDestinationMapper.new
31
32
  @result_error_handler = Support::ResultErrorHandler.new(errors: @errors)
@@ -41,15 +42,15 @@ module Csvtool
41
42
 
42
43
  pipeline = Steps::WorkflowStepPipeline.new(steps: [
43
44
  Steps::RowExtraction::CollectSourceStep.new(
44
- file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stdout),
45
- separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors)
45
+ file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stderr),
46
+ separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors)
46
47
  ),
47
48
  Steps::RowExtraction::ReadHeadersStep.new,
48
- Steps::RowExtraction::CollectRangeStep.new(stdin: @stdin, stdout: @stdout),
49
+ Steps::RowExtraction::CollectRangeStep.new(stdin: @stdin, stdout: @stderr),
49
50
  Steps::RowExtraction::CollectDestinationStep.new(
50
51
  output_destination_prompt: Interface::CLI::Prompts::OutputDestinationPrompt.new(
51
52
  stdin: @stdin,
52
- stdout: @stdout,
53
+ stdout: @stderr,
53
54
  errors: @errors
54
55
  )
55
56
  ),
@@ -20,11 +20,12 @@ module Csvtool
20
20
  module CLI
21
21
  module Workflows
22
22
  class RunRowRandomizationWorkflow
23
- def initialize(stdin:, stdout:, use_case: Application::UseCases::RunRowRandomization.new)
23
+ def initialize(stdin:, stdout:, stderr: stdout, use_case: Application::UseCases::RunRowRandomization.new)
24
24
  @stdin = stdin
25
25
  @stdout = stdout
26
+ @stderr = stderr
26
27
  @use_case = use_case
27
- @errors = Interface::CLI::Errors::Presenter.new(stdout: stdout)
28
+ @errors = Interface::CLI::Errors::Presenter.new(stdout: @stderr)
28
29
  @session_builder = Builders::RowRandomizationSessionBuilder.new
29
30
  @output_destination_mapper = Support::OutputDestinationMapper.new
30
31
  @result_error_handler = Support::ResultErrorHandler.new(errors: @errors)
@@ -41,15 +42,15 @@ module Csvtool
41
42
 
42
43
  pipeline = Steps::WorkflowStepPipeline.new(steps: [
43
44
  Steps::RowRandomization::CollectInputsStep.new(
44
- file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stdout),
45
- separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors),
46
- headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stdout),
47
- seed_prompt: Interface::CLI::Prompts::SeedPrompt.new(stdin: @stdin, stdout: @stdout, errors: @errors)
45
+ file_path_prompt: Interface::CLI::Prompts::FilePathPrompt.new(stdin: @stdin, stdout: @stderr),
46
+ separator_prompt: Interface::CLI::Prompts::SeparatorPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors),
47
+ headers_present_prompt: Interface::CLI::Prompts::HeadersPresentPrompt.new(stdin: @stdin, stdout: @stderr),
48
+ seed_prompt: Interface::CLI::Prompts::SeedPrompt.new(stdin: @stdin, stdout: @stderr, errors: @errors)
48
49
  ),
49
50
  Steps::RowRandomization::CollectDestinationStep.new(
50
51
  output_destination_prompt: Interface::CLI::Prompts::OutputDestinationPrompt.new(
51
52
  stdin: @stdin,
52
- stdout: @stdout,
53
+ stdout: @stderr,
53
54
  errors: @errors
54
55
  )
55
56
  ),
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Csvtool
4
- VERSION = "0.8.0.alpha"
4
+ VERSION = "1.0.0"
5
5
  end