tabular 0.0.1 → 0.0.2

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/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg
data/README CHANGED
@@ -2,12 +2,22 @@ Tabular is a Ruby library for reading, writing, and manipulating CSV, tab-delimi
2
2
 
3
3
  I extracted it from production code. Still extracting it, actually. I need to read structured data and manipulate it via a common interface before persisting it with ActiveRecord.
4
4
 
5
+ Install
6
+ -------
7
+ sudo gem install tabular
8
+
9
+ (The gem is hosted on Gemcutter, not RubyForge)
10
+
5
11
 
6
12
  Dependencies
7
13
  ------------
8
14
  For tab-delimited data: Ruby standard lib
9
- For CSV: FasterCSV
10
- For Excel: Spreadsheet gem
15
+
16
+ For CSV: FasterCSV (http://fastercsv.rubyforge.org/)
17
+ sudo gem install fastercsv
18
+
19
+ For Excel: Spreadsheet gem (http://spreadsheet.rubyforge.org/)
20
+ sudo gem install spreadsheet
11
21
 
12
22
 
13
23
  Examples
@@ -30,10 +40,14 @@ Table.read assumes that .txt files are tab-delimited, .csv files are comma-delim
30
40
 
31
41
  Table.new accepts an Array of Arrays.
32
42
 
33
- Table.new also accepts an options hash. Currently, :columns is the only option. Examples:
43
+ Table.new also accepts an options hash.
44
+
45
+ :columns option to map columns to a different key or type:
34
46
  :city_state => :location -- Maps :city_state column to :location. A column with a "City State" header would be accessed as row[:location]
35
47
  :flyer_approved => { :column_type => :boolean } -- Coerce :flyer_approved column cells to booleans.
36
48
 
49
+ :as => [:csv, :xls, :txt] to override file format
50
+
37
51
 
38
52
  Tests
39
53
  -----
@@ -43,4 +57,4 @@ There's basic test coverage. More comprehensive test coverage needs to be extrac
43
57
  Copyright
44
58
  ---------
45
59
 
46
- Copyright (c) 2009 Scott Willson. See LICENSE for details.
60
+ Copyright (c) 2010 Scott Willson. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -1,16 +1,19 @@
1
1
  module Tabular
2
2
  # The Table's header: a list of Columns.
3
3
  class Columns
4
+ include Enumerable
5
+
4
6
  # +data+ -- array of header names
5
7
  # +columns_map+ -- see Table. Maps column names and type conversion.
6
8
  def initialize(data, columns_map = {})
7
- @columns_map = columns_map
9
+ columns_map ||= {}
10
+ @columns_map = normalize_columns_map(columns_map)
8
11
  @column_indexes = {}
9
12
  @columns_by_key = {}
10
13
  index = 0
11
14
  @columns = nil
12
15
  @columns = data.map do |column|
13
- new_column = Tabular::Column.new(column, columns_map)
16
+ new_column = Tabular::Column.new(column, @columns_map)
14
17
  unless new_column.key.blank?
15
18
  @column_indexes[new_column.key] = index
16
19
  @columns_by_key[new_column.key] = new_column
@@ -51,5 +54,21 @@ module Tabular
51
54
  end
52
55
  @columns << column
53
56
  end
57
+
58
+
59
+ private
60
+
61
+ def normalize_columns_map(columns_map)
62
+ normalized_columns_map = {}
63
+ columns_map.each do |key, value|
64
+ case value
65
+ when Hash, Symbol
66
+ normalized_columns_map[key.to_sym] = value
67
+ else
68
+ normalized_columns_map[key.to_sym] = value.to_sym
69
+ end
70
+ end
71
+ normalized_columns_map
72
+ end
54
73
  end
55
74
  end
data/lib/tabular/row.rb CHANGED
@@ -3,12 +3,15 @@ module Tabular
3
3
  class Row
4
4
  include Enumerable
5
5
 
6
- # +columns+ -- array of string
6
+ attr_reader :index
7
+
8
+ # +table+ -- Table
7
9
  # +cell+ -- array (not neccessarily Strings)
8
- def initialize(columns, cells = [])
9
- @columns = columns
10
+ def initialize(table, cells = [])
11
+ @table = table
10
12
  @array = cells
11
13
  @hash = nil
14
+ @index = table.rows.size
12
15
  end
13
16
 
14
17
  # Cell value by symbol. E.g., row[:phone_number]
@@ -16,13 +19,13 @@ module Tabular
16
19
  hash[key]
17
20
  end
18
21
 
19
- # Set cell value. Adds cell to end of Row and adds new Column if there is no Column fo +key_
22
+ # Set cell value. Adds cell to end of Row and adds new Column if there is no Column for +key_
20
23
  def []=(key, value)
21
- if @columns.has_key?(key)
22
- @array[@columns.index(key)] = value
24
+ if columns.has_key?(key)
25
+ @array[columns.index(key)] = value
23
26
  else
24
27
  @array << value
25
- @columns << key
28
+ columns << key
26
29
  end
27
30
  hash[key] = value
28
31
  end
@@ -37,6 +40,16 @@ module Tabular
37
40
  @array.join(sep)
38
41
  end
39
42
 
43
+ def previous
44
+ if index > 0
45
+ @table.rows[index - 1]
46
+ end
47
+ end
48
+
49
+ def columns
50
+ @table.columns
51
+ end
52
+
40
53
  def to_hash
41
54
  hash.dup
42
55
  end
@@ -52,12 +65,11 @@ module Tabular
52
65
 
53
66
  protected
54
67
 
55
-
56
68
  def hash #:nodoc:
57
69
  unless @hash
58
70
  @hash = Hash.new
59
- @columns.each do |column|
60
- index = @columns.index(column.key)
71
+ columns.each do |column|
72
+ index = columns.index(column.key)
61
73
  if index
62
74
  case column.column_type
63
75
  when :boolean
data/lib/tabular/table.rb CHANGED
@@ -1,27 +1,44 @@
1
1
  module Tabular
2
2
  # Simple Enumerable list of Hashes. Use Table.read(file_path) to read file.
3
3
  class Table
4
- attr_reader :columns, :rows
4
+ attr_reader :rows
5
5
 
6
6
  # Assumes .txt = tab-delimited, .csv = CSV, .xls = Excel. Assumes first row is the header.
7
7
  # Normalizes column names to lower-case with underscores.
8
8
  def self.read(file_path, *options)
9
9
  raise "Could not find '#{file_path}'" unless File.exists?(file_path)
10
+ options = extract_options(options)
11
+ as = options.delete(:as)
10
12
 
11
- case File.extname(file_path)
12
- when ".xls", ".xlsx"
13
+ if as.present?
14
+ format = as
15
+ else
16
+ format = case File.extname(file_path)
17
+ when ".xls", ".xlsx"
18
+ :xls
19
+ when ".txt"
20
+ :txt
21
+ when ".csv"
22
+ :csv
23
+ end
24
+ end
25
+
26
+ case format
27
+ when :xls
13
28
  require "spreadsheet"
14
29
  # Row#to_a coerces Excel data to Strings, but we want Dates and Numbers
15
30
  data = []
16
31
  Spreadsheet.open(file_path).worksheets.first.each do |excel_row|
17
32
  data << excel_row.inject([]) { |row, cell| row << cell; row }
18
33
  end
19
- when ".txt"
34
+ when :txt
20
35
  require "csv"
21
36
  data = ::CSV.open(file_path, "r","\t").collect { |row| row }
22
- when ".csv"
37
+ when :csv
23
38
  require "fastercsv"
24
39
  data = FasterCSV.read(file_path)
40
+ else
41
+ raise "Cannot read '#{format}' format. Expected :xls, :xlsx, :txt, or :csv"
25
42
  end
26
43
 
27
44
  Table.new data, options
@@ -31,20 +48,16 @@ module Tabular
31
48
  # Maps rows to Hash-like Tabular::Rows.
32
49
  #
33
50
  # Options:
34
- # :column => { :original_name => :preferred_name, :column_name => { :column_type => :boolean } }
51
+ # :columns => { :original_name => :preferred_name, :column_name => { :column_type => :boolean } }
35
52
  def initialize(rows = [], *options)
36
- if options
37
- options = options.flatten.first || {}
38
- else
39
- options = {}
40
- end
53
+ options = Table.extract_options(options)
54
+ @rows = []
41
55
 
42
56
  rows.each do |row|
43
- if columns
44
- @rows << Tabular::Row.new(columns, row)
57
+ if @columns
58
+ self << row
45
59
  else
46
60
  @columns = Tabular::Columns.new(row, options[:columns])
47
- @rows = []
48
61
  end
49
62
  end
50
63
  end
@@ -54,12 +67,31 @@ module Tabular
54
67
  rows[index]
55
68
  end
56
69
 
70
+ def <<(row)
71
+ @rows << Tabular::Row.new(self, row)
72
+ end
73
+
57
74
  def inspect
58
75
  rows.map { |row| row.join(",") }.join("\n")
59
76
  end
60
77
 
78
+ def columns
79
+ @columns || Tabular::Columns.new([])
80
+ end
81
+
61
82
  def to_s
62
83
  "#<#{self.class} #{rows.size}>"
63
84
  end
85
+
86
+
87
+ private
88
+
89
+ def self.extract_options(options)
90
+ if options
91
+ options.flatten.first || {}
92
+ else
93
+ {}
94
+ end
95
+ end
64
96
  end
65
97
  end
data/tabular.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{tabular}
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Scott Willson"]
12
- s.date = %q{2009-12-15}
12
+ s.date = %q{2010-06-07}
13
13
  s.description = %q{Tabular is a Ruby library for reading, writing, and manipulating CSV, tab-delimited and Excel data.}
14
14
  s.email = %q{scott.willson@gmail.cpm}
15
15
  s.extra_rdoc_files = [
@@ -17,7 +17,8 @@ Gem::Specification.new do |s|
17
17
  "README"
18
18
  ]
19
19
  s.files = [
20
- "LICENSE",
20
+ ".gitignore",
21
+ "LICENSE",
21
22
  "README",
22
23
  "Rakefile",
23
24
  "VERSION",
@@ -33,6 +34,7 @@ Gem::Specification.new do |s|
33
34
  "test/fixtures/blank.txt",
34
35
  "test/fixtures/excel.xls",
35
36
  "test/fixtures/sample.csv",
37
+ "test/fixtures/sample.lif",
36
38
  "test/helper.rb",
37
39
  "test/row_test.rb",
38
40
  "test/table_test.rb"
@@ -40,7 +42,7 @@ Gem::Specification.new do |s|
40
42
  s.homepage = %q{http://github.com/scottwillson/tabular}
41
43
  s.rdoc_options = ["--charset=UTF-8"]
42
44
  s.require_paths = ["lib"]
43
- s.rubygems_version = %q{1.3.5}
45
+ s.rubygems_version = %q{1.3.7}
44
46
  s.summary = %q{Read, write, and manipulate CSV, tab-delimited and Excel data}
45
47
  s.test_files = [
46
48
  "test/column_test.rb",
@@ -54,7 +56,7 @@ Gem::Specification.new do |s|
54
56
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
57
  s.specification_version = 3
56
58
 
57
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
59
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
58
60
  else
59
61
  end
60
62
  else
@@ -0,0 +1,5 @@
1
+ "Place ","Number","Last Name","First Name","Team","Category Raced"
2
+ "1","189","Willson","Scott","Gentle Lover","Senior Men 1/2/3","11",,"11"
3
+ "2","190","Phinney","Harry","CCCP","Senior Men 1/2/3","9",,
4
+ "3","10a","Holland","Steve","Huntair","Senior Men 1/2/3",,"3",
5
+ "dnf","100","Bourcier","Paul","Hutch's","Senior Men 1/2/3",,,"1"
data/test/row_test.rb CHANGED
@@ -3,7 +3,7 @@ require "helper"
3
3
  module Tabular
4
4
  class RowTest < Test::Unit::TestCase
5
5
  def test_new
6
- row = Row.new([])
6
+ row = Row.new(Table.new)
7
7
  assert_equal nil, row[:city], "[]"
8
8
 
9
9
  assert_equal "", row.join, "join"
@@ -16,8 +16,8 @@ module Tabular
16
16
  end
17
17
 
18
18
  def test_set
19
- columns = Columns.new([ "planet", "star" ])
20
- row = Row.new(columns, [ "Mars", "Sun" ])
19
+ table = Table.new([[ "planet", "star" ]])
20
+ row = Row.new(table, [ "Mars", "Sun" ])
21
21
 
22
22
  assert_equal "Sun", row[:star], "row[:star]"
23
23
 
@@ -29,29 +29,37 @@ module Tabular
29
29
  end
30
30
 
31
31
  def test_join
32
- columns = Columns.new([ "planet", "star" ])
33
- row = Row.new(columns, [ "Mars", "Sun" ])
32
+ table = Table.new([[ "planet", "star" ]])
33
+ row = Row.new(table, [ "Mars", "Sun" ])
34
34
  assert_equal "MarsSun", row.join, "join"
35
35
  assert_equal "Mars-Sun", row.join("-"), "join '-'"
36
36
  end
37
37
 
38
38
  def test_to_hash
39
- columns = Columns.new([ "planet", "star" ])
40
- row = Row.new(columns, [ "Mars", "Sun" ])
39
+ table = Table.new([[ "planet", "star" ]])
40
+ row = Row.new(table, [ "Mars", "Sun" ])
41
41
  assert_equal({ :planet => "Mars", :star => "Sun"}, row.to_hash, "to_hash")
42
42
  end
43
43
 
44
44
  def test_inspect
45
- columns = Columns.new([ "planet", "star" ])
46
- row = Row.new(columns, [ "Mars", "Sun" ])
45
+ table = Table.new([[ "planet", "star" ]])
46
+ row = Row.new(table, [ "Mars", "Sun" ])
47
47
  assert_equal "{:planet=>\"Mars\", :star=>\"Sun\"}", row.inspect, "inspect"
48
48
  end
49
49
 
50
50
  def test_to_s
51
- columns = Columns.new([ "planet", "star" ])
52
- row = Row.new(columns, [ "Mars", "Sun" ])
51
+ table = Table.new([[ "planet", "star" ]])
52
+ row = Row.new(table, [ "Mars", "Sun" ])
53
53
  assert_equal "Mars, Sun", row.to_s, "to_s"
54
54
  end
55
+
56
+ def test_previous
57
+ table = Table.new([[ "planet", "star" ]])
58
+ table << [ "Mars", "Sun" ]
59
+ table << [ "Jupiter", "Sun" ]
60
+ assert_equal nil, table.rows.first.previous, "previous of first Row"
61
+ assert_equal "Mars", table.rows.last.previous[:planet], "previous"
62
+ end
55
63
  end
56
64
  end
57
65
 
data/test/table_test.rb CHANGED
@@ -32,6 +32,21 @@ module Tabular
32
32
  table = Table.read(File.expand_path(File.dirname(__FILE__) + "/fixtures/excel.xls"))
33
33
  assert_equal Date.new(2006, 1, 20), table[0][:date], "0.0"
34
34
  end
35
+
36
+ def test_read_as
37
+ table = Table.read(File.expand_path(File.dirname(__FILE__) + "/fixtures/sample.lif"), :as => :csv)
38
+ assert_equal 4, table.rows.size, "rows"
39
+ end
40
+
41
+ def test_column_map
42
+ data = [
43
+ [ "nom", "equipe", "homme" ],
44
+ [ "Hinault", "Team Z", "true" ]
45
+ ]
46
+ table = Table.new(data, :columns => { :nom => :name, :equipe => :team, :homme => { :column_type => :boolean } })
47
+ assert_equal "Hinault", table.rows.first[:name], ":name"
48
+ assert_equal "Team Z", table.rows.first[:team], ":team"
49
+ assert_equal true, table.rows.first[:homme], "boolean"
50
+ end
35
51
  end
36
52
  end
37
-
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tabular
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
5
11
  platform: ruby
6
12
  authors:
7
13
  - Scott Willson
@@ -9,7 +15,7 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-12-15 00:00:00 -08:00
18
+ date: 2010-06-07 00:00:00 -07:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
@@ -23,6 +29,7 @@ extra_rdoc_files:
23
29
  - LICENSE
24
30
  - README
25
31
  files:
32
+ - .gitignore
26
33
  - LICENSE
27
34
  - README
28
35
  - Rakefile
@@ -39,6 +46,7 @@ files:
39
46
  - test/fixtures/blank.txt
40
47
  - test/fixtures/excel.xls
41
48
  - test/fixtures/sample.csv
49
+ - test/fixtures/sample.lif
42
50
  - test/helper.rb
43
51
  - test/row_test.rb
44
52
  - test/table_test.rb
@@ -52,21 +60,27 @@ rdoc_options:
52
60
  require_paths:
53
61
  - lib
54
62
  required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
55
64
  requirements:
56
65
  - - ">="
57
66
  - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
58
70
  version: "0"
59
- version:
60
71
  required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
61
73
  requirements:
62
74
  - - ">="
63
75
  - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
64
79
  version: "0"
65
- version:
66
80
  requirements: []
67
81
 
68
82
  rubyforge_project:
69
- rubygems_version: 1.3.5
83
+ rubygems_version: 1.3.7
70
84
  signing_key:
71
85
  specification_version: 3
72
86
  summary: Read, write, and manipulate CSV, tab-delimited and Excel data