csvops 0.7.0.alpha → 0.9.0.alpha

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +80 -20
  3. data/docs/architecture.md +67 -4
  4. data/docs/cli-output-conventions.md +49 -0
  5. data/docs/release-v0.8.0-alpha.md +88 -0
  6. data/docs/release-v0.9.0-alpha.md +80 -0
  7. data/lib/csvtool/application/use_cases/run_csv_stats.rb +64 -0
  8. data/lib/csvtool/cli.rb +136 -12
  9. data/lib/csvtool/domain/csv_stats_session/stats_options.rb +11 -0
  10. data/lib/csvtool/domain/csv_stats_session/stats_session.rb +25 -0
  11. data/lib/csvtool/domain/csv_stats_session/stats_source.rb +17 -0
  12. data/lib/csvtool/infrastructure/csv/csv_stats_scanner.rb +67 -0
  13. data/lib/csvtool/infrastructure/output/csv_stats_file_writer.rb +26 -0
  14. data/lib/csvtool/interface/cli/menu_loop.rb +9 -5
  15. data/lib/csvtool/interface/cli/output/color_policy.rb +25 -0
  16. data/lib/csvtool/interface/cli/output/colorizer.rb +27 -0
  17. data/lib/csvtool/interface/cli/output/formatters/csv_row_formatter.rb +19 -0
  18. data/lib/csvtool/interface/cli/output/formatters/stats_formatter.rb +57 -0
  19. data/lib/csvtool/interface/cli/output/streams.rb +22 -0
  20. data/lib/csvtool/interface/cli/output/table_renderer.rb +70 -0
  21. data/lib/csvtool/interface/cli/workflows/builders/csv_stats_session_builder.rb +28 -0
  22. data/lib/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter.rb +17 -5
  23. data/lib/csvtool/interface/cli/workflows/presenters/csv_parity_presenter.rb +15 -4
  24. data/lib/csvtool/interface/cli/workflows/presenters/csv_split_presenter.rb +15 -6
  25. data/lib/csvtool/interface/cli/workflows/presenters/csv_stats_presenter.rb +43 -0
  26. data/lib/csvtool/interface/cli/workflows/presenters/row_extraction_presenter.rb +5 -4
  27. data/lib/csvtool/interface/cli/workflows/presenters/row_randomization_presenter.rb +5 -4
  28. data/lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb +9 -8
  29. data/lib/csvtool/interface/cli/workflows/run_csv_parity_workflow.rb +6 -5
  30. data/lib/csvtool/interface/cli/workflows/run_csv_split_workflow.rb +11 -10
  31. data/lib/csvtool/interface/cli/workflows/run_csv_stats_workflow.rb +78 -0
  32. data/lib/csvtool/interface/cli/workflows/run_extraction_workflow.rb +9 -8
  33. data/lib/csvtool/interface/cli/workflows/run_row_extraction_workflow.rb +7 -6
  34. data/lib/csvtool/interface/cli/workflows/run_row_randomization_workflow.rb +8 -7
  35. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/build_session_step.rb +25 -0
  36. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/collect_destination_step.rb +27 -0
  37. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/collect_inputs_step.rb +31 -0
  38. data/lib/csvtool/interface/cli/workflows/steps/csv_stats/execute_step.rb +27 -0
  39. data/lib/csvtool/version.rb +1 -1
  40. data/test/csvtool/application/use_cases/run_csv_stats_test.rb +165 -0
  41. data/test/csvtool/cli_test.rb +376 -68
  42. data/test/csvtool/cli_unit_test.rb +5 -5
  43. data/test/csvtool/infrastructure/csv/csv_stats_scanner_test.rb +68 -0
  44. data/test/csvtool/infrastructure/output/csv_stats_file_writer_test.rb +38 -0
  45. data/test/csvtool/interface/cli/menu_loop_test.rb +34 -11
  46. data/test/csvtool/interface/cli/output/color_policy_test.rb +40 -0
  47. data/test/csvtool/interface/cli/output/colorizer_test.rb +28 -0
  48. data/test/csvtool/interface/cli/output/formatters/csv_row_formatter_test.rb +22 -0
  49. data/test/csvtool/interface/cli/output/formatters/stats_formatter_test.rb +51 -0
  50. data/test/csvtool/interface/cli/output/streams_test.rb +25 -0
  51. data/test/csvtool/interface/cli/output/table_renderer_test.rb +36 -0
  52. data/test/csvtool/interface/cli/workflows/builders/csv_stats_session_builder_test.rb +19 -0
  53. data/test/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter_test.rb +4 -1
  54. data/test/csvtool/interface/cli/workflows/presenters/csv_parity_presenter_test.rb +5 -1
  55. data/test/csvtool/interface/cli/workflows/presenters/csv_split_presenter_test.rb +22 -4
  56. data/test/csvtool/interface/cli/workflows/presenters/csv_stats_presenter_test.rb +39 -0
  57. data/test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb +10 -7
  58. data/test/csvtool/interface/cli/workflows/run_csv_parity_workflow_test.rb +3 -1
  59. data/test/csvtool/interface/cli/workflows/run_csv_split_workflow_test.rb +5 -3
  60. data/test/csvtool/interface/cli/workflows/run_csv_stats_workflow_test.rb +151 -0
  61. data/test/csvtool/interface/cli/workflows/steps/csv_stats/build_session_step_test.rb +36 -0
  62. data/test/csvtool/interface/cli/workflows/steps/csv_stats/collect_destination_step_test.rb +49 -0
  63. data/test/csvtool/interface/cli/workflows/steps/csv_stats/collect_inputs_step_test.rb +61 -0
  64. data/test/csvtool/interface/cli/workflows/steps/csv_stats/execute_step_test.rb +65 -0
  65. metadata +39 -1
