csvops 0.3.0.alpha → 0.5.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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +69 -149
  3. data/docs/architecture.md +396 -0
  4. data/docs/release-v0.4.0-alpha.md +87 -0
  5. data/docs/release-v0.5.0-alpha.md +89 -0
  6. data/lib/csvtool/application/use_cases/run_cross_csv_dedupe.rb +96 -0
  7. data/lib/csvtool/application/use_cases/run_extraction.rb +63 -88
  8. data/lib/csvtool/application/use_cases/run_row_extraction.rb +45 -73
  9. data/lib/csvtool/application/use_cases/run_row_randomization.rb +56 -73
  10. data/lib/csvtool/cli.rb +11 -7
  11. data/lib/csvtool/domain/cross_csv_dedupe_session/column_selector.rb +44 -0
  12. data/lib/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session.rb +46 -0
  13. data/lib/csvtool/domain/cross_csv_dedupe_session/csv_profile.rb +24 -0
  14. data/lib/csvtool/domain/cross_csv_dedupe_session/key_mapping.rb +22 -0
  15. data/lib/csvtool/domain/cross_csv_dedupe_session/match_options.rb +29 -0
  16. data/lib/csvtool/domain/row_randomization_session/randomization_source.rb +1 -0
  17. data/lib/csvtool/domain/row_session/row_source.rb +3 -0
  18. data/lib/csvtool/domain/{column_session → shared}/output_destination.rb +1 -1
  19. data/lib/csvtool/infrastructure/csv/cross_csv_deduper.rb +85 -0
  20. data/lib/csvtool/infrastructure/csv/selector_validator.rb +30 -0
  21. data/lib/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer.rb +23 -0
  22. data/lib/csvtool/infrastructure/output/csv_file_writer.rb +1 -7
  23. data/lib/csvtool/infrastructure/output/csv_randomized_row_file_writer.rb +23 -0
  24. data/lib/csvtool/infrastructure/output/csv_row_file_writer.rb +2 -9
  25. data/lib/csvtool/interface/cli/menu_loop.rb +5 -2
  26. data/lib/csvtool/interface/cli/prompts/dedupe_key_selector_prompt.rb +30 -0
  27. data/lib/csvtool/interface/cli/prompts/file_path_prompt.rb +4 -2
  28. data/lib/csvtool/interface/cli/prompts/headers_present_prompt.rb +4 -2
  29. data/lib/csvtool/interface/cli/prompts/separator_prompt.rb +4 -2
  30. data/lib/csvtool/interface/cli/prompts/yes_no_prompt.rb +26 -0
  31. data/lib/csvtool/interface/cli/workflows/builders/column_session_builder.rb +32 -0
  32. data/lib/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder.rb +35 -0
  33. data/lib/csvtool/interface/cli/workflows/builders/row_extraction_session_builder.rb +22 -0
  34. data/lib/csvtool/interface/cli/workflows/builders/row_randomization_session_builder.rb +28 -0
  35. data/lib/csvtool/interface/cli/workflows/presenters/column_extraction_presenter.rb +25 -0
  36. data/lib/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter.rb +39 -0
  37. data/lib/csvtool/interface/cli/workflows/presenters/row_extraction_presenter.rb +34 -0
  38. data/lib/csvtool/interface/cli/workflows/presenters/row_randomization_presenter.rb +34 -0
  39. data/lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb +86 -0
  40. data/lib/csvtool/interface/cli/workflows/run_extraction_workflow.rb +88 -0
  41. data/lib/csvtool/interface/cli/workflows/run_row_extraction_workflow.rb +86 -0
  42. data/lib/csvtool/interface/cli/workflows/run_row_randomization_workflow.rb +80 -0
  43. data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step.rb +55 -0
  44. data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_profiles_step.rb +52 -0
  45. data/lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/execute_step.rb +34 -0
  46. data/lib/csvtool/interface/cli/workflows/steps/extraction/build_preview_step.rb +40 -0
  47. data/lib/csvtool/interface/cli/workflows/steps/extraction/collect_destination_step.rb +28 -0
  48. data/lib/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step.rb +47 -0
  49. data/lib/csvtool/interface/cli/workflows/steps/extraction/execute_step.rb +32 -0
  50. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_destination_step.rb +33 -0
  51. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_range_step.rb +35 -0
  52. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step.rb +32 -0
  53. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/execute_step.rb +43 -0
  54. data/lib/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step.rb +29 -0
  55. data/lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_destination_step.rb +34 -0
  56. data/lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step.rb +49 -0
  57. data/lib/csvtool/interface/cli/workflows/steps/row_randomization/execute_step.rb +37 -0
  58. data/lib/csvtool/interface/cli/workflows/steps/workflow_step_pipeline.rb +25 -0
  59. data/lib/csvtool/interface/cli/workflows/support/output_destination_mapper.rb +23 -0
  60. data/lib/csvtool/interface/cli/workflows/support/result_error_handler.rb +22 -0
  61. data/lib/csvtool/version.rb +1 -1
  62. data/test/csvtool/application/use_cases/io_boundary_test.rb +26 -0
  63. data/test/csvtool/application/use_cases/run_cross_csv_dedupe_test.rb +141 -0
  64. data/test/csvtool/application/use_cases/run_extraction_test.rb +72 -16
  65. data/test/csvtool/application/use_cases/run_row_extraction_test.rb +82 -102
  66. data/test/csvtool/application/use_cases/run_row_randomization_test.rb +96 -86
  67. data/test/csvtool/cli_test.rb +130 -16
  68. data/test/csvtool/cli_unit_test.rb +16 -3
  69. data/test/csvtool/domain/column_session/column_session_test.rb +2 -2
  70. data/test/csvtool/domain/column_session/csv_source_test.rb +10 -0
  71. data/test/csvtool/domain/cross_csv_dedupe_session/column_selector_test.rb +42 -0
  72. data/test/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session_test.rb +75 -0
  73. data/test/csvtool/domain/cross_csv_dedupe_session/csv_profile_test.rb +26 -0
  74. data/test/csvtool/domain/cross_csv_dedupe_session/key_mapping_test.rb +31 -0
  75. data/test/csvtool/domain/cross_csv_dedupe_session/match_options_test.rb +52 -0
  76. data/test/csvtool/domain/row_randomization_session/randomization_session_test.rb +2 -2
  77. data/test/csvtool/domain/row_randomization_session/randomization_source_test.rb +15 -1
  78. data/test/csvtool/domain/row_session/row_session_test.rb +2 -2
  79. data/test/csvtool/domain/row_session/row_source_test.rb +16 -0
  80. data/test/csvtool/domain/shared/output_destination_test.rb +24 -0
  81. data/test/csvtool/infrastructure/csv/cross_csv_deduper_test.rb +155 -0
  82. data/test/csvtool/infrastructure/csv/selector_validator_test.rb +72 -0
  83. data/test/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer_test.rb +32 -0
  84. data/test/csvtool/infrastructure/output/csv_file_writer_test.rb +0 -4
  85. data/test/csvtool/infrastructure/output/csv_randomized_row_file_writer_test.rb +32 -0
  86. data/test/csvtool/infrastructure/output/csv_row_file_writer_test.rb +1 -4
  87. data/test/csvtool/interface/cli/menu_loop_test.rb +50 -13
  88. data/test/csvtool/interface/cli/prompts/dedupe_key_selector_prompt_test.rb +30 -0
  89. data/test/csvtool/interface/cli/prompts/file_path_prompt_test.rb +9 -0
  90. data/test/csvtool/interface/cli/prompts/headers_present_prompt_test.rb +10 -0
  91. data/test/csvtool/interface/cli/prompts/separator_prompt_test.rb +10 -0
  92. data/test/csvtool/interface/cli/prompts/yes_no_prompt_test.rb +22 -0
  93. data/test/csvtool/interface/cli/workflows/builders/column_session_builder_test.rb +17 -0
  94. data/test/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder_test.rb +36 -0
  95. data/test/csvtool/interface/cli/workflows/builders/row_extraction_session_builder_test.rb +21 -0
  96. data/test/csvtool/interface/cli/workflows/builders/row_randomization_session_builder_test.rb +26 -0
  97. data/test/csvtool/interface/cli/workflows/presenters/column_extraction_presenter_test.rb +24 -0
  98. data/test/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter_test.rb +30 -0
  99. data/test/csvtool/interface/cli/workflows/presenters/row_extraction_presenter_test.rb +33 -0
  100. data/test/csvtool/interface/cli/workflows/presenters/row_randomization_presenter_test.rb +33 -0
  101. data/test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb +246 -0
  102. data/test/csvtool/interface/cli/workflows/run_extraction_workflow_test.rb +56 -0
  103. data/test/csvtool/interface/cli/workflows/run_row_extraction_workflow_test.rb +83 -0
  104. data/test/csvtool/interface/cli/workflows/run_row_randomization_workflow_test.rb +69 -0
  105. data/test/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step_test.rb +41 -0
  106. data/test/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step_test.rb +66 -0
  107. data/test/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step_test.rb +39 -0
  108. data/test/csvtool/interface/cli/workflows/steps/row_extraction/execute_step_test.rb +91 -0
  109. data/test/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step_test.rb +57 -0
  110. data/test/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step_test.rb +37 -0
  111. data/test/csvtool/interface/cli/workflows/steps/workflow_step_pipeline_test.rb +30 -0
  112. data/test/csvtool/interface/cli/workflows/support/output_destination_mapper_test.rb +23 -0
  113. data/test/csvtool/interface/cli/workflows/support/result_error_handler_test.rb +34 -0
  114. data/test/fixtures/dedupe_reference.csv +3 -0
  115. data/test/fixtures/dedupe_reference.tsv +3 -0
  116. data/test/fixtures/dedupe_reference_all.csv +5 -0
  117. data/test/fixtures/dedupe_reference_no_headers.csv +2 -0
  118. data/test/fixtures/dedupe_reference_none.csv +2 -0
  119. data/test/fixtures/dedupe_reference_normalization.csv +3 -0
  120. data/test/fixtures/dedupe_source.csv +6 -0
  121. data/test/fixtures/dedupe_source.tsv +6 -0
  122. data/test/fixtures/dedupe_source_no_headers.csv +5 -0
  123. data/test/fixtures/dedupe_source_normalization.csv +4 -0
  124. metadata +93 -8
  125. data/lib/csvtool/domain/row_randomization_session/randomization_output_destination.rb +0 -31
  126. data/lib/csvtool/domain/row_session/row_output_destination.rb +0 -31
  127. data/test/csvtool/domain/column_session/output_destination_test.rb +0 -18
  128. data/test/csvtool/domain/row_randomization_session/randomization_output_destination_test.rb +0 -21
  129. data/test/csvtool/domain/row_session/row_output_destination_test.rb +0 -23
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step"
5
+
6
+ class ReadHeadersStepTest < 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 read_headers(file_path:, col_sep:)
17
+ @file_path = file_path
18
+ @col_sep = col_sep
19
+ @result
20
+ end
21
+
22
+ attr_reader :file_path, :col_sep
23
+ end
24
+
25
+ def test_sets_headers_on_success
26
+ use_case = FakeUseCase.new(Result.new(true, { headers: ["name", "city"] }))
27
+ step = Csvtool::Interface::CLI::Workflows::Steps::RowExtraction::ReadHeadersStep.new
28
+ context = {
29
+ use_case: use_case,
30
+ file_path: "/tmp/data.csv",
31
+ col_sep: ",",
32
+ handle_error: ->(_result) { raise "should not be called" }
33
+ }
34
+
35
+ result = step.call(context)
36
+
37
+ assert_nil result
38
+ assert_equal ["name", "city"], context[:headers]
39
+ end
40
+
41
+ def test_halts_and_routes_error_when_failure
42
+ failing_result = Result.new(false, {})
43
+ use_case = FakeUseCase.new(failing_result)
44
+ handled = []
45
+ step = Csvtool::Interface::CLI::Workflows::Steps::RowExtraction::ReadHeadersStep.new
46
+
47
+ result = step.call(
48
+ use_case: use_case,
49
+ file_path: "/tmp/data.csv",
50
+ col_sep: ",",
51
+ handle_error: ->(r) { handled << r }
52
+ )
53
+
54
+ assert_equal :halt, result
55
+ assert_equal [failing_result], handled
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step"
5
+ require "csvtool/interface/cli/prompts/seed_prompt"
6
+
7
+ class RowRandomizationCollectInputsStepTest < Minitest::Test
8
+ Result = Struct.new(:ok, :data) do
9
+ def ok? = ok
10
+ end
11
+
12
+ class FakeUseCase
13
+ def read_headers(file_path:, col_sep:, headers_present:)
14
+ Result.new(true, { headers: ["name"] })
15
+ end
16
+ end
17
+
18
+ def test_halts_when_seed_invalid
19
+ file_prompt = Object.new
20
+ separator_prompt = Object.new
21
+ headers_prompt = Object.new
22
+ seed_prompt = Object.new
23
+ def file_prompt.call = "/tmp/data.csv"
24
+ def separator_prompt.call = ","
25
+ def headers_prompt.call = true
26
+ def seed_prompt.call = Csvtool::Interface::CLI::Prompts::SeedPrompt::INVALID
27
+
28
+ step = Csvtool::Interface::CLI::Workflows::Steps::RowRandomization::CollectInputsStep.new(
29
+ file_path_prompt: file_prompt,
30
+ separator_prompt: separator_prompt,
31
+ headers_present_prompt: headers_prompt,
32
+ seed_prompt: seed_prompt
33
+ )
34
+
35
+ assert_equal :halt, step.call(use_case: FakeUseCase.new, handle_error: ->(_r) {})
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/steps/workflow_step_pipeline"
5
+
6
+ class WorkflowStepPipelineTest < Minitest::Test
7
+ def test_runs_all_steps_when_no_halt
8
+ calls = []
9
+ step_1 = ->(_ctx) { calls << :one; nil }
10
+ step_2 = ->(_ctx) { calls << :two; nil }
11
+ pipeline = Csvtool::Interface::CLI::Workflows::Steps::WorkflowStepPipeline.new(steps: [step_1, step_2])
12
+
13
+ result = pipeline.call({})
14
+
15
+ assert_equal true, result
16
+ assert_equal %i[one two], calls
17
+ end
18
+
19
+ def test_stops_on_halt
20
+ calls = []
21
+ step_1 = ->(_ctx) { calls << :one; :halt }
22
+ step_2 = ->(_ctx) { calls << :two; nil }
23
+ pipeline = Csvtool::Interface::CLI::Workflows::Steps::WorkflowStepPipeline.new(steps: [step_1, step_2])
24
+
25
+ result = pipeline.call({})
26
+
27
+ assert_equal false, result
28
+ assert_equal [:one], calls
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/support/output_destination_mapper"
5
+
6
+ class OutputDestinationMapperTest < Minitest::Test
7
+ def test_maps_console_destination
8
+ mapper = Csvtool::Interface::CLI::Workflows::Support::OutputDestinationMapper.new
9
+
10
+ destination = mapper.call({ mode: :console })
11
+
12
+ assert_equal true, destination.console?
13
+ end
14
+
15
+ def test_maps_file_destination
16
+ mapper = Csvtool::Interface::CLI::Workflows::Support::OutputDestinationMapper.new
17
+
18
+ destination = mapper.call({ mode: :file, path: "/tmp/out.csv" })
19
+
20
+ assert_equal true, destination.file?
21
+ assert_equal "/tmp/out.csv", destination.path
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/support/result_error_handler"
5
+
6
+ class ResultErrorHandlerTest < Minitest::Test
7
+ Result = Struct.new(:error)
8
+
9
+ def test_dispatches_mapped_error_action
10
+ calls = []
11
+ errors = Object.new
12
+ handler = Csvtool::Interface::CLI::Workflows::Support::ResultErrorHandler.new(errors: errors)
13
+ result = Result.new(:no_headers)
14
+
15
+ handler.call(result, {
16
+ no_headers: ->(_r, _e) { calls << :called }
17
+ })
18
+
19
+ assert_equal [:called], calls
20
+ end
21
+
22
+ def test_ignores_unmapped_error
23
+ calls = []
24
+ errors = Object.new
25
+ handler = Csvtool::Interface::CLI::Workflows::Support::ResultErrorHandler.new(errors: errors)
26
+ result = Result.new(:unknown)
27
+
28
+ handler.call(result, {
29
+ no_headers: ->(_r, _e) { calls << :called }
30
+ })
31
+
32
+ assert_empty calls
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ external_id
2
+ 2
3
+ 4
@@ -0,0 +1,3 @@
1
+ external_id
2
+ 2
3
+ 4
@@ -0,0 +1,5 @@
1
+ external_id
2
+ 1
3
+ 2
4
+ 3
5
+ 4
@@ -0,0 +1,2 @@
1
+ external_id
2
+ 999
@@ -0,0 +1,3 @@
1
+ external_id
2
+ a1
3
+ C3
@@ -0,0 +1,6 @@
1
+ customer_id,name
2
+ 1,Alice
3
+ 2,Bob
4
+ 3,Cara
5
+ 4,Dan
6
+ 2,Bob Duplicate
@@ -0,0 +1,6 @@
1
+ customer_id name
2
+ 1 Alice
3
+ 2 Bob
4
+ 3 Cara
5
+ 4 Dan
6
+ 2 Bob Duplicate
@@ -0,0 +1,5 @@
1
+ 1,Alice
2
+ 2,Bob
3
+ 3,Cara
4
+ 4,Dan
5
+ 2,Bob Duplicate
@@ -0,0 +1,4 @@
1
+ customer_id,name
2
+ A1 ,Alice
3
+ B2,Bob
4
+ c3,Cara
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csvops
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0.alpha
4
+ version: 0.5.0.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Hall
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-21 00:00:00.000000000 Z
11
+ date: 2026-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: csv
@@ -67,10 +67,14 @@ files:
67
67
  - bin/csvtool
