csvops 0.2.0.alpha → 0.4.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +56 -108
  3. data/docs/architecture.md +266 -0
  4. data/docs/release-v0.3.0-alpha.md +74 -0
  5. data/docs/release-v0.4.0-alpha.md +87 -0
  6. data/lib/csvtool/application/use_cases/run_cross_csv_dedupe.rb +93 -0
  7. data/lib/csvtool/application/use_cases/run_extraction.rb +3 -3
  8. data/lib/csvtool/application/use_cases/run_row_extraction.rb +3 -3
  9. data/lib/csvtool/application/use_cases/run_row_randomization.rb +105 -0
  10. data/lib/csvtool/cli.rb +9 -1
  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_options.rb +17 -0
  17. data/lib/csvtool/domain/row_randomization_session/randomization_session.rb +25 -0
  18. data/lib/csvtool/domain/row_randomization_session/randomization_source.rb +24 -0
  19. data/lib/csvtool/domain/row_session/row_source.rb +3 -0
  20. data/lib/csvtool/domain/{column_session → shared}/output_destination.rb +1 -1
  21. data/lib/csvtool/infrastructure/csv/cross_csv_deduper.rb +85 -0
  22. data/lib/csvtool/infrastructure/csv/row_randomizer.rb +83 -0
  23. data/lib/csvtool/infrastructure/csv/selector_validator.rb +30 -0
  24. data/lib/csvtool/interface/cli/errors/presenter.rb +4 -0
  25. data/lib/csvtool/interface/cli/menu_loop.rb +8 -2
  26. data/lib/csvtool/interface/cli/prompts/headers_present_prompt.rb +22 -0
  27. data/lib/csvtool/interface/cli/prompts/seed_prompt.rb +29 -0
  28. data/lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb +163 -0
  29. data/lib/csvtool/version.rb +1 -1
  30. data/test/csvtool/application/use_cases/run_cross_csv_dedupe_test.rb +113 -0
  31. data/test/csvtool/application/use_cases/run_row_randomization_test.rb +124 -0
  32. data/test/csvtool/cli_test.rb +231 -12
  33. data/test/csvtool/cli_unit_test.rb +27 -2
  34. data/test/csvtool/domain/column_session/column_session_test.rb +2 -2
  35. data/test/csvtool/domain/column_session/csv_source_test.rb +10 -0
  36. data/test/csvtool/domain/cross_csv_dedupe_session/column_selector_test.rb +42 -0
  37. data/test/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session_test.rb +75 -0
  38. data/test/csvtool/domain/cross_csv_dedupe_session/csv_profile_test.rb +26 -0
  39. data/test/csvtool/domain/cross_csv_dedupe_session/key_mapping_test.rb +31 -0
  40. data/test/csvtool/domain/cross_csv_dedupe_session/match_options_test.rb +52 -0
  41. data/test/csvtool/domain/row_randomization_session/randomization_options_test.rb +20 -0
  42. data/test/csvtool/domain/row_randomization_session/randomization_session_test.rb +26 -0
  43. data/test/csvtool/domain/row_randomization_session/randomization_source_test.rb +42 -0
  44. data/test/csvtool/domain/row_session/row_session_test.rb +2 -2
  45. data/test/csvtool/domain/row_session/row_source_test.rb +16 -0
  46. data/test/csvtool/domain/shared/output_destination_test.rb +24 -0
  47. data/test/csvtool/infrastructure/csv/cross_csv_deduper_test.rb +155 -0
  48. data/test/csvtool/infrastructure/csv/row_randomizer_test.rb +37 -0
  49. data/test/csvtool/infrastructure/csv/selector_validator_test.rb +72 -0
  50. data/test/csvtool/interface/cli/errors/presenter_test.rb +2 -0
  51. data/test/csvtool/interface/cli/menu_loop_test.rb +78 -10
  52. data/test/csvtool/interface/cli/prompts/headers_present_prompt_test.rb +14 -0
  53. data/test/csvtool/interface/cli/prompts/seed_prompt_test.rb +39 -0
  54. data/test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb +246 -0
  55. data/test/fixtures/dedupe_reference.csv +3 -0
  56. data/test/fixtures/dedupe_reference.tsv +3 -0
  57. data/test/fixtures/dedupe_reference_all.csv +5 -0
  58. data/test/fixtures/dedupe_reference_no_headers.csv +2 -0
  59. data/test/fixtures/dedupe_reference_none.csv +2 -0
  60. data/test/fixtures/dedupe_reference_normalization.csv +3 -0
  61. data/test/fixtures/dedupe_source.csv +6 -0
  62. data/test/fixtures/dedupe_source.tsv +6 -0
  63. data/test/fixtures/dedupe_source_no_headers.csv +5 -0
  64. data/test/fixtures/dedupe_source_normalization.csv +4 -0
  65. data/test/fixtures/sample_people_no_headers.csv +3 -0
  66. metadata +50 -6
  67. data/lib/csvtool/domain/row_session/row_output_destination.rb +0 -31
  68. data/test/csvtool/domain/column_session/output_destination_test.rb +0 -18
  69. data/test/csvtool/domain/row_session/row_output_destination_test.rb +0 -23
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../../test_helper"
4
+ require "csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow"
5
+ require "tmpdir"
6
+
7
+ class RunCrossCsvDedupeWorkflowTest < Minitest::Test
8
+ def fixture_path(name)
9
+ File.expand_path("../../../../fixtures/#{name}", __dir__)
10
+ end
11
+
12
+ def test_dedupes_source_rows_by_reference_column
13
+ output = StringIO.new
14
+ input = [
15
+ fixture_path("dedupe_source.csv"),
16
+ "",
17
+ "",
18
+ fixture_path("dedupe_reference.csv"),
19
+ "",
20
+ "",
21
+ "customer_id",
22
+ "external_id",
23
+ "",
24
+ "",
25
+ ""
26
+ ].join("\n") + "\n"
27
+
28
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
29
+ .new(stdin: StringIO.new(input), stdout: output)
30
+ .call
31
+
32
+ assert_includes output.string, "CSV file path:"
33
+ assert_includes output.string, "Reference CSV file path:"
34
+ assert_includes output.string, "Source key column name:"
35
+ assert_includes output.string, "Reference key column name:"
36
+ assert_includes output.string, "customer_id,name"
37
+ assert_includes output.string, "1,Alice"
38
+ assert_includes output.string, "3,Cara"
39
+ refute_includes output.string, "2,Bob"
40
+ refute_includes output.string, "4,Dan"
41
+ assert_includes output.string, "Summary: source_rows=5 removed_rows=3 kept_rows=2"
42
+ end
43
+
44
+ def test_can_write_deduped_rows_to_file
45
+ output = StringIO.new
46
+
47
+ Dir.mktmpdir do |dir|
48
+ output_path = File.join(dir, "deduped.csv")
49
+ input = [
50
+ fixture_path("dedupe_source.csv"),
51
+ "",
52
+ "",
53
+ fixture_path("dedupe_reference.csv"),
54
+ "",
55
+ "",
56
+ "customer_id",
57
+ "external_id",
58
+ "",
59
+ "",
60
+ "2",
61
+ output_path
62
+ ].join("\n") + "\n"
63
+
64
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
65
+ .new(stdin: StringIO.new(input), stdout: output)
66
+ .call
67
+
68
+ assert_includes output.string, "Wrote output to #{output_path}"
69
+ 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"
71
+ end
72
+ end
73
+
74
+ def test_supports_tsv_separators
75
+ output = StringIO.new
76
+ input = [
77
+ fixture_path("dedupe_source.tsv"),
78
+ "2",
79
+ "",
80
+ fixture_path("dedupe_reference.tsv"),
81
+ "2",
82
+ "",
83
+ "customer_id",
84
+ "external_id",
85
+ "",
86
+ "",
87
+ ""
88
+ ].join("\n") + "\n"
89
+
90
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
91
+ .new(stdin: StringIO.new(input), stdout: output)
92
+ .call
93
+
94
+ assert_includes output.string, "customer_id\tname"
95
+ assert_includes output.string, "1\tAlice"
96
+ assert_includes output.string, "3\tCara"
97
+ end
98
+
99
+ def test_headerless_mode_supports_column_index
100
+ output = StringIO.new
101
+ input = [
102
+ fixture_path("dedupe_source_no_headers.csv"),
103
+ "",
104
+ "n",
105
+ fixture_path("dedupe_reference_no_headers.csv"),
106
+ "",
107
+ "n",
108
+ "1",
109
+ "1",
110
+ "",
111
+ "",
112
+ ""
113
+ ].join("\n") + "\n"
114
+
115
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
116
+ .new(stdin: StringIO.new(input), stdout: output)
117
+ .call
118
+
119
+ refute_includes output.string, "customer_id,name"
120
+ assert_includes output.string, "1,Alice"
121
+ assert_includes output.string, "3,Cara"
122
+ assert_includes output.string, "Summary: source_rows=5 removed_rows=3 kept_rows=2"
123
+ end
124
+
125
+ def test_reports_column_not_found_when_missing
126
+ output = StringIO.new
127
+ input = [
128
+ fixture_path("dedupe_source.csv"),
129
+ "",
130
+ "",
131
+ fixture_path("dedupe_reference.csv"),
132
+ "",
133
+ "",
134
+ "missing",
135
+ "external_id",
136
+ "",
137
+ ""
138
+ ].join("\n") + "\n"
139
+
140
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
141
+ .new(stdin: StringIO.new(input), stdout: output)
142
+ .call
143
+
144
+ assert_includes output.string, "Column not found."
145
+ end
146
+
147
+ def test_reports_when_no_rows_were_removed
148
+ output = StringIO.new
149
+ input = [
150
+ fixture_path("dedupe_source.csv"),
151
+ "",
152
+ "",
153
+ fixture_path("dedupe_reference_none.csv"),
154
+ "",
155
+ "",
156
+ "customer_id",
157
+ "external_id",
158
+ "",
159
+ "",
160
+ ""
161
+ ].join("\n") + "\n"
162
+
163
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
164
+ .new(stdin: StringIO.new(input), stdout: output)
165
+ .call
166
+
167
+ assert_includes output.string, "Summary: source_rows=5 removed_rows=0 kept_rows=5"
168
+ assert_includes output.string, "No rows removed; no matching keys found."
169
+ end
170
+
171
+ def test_reports_when_all_rows_were_removed
172
+ output = StringIO.new
173
+ input = [
174
+ fixture_path("dedupe_source.csv"),
175
+ "",
176
+ "",
177
+ fixture_path("dedupe_reference_all.csv"),
178
+ "",
179
+ "",
180
+ "customer_id",
181
+ "external_id",
182
+ "",
183
+ "",
184
+ ""
185
+ ].join("\n") + "\n"
186
+
187
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
188
+ .new(stdin: StringIO.new(input), stdout: output)
189
+ .call
190
+
191
+ assert_includes output.string, "Summary: source_rows=5 removed_rows=5 kept_rows=0"
192
+ assert_includes output.string, "All source rows were removed by dedupe."
193
+ end
194
+
195
+ def test_normalization_trim_on_and_case_insensitive_on_matches_equivalent_keys
196
+ output = StringIO.new
197
+ input = [
198
+ fixture_path("dedupe_source_normalization.csv"),
199
+ "",
200
+ "",
201
+ fixture_path("dedupe_reference_normalization.csv"),
202
+ "",
203
+ "",
204
+ "customer_id",
205
+ "external_id",
206
+ "",
207
+ "y",
208
+ ""
209
+ ].join("\n") + "\n"
210
+
211
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
212
+ .new(stdin: StringIO.new(input), stdout: output)
213
+ .call
214
+
215
+ refute_includes output.string, " A1 ,Alice"
216
+ refute_includes output.string, "c3,Cara"
217
+ assert_includes output.string, "B2,Bob"
218
+ assert_includes output.string, "Summary: source_rows=3 removed_rows=2 kept_rows=1"
219
+ end
220
+
221
+ def test_normalization_disabled_preserves_exact_match_behavior
222
+ output = StringIO.new
223
+ input = [
224
+ fixture_path("dedupe_source_normalization.csv"),
225
+ "",
226
+ "",
227
+ fixture_path("dedupe_reference_normalization.csv"),
228
+ "",
229
+ "",
230
+ "customer_id",
231
+ "external_id",
232
+ "n",
233
+ "n",
234
+ ""
235
+ ].join("\n") + "\n"
236
+
237
+ Csvtool::Interface::CLI::Workflows::RunCrossCsvDedupeWorkflow
238
+ .new(stdin: StringIO.new(input), stdout: output)
239
+ .call
240
+
241
+ assert_includes output.string, " A1 ,Alice"
242
+ assert_includes output.string, "B2,Bob"
243
+ assert_includes output.string, "c3,Cara"
244
+ assert_includes output.string, "Summary: source_rows=3 removed_rows=0 kept_rows=3"
245
+ end
246
+ 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
@@ -0,0 +1,3 @@
1
+ Alice,London
2
+ Bob,Paris
3
+ Cara,Berlin
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.2.0.alpha
4
+ version: 0.4.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,26 +67,41 @@ 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
73
+ - docs/release-v0.3.0-alpha.md
74
+ - docs/release-v0.4.0-alpha.md
72
75
  - exe/csvtool