@@ -38,7 +38,10 @@ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
38
38
  assert_includes output.string, "3,Cara"
39
39
  refute_includes output.string, "2,Bob"
40
40
  refute_includes output.string, "4,Dan"
41
- assert_includes output.string, "Summary: source_rows=5 removed_rows=3 kept_rows=2"
41
+ assert_includes output.string, "Summary"
42
+ assert_includes output.string, "Source rows"
43
+ assert_includes output.string, "Removed rows"
44
+ assert_includes output.string, "Kept rows"
42
45
  end
43
46
 
44
47
  def test_can_write_deduped_rows_to_file
@@ -67,7 +70,7 @@ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
67
70
 
68
71
  assert_includes output.string, "Wrote output to #{output_path}"
69
72
  assert_equal "customer_id,name\n1,Alice\n3,Cara\n", File.read(output_path)
70
- assert_includes output.string, "Summary: source_rows=5 removed_rows=3 kept_rows=2"
73
+ assert_includes output.string, "Summary"
71
74
  end
72
75
  end
73
76
 
@@ -119,7 +122,7 @@ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
119
122
  refute_includes output.string, "customer_id,name"
120
123
  assert_includes output.string, "1,Alice"
121
124
  assert_includes output.string, "3,Cara"
122
- assert_includes output.string, "Summary: source_rows=5 removed_rows=3 kept_rows=2"
125
+ assert_includes output.string, "Summary"
123
126
  end
124
127
 
125
128
  def test_reports_column_not_found_when_missing
@@ -164,7 +167,7 @@ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
164
167
  .new(stdin: StringIO.new(input), stdout: output)
165
168
  .call
166
169
 
167
- assert_includes output.string, "Summary: source_rows=5 removed_rows=0 kept_rows=5"
170
+ assert_includes output.string, "Summary"
168
171
  assert_includes output.string, "No rows removed; no matching keys found."
169
172
  end
170
173
 
@@ -188,7 +191,7 @@ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
188
191
  .new(stdin: StringIO.new(input), stdout: output)
189
192
  .call
190
193
 
191
- assert_includes output.string, "Summary: source_rows=5 removed_rows=5 kept_rows=0"
194
+ assert_includes output.string, "Summary"
192
195
  assert_includes output.string, "All source rows were removed by dedupe."
193
196
  end
194
197
 
@@ -215,7 +218,7 @@ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
215
218
  refute_includes output.string, " A1 ,Alice"
216
219
  refute_includes output.string, "c3,Cara"
217
220
  assert_includes output.string, "B2,Bob"
218
- assert_includes output.string, "Summary: source_rows=3 removed_rows=2 kept_rows=1"
221
+ assert_includes output.string, "Summary"
219
222
  end
220
223
 
221
224
  def test_normalization_disabled_preserves_exact_match_behavior
@@ -241,6 +244,6 @@ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
241
244
  assert_includes output.string, " A1 ,Alice"
242
245
  assert_includes output.string, "B2,Bob"
243
246
  assert_includes output.string, "c3,Cara"
244
- assert_includes output.string, "Summary: source_rows=3 removed_rows=0 kept_rows=3"
247
+ assert_includes output.string, "Summary"
245
248
  end
