csv_query 1.0.0 → 1.0.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.
- data/.travis.yml +4 -0
- data/Gemfile +2 -0
- data/README.md +2 -0
- data/Rakefile +7 -0
- data/lib/csv_query/command_line.rb +6 -8
- data/lib/csv_query/outputter.rb +55 -0
- data/lib/csv_query/query.rb +10 -27
- data/lib/csv_query/version.rb +1 -1
- data/test/csv_query/outputter_test.rb +74 -0
- data/test/csv_query/query_test.rb +41 -0
- data/test/fixtures/simple.csv +2 -0
- data/test/test_helper.rb +14 -0
- metadata +16 -3
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'csv_query/outputter'
|
1
2
|
require 'csv_query/query'
|
2
3
|
|
3
4
|
module CsvQuery
|
@@ -5,10 +6,6 @@ module CsvQuery
|
|
5
6
|
def self.parse_options_from_commandline
|
6
7
|
options = {}
|
7
8
|
|
8
|
-
# Set defaults
|
9
|
-
options[:delimiter] = ','
|
10
|
-
options[:select] = '*'
|
11
|
-
|
12
9
|
OptionParser.new do |opts|
|
13
10
|
opts.banner = "Usage: csvq [options] [CSV file]"
|
14
11
|
opts.separator ""
|
@@ -16,7 +13,7 @@ module CsvQuery
|
|
16
13
|
opts.on(
|
17
14
|
"-d",
|
18
15
|
"--delimiter DELIMITER",
|
19
|
-
"Sets the DELIMITER used between fields in the CSV data. Default: #{
|
16
|
+
"Sets the DELIMITER used between fields in the CSV data. Default: #{Query::DEFAULT_OPTIONS[:delimiter].inspect}"
|
20
17
|
) do |d|
|
21
18
|
options[:delimiter] = d
|
22
19
|
end
|
@@ -37,7 +34,7 @@ module CsvQuery
|
|
37
34
|
opts.on(
|
38
35
|
"-s",
|
39
36
|
"--select SQL",
|
40
|
-
"The SQL statement to select what fields to return. Unused if --query is given. Default: #{
|
37
|
+
"The SQL statement to select what fields to return. Unused if --query is given. Default: #{Query::DEFAULT_OPTIONS[:select].inspect}."
|
41
38
|
) do |s|
|
42
39
|
options[:select] = s
|
43
40
|
end
|
@@ -59,9 +56,10 @@ module CsvQuery
|
|
59
56
|
end
|
60
57
|
|
61
58
|
def self.run
|
59
|
+
csv_data = ARGF.read
|
60
|
+
outputter = CsvQuery::Outputter
|
62
61
|
options = parse_options_from_commandline
|
63
|
-
|
64
|
-
CsvQuery::Query.new(ARGF.read, options).run
|
62
|
+
CsvQuery::Query.new(csv_data, outputter, options).run
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module CsvQuery
|
2
|
+
class Outputter
|
3
|
+
attr_reader :results
|
4
|
+
|
5
|
+
def self.output(results)
|
6
|
+
new(results).output
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(results)
|
10
|
+
@results = results
|
11
|
+
end
|
12
|
+
|
13
|
+
def output
|
14
|
+
results.each_with_index do |result, index|
|
15
|
+
puts format_string % result
|
16
|
+
if index == 0
|
17
|
+
puts separator_line
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def column_widths
|
25
|
+
return @column_widths if @column_widths
|
26
|
+
num_columns = if results.first
|
27
|
+
results.first.size
|
28
|
+
else
|
29
|
+
0
|
30
|
+
end
|
31
|
+
|
32
|
+
column_widths = [0] * num_columns
|
33
|
+
results.collect { |row|
|
34
|
+
row.each_with_index do |column, index|
|
35
|
+
width = column.size
|
36
|
+
column_widths[index] = width if width > column_widths[index]
|
37
|
+
end
|
38
|
+
}
|
39
|
+
return column_widths
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_string
|
43
|
+
return @format_string if @format_string
|
44
|
+
|
45
|
+
format_strings = column_widths.collect { |width|
|
46
|
+
"%#{width}s"
|
47
|
+
}
|
48
|
+
@format_string = format_strings.join(" | ")
|
49
|
+
end
|
50
|
+
|
51
|
+
def separator_line
|
52
|
+
column_widths.collect { |width| '-' * width }.join('-+-')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/csv_query/query.rb
CHANGED
@@ -6,9 +6,15 @@ module CsvQuery
|
|
6
6
|
class Query
|
7
7
|
attr_reader :csv_data, :options
|
8
8
|
|
9
|
-
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
:delimiter => ',',
|
11
|
+
:select => '*'
|
12
|
+
}
|
13
|
+
|
14
|
+
def initialize(csv_data, outputter, options = {})
|
10
15
|
@csv_data = csv_data
|
11
|
-
@
|
16
|
+
@outputter = outputter
|
17
|
+
@options = options.merge(DEFAULT_OPTIONS)
|
12
18
|
end
|
13
19
|
|
14
20
|
def run
|
@@ -72,30 +78,7 @@ module CsvQuery
|
|
72
78
|
end
|
73
79
|
|
74
80
|
def output_results_table(results)
|
75
|
-
|
76
|
-
results.first.size
|
77
|
-
else
|
78
|
-
0
|
79
|
-
end
|
80
|
-
column_widths = [0] * num_columns
|
81
|
-
results.collect { |row|
|
82
|
-
row.each_with_index do |column, index|
|
83
|
-
width = column.size
|
84
|
-
column_widths[index] = width if width > column_widths[index]
|
85
|
-
end
|
86
|
-
}
|
87
|
-
format_strings = column_widths.collect { |width|
|
88
|
-
"%#{width}s"
|
89
|
-
}
|
90
|
-
format_string = format_strings.join(" | ")
|
91
|
-
|
92
|
-
results.each_with_index do |result, index|
|
93
|
-
puts format_string % result
|
94
|
-
if index == 0
|
95
|
-
# Seperate headers and results
|
96
|
-
puts column_widths.collect { |width| '-' * width }.join('-+-')
|
97
|
-
end
|
98
|
-
end
|
81
|
+
@outputter.output(results)
|
99
82
|
end
|
100
83
|
|
101
84
|
def parse_csv_data
|
@@ -104,7 +87,7 @@ module CsvQuery
|
|
104
87
|
:col_sep => options[:delimiter]
|
105
88
|
}
|
106
89
|
|
107
|
-
|
90
|
+
CSV.parse(csv_data, csv_options)
|
108
91
|
end
|
109
92
|
|
110
93
|
def run_query
|
data/lib/csv_query/version.rb
CHANGED
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require 'csv_query/outputter'
|
4
|
+
|
5
|
+
describe CsvQuery::Outputter do
|
6
|
+
describe "creating a new instance" do
|
7
|
+
it "stores results for later access" do
|
8
|
+
results = [["Foo"]]
|
9
|
+
CsvQuery::Outputter.new(results).results.must_equal([["Foo"]])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".output" do
|
14
|
+
it "outputs results to STDOUT" do
|
15
|
+
output = capture_stdout do
|
16
|
+
CsvQuery::Outputter.output([['Foo']])
|
17
|
+
end
|
18
|
+
output.must_equal("Foo\n---\n")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#output" do
|
23
|
+
it "outputs results to STDOUT" do
|
24
|
+
results = [
|
25
|
+
["Foo", "Bar"],
|
26
|
+
["Baz", "Qux"]
|
27
|
+
]
|
28
|
+
|
29
|
+
output = capture_stdout do
|
30
|
+
CsvQuery::Outputter.output(results)
|
31
|
+
end
|
32
|
+
|
33
|
+
output.must_equal <<EOS
|
34
|
+
Foo | Bar
|
35
|
+
----+----
|
36
|
+
Baz | Qux
|
37
|
+
EOS
|
38
|
+
end
|
39
|
+
|
40
|
+
it "adapts column widths to result widths" do
|
41
|
+
results = [
|
42
|
+
["A", "B", "Somewhat long header"],
|
43
|
+
["1", "Somewhat long result", "3"]
|
44
|
+
]
|
45
|
+
|
46
|
+
output = capture_stdout do
|
47
|
+
CsvQuery::Outputter.output(results)
|
48
|
+
end
|
49
|
+
|
50
|
+
output.must_equal <<EOS
|
51
|
+
A | B | Somewhat long header
|
52
|
+
--+----------------------+---------------------
|
53
|
+
1 | Somewhat long result | 3
|
54
|
+
EOS
|
55
|
+
end
|
56
|
+
|
57
|
+
it "works with numeric results" do
|
58
|
+
results = [
|
59
|
+
["Animal", "COUNT(*)"],
|
60
|
+
["Monkeys", 12]
|
61
|
+
]
|
62
|
+
|
63
|
+
output = capture_stdout do
|
64
|
+
CsvQuery::Outputter.output(results)
|
65
|
+
end
|
66
|
+
|
67
|
+
output.must_equal <<EOS
|
68
|
+
Animal | COUNT(*)
|
69
|
+
--------+---------
|
70
|
+
Monkeys | 12
|
71
|
+
EOS
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require 'csv_query/query'
|
4
|
+
require 'csv_query/outputter'
|
5
|
+
|
6
|
+
describe CsvQuery::Query do
|
7
|
+
|
8
|
+
describe "creating a new instance" do
|
9
|
+
it "stores CSV data for later use" do
|
10
|
+
query = CsvQuery::Query.new('foo', CsvQuery::Outputter, {:bar => 'baz'})
|
11
|
+
query.csv_data.must_equal('foo')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "merges options with default options" do
|
15
|
+
query = CsvQuery::Query.new('foo', CsvQuery::Outputter, {:bar => 'baz'})
|
16
|
+
query.options[:delimiter].must_equal(',')
|
17
|
+
query.options[:select].must_equal('*')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "preserves extra options" do
|
21
|
+
query = CsvQuery::Query.new('foo', CsvQuery::Outputter, {:bar => 'baz'})
|
22
|
+
query.options[:bar].must_equal('baz')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#run" do
|
27
|
+
it "outputs results" do
|
28
|
+
csv_data = "Foo\nBar"
|
29
|
+
results = [["Foo"], ["Bar"]]
|
30
|
+
|
31
|
+
outputter = MiniTest::Mock.new
|
32
|
+
outputter.expect(:output, '', [results])
|
33
|
+
|
34
|
+
query = CsvQuery::Query.new(csv_data, outputter)
|
35
|
+
query.run
|
36
|
+
|
37
|
+
outputter.verify
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
# Require files from the project lib-directory
|
5
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
6
|
+
|
7
|
+
def capture_stdout
|
8
|
+
existing_stream = $stdout
|
9
|
+
$stdout = StringIO.new
|
10
|
+
yield
|
11
|
+
output = $stdout.string
|
12
|
+
$stdout = existing_stream
|
13
|
+
return output
|
14
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv_query
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sqlite3
|
@@ -36,6 +36,7 @@ extensions: []
|
|
36
36
|
extra_rdoc_files: []
|
37
37
|
files:
|
38
38
|
- .gitignore
|
39
|
+
- .travis.yml
|
39
40
|
- Gemfile
|
40
41
|
- LICENSE
|
41
42
|
- README.md
|
@@ -44,8 +45,13 @@ files:
|
|
44
45
|
- csv_query.gemspec
|
45
46
|
- lib/csv_query.rb
|
46
47
|
- lib/csv_query/command_line.rb
|
48
|
+
- lib/csv_query/outputter.rb
|
47
49
|
- lib/csv_query/query.rb
|
48
50
|
- lib/csv_query/version.rb
|
51
|
+
- test/csv_query/outputter_test.rb
|
52
|
+
- test/csv_query/query_test.rb
|
53
|
+
- test/fixtures/simple.csv
|
54
|
+
- test/test_helper.rb
|
49
55
|
homepage: http://mentalized.net
|
50
56
|
licenses: []
|
51
57
|
post_install_message:
|
@@ -64,10 +70,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
70
|
- - ! '>='
|
65
71
|
- !ruby/object:Gem::Version
|
66
72
|
version: '0'
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
hash: 174621903631973785
|
67
76
|
requirements: []
|
68
77
|
rubyforge_project:
|
69
78
|
rubygems_version: 1.8.24
|
70
79
|
signing_key:
|
71
80
|
specification_version: 3
|
72
81
|
summary: Use SQL to query CSV data
|
73
|
-
test_files:
|
82
|
+
test_files:
|
83
|
+
- test/csv_query/outputter_test.rb
|
84
|
+
- test/csv_query/query_test.rb
|
85
|
+
- test/fixtures/simple.csv
|
86
|
+
- test/test_helper.rb
|