68
68
  - bin/tool
69
69
  - csvops.gemspec
70
+ - docs/architecture.md
70
71
  - docs/release-v0.1.0-alpha.md
71
72
  - docs/release-v0.2.0-alpha.md
72
73
  - docs/release-v0.3.0-alpha.md
74
+ - docs/release-v0.4.0-alpha.md
75
+ - docs/release-v0.5.0-alpha.md
73
76
  - exe/csvtool
77
+ - lib/csvtool/application/use_cases/run_cross_csv_dedupe.rb
74
78
  - lib/csvtool/application/use_cases/run_extraction.rb
75
79
  - lib/csvtool/application/use_cases/run_row_extraction.rb
76
80
  - lib/csvtool/application/use_cases/run_row_randomization.rb
@@ -80,37 +84,78 @@ files:
80
84
  - lib/csvtool/domain/column_session/csv_source.rb
81
85
  - lib/csvtool/domain/column_session/extraction_options.rb
82
86
  - lib/csvtool/domain/column_session/extraction_value.rb
83
- - lib/csvtool/domain/column_session/output_destination.rb
84
87
  - lib/csvtool/domain/column_session/preview.rb
85
88
  - lib/csvtool/domain/column_session/separator.rb
89
+ - lib/csvtool/domain/cross_csv_dedupe_session/column_selector.rb
90
+ - lib/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session.rb
91
+ - lib/csvtool/domain/cross_csv_dedupe_session/csv_profile.rb
92
+ - lib/csvtool/domain/cross_csv_dedupe_session/key_mapping.rb
93
+ - lib/csvtool/domain/cross_csv_dedupe_session/match_options.rb
86
94
  - lib/csvtool/domain/row_randomization_session/randomization_options.rb