246
249
  end
@@ -62,7 +62,9 @@ class RunCsvParityWorkflowTest < Minitest::Test
62
62
  assert_includes stdout.string, "Choose separator:"
63
63
  assert_includes stdout.string, "Headers present? [Y/n]: "
64
64
  assert_includes stdout.string, "MATCH"
65
- assert_includes stdout.string, "Summary: left_rows=3 right_rows=3 left_only=0 right_only=0"
65
+ assert_includes stdout.string, "Metric"
66
+ assert_includes stdout.string, "Left rows"
67
+ assert_includes stdout.string, "Right rows"
66
68
  end
67
69
 
68
70
  def test_prints_mismatch_examples_when_not_equal
@@ -24,8 +24,9 @@ class RunCsvSplitWorkflowTest < Minitest::Test
24
24
  ).call
25
25
 
26
26
  assert_includes out.string, "Split complete."
27
- assert_includes out.string, "Chunk size: 10"
28
- assert_includes out.string, "Chunks written: 3"
27
+ assert_includes out.string, "Metric"
28
+ assert_includes out.string, "Chunk size"
29
+ assert_includes out.string, "Chunks written"
29
30
  assert File.file?(File.join(dir, "people_part_001.csv"))
30
31
  assert File.file?(File.join(dir, "people_part_002.csv"))
31
32
  assert File.file?(File.join(dir, "people_part_003.csv"))
@@ -194,7 +195,8 @@ class RunCsvSplitWorkflowTest < Minitest::Test
194
195
  assert_includes lines[1], ",10"
195
196
  assert_includes lines[2], ",10"
196
197
  assert_includes lines[3], ",5"
197
- assert_includes out.string, "Manifest: #{manifest_path}"
198
+ assert_includes out.string, "Manifest"
199
+ assert_includes out.string, "manifest.csv"
198
200
  end
199
201
  end
200
202
  end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/run_csv_stats_workflow"
