csv_to_yaml 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/lib/csv_to_yaml/converter.rb +89 -0
- data/lib/csv_to_yaml/errors.rb +12 -0
- data/lib/csv_to_yaml/version.rb +5 -0
- data/lib/csv_to_yaml.rb +35 -0
- data/spec/csv_to_yaml_spec.rb +279 -0
- metadata +97 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: efb0d27827ab1b8b65d932e2ab99592df354b85b1c6d2a7dc4a616735524b010
|
|
4
|
+
data.tar.gz: 92594a121766813967749c4ed1948db796ac13dbafeb843b1abcab2a027e8482
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 267e1d0c52d49b2e3b3dfae5fd82ecfd075f0b6ecd7d5d8af419ad00d6dfa637f0af913f39607eb4211a9be05f421b361d4355bb26e2887c0cebfc9d24662dbc
|
|
7
|
+
data.tar.gz: 8ac49a1370650e33ebbaec656e38a9bc30a69ba31fc9164fa0984aa3e0acb347f22420d25bf98bb5dff8c76a1dbbe4b627a38708ccfd2f62336eb3bbd76944c2
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## [Unreleased]
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2024-08-03
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Initial release of CsvToYaml gem
|
|
8
|
+
- Core functionality to convert CSV files to YAML format
|
|
9
|
+
- Automatic data type inference for integers, floats, booleans, and strings
|
|
10
|
+
- Error handling for empty files and invalid CSV formats
|
|
11
|
+
- Basic documentation including README and this CHANGELOG
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- `CsvToYaml.convert` method to convert CSV files to YAML
|
|
16
|
+
- `CsvToYaml::Converter` class for handling the conversion process
|
|
17
|
+
- Custom error classes: `ConversionError`, `EmptyFileError`, and `InvalidCsvFormatError`
|
|
18
|
+
|
|
19
|
+
### Dependencies
|
|
20
|
+
|
|
21
|
+
- Uses standard library modules: CSV and YAML
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Kazuya INOUE
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# CsvToYaml
|
|
2
|
+
|
|
3
|
+
CsvToYaml is a Ruby gem that provides an easy way to convert CSV(Comma Separated Values) files to YAML(YAML Ain't Markup Language) format. It handles various data types and attempts to infer and convert them appropriately.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Convert CSV files to YAML format
|
|
8
|
+
- Automatic data type inference and conversion
|
|
9
|
+
- Handles empty files and invalid CSV formats
|
|
10
|
+
- Simple and easy-to-use API
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
15
|
+
|
|
16
|
+
$ bundle add csv_to_yaml
|
|
17
|
+
|
|
18
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
19
|
+
|
|
20
|
+
$ gem install csv_to_yaml
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
Here's a basic example of how to use CsvToYaml:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
require 'csv_to_yaml'
|
|
28
|
+
|
|
29
|
+
# Convert a CSV file to YAML
|
|
30
|
+
CsvToYaml.convert('input.csv', 'output.yaml')
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This will read the `input.csv` file, convert its contents to YAML format, and save the result to `output.yaml`.
|
|
34
|
+
|
|
35
|
+
## Error Handling
|
|
36
|
+
|
|
37
|
+
CsvToYaml provides specific error classes to handle different scenarios:
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
begin
|
|
41
|
+
CsvToYaml.convert('input.csv', 'output.yaml')
|
|
42
|
+
rescue CsvToYaml::EmptyFileError
|
|
43
|
+
puts "The input file is empty"
|
|
44
|
+
rescue CsvToYaml::InvalidCsvFormatError
|
|
45
|
+
puts "The input file is not a valid CSV"
|
|
46
|
+
rescue CsvToYaml::ConversionError => e
|
|
47
|
+
puts "Conversion failed: #{e.message}"
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Development
|
|
52
|
+
|
|
53
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
54
|
+
|
|
55
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
56
|
+
|
|
57
|
+
## Contributing
|
|
58
|
+
|
|
59
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/kazuyainoue0124/csv_to_yaml.
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
|
|
63
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CsvToYaml
|
|
4
|
+
# Converter class handles the actual conversion from CSV to YAML
|
|
5
|
+
class Converter
|
|
6
|
+
# Convert CSV file to YAML file
|
|
7
|
+
#
|
|
8
|
+
# @param input_csv [String] Path to input CSV file
|
|
9
|
+
# @param output_yaml [String] Path to output YAML file
|
|
10
|
+
# @return [void]
|
|
11
|
+
# @raise [CsvToYaml::ConversionError] If any error occurs during conversion
|
|
12
|
+
# @raise [CsvToYaml::EmptyFileError] If the input file is empty
|
|
13
|
+
# @raise [CsvToYaml::InvalidCsvFormatError] If the input file is not in a valid CSV format
|
|
14
|
+
def convert(input_csv, output_yaml)
|
|
15
|
+
validate_csv_format(input_csv)
|
|
16
|
+
data = read_csv(input_csv)
|
|
17
|
+
write_yaml(data, output_yaml)
|
|
18
|
+
rescue EmptyFileError => e
|
|
19
|
+
raise e
|
|
20
|
+
rescue InvalidCsvFormatError => e
|
|
21
|
+
raise e
|
|
22
|
+
rescue StandardError => e
|
|
23
|
+
raise ConversionError, "Failed to convert CSV to YAML: #{e.message}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
# Validate the format of the input file
|
|
29
|
+
#
|
|
30
|
+
# @param file_path [String] Path to the input file
|
|
31
|
+
# @raise [CsvToYaml::EmptyFileError] If the file is empty
|
|
32
|
+
# @raise [CsvToYaml::InvalidCsvFormatError] If the file is not a valid CSV
|
|
33
|
+
def validate_csv_format(file_path)
|
|
34
|
+
raise EmptyFileError, "Input file '#{file_path}' is empty" if File.zero?(file_path)
|
|
35
|
+
|
|
36
|
+
File.open(file_path, "rb") do |file|
|
|
37
|
+
first_line = file.readline.force_encoding("ASCII-8BIT")
|
|
38
|
+
unless first_line.include?(",".b)
|
|
39
|
+
raise InvalidCsvFormatError, "The file content does not appear to be a valid CSV format"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
rescue EOFError
|
|
43
|
+
raise ConversionError, "The input file is empty or not readable"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Read and parse CSV file
|
|
47
|
+
#
|
|
48
|
+
# @param input_csv [String] Path to input CSV file
|
|
49
|
+
# @return [Array<Hash>] Parsed CSV data
|
|
50
|
+
def read_csv(input_csv)
|
|
51
|
+
csv_data = CSV.read(input_csv, headers: true)
|
|
52
|
+
csv_data.map { |row| convert_types(row.to_h) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Convert data types
|
|
56
|
+
#
|
|
57
|
+
# @param row [Hash] A row of CSV data
|
|
58
|
+
# @return [Hash] Converted data
|
|
59
|
+
def convert_types(row)
|
|
60
|
+
row.each_with_object({}) do |(key, value), new_row|
|
|
61
|
+
new_row[key] = infer_and_convert_type(value) unless key.nil?
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Infer and convert the type of a value
|
|
66
|
+
#
|
|
67
|
+
# @param value [String] The value to convert
|
|
68
|
+
# @return [Object] The converted value
|
|
69
|
+
def infer_and_convert_type(value)
|
|
70
|
+
case value
|
|
71
|
+
when /\A\d+\z/ then value.to_i
|
|
72
|
+
when /\A\d+\.\d+\z/ then value.to_f
|
|
73
|
+
when /\A(true|false)\z/i then value.downcase == "true"
|
|
74
|
+
else value
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Write data to YAML file
|
|
79
|
+
#
|
|
80
|
+
# @param data [Array<Hash>] The data to write
|
|
81
|
+
# @param output_yaml [String] Path to output YAML file
|
|
82
|
+
# @return [void]
|
|
83
|
+
def write_yaml(data, output_yaml)
|
|
84
|
+
File.open(output_yaml, "w") do |f|
|
|
85
|
+
f.write(data.to_yaml.sub(/^---\n/, ""))
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CsvToYaml
|
|
4
|
+
# Base error class for CsvToYaml
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
# Error raised when conversion fails
|
|
7
|
+
class ConversionError < Error; end
|
|
8
|
+
# Error raised when the input file is empty or not readable
|
|
9
|
+
class EmptyFileError < Error; end
|
|
10
|
+
# Error raised when the input file is not a valid CSV
|
|
11
|
+
class InvalidCsvFormatError < Error; end
|
|
12
|
+
end
|
data/lib/csv_to_yaml.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "csv_to_yaml/version"
|
|
4
|
+
require_relative "csv_to_yaml/converter"
|
|
5
|
+
require_relative "csv_to_yaml/errors"
|
|
6
|
+
require "csv"
|
|
7
|
+
require "yaml"
|
|
8
|
+
|
|
9
|
+
# CsvToYaml is a module that provides functionality to convert CSV files to YAML format.
|
|
10
|
+
#
|
|
11
|
+
# This gem allows you to easily transform data from CSV (Comma-Separated Values) format
|
|
12
|
+
# to YAML (YAML Ain't Markup Language) format. It handles various data types and
|
|
13
|
+
# attempts to infer and convert them appropriately.
|
|
14
|
+
#
|
|
15
|
+
# @example Converting a CSV file to YAML
|
|
16
|
+
# CsvToYaml.convert('input.csv', 'output.yaml')
|
|
17
|
+
#
|
|
18
|
+
# @note This gem assumes that the input CSV file has headers.
|
|
19
|
+
#
|
|
20
|
+
# @see https://github.com/kazuyainoue0124/csv_to_yaml for more information and usage examples.
|
|
21
|
+
module CsvToYaml
|
|
22
|
+
class << self
|
|
23
|
+
# Converts a CSV file to YAML format
|
|
24
|
+
#
|
|
25
|
+
# @param input_csv [String] Path to the input CSV file
|
|
26
|
+
# @param output_yaml [String] Path to the output YAML file
|
|
27
|
+
# @return [void]
|
|
28
|
+
# @raise [CsvToYaml::ConversionError] If any error occurs during conversion
|
|
29
|
+
# @raise [CsvToYaml::EmptyFileError] If the input file is empty
|
|
30
|
+
# @raise [CsvToYaml::InvalidCsvFormatError] If the input file is not in a valid CSV format
|
|
31
|
+
def convert(input_csv, output_yaml)
|
|
32
|
+
Converter.new.convert(input_csv, output_yaml)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe CsvToYaml do
|
|
4
|
+
let(:input_csv) { Tempfile.new(["input", ".csv"]) }
|
|
5
|
+
let(:output_yaml) { Tempfile.new(["output", ".yml"]) }
|
|
6
|
+
|
|
7
|
+
after do
|
|
8
|
+
input_csv.close
|
|
9
|
+
input_csv.unlink
|
|
10
|
+
output_yaml.close
|
|
11
|
+
output_yaml.unlink
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "has a version number" do
|
|
15
|
+
expect(CsvToYaml::VERSION).not_to be nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe ".convert" do
|
|
19
|
+
context "Positive tests" do
|
|
20
|
+
# Test for valid CSV data conversion
|
|
21
|
+
context "with valid csv data" do
|
|
22
|
+
before do
|
|
23
|
+
input_csv.write(<<~CSV)
|
|
24
|
+
id,name,age,salary,active
|
|
25
|
+
1,Alice,30,50000.0,true
|
|
26
|
+
2,Bob,25,40000.5,false
|
|
27
|
+
3,Charlie,35,60000.0,true
|
|
28
|
+
CSV
|
|
29
|
+
input_csv.rewind
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "converts CSV to YAML with correct data types" do
|
|
33
|
+
described_class.convert(input_csv.path, output_yaml.path)
|
|
34
|
+
yaml_content = YAML.load_file(output_yaml.path)
|
|
35
|
+
|
|
36
|
+
expect(yaml_content).to eq(
|
|
37
|
+
[
|
|
38
|
+
{ "id" => 1, "name" => "Alice", "age" => 30, "salary" => 50_000.0, "active" => true },
|
|
39
|
+
{ "id" => 2, "name" => "Bob", "age" => 25, "salary" => 40_000.5, "active" => false },
|
|
40
|
+
{ "id" => 3, "name" => "Charlie", "age" => 35, "salary" => 60_000.0, "active" => true }
|
|
41
|
+
]
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Test for overwriting existing output file
|
|
47
|
+
context "when output file already exists" do
|
|
48
|
+
let(:existing_output) { Tempfile.new(["existing_output", ".yml"]) }
|
|
49
|
+
|
|
50
|
+
before do
|
|
51
|
+
existing_output.write("Existing content\n")
|
|
52
|
+
existing_output.rewind
|
|
53
|
+
|
|
54
|
+
input_csv.write(<<~CSV)
|
|
55
|
+
id,name
|
|
56
|
+
1,Alice
|
|
57
|
+
2,Bob
|
|
58
|
+
CSV
|
|
59
|
+
input_csv.rewind
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
after do
|
|
63
|
+
existing_output.close
|
|
64
|
+
existing_output.unlink
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "overwrites the existing file" do
|
|
68
|
+
described_class.convert(input_csv.path, existing_output.path)
|
|
69
|
+
yaml_content = YAML.load_file(existing_output.path)
|
|
70
|
+
|
|
71
|
+
expect(yaml_content).to eq(
|
|
72
|
+
[
|
|
73
|
+
{ "id" => 1, "name" => "Alice" },
|
|
74
|
+
{ "id" => 2, "name" => "Bob" }
|
|
75
|
+
]
|
|
76
|
+
)
|
|
77
|
+
expect(File.read(existing_output.path)).not_to include("Existing content")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Test for creating new output file
|
|
82
|
+
context "when output file does not exist" do
|
|
83
|
+
let(:non_existent_output) { "non_existent_output.yml" }
|
|
84
|
+
|
|
85
|
+
before do
|
|
86
|
+
input_csv.write(<<~CSV)
|
|
87
|
+
id,name
|
|
88
|
+
1,Alice
|
|
89
|
+
2,Bob
|
|
90
|
+
CSV
|
|
91
|
+
input_csv.rewind
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
after do
|
|
95
|
+
File.delete(non_existent_output) if File.exist?(non_existent_output)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "creates a new file" do
|
|
99
|
+
expect(File.exist?(non_existent_output)).to be false
|
|
100
|
+
described_class.convert(input_csv.path, non_existent_output)
|
|
101
|
+
expect(File.exist?(non_existent_output)).to be true
|
|
102
|
+
|
|
103
|
+
yaml_content = YAML.load_file(non_existent_output)
|
|
104
|
+
expect(yaml_content).to eq(
|
|
105
|
+
[
|
|
106
|
+
{ "id" => 1, "name" => "Alice" },
|
|
107
|
+
{ "id" => 2, "name" => "Bob" }
|
|
108
|
+
]
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Test for processing large files
|
|
114
|
+
context "with large CSV file" do
|
|
115
|
+
before do
|
|
116
|
+
input_csv.write("id,name,value\n")
|
|
117
|
+
10_000.times do |i|
|
|
118
|
+
input_csv.write("#{i},name#{i},#{i * 10}\n")
|
|
119
|
+
end
|
|
120
|
+
input_csv.rewind
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "processes large files correctly" do
|
|
124
|
+
described_class.convert(input_csv.path, output_yaml.path)
|
|
125
|
+
yaml_content = YAML.load_file(output_yaml.path)
|
|
126
|
+
|
|
127
|
+
expect(yaml_content.size).to eq(10_000)
|
|
128
|
+
expect(yaml_content.first).to eq({ "id" => 0, "name" => "name0", "value" => 0 })
|
|
129
|
+
expect(yaml_content.last).to eq({ "id" => 9999, "name" => "name9999", "value" => 99_990 })
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "Edge cases" do
|
|
135
|
+
# Test for header-only file
|
|
136
|
+
context "with CSV file containing only headers" do
|
|
137
|
+
before do
|
|
138
|
+
input_csv.write("id,name,age\n")
|
|
139
|
+
input_csv.rewind
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "produces an empty YAML file" do
|
|
143
|
+
described_class.convert(input_csv.path, output_yaml.path)
|
|
144
|
+
yaml_content = YAML.load_file(output_yaml.path)
|
|
145
|
+
|
|
146
|
+
expect(yaml_content).to eq([])
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Test for mixed data types
|
|
151
|
+
context "with CSV containing mixed row data types" do
|
|
152
|
+
before do
|
|
153
|
+
input_csv.write(<<~CSV)
|
|
154
|
+
id,name,value
|
|
155
|
+
1,Test,123
|
|
156
|
+
2,Another test,456.78
|
|
157
|
+
3,Yet another test,true
|
|
158
|
+
4,String test,abc
|
|
159
|
+
CSV
|
|
160
|
+
input_csv.rewind
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "converts data types correctly" do
|
|
164
|
+
described_class.convert(input_csv.path, output_yaml.path)
|
|
165
|
+
yaml_content = YAML.load_file(output_yaml.path)
|
|
166
|
+
|
|
167
|
+
expect(yaml_content).to eq(
|
|
168
|
+
[
|
|
169
|
+
{ "id" => 1, "name" => "Test", "value" => 123 },
|
|
170
|
+
{ "id" => 2, "name" => "Another test", "value" => 456.78 },
|
|
171
|
+
{ "id" => 3, "name" => "Yet another test", "value" => true },
|
|
172
|
+
{ "id" => 4, "name" => "String test", "value" => "abc" }
|
|
173
|
+
]
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Test for empty data rows
|
|
179
|
+
context "with empty data rows" do
|
|
180
|
+
before do
|
|
181
|
+
input_csv.write(<<~CSV)
|
|
182
|
+
id,name,age
|
|
183
|
+
1,Alice,
|
|
184
|
+
2,,
|
|
185
|
+
3,Bob,30
|
|
186
|
+
CSV
|
|
187
|
+
input_csv.rewind
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "handles empty data rows correctly" do
|
|
191
|
+
described_class.convert(input_csv.path, output_yaml.path)
|
|
192
|
+
yaml_content = YAML.load_file(output_yaml.path)
|
|
193
|
+
|
|
194
|
+
expect(yaml_content).to eq(
|
|
195
|
+
[
|
|
196
|
+
{ "id" => 1, "name" => "Alice", "age" => nil },
|
|
197
|
+
{ "id" => 2, "name" => nil, "age" => nil },
|
|
198
|
+
{ "id" => 3, "name" => "Bob", "age" => 30 }
|
|
199
|
+
]
|
|
200
|
+
)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
context "Error handling" do
|
|
206
|
+
# Test for invalid input file path
|
|
207
|
+
context "with invalid input file path" do
|
|
208
|
+
before do
|
|
209
|
+
input_csv.write(<<~CSV)
|
|
210
|
+
id,name,age
|
|
211
|
+
1,Alice,30
|
|
212
|
+
2,Bob,25
|
|
213
|
+
3,Charlie
|
|
214
|
+
CSV
|
|
215
|
+
input_csv.rewind
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it "raises a ConversionError" do
|
|
219
|
+
expect do
|
|
220
|
+
described_class.convert("invalid.csv", output_yaml.path)
|
|
221
|
+
end.to raise_error(CsvToYaml::ConversionError, /Failed to convert CSV to YAML/)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Test for invalid output file path
|
|
226
|
+
context "with invalid output file path" do
|
|
227
|
+
before do
|
|
228
|
+
input_csv.write(<<~CSV)
|
|
229
|
+
id,name,age
|
|
230
|
+
1,Alice,30
|
|
231
|
+
2,Bob,25
|
|
232
|
+
3,Charlie
|
|
233
|
+
CSV
|
|
234
|
+
input_csv.rewind
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it "raises a ConversionError" do
|
|
238
|
+
expect do
|
|
239
|
+
described_class.convert(input_csv.path, "/invalid/path/output.yml")
|
|
240
|
+
end.to raise_error(CsvToYaml::ConversionError, /Failed to convert CSV to YAML/)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Test for empty CSV file
|
|
245
|
+
context "with empty CSV file" do
|
|
246
|
+
before do
|
|
247
|
+
input_csv.write("")
|
|
248
|
+
input_csv.rewind
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "raises a EmptyFileError" do
|
|
252
|
+
expect do
|
|
253
|
+
described_class.convert(input_csv.path, output_yaml.path)
|
|
254
|
+
end.to raise_error(CsvToYaml::EmptyFileError, /Input file '#{input_csv.path}' is empty/)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Test for invalid CSV format
|
|
259
|
+
context "with invalid CSV format" do
|
|
260
|
+
before do
|
|
261
|
+
input_csv.write(<<~CSV)
|
|
262
|
+
id:name:age
|
|
263
|
+
1:Alice:30
|
|
264
|
+
2:Bob:25
|
|
265
|
+
3:Charlie
|
|
266
|
+
CSV
|
|
267
|
+
input_csv.rewind
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it "raises a InvalidCsvFormatError" do
|
|
271
|
+
expect do
|
|
272
|
+
described_class.convert(input_csv.path, output_yaml.path)
|
|
273
|
+
end.to raise_error(CsvToYaml::InvalidCsvFormatError,
|
|
274
|
+
/The file content does not appear to be a valid CSV format/)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: csv_to_yaml
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- kazuyainoue0124
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2024-08-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '13.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '13.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rubocop
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.21'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.21'
|
|
55
|
+
description: This gem reads a CSV file and converts its content into a YAML file.
|
|
56
|
+
email:
|
|
57
|
+
- kazuyainoue0124@users.noreply.github.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- CHANGELOG.md
|
|
63
|
+
- LICENSE.txt
|
|
64
|
+
- README.md
|
|
65
|
+
- lib/csv_to_yaml.rb
|
|
66
|
+
- lib/csv_to_yaml/converter.rb
|
|
67
|
+
- lib/csv_to_yaml/errors.rb
|
|
68
|
+
- lib/csv_to_yaml/version.rb
|
|
69
|
+
- spec/csv_to_yaml_spec.rb
|
|
70
|
+
homepage: https://github.com/kazuyainoue0124/csv_to_yaml
|
|
71
|
+
licenses:
|
|
72
|
+
- MIT
|
|
73
|
+
metadata:
|
|
74
|
+
homepage_uri: https://github.com/kazuyainoue0124/csv_to_yaml
|
|
75
|
+
source_code_uri: https://github.com/kazuyainoue0124/csv_to_yaml
|
|
76
|
+
changelog_uri: https://github.com/kazuyainoue0124/csv_to_yaml/blob/main/CHANGELOG.md
|
|
77
|
+
post_install_message:
|
|
78
|
+
rdoc_options: []
|
|
79
|
+
require_paths:
|
|
80
|
+
- lib
|
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: 3.0.0
|
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
requirements: []
|
|
92
|
+
rubygems_version: 3.5.14
|
|
93
|
+
signing_key:
|
|
94
|
+
specification_version: 4
|
|
95
|
+
summary: A gem to convert CSV data to YAML format
|
|
96
|
+
test_files:
|
|
97
|
+
- spec/csv_to_yaml_spec.rb
|