87
- - lib/csvtool/domain/row_randomization_session/randomization_output_destination.rb
88
95
  - lib/csvtool/domain/row_randomization_session/randomization_session.rb
89
96
  - lib/csvtool/domain/row_randomization_session/randomization_source.rb
90
- - lib/csvtool/domain/row_session/row_output_destination.rb
91
97
  - lib/csvtool/domain/row_session/row_range.rb
92
98
  - lib/csvtool/domain/row_session/row_session.rb
93
99
  - lib/csvtool/domain/row_session/row_source.rb
100
+ - lib/csvtool/domain/shared/output_destination.rb
101
+ - lib/csvtool/infrastructure/csv/cross_csv_deduper.rb
94
102
  - lib/csvtool/infrastructure/csv/header_reader.rb
95
103
  - lib/csvtool/infrastructure/csv/row_randomizer.rb
96
104
  - lib/csvtool/infrastructure/csv/row_streamer.rb
105
+ - lib/csvtool/infrastructure/csv/selector_validator.rb
97
106
  - lib/csvtool/infrastructure/csv/value_streamer.rb
98
107
  - lib/csvtool/infrastructure/output/console_writer.rb
108
+ - lib/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer.rb
99
109
  - lib/csvtool/infrastructure/output/csv_file_writer.rb