5
+ require "tmpdir"
6
+
7
+ class RunCsvStatsWorkflowTest < Minitest::Test
8
+ def fixture_path(name)
9
+ File.expand_path("../../../../fixtures/#{name}", __dir__)
10
+ end
11
+
12
+ def test_workflow_prints_core_stats_summary
13
+ out = StringIO.new
14
+ input = [fixture_path("sample_people.csv"), "", ""].join("\n") + "\n"
15
+
16
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
17
+ stdin: StringIO.new(input),
18
+ stdout: out
19
+ ).call
20
+
21
+ assert_includes out.string, "CSV Stats Summary"
22
+ assert_includes out.string, "Metric"
23
+ assert_includes out.string, "Rows"
24
+ assert_includes out.string, "Columns"
25
+ assert_includes out.string, "Headers"
26
+ assert_includes out.string, "Column completeness:"
27
+ assert_includes out.string, "name"
28
+ assert_includes out.string, "city"
29
+ end
30
+
31
+ def test_workflow_supports_tsv_separator
32
+ out = StringIO.new
33
+ input = [fixture_path("sample_people.tsv"), "2", ""].join("\n") + "\n"
34
+
35
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
36
+ stdin: StringIO.new(input),
37
+ stdout: out
38
+ ).call
39
+
40
+ assert_includes out.string, "Rows"
41
+ assert_includes out.string, "Columns"
42
+ assert_includes out.string, "Headers"
43
+ end
44
+
45
+ def test_workflow_supports_headerless_mode
46
+ out = StringIO.new
47
+ input = [fixture_path("sample_people_no_headers.csv"), "", "n"].join("\n") + "\n"
48
+
49
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
50
+ stdin: StringIO.new(input),
51
+ stdout: out
52
+ ).call
53
+
54
+ assert_includes out.string, "Rows"
55
+ assert_includes out.string, "Columns"
56
+ refute_includes out.string, "Headers |"
57
+ assert_includes out.string, "column_1"
58
+ assert_includes out.string, "column_2"
59
+ end
60
+
61
+ def test_workflow_supports_custom_separator
62
+ out = StringIO.new
63
+ input = [fixture_path("sample_people_colon.txt"), "5", ":", ""].join("\n") + "\n"
64
+
65
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
66
+ stdin: StringIO.new(input),
67
+ stdout: out
68
+ ).call
69
+
70
+ assert_includes out.string, "Rows"
71
+ assert_includes out.string, "Columns"
72
+ assert_includes out.string, "Headers"
73
+ end
74
+
75
+ def test_workflow_prints_column_completeness_for_blank_values
76
+ out = StringIO.new
77
+ input = [fixture_path("sample_people_blanks.csv"), "", ""].join("\n") + "\n"
78
+
79
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
80
+ stdin: StringIO.new(input),
81
+ stdout: out
82
+ ).call
83
+
84
+ assert_includes out.string, "name"
85
+ assert_includes out.string, "3"
86
+ assert_includes out.string, "2"
87
+ assert_includes out.string, "city"
88
+ assert_includes out.string, "4"
89
+ assert_includes out.string, "1"
90
+ end
91
+
92
+ def test_workflow_reports_missing_file
93
+ out = StringIO.new
94
+ input = ["/tmp/does-not-exist.csv", "", ""].join("\n") + "\n"
95
+
96
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
97
+ stdin: StringIO.new(input),
98
+ stdout: out
99
+ ).call
100
+
101
+ assert_includes out.string, "File not found: /tmp/does-not-exist.csv"
102
+ refute_includes out.string, "Traceback"
103
+ end
104
+
105
+ def test_workflow_reports_parse_error
106
+ out = StringIO.new
107
+ input = [fixture_path("sample_people_bad_tail.csv"), "", ""].join("\n") + "\n"
108
+
109
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
110
+ stdin: StringIO.new(input),
111
+ stdout: out
112
+ ).call
113
+
114
+ assert_includes out.string, "Could not parse CSV file."
115
+ refute_includes out.string, "Traceback"
116
+ end
117
+
118
+ def test_workflow_can_write_stats_to_file
119
+ out = StringIO.new
120
+
121
+ Dir.mktmpdir do |dir|
122
+ output_path = File.join(dir, "stats.csv")
123
+ input = [fixture_path("sample_people.csv"), "", "", "2", output_path].join("\n") + "\n"
124
+
125
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
126
+ stdin: StringIO.new(input),
127
+ stdout: out
128
+ ).call
129
+
130
+ assert_includes out.string, "Wrote output to #{output_path}"
131
+ csv_text = File.read(output_path)
132
+ assert_includes csv_text, "metric,value"
133
+ assert_includes csv_text, "row_count,3"
134
+ assert_includes csv_text, "column_count,2"
135
+ end
136
+ end
137
+
138
+ def test_workflow_reports_cannot_write_output_file
139
+ out = StringIO.new
140
+ output_path = "/tmp/does-not-exist-dir/stats.csv"
141
+ input = [fixture_path("sample_people.csv"), "", "", "2", output_path].join("\n") + "\n"
142
+
143
+ Csvtool::Interface::CLI::Workflows::RunCsvStatsWorkflow.new(
144
+ stdin: StringIO.new(input),
145
+ stdout: out
146
+ ).call
147
+
148
+ assert_includes out.string, "Cannot write output file: #{output_path} (Errno::ENOENT)"
149
+ refute_includes out.string, "Traceback"
150
+ end
151
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/steps/csv_stats/build_session_step"
5
+
6
+ class CsvStatsBuildSessionStepTest < Minitest::Test
7
+ class FakeBuilder
8
+ attr_reader :params
9
+
10
+ def call(**params)
11
+ @params = params
12
+ :session
13
+ end
14
+ end
15
+
16
+ def test_builds_session_from_context
17
+ builder = FakeBuilder.new
18
+ step = Csvtool::Interface::CLI::Workflows::Steps::CsvStats::BuildSessionStep.new
19
+ context = {
20
+ session_builder: builder,
21
+ file_path: "/tmp/data.csv",
22
+ col_sep: "\t",
23
+ headers_present: true,
24
+ output_destination: :destination
25
+ }
26
+
27
+ result = step.call(context)
28
+
29
+ assert_nil result
30
+ assert_equal :session, context[:session]
31
+ assert_equal "/tmp/data.csv", builder.params[:file_path]
32
+ assert_equal "\t", builder.params[:col_sep]
33
+ assert_equal true, builder.params[:headers_present]
34
+ assert_equal :destination, builder.params[:destination]
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/steps/csv_stats/collect_destination_step"
5
+
6
+ class CsvStatsCollectDestinationStepTest < Minitest::Test
7
+ class FakePrompt
8
+ def initialize(result)
9
+ @result = result
10
+ end
11
+
12
+ def call
13
+ @result
14
+ end
15
+ end
16
+
17
+ class FakeMapper
18
+ attr_reader :input
19
+
20
+ def call(input)
21
+ @input = input
22
+ :mapped_destination
23
+ end
24
+ end
25
+
26
+ def test_collects_and_maps_destination
27
+ mapper = FakeMapper.new
28
+ step = Csvtool::Interface::CLI::Workflows::Steps::CsvStats::CollectDestinationStep.new(
29
+ output_destination_prompt: FakePrompt.new({ mode: :file, path: "/tmp/out.csv" })
30
+ )
31
+ context = { output_destination_mapper: mapper }
32
+
33
+ result = step.call(context)
34
+
35
+ assert_nil result
36
+ assert_equal({ mode: :file, path: "/tmp/out.csv" }, mapper.input)
37
+ assert_equal :mapped_destination, context[:output_destination]
38
+ end
39
+
40
+ def test_halts_when_destination_prompt_returns_nil
41
+ step = Csvtool::Interface::CLI::Workflows::Steps::CsvStats::CollectDestinationStep.new(
42
+ output_destination_prompt: FakePrompt.new(nil)
43
+ )
44
+
45
+ result = step.call(output_destination_mapper: FakeMapper.new)
46
+
47
+ assert_equal :halt, result
48
+ end
49
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/steps/csv_stats/collect_inputs_step"
5
+
6
+ class CsvStatsCollectInputsStepTest < Minitest::Test
7
+ class FakeFilePathPrompt
8
+ attr_reader :label
9
+
10
+ def call(label:)
11
+ @label = label
12
+ "/tmp/input.csv"
13
+ end
14
+ end
15
+
16
+ class FakeSeparatorPrompt
17
+ def initialize(result)
18
+ @result = result
19
+ end
20
+
21
+ def call
22
+ @result
23
+ end
24
+ end
25
+
26
+ class FakeHeadersPresentPrompt
27
+ def call
28
+ false
29
+ end
30
+ end
31
+
32
+ def test_collects_inputs_into_context
33
+ file_prompt = FakeFilePathPrompt.new
34
+ step = Csvtool::Interface::CLI::Workflows::Steps::CsvStats::CollectInputsStep.new(
35
+ file_path_prompt: file_prompt,
36
+ separator_prompt: FakeSeparatorPrompt.new(";"),
37
+ headers_present_prompt: FakeHeadersPresentPrompt.new
38
+ )
39
+ context = {}
40
+
41
+ result = step.call(context)
42
+
43
+ assert_nil result
44
+ assert_equal "CSV file path: ", file_prompt.label
45
+ assert_equal "/tmp/input.csv", context[:file_path]
46
+ assert_equal ";", context[:col_sep]
47
+ assert_equal false, context[:headers_present]
48
+ end
49
+
50
+ def test_halts_when_separator_prompt_returns_nil
51
+ step = Csvtool::Interface::CLI::Workflows::Steps::CsvStats::CollectInputsStep.new(
52
+ file_path_prompt: FakeFilePathPrompt.new,
53
+ separator_prompt: FakeSeparatorPrompt.new(nil),
54
+ headers_present_prompt: FakeHeadersPresentPrompt.new
55
+ )
56
+
57
+ result = step.call({})
58
+
59
+ assert_equal :halt, result
60
+ end
61
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/steps/csv_stats/execute_step"
5
+
6
+ class CsvStatsExecuteStepTest < Minitest::Test
7
+ Result = Struct.new(:ok, :data) do
8
+ def ok? = ok
9
+ end
10
+
11
+ class FakeUseCase
12
+ def initialize(result)
13
+ @result = result
14
+ end
15
+
16
+ def call(session:)
17
+ @result
18
+ end
19
+ end
20
+
21
+ class FakePresenter
22
+ attr_reader :summary_data, :written_path
23
+
24
+ def print_summary(data)
25
+ @summary_data = data
26
+ end
27
+
28
+ def print_file_written(path)
29
+ @written_path = path
30
+ end
31
+ end
32
+
33
+ def test_prints_summary_and_file_path_when_present
34
+ presenter = FakePresenter.new
35
+ result = Result.new(true, { row_count: 2, output_path: "/tmp/stats.csv" })
36
+ step = Csvtool::Interface::CLI::Workflows::Steps::CsvStats::ExecuteStep.new
37
+
38
+ outcome = step.call(
39
+ session: :session,
40
+ use_case: FakeUseCase.new(result),
41
+ presenter: presenter,
42
+ handle_error: ->(_result) { raise "unexpected" }
43
+ )
44
+
45
+ assert_nil outcome
46
+ assert_equal result.data, presenter.summary_data
47
+ assert_equal "/tmp/stats.csv", presenter.written_path
48
+ end
49
+
50
+ def test_halts_on_use_case_failure
51
+ fail_result = Result.new(false, { reason: :bad })
52
+ handled = []
53
+ step = Csvtool::Interface::CLI::Workflows::Steps::CsvStats::ExecuteStep.new
54
+
55
+ outcome = step.call(
56
+ session: :session,
57
+ use_case: FakeUseCase.new(fail_result),
58
+ presenter: FakePresenter.new,
59
+ handle_error: ->(result) { handled << result }
60
+ )
61
+
62
+ assert_equal :halt, outcome
63
+ assert_equal [fail_result], handled
64
+ end
65
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csvops
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.alpha
4
+ version: 0.9.0.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Hall
@@ -68,6 +68,7 @@ files:
68
68
  - bin/tool
