csv_tools 0.1.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 90e76e93fa5688fed25b5c7870d318929bfc505e
4
+ data.tar.gz: 544f99192cddc9152eb8787844688ac6844acc79
5
+ SHA512:
6
+ metadata.gz: 5a350262ab443cdbe23a7f1cd8c80a51187471f116da264d1571b9bf5bc529eb2891b7082913c48fcbacee4a116d7befd3646d8da39ef2b6e64e23500e6c5c38
7
+ data.tar.gz: 123b2e8424f7d6a169f2c775cd6e07c4749bca58d37ab6a3e95e5e9781420639da5eed9998fc70cdad963a4d4b42ee0d257e38bc1338a10f2d25eab5a2b4df78
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in csv_tools.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Joey Freund
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,73 @@
1
+ # CSV Tools
2
+
3
+ A simple utility library and scripts to perform simple operations on CSV files.
4
+ At the moment, the following operations are supported:
5
+
6
+ * Selecting specific columns (by index)
7
+ * Filter rows, based on a specific field
8
+ * Join two CSV files on a single column
9
+
10
+ ## Installation
11
+
12
+ ```
13
+ gem install csv_tools
14
+ ```
15
+
16
+ ## Examples
17
+
18
+ Using the following data files
19
+
20
+ ```sh
21
+ $ cat students.csv
22
+ student-id,name
23
+ 1,Alice
24
+ 2,Bob
25
+ 3,Rob
26
+ 4,Allie
27
+
28
+ $ cat marks.csv
29
+ student-id,Assignment 1,Assignment 2,Test
30
+ 1,72,83,77
31
+ 2,53,61,58
32
+ 3,85,88,87
33
+ 4,92,80,75
34
+ ```
35
+
36
+ #### Select
37
+
38
+ Select specific columns, by index.
39
+
40
+ ```sh
41
+ $ csv_select marks.csv 0 3
42
+ student-id,Test
43
+ 1,77
44
+ 2,58
45
+ 3,87
46
+ 4,75
47
+ ```
48
+
49
+ #### Join
50
+
51
+ Join two files on a column (called `student-id`)
52
+
53
+ ```sh
54
+ $ csv_join students.csv marks.csv student-id
55
+ student-id,name,Assignment 1,Assignment 2,Test
56
+ 1,Alice,72,83,77
57
+ 2,Bob,53,61,58
58
+ 3,Rob,85,88,87
59
+ 4,Allie,92,80,75
60
+ ```
61
+
62
+ #### Filter
63
+
64
+ Keep rows whose second column (i.e. at index 1) contains the string `ob`
65
+
66
+ ```sh
67
+ $ csv_join students.csv marks.csv student-id > joined.csv
68
+
69
+ $ csv_filter joined.csv 1 ob
70
+ student-id,name,Assignment 1,Assignment 2,Test
71
+ 2,Bob,53,61,58
72
+ 3,Rob,85,88,87
73
+ ```
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/csv_filter ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'csv_tools'
4
+
5
+ if ARGV.length != 3
6
+ abort("Usage: #{File.basename($0)} CSV-FILE COLUMN-INDEX FIELD-VALUE")
7
+ end
8
+
9
+ column_index = ARGV[1].to_i
10
+ raise "Invalid index #{ARGV[1]}" if column_index.nil?
11
+ CSVTools::csv_filter(ARGV[0], column_index, ARGV[2])
data/bin/csv_join ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'csv_tools'
4
+
5
+
6
+ if ARGV.length != 3
7
+ abort("Usage: #{File.basename($0)} CSV-FILE1 CSV-FILE2 JOIN-BY-COLUMN")
8
+ end
9
+
10
+ CSVTools::csv_join(ARGV[0], ARGV[1], ARGV[2])
data/bin/csv_select ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'csv_tools'
4
+
5
+ if ARGV.length < 3
6
+ abort("Usage: #{File.basename($0)} CSV-FILE COLUMN-INDEX [COLUMN-INDEX ...]")
7
+ end
8
+
9
+ indices = ARGV[1..-1].map {|s| s.to_i}
10
+ raise "Invalid indices #{ARGV[1..-1]}" if indices.any? {|i| i.nil?}
11
+ CSVTools::csv_select(ARGV[0], indices)
data/csv_tools.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'csv_tools/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "csv_tools"
8
+ spec.version = CSVTools::VERSION
9
+ spec.authors = ["Joey Freund"]
10
+ spec.email = ["joeyfreund@gmail.com"]
11
+
12
+ spec.summary = %q{Command-line tools for CSV file manipulation.}
13
+ spec.description = %q{Manipulate CSV files as if they were SQL tables.}
14
+ spec.homepage = "https://github.com/joeyfreund/csv_tools"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
@@ -0,0 +1,3 @@
1
+ module CSVTools
2
+ VERSION = "0.1.1"
3
+ end
data/lib/csv_tools.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'csv'
2
+ require 'set'
3
+ require "csv_tools/version"
4
+
5
+
6
+
7
+ module CSVTools
8
+
9
+
10
+ DEFAULT_CSV_READ_OPTS = {headers: true, skip_blanks: true}
11
+
12
+
13
+ # @param csv_table [CSV::Table]
14
+ # @param column_index [integer]
15
+ # @return Hash[string --> Array of string-arrays]
16
+ def CSVTools.group_by_column(csv_table, column_index)
17
+ result = {}
18
+
19
+ csv_table.group_by {|row| row.fields[column_index]} .each do |key, row_objects|
20
+ result[key] = row_objects.map do |row|
21
+ row.fields[0...column_index] + row.fields[column_index + 1...row.fields.length]
22
+ end
23
+ end
24
+
25
+ return result
26
+ end
27
+
28
+
29
+
30
+
31
+ def CSVTools.csv_join(path1, path2, join_by_column, out = STDOUT)
32
+ csv1, csv2 = [path1, path2].map {|p| CSV.read(p, DEFAULT_CSV_READ_OPTS)}
33
+
34
+ # Make sure the join-by column exists in both CSV's
35
+ index1, index2 = [csv1, csv2].map {|csv| csv.headers.index(join_by_column) }
36
+ raise "#{path1} does not have a column '#{join_by_column}'" if index1.nil?
37
+ raise "#{path2} does not have a column '#{join_by_column}'" if index2.nil?
38
+
39
+ # Print the header line (join-by column is first, and appears only once)
40
+ h1, h2 = [csv1.headers , csv2.headers]
41
+ h1.delete_at(index1)
42
+ h2.delete_at(index2)
43
+ out.puts join_by_column + ',' + h1.join(",") + ',' + h2.join(',')
44
+
45
+ # Print the data rows ...
46
+ hash1 = group_by_column(csv1, index1)
47
+ hash2 = group_by_column(csv2, index2)
48
+
49
+ # And now ... JOIN the two CSV's (adding nil's for missing rows)
50
+ (hash1.keys + hash2.keys).to_set.each do |key|
51
+ rows1 = hash1[key] || [ [nil] * (csv1.headers.length - 1)]
52
+ rows2 = hash2[key] || [ [nil] * (csv2.headers.length - 1)]
53
+
54
+ rows1.each do |r1|
55
+ rows2.each do |r2|
56
+ out.puts key + ',' + r1.join(',') + ',' + r2.join(',')
57
+ end
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+
64
+
65
+
66
+ def CSVTools.select_values(values, indices)
67
+ raise "Invalid indices #{indices} for #{values}" if indices.any? {|i| i < 0 || i >= values.length}
68
+ return indices.map {|i| values[i]}
69
+ end
70
+
71
+
72
+ def CSVTools.csv_select(path, column_indices, out = STDOUT)
73
+ csv = CSV.read(path, DEFAULT_CSV_READ_OPTS)
74
+
75
+ out.puts select_values(csv.headers, column_indices).join(',')
76
+ csv.each do |row|
77
+ out.puts select_values(row.fields, column_indices).join(',')
78
+ end
79
+ end
80
+
81
+
82
+ def CSVTools.csv_filter(path, column_index, field_value, out = STDOUT)
83
+ csv = CSV.read(path, DEFAULT_CSV_READ_OPTS)
84
+
85
+ out.puts csv.headers.join(',')
86
+ csv.select {|row| row.fields[column_index].downcase.include? field_value.downcase} .each do |row|
87
+ out.puts row.fields.join(',')
88
+ end
89
+ end
90
+
91
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: csv_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Joey Freund
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Manipulate CSV files as if they were SQL tables.
42
+ email:
43
+ - joeyfreund@gmail.com
44
+ executables:
45
+ - csv_filter
46
+ - csv_join
47
+ - csv_select
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".gitignore"
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - bin/csv_filter
57
+ - bin/csv_join
58
+ - bin/csv_select
59
+ - csv_tools.gemspec
60
+ - lib/csv_tools.rb
61
+ - lib/csv_tools/version.rb
62
+ homepage: https://github.com/joeyfreund/csv_tools
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.4.8
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Command-line tools for CSV file manipulation.
86
+ test_files: []