110
+ - lib/csvtool/infrastructure/output/csv_randomized_row_file_writer.rb
100
111
  - lib/csvtool/infrastructure/output/csv_row_console_writer.rb
101
112
  - lib/csvtool/infrastructure/output/csv_row_file_writer.rb
102
113
  - lib/csvtool/interface/cli/errors/presenter.rb
103
114
  - lib/csvtool/interface/cli/menu_loop.rb
104
115
  - lib/csvtool/interface/cli/prompts/column_selector_prompt.rb
105
116
  - lib/csvtool/interface/cli/prompts/confirm_prompt.rb
117
+ - lib/csvtool/interface/cli/prompts/dedupe_key_selector_prompt.rb
106
118
  - lib/csvtool/interface/cli/prompts/file_path_prompt.rb
107
119
  - lib/csvtool/interface/cli/prompts/headers_present_prompt.rb
108
120
  - lib/csvtool/interface/cli/prompts/output_destination_prompt.rb
109
121
  - lib/csvtool/interface/cli/prompts/seed_prompt.rb
110
122
  - lib/csvtool/interface/cli/prompts/separator_prompt.rb
111
123
  - lib/csvtool/interface/cli/prompts/skip_blanks_prompt.rb
124
+ - lib/csvtool/interface/cli/prompts/yes_no_prompt.rb
125
+ - lib/csvtool/interface/cli/workflows/builders/column_session_builder.rb
126
+ - lib/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder.rb
127
+ - lib/csvtool/interface/cli/workflows/builders/row_extraction_session_builder.rb
128
+ - lib/csvtool/interface/cli/workflows/builders/row_randomization_session_builder.rb
129
+ - lib/csvtool/interface/cli/workflows/presenters/column_extraction_presenter.rb
130
+ - lib/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter.rb
131
+ - lib/csvtool/interface/cli/workflows/presenters/row_extraction_presenter.rb
132
+ - lib/csvtool/interface/cli/workflows/presenters/row_randomization_presenter.rb
133
+ - lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb
134
+ - lib/csvtool/interface/cli/workflows/run_extraction_workflow.rb
135
+ - lib/csvtool/interface/cli/workflows/run_row_extraction_workflow.rb
136
+ - lib/csvtool/interface/cli/workflows/run_row_randomization_workflow.rb
137
+ - lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step.rb
138
+ - lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_profiles_step.rb
139
+ - lib/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/execute_step.rb
140
+ - lib/csvtool/interface/cli/workflows/steps/extraction/build_preview_step.rb
141
+ - lib/csvtool/interface/cli/workflows/steps/extraction/collect_destination_step.rb
142
+ - lib/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step.rb
143
+ - lib/csvtool/interface/cli/workflows/steps/extraction/execute_step.rb
144
+ - lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_destination_step.rb
145
+ - lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_range_step.rb
146
+ - lib/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step.rb
147
+ - lib/csvtool/interface/cli/workflows/steps/row_extraction/execute_step.rb
148
+ - lib/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step.rb
149
+ - lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_destination_step.rb
150
+ - lib/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step.rb
151
+ - lib/csvtool/interface/cli/workflows/steps/row_randomization/execute_step.rb
152
+ - lib/csvtool/interface/cli/workflows/steps/workflow_step_pipeline.rb
153
+ - lib/csvtool/interface/cli/workflows/support/output_destination_mapper.rb
154
+ - lib/csvtool/interface/cli/workflows/support/result_error_handler.rb
112
155
  - lib/csvtool/services/preview_builder.rb