69
69
  - csvops.gemspec
70
70
  - docs/architecture.md
71
+ - docs/cli-output-conventions.md
71
72
  - docs/release-v0.1.0-alpha.md
72
73
  - docs/release-v0.2.0-alpha.md
73
74
  - docs/release-v0.3.0-alpha.md
@@ -75,10 +76,13 @@ files:
75
76
  - docs/release-v0.5.0-alpha.md
76
77
  - docs/release-v0.6.0-alpha.md
77
78
  - docs/release-v0.7.0-alpha.md
79
+ - docs/release-v0.8.0-alpha.md
80
+ - docs/release-v0.9.0-alpha.md
78
81
  - exe/csvtool
79
82
  - lib/csvtool/application/use_cases/run_cross_csv_dedupe.rb
80
83
  - lib/csvtool/application/use_cases/run_csv_parity.rb
81
84
  - lib/csvtool/application/use_cases/run_csv_split.rb
85
+ - lib/csvtool/application/use_cases/run_csv_stats.rb
82
86
  - lib/csvtool/application/use_cases/run_extraction.rb
83
87
  - lib/csvtool/application/use_cases/run_row_extraction.rb
84
88
  - lib/csvtool/application/use_cases/run_row_randomization.rb
@@ -101,6 +105,9 @@ files:
101
105
  - lib/csvtool/domain/csv_split_session/split_options.rb