76
+ - lib/csvtool/application/use_cases/run_cross_csv_dedupe.rb
73
77
  - lib/csvtool/application/use_cases/run_extraction.rb
74
78
  - lib/csvtool/application/use_cases/run_row_extraction.rb
79
+ - lib/csvtool/application/use_cases/run_row_randomization.rb
75
80
  - lib/csvtool/cli.rb
76
81
  - lib/csvtool/domain/column_session/column_selection.rb
77
82
  - lib/csvtool/domain/column_session/column_session.rb
78
83
  - lib/csvtool/domain/column_session/csv_source.rb
79
84
  - lib/csvtool/domain/column_session/extraction_options.rb
80
85
  - lib/csvtool/domain/column_session/extraction_value.rb
81
- - lib/csvtool/domain/column_session/output_destination.rb
82
86
  - lib/csvtool/domain/column_session/preview.rb
83
87
  - lib/csvtool/domain/column_session/separator.rb
84
- - lib/csvtool/domain/row_session/row_output_destination.rb
88
+ - lib/csvtool/domain/cross_csv_dedupe_session/column_selector.rb
89
+ - lib/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session.rb
90
+ - lib/csvtool/domain/cross_csv_dedupe_session/csv_profile.rb
91
+ - lib/csvtool/domain/cross_csv_dedupe_session/key_mapping.rb
92
+ - lib/csvtool/domain/cross_csv_dedupe_session/match_options.rb
93
+ - lib/csvtool/domain/row_randomization_session/randomization_options.rb
94
+ - lib/csvtool/domain/row_randomization_session/randomization_session.rb
95
+ - lib/csvtool/domain/row_randomization_session/randomization_source.rb
85
96
  - lib/csvtool/domain/row_session/row_range.rb