113
156
  - lib/csvtool/version.rb
157
+ - test/csvtool/application/use_cases/io_boundary_test.rb
158
+ - test/csvtool/application/use_cases/run_cross_csv_dedupe_test.rb
114
159
  - test/csvtool/application/use_cases/run_extraction_test.rb
115
160
  - test/csvtool/application/use_cases/run_row_extraction_test.rb
116
161
  - test/csvtool/application/use_cases/run_row_randomization_test.rb
@@ -121,36 +166,76 @@ files:
121
166
  - test/csvtool/domain/column_session/csv_source_test.rb
122
167
  - test/csvtool/domain/column_session/extraction_options_test.rb
123
168
  - test/csvtool/domain/column_session/extraction_value_test.rb
124
- - test/csvtool/domain/column_session/output_destination_test.rb
125
169
  - test/csvtool/domain/column_session/preview_test.rb
126
170
  - test/csvtool/domain/column_session/separator_test.rb
171
+ - test/csvtool/domain/cross_csv_dedupe_session/column_selector_test.rb
172
+ - test/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session_test.rb
173
+ - test/csvtool/domain/cross_csv_dedupe_session/csv_profile_test.rb
174
+ - test/csvtool/domain/cross_csv_dedupe_session/key_mapping_test.rb
175
+ - test/csvtool/domain/cross_csv_dedupe_session/match_options_test.rb
127
176
  - test/csvtool/domain/row_randomization_session/randomization_options_test.rb
