csv_monster 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.
- data/.gitignore +1 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +26 -0
- data/LICENSE +22 -0
- data/README.md +18 -0
- data/Rakefile +13 -0
- data/TODO.md +17 -0
- data/csv_monster.gemspec +19 -0
- data/lib/csv_monster/version.rb +3 -0
- data/lib/csv_monster.rb +75 -0
- data/spec/csv_monster_spec.rb +214 -0
- data/spec/support/another_sample.csv +3 -0
- data/spec/support/odd_number_of_records.csv +6 -0
- data/spec/support/sample.csv +3 -0
- data/spec/support/test/.gitkeep +0 -0
- metadata +100 -0
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*.gem
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
csv_monster (0.0.1)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
diff-lcs (1.2.4)
|
|
10
|
+
rake (10.0.4)
|
|
11
|
+
rspec (2.13.0)
|
|
12
|
+
rspec-core (~> 2.13.0)
|
|
13
|
+
rspec-expectations (~> 2.13.0)
|
|
14
|
+
rspec-mocks (~> 2.13.0)
|
|
15
|
+
rspec-core (2.13.1)
|
|
16
|
+
rspec-expectations (2.13.0)
|
|
17
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
|
18
|
+
rspec-mocks (2.13.1)
|
|
19
|
+
|
|
20
|
+
PLATFORMS
|
|
21
|
+
ruby
|
|
22
|
+
|
|
23
|
+
DEPENDENCIES
|
|
24
|
+
csv_monster!
|
|
25
|
+
rake
|
|
26
|
+
rspec
|
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Jeff Iacono, Joe Prang & Square Inc.
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# CSVMonster
|
|
2
|
+
|
|
3
|
+
```ruby
|
|
4
|
+
require './lib/csv_monster'
|
|
5
|
+
|
|
6
|
+
first = CSVMonster.new 'first.csv'
|
|
7
|
+
second = CSVMonster.new 'second.csv'
|
|
8
|
+
parts = CSVMonster.new ['first.csv', 'second.csv']
|
|
9
|
+
whole = CSVMonster.new 'first_and_second_already_combined.csv'
|
|
10
|
+
|
|
11
|
+
# using the + operator
|
|
12
|
+
puts (whole == (first + second)) ? "matchy!" : "no matchy!"
|
|
13
|
+
|
|
14
|
+
# using the initializer
|
|
15
|
+
puts "whole contains #{whole.content_length} records"
|
|
16
|
+
puts "parts contain #{parts.content_length} records"
|
|
17
|
+
puts whole == parts ? "matchy!" : "no matchy!"
|
|
18
|
+
```
|
data/Rakefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
require "bundler/gem_tasks"
|
|
3
|
+
begin
|
|
4
|
+
require 'rspec/core/rake_task'
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
|
7
|
+
t.rspec_opts = '-b'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
task default: :spec
|
|
11
|
+
rescue LoadError
|
|
12
|
+
$stderr.puts "rspec not available, spec task not provided"
|
|
13
|
+
end
|
data/TODO.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
### add split method
|
|
4
|
+
Add in a #split method that takes an integer and splits its content into that
|
|
5
|
+
many equal parts and writes each.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
e = ExtendedCSV.new 'somefile.csv' # 1 header + 20 rows
|
|
11
|
+
e.split(4)
|
|
12
|
+
#=> wrote 4 different files:
|
|
13
|
+
# - somefile_1.csv # 1 header + 5 rows
|
|
14
|
+
# - somefile_2.csv # 1 header + 5 rows
|
|
15
|
+
# - somefile_3.csv # 1 header + 5 rows
|
|
16
|
+
# - somefile_4.csv # 1 header + 5 rows
|
|
17
|
+
```
|
data/csv_monster.gemspec
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require File.expand_path('../lib/csv_monster/version', __FILE__)
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |gem|
|
|
4
|
+
gem.authors = ["Jeff Iacono", "Joe Prang"]
|
|
5
|
+
gem.email = ["jeff.iacono@gmail.com", "joseph.prang@gmail.com"]
|
|
6
|
+
gem.summary = "A monster of a CSV util"
|
|
7
|
+
gem.description = "A set of utils for working with CSV files"
|
|
8
|
+
gem.homepage = ''
|
|
9
|
+
gem.license = 'MIT'
|
|
10
|
+
gem.name = 'csv_monster'
|
|
11
|
+
gem.date = '2013-06-19'
|
|
12
|
+
gem.version = CSVMonster::VERSION
|
|
13
|
+
gem.require_paths = ["lib"]
|
|
14
|
+
gem.files = `git ls-files`.split($\)
|
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
16
|
+
|
|
17
|
+
gem.add_development_dependency "rake"
|
|
18
|
+
gem.add_development_dependency "rspec", [">= 2"]
|
|
19
|
+
end
|
data/lib/csv_monster.rb
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'csv'
|
|
2
|
+
require 'csv_monster/version'
|
|
3
|
+
|
|
4
|
+
class CSVMonster
|
|
5
|
+
attr_reader :filepaths
|
|
6
|
+
|
|
7
|
+
def initialize filepaths = nil
|
|
8
|
+
self.filepaths = filepaths
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def filepaths= filepaths
|
|
12
|
+
@filepaths = [*filepaths]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def + other_csv_monster
|
|
16
|
+
self.class.new self.filepaths + other_csv_monster.filepaths
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def == other_csv_monster
|
|
20
|
+
content == other_csv_monster.content
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def content
|
|
24
|
+
return @content if defined? @content
|
|
25
|
+
|
|
26
|
+
@content ||= []
|
|
27
|
+
@filepaths.each_with_index do |csv_filepath, i|
|
|
28
|
+
csv = CSV.parse(File.read(csv_filepath))
|
|
29
|
+
csv.shift unless i == 0
|
|
30
|
+
|
|
31
|
+
csv.each do |row|
|
|
32
|
+
@content << row
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
@content
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def content_length
|
|
40
|
+
content.length
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def split split_count
|
|
44
|
+
header, *tail = self.content
|
|
45
|
+
splits = []
|
|
46
|
+
|
|
47
|
+
tail.each_with_index do |row, i|
|
|
48
|
+
if (i % (tail.length / split_count)).zero? && split_count > splits.length
|
|
49
|
+
splits << self.class.new
|
|
50
|
+
splits.last.content << header
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
splits.last.content << row
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
splits
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def write! outfile = nil
|
|
60
|
+
outfile ||= default_outfile_name
|
|
61
|
+
CSV.open(outfile, "wb") do |csv|
|
|
62
|
+
content.each do |row|
|
|
63
|
+
csv << row
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
puts "wrote #{content.length} rows to #{outfile}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def default_outfile_name
|
|
73
|
+
"#{Time.now.strftime("%Y%m%d%H%M%S")}_#{@filepaths.length}_files.csv"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
require './lib/csv_monster'
|
|
2
|
+
|
|
3
|
+
def sample_csv_filepath
|
|
4
|
+
File.expand_path(File.join("..", "support", "sample.csv"), __FILE__)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def another_sample_csv_filepath
|
|
8
|
+
File.expand_path(File.join("..", "support", "another_sample.csv"), __FILE__)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def odd_number_of_records_csv_filepath
|
|
12
|
+
File.expand_path(File.join("..", "support", "odd_number_of_records.csv"), __FILE__)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def safely_rm file
|
|
16
|
+
FileUtils.rm file if File.exists? file
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe CSVMonster do
|
|
20
|
+
describe "#+" do
|
|
21
|
+
let(:csv_monster) { described_class.new sample_csv_filepath }
|
|
22
|
+
let(:another_csv_monster) { described_class.new another_sample_csv_filepath }
|
|
23
|
+
|
|
24
|
+
subject { csv_monster + another_csv_monster }
|
|
25
|
+
|
|
26
|
+
it "yields a new instance with the combination of the two's content" do
|
|
27
|
+
expect(csv_monster.content).to eq [["header_1", "header_2"],
|
|
28
|
+
["row_1_column_1_entry", "row_1_column_2_entry"],
|
|
29
|
+
["row_2_column_1_entry", "row_2_column_2_entry"]]
|
|
30
|
+
|
|
31
|
+
expect(another_csv_monster.content).to eq [["header_1", "header_2"],
|
|
32
|
+
["row_1_column_1_entry_diff_content", "row_1_column_2_entry_diff_content"],
|
|
33
|
+
["row_2_column_1_entry_diff_content", "row_2_column_2_entry_diff_content"]]
|
|
34
|
+
|
|
35
|
+
result = subject
|
|
36
|
+
|
|
37
|
+
expect(csv_monster.content).to eq [["header_1", "header_2"],
|
|
38
|
+
["row_1_column_1_entry", "row_1_column_2_entry"],
|
|
39
|
+
["row_2_column_1_entry", "row_2_column_2_entry"]]
|
|
40
|
+
|
|
41
|
+
expect(another_csv_monster.content).to eq [["header_1", "header_2"],
|
|
42
|
+
["row_1_column_1_entry_diff_content", "row_1_column_2_entry_diff_content"],
|
|
43
|
+
["row_2_column_1_entry_diff_content", "row_2_column_2_entry_diff_content"]]
|
|
44
|
+
|
|
45
|
+
expect(result.content).to eq [["header_1", "header_2"],
|
|
46
|
+
["row_1_column_1_entry", "row_1_column_2_entry"],
|
|
47
|
+
["row_2_column_1_entry", "row_2_column_2_entry"],
|
|
48
|
+
["row_1_column_1_entry_diff_content", "row_1_column_2_entry_diff_content"],
|
|
49
|
+
["row_2_column_1_entry_diff_content", "row_2_column_2_entry_diff_content"]]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "#==" do
|
|
54
|
+
let(:csv_monster) { described_class.new }
|
|
55
|
+
let(:another_csv_monster) { described_class.new }
|
|
56
|
+
|
|
57
|
+
context "when the content is the same" do
|
|
58
|
+
before do
|
|
59
|
+
csv_monster.filepaths = sample_csv_filepath
|
|
60
|
+
another_csv_monster.filepaths = sample_csv_filepath
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
subject { csv_monster == another_csv_monster }
|
|
64
|
+
it { expect(subject).to be_true }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context "when the content is different" do
|
|
68
|
+
before do
|
|
69
|
+
csv_monster.filepaths = sample_csv_filepath
|
|
70
|
+
another_csv_monster.filepaths = another_sample_csv_filepath
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
subject { csv_monster == another_csv_monster }
|
|
74
|
+
it { expect(subject).to be_false }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe "#content" do
|
|
79
|
+
let(:csv_monster) { described_class.new }
|
|
80
|
+
|
|
81
|
+
context "with a single csv file" do
|
|
82
|
+
before { csv_monster.filepaths = sample_csv_filepath }
|
|
83
|
+
subject { csv_monster.content }
|
|
84
|
+
it { expect(subject).to eq [["header_1", "header_2"],
|
|
85
|
+
["row_1_column_1_entry", "row_1_column_2_entry"],
|
|
86
|
+
["row_2_column_1_entry", "row_2_column_2_entry"]] }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context "with multiple csv files" do
|
|
90
|
+
before { csv_monster.filepaths = [sample_csv_filepath, another_sample_csv_filepath] }
|
|
91
|
+
subject { csv_monster.content }
|
|
92
|
+
|
|
93
|
+
it "combines the content, removing headers from all but the first" do
|
|
94
|
+
expect(subject).to eq [["header_1", "header_2"],
|
|
95
|
+
["row_1_column_1_entry", "row_1_column_2_entry"],
|
|
96
|
+
["row_2_column_1_entry", "row_2_column_2_entry"],
|
|
97
|
+
["row_1_column_1_entry_diff_content", "row_1_column_2_entry_diff_content"],
|
|
98
|
+
["row_2_column_1_entry_diff_content", "row_2_column_2_entry_diff_content"]]
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe "#content_length" do
|
|
104
|
+
let(:csv_monster) { described_class.new sample_csv_filepath }
|
|
105
|
+
subject { csv_monster.content_length }
|
|
106
|
+
|
|
107
|
+
it "equals the number of entries" do
|
|
108
|
+
expect(subject).to eq 3
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "#split" do
|
|
113
|
+
let(:number_of_splits) { 2 }
|
|
114
|
+
|
|
115
|
+
context "with an even number of records (excluding header)" do
|
|
116
|
+
let(:csv_monster) { described_class.new sample_csv_filepath }
|
|
117
|
+
|
|
118
|
+
subject { csv_monster.split(number_of_splits) }
|
|
119
|
+
|
|
120
|
+
it "leaves the original instance unchanged" do
|
|
121
|
+
expect(csv_monster.content).to eq [["header_1", "header_2"],
|
|
122
|
+
["row_1_column_1_entry", "row_1_column_2_entry"],
|
|
123
|
+
["row_2_column_1_entry", "row_2_column_2_entry"]]
|
|
124
|
+
|
|
125
|
+
subject
|
|
126
|
+
|
|
127
|
+
expect(csv_monster.content).to eq [["header_1", "header_2"],
|
|
128
|
+
["row_1_column_1_entry", "row_1_column_2_entry"],
|
|
129
|
+
["row_2_column_1_entry", "row_2_column_2_entry"]]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "returns the specified number of objects of the same type" do
|
|
133
|
+
result = subject
|
|
134
|
+
|
|
135
|
+
expect(result.length).to eq number_of_splits
|
|
136
|
+
|
|
137
|
+
expect(result[0]).to be_an_instance_of described_class
|
|
138
|
+
expect(result[1]).to be_an_instance_of described_class
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
it "splits the content amongst the parts evenly" do
|
|
143
|
+
result = subject
|
|
144
|
+
|
|
145
|
+
expect(result[0].content).to eq [["header_1", "header_2"],
|
|
146
|
+
["row_1_column_1_entry", "row_1_column_2_entry"]]
|
|
147
|
+
|
|
148
|
+
expect(result[1].content).to eq [["header_1", "header_2"],
|
|
149
|
+
["row_2_column_1_entry", "row_2_column_2_entry"]]
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "with an odd number of records (excluding header)" do
|
|
154
|
+
let(:csv_monster) { described_class.new odd_number_of_records_csv_filepath }
|
|
155
|
+
|
|
156
|
+
subject { csv_monster.split(number_of_splits) }
|
|
157
|
+
|
|
158
|
+
it "leaves the original instance unchanged" do
|
|
159
|
+
expect(csv_monster.content).to eq [["header_1", "header_2"],
|
|
160
|
+
["odd_row_1_column_1_entry", "odd_row_1_column_2_entry"],
|
|
161
|
+
["odd_row_2_column_1_entry", "odd_row_2_column_2_entry"],
|
|
162
|
+
["odd_row_3_column_1_entry", "odd_row_3_column_2_entry"],
|
|
163
|
+
["odd_row_4_column_1_entry", "odd_row_4_column_2_entry"],
|
|
164
|
+
["odd_row_5_column_1_entry", "odd_row_5_column_2_entry"]]
|
|
165
|
+
|
|
166
|
+
subject
|
|
167
|
+
|
|
168
|
+
expect(csv_monster.content).to eq [["header_1", "header_2"],
|
|
169
|
+
["odd_row_1_column_1_entry", "odd_row_1_column_2_entry"],
|
|
170
|
+
["odd_row_2_column_1_entry", "odd_row_2_column_2_entry"],
|
|
171
|
+
["odd_row_3_column_1_entry", "odd_row_3_column_2_entry"],
|
|
172
|
+
["odd_row_4_column_1_entry", "odd_row_4_column_2_entry"],
|
|
173
|
+
["odd_row_5_column_1_entry", "odd_row_5_column_2_entry"]]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "returns the specified number of objects of the same type" do
|
|
177
|
+
result = subject
|
|
178
|
+
expect(result.length).to eq number_of_splits
|
|
179
|
+
expect(result[0]).to be_an_instance_of described_class
|
|
180
|
+
expect(result[1]).to be_an_instance_of described_class
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it "splits the content amongst the parts approximately evenly" do
|
|
184
|
+
result = subject
|
|
185
|
+
|
|
186
|
+
expect(result[0].content).to eq [["header_1", "header_2"],
|
|
187
|
+
["odd_row_1_column_1_entry", "odd_row_1_column_2_entry"],
|
|
188
|
+
["odd_row_2_column_1_entry", "odd_row_2_column_2_entry"]]
|
|
189
|
+
|
|
190
|
+
expect(result[1].content).to eq [["header_1", "header_2"],
|
|
191
|
+
["odd_row_3_column_1_entry", "odd_row_3_column_2_entry"],
|
|
192
|
+
["odd_row_4_column_1_entry", "odd_row_4_column_2_entry"],
|
|
193
|
+
["odd_row_5_column_1_entry", "odd_row_5_column_2_entry"]]
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
describe "#write!" do
|
|
199
|
+
let(:infile) { sample_csv_filepath }
|
|
200
|
+
let(:outfile) { File.expand_path(File.join("..", "support", "test", "write_sample.csv"), __FILE__) }
|
|
201
|
+
let(:csv_monster) { described_class.new infile }
|
|
202
|
+
|
|
203
|
+
before { safely_rm outfile }
|
|
204
|
+
after { safely_rm outfile }
|
|
205
|
+
|
|
206
|
+
subject { csv_monster.write! outfile }
|
|
207
|
+
|
|
208
|
+
it "writes the file to the specified location" do
|
|
209
|
+
expect(File.exists? outfile).to be_false
|
|
210
|
+
subject
|
|
211
|
+
expect(FileUtils.identical? infile, outfile).to be_true
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
header_1,header_2
|
|
2
|
+
odd_row_1_column_1_entry,odd_row_1_column_2_entry
|
|
3
|
+
odd_row_2_column_1_entry,odd_row_2_column_2_entry
|
|
4
|
+
odd_row_3_column_1_entry,odd_row_3_column_2_entry
|
|
5
|
+
odd_row_4_column_1_entry,odd_row_4_column_2_entry
|
|
6
|
+
odd_row_5_column_1_entry,odd_row_5_column_2_entry
|
|
File without changes
|
metadata
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: csv_monster
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Jeff Iacono
|
|
9
|
+
- Joe Prang
|
|
10
|
+
autorequire:
|
|
11
|
+
bindir: bin
|
|
12
|
+
cert_chain: []
|
|
13
|
+
date: 2013-06-19 00:00:00.000000000 Z
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: rake
|
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
|
18
|
+
none: false
|
|
19
|
+
requirements:
|
|
20
|
+
- - ! '>='
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '0'
|
|
23
|
+
type: :development
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
none: false
|
|
27
|
+
requirements:
|
|
28
|
+
- - ! '>='
|
|
29
|
+
- !ruby/object:Gem::Version
|
|
30
|
+
version: '0'
|
|
31
|
+
- !ruby/object:Gem::Dependency
|
|
32
|
+
name: rspec
|
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
|
34
|
+
none: false
|
|
35
|
+
requirements:
|
|
36
|
+
- - ! '>='
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '2'
|
|
39
|
+
type: :development
|
|
40
|
+
prerelease: false
|
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
42
|
+
none: false
|
|
43
|
+
requirements:
|
|
44
|
+
- - ! '>='
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '2'
|
|
47
|
+
description: A set of utils for working with CSV files
|
|
48
|
+
email:
|
|
49
|
+
- jeff.iacono@gmail.com
|
|
50
|
+
- joseph.prang@gmail.com
|
|
51
|
+
executables: []
|
|
52
|
+
extensions: []
|
|
53
|
+
extra_rdoc_files: []
|
|
54
|
+
files:
|
|
55
|
+
- .gitignore
|
|
56
|
+
- Gemfile
|
|
57
|
+
- Gemfile.lock
|
|
58
|
+
- LICENSE
|
|
59
|
+
- README.md
|
|
60
|
+
- Rakefile
|
|
61
|
+
- TODO.md
|
|
62
|
+
- csv_monster.gemspec
|
|
63
|
+
- lib/csv_monster.rb
|
|
64
|
+
- lib/csv_monster/version.rb
|
|
65
|
+
- spec/csv_monster_spec.rb
|
|
66
|
+
- spec/support/another_sample.csv
|
|
67
|
+
- spec/support/odd_number_of_records.csv
|
|
68
|
+
- spec/support/sample.csv
|
|
69
|
+
- spec/support/test/.gitkeep
|
|
70
|
+
homepage: ''
|
|
71
|
+
licenses:
|
|
72
|
+
- MIT
|
|
73
|
+
post_install_message:
|
|
74
|
+
rdoc_options: []
|
|
75
|
+
require_paths:
|
|
76
|
+
- lib
|
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
|
+
none: false
|
|
79
|
+
requirements:
|
|
80
|
+
- - ! '>='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
|
+
none: false
|
|
85
|
+
requirements:
|
|
86
|
+
- - ! '>='
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
requirements: []
|
|
90
|
+
rubyforge_project:
|
|
91
|
+
rubygems_version: 1.8.21
|
|
92
|
+
signing_key:
|
|
93
|
+
specification_version: 3
|
|
94
|
+
summary: A monster of a CSV util
|
|
95
|
+
test_files:
|
|
96
|
+
- spec/csv_monster_spec.rb
|
|
97
|
+
- spec/support/another_sample.csv
|
|
98
|
+
- spec/support/odd_number_of_records.csv
|
|
99
|
+
- spec/support/sample.csv
|
|
100
|
+
- spec/support/test/.gitkeep
|