86
97
  - lib/csvtool/domain/row_session/row_session.rb
87
98
  - lib/csvtool/domain/row_session/row_source.rb
99
+ - lib/csvtool/domain/shared/output_destination.rb
100
+ - lib/csvtool/infrastructure/csv/cross_csv_deduper.rb
88
101
  - lib/csvtool/infrastructure/csv/header_reader.rb
102
+ - lib/csvtool/infrastructure/csv/row_randomizer.rb
89
103
  - lib/csvtool/infrastructure/csv/row_streamer.rb
104
+ - lib/csvtool/infrastructure/csv/selector_validator.rb
90
105
  - lib/csvtool/infrastructure/csv/value_streamer.rb
91
106
  - lib/csvtool/infrastructure/output/console_writer.rb
92
107
  - lib/csvtool/infrastructure/output/csv_file_writer.rb
@@ -97,13 +112,18 @@ files:
97
112
  - lib/csvtool/interface/cli/prompts/column_selector_prompt.rb
98
113
  - lib/csvtool/interface/cli/prompts/confirm_prompt.rb
99
114
  - lib/csvtool/interface/cli/prompts/file_path_prompt.rb
115
+ - lib/csvtool/interface/cli/prompts/headers_present_prompt.rb
100
116
  - lib/csvtool/interface/cli/prompts/output_destination_prompt.rb