128
- - test/csvtool/domain/row_randomization_session/randomization_output_destination_test.rb
129
177
  - test/csvtool/domain/row_randomization_session/randomization_session_test.rb
130
178
  - test/csvtool/domain/row_randomization_session/randomization_source_test.rb
131
- - test/csvtool/domain/row_session/row_output_destination_test.rb
132
179
  - test/csvtool/domain/row_session/row_range_test.rb
133
180
  - test/csvtool/domain/row_session/row_session_test.rb
134
181
  - test/csvtool/domain/row_session/row_source_test.rb
182
+ - test/csvtool/domain/shared/output_destination_test.rb
183
+ - test/csvtool/infrastructure/csv/cross_csv_deduper_test.rb
135
184
  - test/csvtool/infrastructure/csv/header_reader_test.rb
136
185
  - test/csvtool/infrastructure/csv/row_randomizer_test.rb
137
186
  - test/csvtool/infrastructure/csv/row_streamer_test.rb
187
+ - test/csvtool/infrastructure/csv/selector_validator_test.rb
138
188
  - test/csvtool/infrastructure/csv/value_streamer_test.rb
139
189
  - test/csvtool/infrastructure/output/console_writer_test.rb
190
+ - test/csvtool/infrastructure/output/csv_cross_csv_dedupe_file_writer_test.rb
140
191
  - test/csvtool/infrastructure/output/csv_file_writer_test.rb