102
106
  - lib/csvtool/domain/csv_split_session/split_session.rb
103
107
  - lib/csvtool/domain/csv_split_session/split_source.rb
108
+ - lib/csvtool/domain/csv_stats_session/stats_options.rb
109
+ - lib/csvtool/domain/csv_stats_session/stats_session.rb
110
+ - lib/csvtool/domain/csv_stats_session/stats_source.rb
104
111
  - lib/csvtool/domain/row_randomization_session/randomization_options.rb
105
112
  - lib/csvtool/domain/row_randomization_session/randomization_session.rb
106
113
  - lib/csvtool/domain/row_randomization_session/randomization_source.rb
@@ -111,6 +118,7 @@ files:
111
118
  - lib/csvtool/infrastructure/csv/cross_csv_deduper.rb
112
119
  - lib/csvtool/infrastructure/csv/csv_parity_comparator.rb
113
120
  - lib/csvtool/infrastructure/csv/csv_splitter.rb
121
+ - lib/csvtool/infrastructure/csv/csv_stats_scanner.rb
114
122
  - lib/csvtool/infrastructure/csv/header_reader.rb
115
123
  - lib/csvtool/infrastructure/csv/row_randomizer.rb
116
124
  - lib/csvtool/infrastructure/csv/row_streamer.rb
@@ -123,8 +131,15 @@ files:
123
131
  - lib/csvtool/infrastructure/output/csv_row_console_writer.rb
124
132
  - lib/csvtool/infrastructure/output/csv_row_file_writer.rb
125
133
  - lib/csvtool/infrastructure/output/csv_split_manifest_writer.rb
134
+ - lib/csvtool/infrastructure/output/csv_stats_file_writer.rb
126
135
  - lib/csvtool/interface/cli/errors/presenter.rb
127
136
  - lib/csvtool/interface/cli/menu_loop.rb
137
+ - lib/csvtool/interface/cli/output/color_policy.rb
138
+ - lib/csvtool/interface/cli/output/colorizer.rb
139
+ - lib/csvtool/interface/cli/output/formatters/csv_row_formatter.rb
140
+ - lib/csvtool/interface/cli/output/formatters/stats_formatter.rb
141
+ - lib/csvtool/interface/cli/output/streams.rb
142
+ - lib/csvtool/interface/cli/output/table_renderer.rb
128
143
  - lib/csvtool/interface/cli/prompts/chunk_size_prompt.rb