117
+ - lib/csvtool/interface/cli/prompts/seed_prompt.rb
101
118
  - lib/csvtool/interface/cli/prompts/separator_prompt.rb
102
119
  - lib/csvtool/interface/cli/prompts/skip_blanks_prompt.rb
120
+ - lib/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow.rb
103
121
  - lib/csvtool/services/preview_builder.rb
104
122
  - lib/csvtool/version.rb
123
+ - test/csvtool/application/use_cases/run_cross_csv_dedupe_test.rb
105
124
  - test/csvtool/application/use_cases/run_extraction_test.rb
106
125
  - test/csvtool/application/use_cases/run_row_extraction_test.rb
126
+ - test/csvtool/application/use_cases/run_row_randomization_test.rb
107
127
  - test/csvtool/cli_test.rb
108
128
  - test/csvtool/cli_unit_test.rb
109
129
  - test/csvtool/domain/column_session/column_selection_test.rb
@@ -111,15 +131,25 @@ files:
111
131
  - test/csvtool/domain/column_session/csv_source_test.rb
112
132
  - test/csvtool/domain/column_session/extraction_options_test.rb
113
133
  - test/csvtool/domain/column_session/extraction_value_test.rb
114
- - test/csvtool/domain/column_session/output_destination_test.rb
115
134
  - test/csvtool/domain/column_session/preview_test.rb