192
+ - test/csvtool/infrastructure/output/csv_randomized_row_file_writer_test.rb
141
193
  - test/csvtool/infrastructure/output/csv_row_console_writer_test.rb
142
194
  - test/csvtool/infrastructure/output/csv_row_file_writer_test.rb
143
195
  - test/csvtool/interface/cli/errors/presenter_test.rb
144
196
  - test/csvtool/interface/cli/menu_loop_test.rb
145
197
  - test/csvtool/interface/cli/prompts/column_selector_prompt_test.rb
146
198
  - test/csvtool/interface/cli/prompts/confirm_prompt_test.rb
199
+ - test/csvtool/interface/cli/prompts/dedupe_key_selector_prompt_test.rb
147
200
  - test/csvtool/interface/cli/prompts/file_path_prompt_test.rb
148
201
  - test/csvtool/interface/cli/prompts/headers_present_prompt_test.rb
149
202
  - test/csvtool/interface/cli/prompts/output_destination_prompt_test.rb
150
203
  - test/csvtool/interface/cli/prompts/seed_prompt_test.rb
151
204
  - test/csvtool/interface/cli/prompts/separator_prompt_test.rb
152
205
  - test/csvtool/interface/cli/prompts/skip_blanks_prompt_test.rb
206
+ - test/csvtool/interface/cli/prompts/yes_no_prompt_test.rb
207
+ - test/csvtool/interface/cli/workflows/builders/column_session_builder_test.rb
208
+ - test/csvtool/interface/cli/workflows/builders/cross_csv_dedupe_session_builder_test.rb
209
+ - test/csvtool/interface/cli/workflows/builders/row_extraction_session_builder_test.rb
210
+ - test/csvtool/interface/cli/workflows/builders/row_randomization_session_builder_test.rb
211
+ - test/csvtool/interface/cli/workflows/presenters/column_extraction_presenter_test.rb
212
+ - test/csvtool/interface/cli/workflows/presenters/cross_csv_dedupe_presenter_test.rb
213
+ - test/csvtool/interface/cli/workflows/presenters/row_extraction_presenter_test.rb
214
+ - test/csvtool/interface/cli/workflows/presenters/row_randomization_presenter_test.rb
215
+ - test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb
216
+ - test/csvtool/interface/cli/workflows/run_extraction_workflow_test.rb
217
+ - test/csvtool/interface/cli/workflows/run_row_extraction_workflow_test.rb
218
+ - test/csvtool/interface/cli/workflows/run_row_randomization_workflow_test.rb
219
+ - test/csvtool/interface/cli/workflows/steps/cross_csv_dedupe/collect_options_step_test.rb
220
+ - test/csvtool/interface/cli/workflows/steps/extraction/collect_inputs_step_test.rb
221
+ - test/csvtool/interface/cli/workflows/steps/row_extraction/collect_source_step_test.rb
222
+ - test/csvtool/interface/cli/workflows/steps/row_extraction/execute_step_test.rb
223
+ - test/csvtool/interface/cli/workflows/steps/row_extraction/read_headers_step_test.rb
224
+ - test/csvtool/interface/cli/workflows/steps/row_randomization/collect_inputs_step_test.rb
225
+ - test/csvtool/interface/cli/workflows/steps/workflow_step_pipeline_test.rb
226
+ - test/csvtool/interface/cli/workflows/support/output_destination_mapper_test.rb
227
+ - test/csvtool/interface/cli/workflows/support/result_error_handler_test.rb
153
228
  - test/csvtool/services/preview_builder_test.rb
