csv_query 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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