116
135
  - test/csvtool/domain/column_session/separator_test.rb
117
- - test/csvtool/domain/row_session/row_output_destination_test.rb
136
+ - test/csvtool/domain/cross_csv_dedupe_session/column_selector_test.rb
137
+ - test/csvtool/domain/cross_csv_dedupe_session/cross_csv_dedupe_session_test.rb
138
+ - test/csvtool/domain/cross_csv_dedupe_session/csv_profile_test.rb
139
+ - test/csvtool/domain/cross_csv_dedupe_session/key_mapping_test.rb
140
+ - test/csvtool/domain/cross_csv_dedupe_session/match_options_test.rb
141
+ - test/csvtool/domain/row_randomization_session/randomization_options_test.rb
142
+ - test/csvtool/domain/row_randomization_session/randomization_session_test.rb
143
+ - test/csvtool/domain/row_randomization_session/randomization_source_test.rb
118
144
  - test/csvtool/domain/row_session/row_range_test.rb
119
145
  - test/csvtool/domain/row_session/row_session_test.rb
120
146
  - test/csvtool/domain/row_session/row_source_test.rb
147
+ - test/csvtool/domain/shared/output_destination_test.rb
148
+ - test/csvtool/infrastructure/csv/cross_csv_deduper_test.rb
121
149
  - test/csvtool/infrastructure/csv/header_reader_test.rb
150
+ - test/csvtool/infrastructure/csv/row_randomizer_test.rb
122
151
  - test/csvtool/infrastructure/csv/row_streamer_test.rb
152
+ - test/csvtool/infrastructure/csv/selector_validator_test.rb
123
153
  - test/csvtool/infrastructure/csv/value_streamer_test.rb
124
154
  - test/csvtool/infrastructure/output/console_writer_test.rb
125
155
  - test/csvtool/infrastructure/output/csv_file_writer_test.rb
@@ -130,10 +160,23 @@ files:
130
160
  - test/csvtool/interface/cli/prompts/column_selector_prompt_test.rb
131
161
  - test/csvtool/interface/cli/prompts/confirm_prompt_test.rb
132
162
  - test/csvtool/interface/cli/prompts/file_path_prompt_test.rb
163
+ - test/csvtool/interface/cli/prompts/headers_present_prompt_test.rb
133
164
  - test/csvtool/interface/cli/prompts/output_destination_prompt_test.rb
165
+ - test/csvtool/interface/cli/prompts/seed_prompt_test.rb
134
166
  - test/csvtool/interface/cli/prompts/separator_prompt_test.rb
135
167
  - test/csvtool/interface/cli/prompts/skip_blanks_prompt_test.rb
168
+ - test/csvtool/interface/cli/workflows/run_cross_csv_dedupe_workflow_test.rb
136
169
  - test/csvtool/services/preview_builder_test.rb
170
+ - test/fixtures/dedupe_reference.csv
171
+ - test/fixtures/dedupe_reference.tsv
172
+ - test/fixtures/dedupe_reference_all.csv
173
+ - test/fixtures/dedupe_reference_no_headers.csv
174
+ - test/fixtures/dedupe_reference_none.csv
175
+ - test/fixtures/dedupe_reference_normalization.csv
176
+ - test/fixtures/dedupe_source.csv
177
+ - test/fixtures/dedupe_source.tsv
178
+ - test/fixtures/dedupe_source_no_headers.csv
179
+ - test/fixtures/dedupe_source_normalization.csv
137
180
  - test/fixtures/empty.csv
138
181
  - test/fixtures/sample_people.csv
139
182
  - test/fixtures/sample_people.tsv
@@ -141,6 +184,7 @@ files:
141
184
  - test/fixtures/sample_people_blanks.csv
142
185
  - test/fixtures/sample_people_colon.txt
143
186
  - test/fixtures/sample_people_many.csv
187
+ - test/fixtures/sample_people_no_headers.csv
144
188
  - test/test_helper.rb
145
189
  homepage: https://github.com/RobertAndrewHall/csvops
146
190
  licenses:
@@ -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,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