129
144
  - lib/csvtool/interface/cli/prompts/column_selector_prompt.rb
130
145
  - lib/csvtool/interface/cli/prompts/confirm_prompt.rb
@@ -142,17 +157,20 @@ files:
142
157
  - lib/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder.rb
143
158
  - lib/csvtool/interface/cli/workflows/builders/csv_parity_session_builder.rb
144
159
  - lib/csvtool/interface/cli/workflows/builders/csv_split_session_builder.rb
160
+ - lib/csvtool/interface/cli/workflows/builders/csv_stats_session_builder.rb
145
161
  - lib/csvtool/interface/cli/workflows/builders/row_extraction_session_builder.rb
146
162
  - lib/csvtool/interface/cli/workflows/builders/row_randomization_session_builder.rb
147
163
  - lib/csvtool/interface/cli/workflows/presenters/column_extraction_presenter.rb
148
164
  - lib/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter.rb
149
165
  - lib/csvtool/interface/cli/workflows/presenters/csv_parity_presenter.rb
150
166
  - lib/csvtool/interface/cli/workflows/presenters/csv_split_presenter.rb
167
+ - lib/csvtool/interface/cli/workflows/presenters/csv_stats_presenter.rb
151
168
  - lib/csvtool/interface/cli/workflows/presenters/row_extraction_presenter.rb
152
169
  - lib/csvtool/interface/cli/workflows/presenters/row_randomization_presenter.rb
153
170
  - lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb
154
171
  - lib/csvtool/interface/cli/workflows/run_csv_parity_workflow.rb
155
172
  - lib/csvtool/interface/cli/workflows/run_csv_split_workflow.rb
173
+ - lib/csvtool/interface/cli/workflows/run_csv_stats_workflow.rb
156
174
  - lib/csvtool/interface/cli/workflows/run_extraction_workflow.rb
157
175
  - lib/csvtool/interface/cli/workflows/run_row_extraction_workflow.rb
158
176
  - lib/csvtool/interface/cli/workflows/run_row_randomization_workflow.rb
@@ -164,6 +182,10 @@ files:
164
182
  - lib/csvtool/interface/cli/workflows/steps/csv_split/collect_manifest_step.rb
165
183
  - lib/csvtool/interface/cli/workflows/steps/csv_split/collect_output_step.rb
166
184
  - lib/csvtool/interface/cli/workflows/steps/csv_split/execute_step.rb
185
+ - lib/csvtool/interface/cli/workflows/steps/csv_stats/build_session_step.rb
186
+ - lib/csvtool/interface/cli/workflows/steps/csv_stats/collect_destination_step.rb
187
+ - lib/csvtool/interface/cli/workflows/steps/csv_stats/collect_inputs_step.rb
188
+ - lib/csvtool/interface/cli/workflows/steps/csv_stats/execute_step.rb
167
189
  - lib/csvtool/interface/cli/workflows/steps/extraction/build_preview_step.rb
168
190
  - lib/csvtool/interface/cli/workflows/steps/extraction/collect_destination_step.rb
169
191
  - lib/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step.rb
@@ -188,6 +210,7 @@ files:
188
210
  - test/csvtool/application/use_cases/run_cross_csv_dedupe_test.rb
189
211
  - test/csvtool/application/use_cases/run_csv_parity_test.rb
190
212
  - test/csvtool/application/use_cases/run_csv_split_test.rb
213
+ - test/csvtool/application/use_cases/run_csv_stats_test.rb
191
214
  - test/csvtool/application/use_cases/run_extraction_test.rb
192
215
  - test/csvtool/application/use_cases/run_row_extraction_test.rb
193
216
  - test/csvtool/application/use_cases/run_row_randomization_test.rb
@@ -218,6 +241,7 @@ files:
218
241
  - test/csvtool/infrastructure/csv/cross_csv_deduper_test.rb
219
242
  - test/csvtool/infrastructure/csv/csv_parity_comparator_test.rb
220
243
  - test/csvtool/infrastructure/csv/csv_splitter_test.rb
244
+ - test/csvtool/infrastructure/csv/csv_stats_scanner_test.rb
221
245
  - test/csvtool/infrastructure/csv/header_reader_test.rb
