array_to_csv 0.0.1 → 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 +4 -4
- data/README.md +102 -0
- data/array_to_csv.gemspec +1 -1
- data/lib/array_to_csv.rb +24 -35
- data/lib/array_to_csv/core_ext.rb +7 -2
- data/lib/array_to_csv/csv_writer.rb +53 -0
- data/spec/array_to_csv_spec.rb +33 -0
- data/spec/core_ext_spec.rb +8 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a35e265bf29320eaad3cc7455ba66882a062347
|
4
|
+
data.tar.gz: 07ccceb8f2ee1868f1de8c812a98b0b5d126799a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10d9744daa78f20ab1c7c42a1777f69866339c773f4e7d08b73b361a69a97ae452f5533446c68c66cd4d839adfdd9774859a2ef889808d51a5f836ea2ad31f4e
|
7
|
+
data.tar.gz: 68bbacbd8721eb81b4b04c19867a682aa782c4cbf35e10da6fc3d018ceb3e69ac2f1a8b9d7615001381c9f387cbd91ce3ce78d962b53dde372f5e328cae716a2
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# array_to_csv
|
2
|
+
|
3
|
+
Simple convenience library for converting an array of hashes to CSV
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'array_to_csv'
|
11
|
+
```
|
12
|
+
|
13
|
+
OR
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'array_to_csv', :require => 'array_to_csv/core_ext'
|
17
|
+
```
|
18
|
+
|
19
|
+
if you want the to_csv method to be added to the Array class.
|
20
|
+
|
21
|
+
Then execute:
|
22
|
+
|
23
|
+
```sh
|
24
|
+
$ bundle install
|
25
|
+
```
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
```sh
|
30
|
+
$ gem install array_to_csv
|
31
|
+
```
|
32
|
+
|
33
|
+
## Example Usage
|
34
|
+
|
35
|
+
### Using Array#to_csv (re-opening the Array class)
|
36
|
+
|
37
|
+
If you require array_to_csv/core_ext,
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
require 'array_to_csv/core_ext'
|
41
|
+
```
|
42
|
+
|
43
|
+
(or require it from within your Gemfile)
|
44
|
+
you can call to_csv directly on an array.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
puts [
|
48
|
+
{:first_name => 'Rob', :last_name => 'Bobber'},
|
49
|
+
{:first_name => 'Bob', :age => 103}
|
50
|
+
].to_csv
|
51
|
+
```
|
52
|
+
|
53
|
+
This outputs:
|
54
|
+
|
55
|
+
first_name,last_name,age
|
56
|
+
Rob,Bobber,
|
57
|
+
Rob,,103
|
58
|
+
|
59
|
+
Which would look something like this in your favourite spreadsheet editor
|
60
|
+
|
61
|
+
| first_name | last_name | age |
|
62
|
+
|------------|-----------|-----|
|
63
|
+
| Rob | Bobber | |
|
64
|
+
| Bob | | 103 |
|
65
|
+
|
66
|
+
When no arguments are given to to_csv, the CSV data is returned as a string.
|
67
|
+
|
68
|
+
You can pass in a file path, and the CSV data will be written directly to file,
|
69
|
+
instead of being returned as a string.
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
[
|
73
|
+
{:first_name => 'Rob', :last_name => 'Bobber'},
|
74
|
+
{:first_name => 'Bob', :age => 103}
|
75
|
+
].to_csv("/tmp/people.csv")
|
76
|
+
```
|
77
|
+
|
78
|
+
You can also pass in a File object as the first argument, or any other
|
79
|
+
IO/IO-like object (anything that implements #write(string) and #close).
|
80
|
+
|
81
|
+
### Without reopening Array class
|
82
|
+
|
83
|
+
If you don't want to being reopening core classes, you can convert an array to CSV
|
84
|
+
like this:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
data = [
|
88
|
+
{:first_name => 'Rob', :last_name => 'Bobber'},
|
89
|
+
{:first_name => 'Bob', :age => 103}
|
90
|
+
]
|
91
|
+
puts ArrayToCsv.new(data).to_csv
|
92
|
+
```
|
93
|
+
|
94
|
+
Which produces the same output as above
|
95
|
+
|
96
|
+
first_name,last_name,age
|
97
|
+
Rob,Bobber,
|
98
|
+
Rob,,103
|
99
|
+
|
100
|
+
The interface for ArrayToCsv#to_csv is the same as that for Array#to_csv.
|
101
|
+
|
102
|
+
You can pass in a file path, File, or IO/IO-like object.
|
data/array_to_csv.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "array_to_csv"
|
7
|
-
spec.version = "0.0
|
7
|
+
spec.version = "0.1.0"
|
8
8
|
spec.authors = ["Joel Plane"]
|
9
9
|
spec.email = ["joel.plane@gmail.com"]
|
10
10
|
spec.description = %q{Adds convenience method Array#to_csv for converting an array of hashes to CSV.}
|
data/lib/array_to_csv.rb
CHANGED
@@ -1,52 +1,41 @@
|
|
1
1
|
class ArrayToCsv
|
2
2
|
|
3
|
-
|
3
|
+
require 'array_to_csv/csv_writer'
|
4
|
+
|
5
|
+
def initialize array, csv_lib=nil
|
4
6
|
@array = array
|
5
|
-
@
|
7
|
+
@csv_lib = csv_lib
|
6
8
|
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
# @return [String, nil]
|
11
|
+
def to_csv io_or_file_path=nil
|
12
|
+
case io_or_file_path
|
13
|
+
when nil
|
14
|
+
to_csv_string
|
15
|
+
when String
|
16
|
+
to_csv_file io_or_file_path
|
17
|
+
else
|
18
|
+
to_csv_io io_or_file_path
|
13
19
|
end
|
14
20
|
end
|
15
21
|
|
16
22
|
private
|
17
23
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def head
|
26
|
-
@head_from_array ||= [].tap do |keys|
|
27
|
-
seen_keys = {}
|
28
|
-
@array.each do |hash|
|
29
|
-
hash.keys.each do |key|
|
30
|
-
unless seen_keys[key]
|
31
|
-
seen_keys[key] = true
|
32
|
-
keys << key
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
24
|
+
# @return [String]
|
25
|
+
def to_csv_string
|
26
|
+
StringIO.new.tap do |string_io|
|
27
|
+
self.to_csv string_io
|
28
|
+
end.string
|
37
29
|
end
|
38
30
|
|
39
|
-
def
|
40
|
-
|
31
|
+
def to_csv_file file_path
|
32
|
+
file_io = File.open(file_path, 'w')
|
33
|
+
self.to_csv file_io
|
41
34
|
end
|
42
35
|
|
43
|
-
#
|
44
|
-
def
|
45
|
-
|
46
|
-
FasterCSV
|
47
|
-
else
|
48
|
-
CSV
|
49
|
-
end
|
36
|
+
# @return [nil]
|
37
|
+
def to_csv_io io
|
38
|
+
CsvWriter.new(@array, io, @csv_lib).write
|
50
39
|
end
|
51
40
|
|
52
41
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class ArrayToCsv::CsvWriter
|
2
|
+
|
3
|
+
def initialize array, io, csv_lib
|
4
|
+
@array, @io = array, io
|
5
|
+
@csv = csv_lib || choose_csv_lib
|
6
|
+
end
|
7
|
+
|
8
|
+
def write
|
9
|
+
each_row do |row|
|
10
|
+
write_line row
|
11
|
+
end
|
12
|
+
@io.close
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def write_line row
|
17
|
+
@io.write @csv.generate_line row
|
18
|
+
end
|
19
|
+
|
20
|
+
def each_row
|
21
|
+
yield head
|
22
|
+
@array.each do |hash|
|
23
|
+
yield row_from_hash hash
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def head
|
28
|
+
@head_from_array ||= [].tap do |keys|
|
29
|
+
seen_keys = {}
|
30
|
+
@array.each do |hash|
|
31
|
+
hash.keys.each do |key|
|
32
|
+
unless seen_keys[key]
|
33
|
+
seen_keys[key] = true
|
34
|
+
keys << key
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def row_from_hash hash
|
42
|
+
hash.values_at(*head)
|
43
|
+
end
|
44
|
+
|
45
|
+
def choose_csv_lib
|
46
|
+
if RUBY_VERSION =~ /^1\.8/
|
47
|
+
FasterCSV
|
48
|
+
else
|
49
|
+
CSV
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/spec/array_to_csv_spec.rb
CHANGED
@@ -41,4 +41,37 @@ describe ArrayToCsv do
|
|
41
41
|
|
42
42
|
end
|
43
43
|
|
44
|
+
describe ".to_csv(io)" do
|
45
|
+
|
46
|
+
subject { ArrayToCsv.new([{:key1 => 'value1'}, {:key2 => 'value2'}]) }
|
47
|
+
|
48
|
+
it "should stream output to provided io object" do
|
49
|
+
io = double
|
50
|
+
expect(io).to receive(:write).with("key1,key2\n")
|
51
|
+
expect(io).to receive(:write).with("value1,\n")
|
52
|
+
expect(io).to receive(:write).with(",value2\n")
|
53
|
+
expect(io).to receive(:close)
|
54
|
+
subject.to_csv(io)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return nil" do
|
58
|
+
io = double :write => nil, :close => nil
|
59
|
+
expect(subject.to_csv(io)).to be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe ".to_csv(file_path)" do
|
65
|
+
|
66
|
+
subject { ArrayToCsv.new([{:key1 => 'value1'}, {:key2 => 'value2'}]) }
|
67
|
+
let(:csv_output) { "key1,key2\nvalue1,\n,value2\n" }
|
68
|
+
let(:test_path) { "/tmp/array_to_csv_test_output.csv" }
|
69
|
+
|
70
|
+
it "should write CSV to file" do
|
71
|
+
subject.to_csv test_path
|
72
|
+
expect(File.read(test_path)).to eq(csv_output)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
44
77
|
end
|
data/spec/core_ext_spec.rb
CHANGED
@@ -16,4 +16,12 @@ describe "array_to_csv/core_ext" do
|
|
16
16
|
expect(array.to_csv).to eq(ArrayToCsv.new(array).to_csv)
|
17
17
|
end
|
18
18
|
|
19
|
+
it "should delegate with arguments" do
|
20
|
+
array = []
|
21
|
+
fake_io, inst = double, double
|
22
|
+
expect(ArrayToCsv).to receive(:new).and_return(inst)
|
23
|
+
expect(inst).to receive(:to_csv).with(fake_io)
|
24
|
+
array.to_csv fake_io
|
25
|
+
end
|
26
|
+
|
19
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: array_to_csv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Plane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -63,10 +63,12 @@ files:
|
|
63
63
|
- .gitignore
|
64
64
|
- Gemfile
|
65
65
|
- LICENSE.txt
|
66
|
+
- README.md
|
66
67
|
- Rakefile
|
67
68
|
- array_to_csv.gemspec
|
68
69
|
- lib/array_to_csv.rb
|
69
70
|
- lib/array_to_csv/core_ext.rb
|
71
|
+
- lib/array_to_csv/csv_writer.rb
|
70
72
|
- spec/array_to_csv_spec.rb
|
71
73
|
- spec/core_ext_spec.rb
|
72
74
|
- test_helper.rb
|