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.
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - rbx-19mode
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in csv_query.gemspec
4
4
  gemspec
5
+
6
+ gem "rake"
data/README.md CHANGED
@@ -11,6 +11,8 @@ For example:
11
11
  --------
12
12
  1
13
13
 
14
+ [![Build Status](https://secure.travis-ci.org/koppen/csv_query.png?branch=master)](https://travis-ci.org/koppen/csv_query)
15
+
14
16
  Assumptions
15
17
  -----------
16
18
 
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = "test/**/*_test.rb"
7
+ end
8
+
9
+ task :default => :test
@@ -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: #{options[:delimiter].inspect}"
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: #{options[:select].inspect}."
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
@@ -6,9 +6,15 @@ module CsvQuery
6
6
  class Query
7
7
  attr_reader :csv_data, :options
8
8
 
9
- def initialize(csv_data, options)
9
+ DEFAULT_OPTIONS = {
10
+ :delimiter => ',',
11
+ :select => '*'
12
+ }
13
+
14
+ def initialize(csv_data, outputter, options = {})
10
15
  @csv_data = csv_data
11
- @options = options
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
- num_columns = if results.first
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
- csv = CSV.parse(csv_data, csv_options)
90
+ CSV.parse(csv_data, csv_options)
108
91
  end
109
92
 
110
93
  def run_query
@@ -1,3 +1,3 @@
1
1
  module CsvQuery
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -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
@@ -0,0 +1,2 @@
1
+ Name,Age,Gender
2
+ Jakob,36,Male
@@ -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.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-10 00:00:00.000000000 Z
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