222
246
  - test/csvtool/infrastructure/csv/row_randomizer_test.rb
223
247
  - test/csvtool/infrastructure/csv/row_streamer_test.rb
@@ -230,8 +254,15 @@ files:
230
254
  - test/csvtool/infrastructure/output/csv_row_console_writer_test.rb
231
255
  - test/csvtool/infrastructure/output/csv_row_file_writer_test.rb
232
256
  - test/csvtool/infrastructure/output/csv_split_manifest_writer_test.rb
257
+ - test/csvtool/infrastructure/output/csv_stats_file_writer_test.rb
233
258
  - test/csvtool/interface/cli/errors/presenter_test.rb
234
259
  - test/csvtool/interface/cli/menu_loop_test.rb
260
+ - test/csvtool/interface/cli/output/color_policy_test.rb
261
+ - test/csvtool/interface/cli/output/colorizer_test.rb
262
+ - test/csvtool/interface/cli/output/formatters/csv_row_formatter_test.rb
263
+ - test/csvtool/interface/cli/output/formatters/stats_formatter_test.rb
264
+ - test/csvtool/interface/cli/output/streams_test.rb
265
+ - test/csvtool/interface/cli/output/table_renderer_test.rb
235
266
  - test/csvtool/interface/cli/prompts/chunk_size_prompt_test.rb
236
267
  - test/csvtool/interface/cli/prompts/column_selector_prompt_test.rb
237
268
  - test/csvtool/interface/cli/prompts/confirm_prompt_test.rb
@@ -249,17 +280,20 @@ files:
249
280
  - test/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder_test.rb
250
281
  - test/csvtool/interface/cli/workflows/builders/csv_parity_session_builder_test.rb
251
282
  - test/csvtool/interface/cli/workflows/builders/csv_split_session_builder_test.rb
283
+ - test/csvtool/interface/cli/workflows/builders/csv_stats_session_builder_test.rb
252
284
  - test/csvtool/interface/cli/workflows/builders/row_extraction_session_builder_test.rb
253
285
  - test/csvtool/interface/cli/workflows/builders/row_randomization_session_builder_test.rb
254
286
  - test/csvtool/interface/cli/workflows/presenters/column_extraction_presenter_test.rb
255
287
  - test/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter_test.rb
256
288
  - test/csvtool/interface/cli/workflows/presenters/csv_parity_presenter_test.rb
257
289
  - test/csvtool/interface/cli/workflows/presenters/csv_split_presenter_test.rb
290
+ - test/csvtool/interface/cli/workflows/presenters/csv_stats_presenter_test.rb
258
291
  - test/csvtool/interface/cli/workflows/presenters/row_extraction_presenter_test.rb
259
292
  - test/csvtool/interface/cli/workflows/presenters/row_randomization_presenter_test.rb
260
293
  - test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb
261
294
  - test/csvtool/interface/cli/workflows/run_csv_parity_workflow_test.rb
262
295
  - test/csvtool/interface/cli/workflows/run_csv_split_workflow_test.rb
296
+ - test/csvtool/interface/cli/workflows/run_csv_stats_workflow_test.rb
263
297
  - test/csvtool/interface/cli/workflows/run_extraction_workflow_test.rb
264
298
  - test/csvtool/interface/cli/workflows/run_row_extraction_workflow_test.rb
265
299
  - test/csvtool/interface/cli/workflows/run_row_randomization_workflow_test.rb
@@ -269,6 +303,10 @@ files:
269
303
  - test/csvtool/interface/cli/workflows/steps/csv_split/collect_manifest_step_test.rb
270
304
  - test/csvtool/interface/cli/workflows/steps/csv_split/collect_output_step_test.rb
271
305
  - test/csvtool/interface/cli/workflows/steps/csv_split/execute_step_test.rb
306
+ - test/csvtool/interface/cli/workflows/steps/csv_stats/build_session_step_test.rb
307
+ - test/csvtool/interface/cli/workflows/steps/csv_stats/collect_destination_step_test.rb
308
+ - test/csvtool/interface/cli/workflows/steps/csv_stats/collect_inputs_step_test.rb
309
+ - test/csvtool/interface/cli/workflows/steps/csv_stats/execute_step_test.rb
272
310
  - test/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step_test.rb
273
311
  - test/csvtool/interface/cli/workflows/steps/parity/build_session_step_test.rb
274
312
  - test/csvtool/interface/cli/workflows/steps/parity/collect_inputs_step_test.rb