229
+ - test/fixtures/dedupe_reference.csv
230
+ - test/fixtures/dedupe_reference.tsv
231
+ - test/fixtures/dedupe_reference_all.csv
232
+ - test/fixtures/dedupe_reference_no_headers.csv
233
+ - test/fixtures/dedupe_reference_none.csv
234
+ - test/fixtures/dedupe_reference_normalization.csv
235
+ - test/fixtures/dedupe_source.csv
236
+ - test/fixtures/dedupe_source.tsv
237
+ - test/fixtures/dedupe_source_no_headers.csv
238
+ - test/fixtures/dedupe_source_normalization.csv
154
239
  - test/fixtures/empty.csv
155
240
  - test/fixtures/sample_people.csv
156
241
  - test/fixtures/sample_people.tsv
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Csvtool
4
- module Domain
5
- module RowRandomizationSession
6
- class RandomizationOutputDestination
7
- attr_reader :mode, :path
8
-
9
- def self.console
10
- new(mode: :console)
11
- end
12
-
13
- def self.file(path:)
14
- new(mode: :file, path: path)
15
- end
16
-
17
- def initialize(mode:, path: nil)
18
- raise ArgumentError, "invalid output mode" unless %i[console file].include?(mode)
19
- raise ArgumentError, "file output path cannot be empty" if mode == :file && path.to_s.empty?
20
-
21
- @mode = mode
22
- @path = path
23
- end
24
-
25
- def file?
26
- @mode == :file
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Csvtool
4
- module Domain
5
- module RowSession
6
- class RowOutputDestination
7
- attr_reader :mode, :path
8
-
9
- def self.console
10
- new(mode: :console)
11
- end
12
-
13
- def self.file(path:)
14
- new(mode: :file, path: path)
15
- end
16
-
17
- def initialize(mode:, path: nil)
18
- raise ArgumentError, "invalid output mode" unless %i[console file].include?(mode)
19
- raise ArgumentError, "file output path cannot be empty" if mode == :file && path.to_s.empty?
20
-
21
- @mode = mode
22
- @path = path
23
- end
24
-
25
- def file?
26
- @mode == :file
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../../test_helper"
4
- require "csvtool/domain/column_session/output_destination"
5
-
6
- class OutputDestinationTest < Minitest::Test
7
- def test_console_factory
8
- destination = Csvtool::Domain::ColumnSession::OutputDestination.console
9
- assert_equal true, destination.console?
10
- assert_equal false, destination.file?
11
- end
12
-
13
- def test_file_factory
14
- destination = Csvtool::Domain::ColumnSession::OutputDestination.file(path: "/tmp/out.csv")
15
- assert_equal true, destination.file?
16
- assert_equal "/tmp/out.csv", destination.path
17
- end
18
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../../test_helper"
4
- require "csvtool/domain/row_randomization_session/randomization_output_destination"
5
-
6
- class RandomizationOutputDestinationTest < Minitest::Test
7
- def test_console_and_file_modes
8
- console = Csvtool::Domain::RowRandomizationSession::RandomizationOutputDestination.console
9
- file = Csvtool::Domain::RowRandomizationSession::RandomizationOutputDestination.file(path: "/tmp/out.csv")
10
-
11
- assert_equal false, console.file?
12
- assert_equal true, file.file?
13
- assert_equal "/tmp/out.csv", file.path
14
- end
15
-
16
- def test_rejects_empty_file_path
17
- assert_raises(ArgumentError) do
18
- Csvtool::Domain::RowRandomizationSession::RandomizationOutputDestination.file(path: "")
19
- end
20
- end
21
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../../../test_helper"
4
- require "csvtool/domain/row_session/row_output_destination"
5
-
6
- class RowRangeOutputDestinationTest < Minitest::Test
7
- def test_console_destination
8
- destination = Csvtool::Domain::RowSession::RowOutputDestination.console
9
- refute destination.file?
10
- end
11
-
12
- def test_file_destination
13
- destination = Csvtool::Domain::RowSession::RowOutputDestination.file(path: "/tmp/out.csv")
14
- assert destination.file?
15
- assert_equal "/tmp/out.csv", destination.path
16
- end
17
-
18
- def test_rejects_empty_file_path
19
- assert_raises(ArgumentError) do
20
- Csvtool::Domain::RowSession::RowOutputDestination.file(path: "")
21
- end
22
- end
23
- end