tabular 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +26 -1
- data/VERSION +1 -1
- data/lib/tabular/column.rb +26 -16
- data/lib/tabular/columns.rb +4 -4
- data/lib/tabular/keys.rb +1 -0
- data/lib/tabular/renderer.rb +4 -0
- data/lib/tabular/row.rb +4 -0
- data/lib/tabular/table.rb +15 -1
- data/tabular.gemspec +1 -1
- data/test/columns_test.rb +1 -1
- metadata +2 -2
data/README
CHANGED
@@ -2,6 +2,12 @@ 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
|
+
Tabular is also handy for display table-like data. For example, I want to display a bike race's results in HTML. I need to drop empty columns: sometimes there are points or times; sometimes not. I need find the most precise time to format all the times in the results correctly.
|
6
|
+
|
7
|
+
Much of the API is a copy of FasterCSV without the focus on CSV.
|
8
|
+
|
9
|
+
Import and display can be configured with Mappers and Renderers. It's a OOP-heavy design that is fast and test-able.
|
10
|
+
|
5
11
|
Install
|
6
12
|
-------
|
7
13
|
sudo gem install tabular
|
@@ -38,7 +44,7 @@ Usage
|
|
38
44
|
-----
|
39
45
|
Table.read assumes that .txt files are tab-delimited, .csv files are comma-delimited, and .xls files are Excel. It assumes that the first row is the header row, and normalizes the header to lower-case with underscores. E.g., "Last Name" becomes "last_name".
|
40
46
|
|
41
|
-
Table.new accepts an Array of Arrays.
|
47
|
+
Table.new accepts an Array of Arrays or an Array of Hashes.
|
42
48
|
|
43
49
|
Table.new also accepts an options hash.
|
44
50
|
|
@@ -56,6 +62,25 @@ There's basic test coverage. More comprehensive test coverage needs to be extrac
|
|
56
62
|
|
57
63
|
Changes
|
58
64
|
-------
|
65
|
+
0.2.1 Documentation!
|
66
|
+
0.2.0 Add several new features that break previous API
|
67
|
+
* New public accessors for Table, Columns, Row, and Column
|
68
|
+
* Mapper to translate source data to Rows
|
69
|
+
* Renderer to control display of Row cells and Column headers
|
70
|
+
* Table#delete_blank_columns! to delete columns that are blank. Zero is considered blank.
|
71
|
+
* Table#delete_homogenous_columns! to delete columns that are all the same value. E.g.,
|
72
|
+
A | B | C
|
73
|
+
=========
|
74
|
+
1 | 2 | 3
|
75
|
+
1 | 6 |
|
76
|
+
1 | * | 5
|
77
|
+
|
78
|
+
Column A would be deleted
|
79
|
+
* Table#strip! to remove whitespace around cell values. By default, Tabular::Table preserves cell whitespace.
|
80
|
+
* Column#max
|
81
|
+
* Column#precision
|
82
|
+
* Ruby 1.8 support is deprcated
|
83
|
+
|
59
84
|
0.0.5 Parse 'invalid' m/d/yy dates
|
60
85
|
|
61
86
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/tabular/column.rb
CHANGED
@@ -2,6 +2,9 @@ module Tabular
|
|
2
2
|
class Column
|
3
3
|
attr_reader :key, :column_type
|
4
4
|
|
5
|
+
# +table+ -- parent Table
|
6
|
+
# +column+ -- parent Columns
|
7
|
+
# +key+ is normalized to a downcase, underscored symbol
|
5
8
|
def initialize(table, columns, key = nil, columns_map = {})
|
6
9
|
@columns = columns
|
7
10
|
@table = table
|
@@ -26,42 +29,31 @@ module Tabular
|
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
29
|
-
def symbolize(key)
|
30
|
-
return nil if key.blank?
|
31
|
-
|
32
|
-
begin
|
33
|
-
key.to_s.strip.gsub(/::/, '/').
|
34
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
35
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
36
|
-
tr("-", "_").
|
37
|
-
gsub(/ +/, "_").
|
38
|
-
downcase.
|
39
|
-
to_sym
|
40
|
-
rescue
|
41
|
-
nil
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
32
|
def rows
|
46
33
|
@table.rows
|
47
34
|
end
|
48
35
|
|
36
|
+
# All cells value under this Column
|
49
37
|
def cells
|
50
38
|
rows.map { |r| r[key] }
|
51
39
|
end
|
52
40
|
|
41
|
+
# Maximum value for cells in the Column. Determine with Ruby #max
|
53
42
|
def max
|
54
43
|
cells.compact.max
|
55
44
|
end
|
56
45
|
|
46
|
+
# Number of zeros to the right of the decimal point. Useful for formtting time data.
|
57
47
|
def precision
|
58
48
|
@precision || cells.map(&:to_f).map {|n| n.round(3) }.map {|n| n.to_s.split(".").last.gsub(/0+$/, "").length }.max
|
59
49
|
end
|
60
50
|
|
51
|
+
# Human-friendly header string. Delegate to +renderer+'s render_header method.
|
61
52
|
def render
|
62
53
|
renderer.render_header self
|
63
54
|
end
|
64
55
|
|
56
|
+
# Renderer
|
65
57
|
def renderer
|
66
58
|
@columns.renderer(key)
|
67
59
|
end
|
@@ -73,5 +65,23 @@ module Tabular
|
|
73
65
|
def to_s
|
74
66
|
key.to_s
|
75
67
|
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def symbolize(key)
|
72
|
+
return nil if key.blank?
|
73
|
+
|
74
|
+
begin
|
75
|
+
key.to_s.strip.gsub(/::/, '/').
|
76
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
77
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
78
|
+
tr("-", "_").
|
79
|
+
gsub(/ +/, "_").
|
80
|
+
downcase.
|
81
|
+
to_sym
|
82
|
+
rescue
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
end
|
76
86
|
end
|
77
87
|
end
|
data/lib/tabular/columns.rb
CHANGED
@@ -6,6 +6,7 @@ module Tabular
|
|
6
6
|
|
7
7
|
attr_accessor :renderer
|
8
8
|
|
9
|
+
# +table+ -- Table
|
9
10
|
# +data+ -- array of header names
|
10
11
|
# +columns_map+ -- see Table. Maps column names and type conversion.
|
11
12
|
def initialize(table, names, columns_map = {})
|
@@ -69,18 +70,17 @@ module Tabular
|
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
73
|
+
# Count of Columns#columns
|
72
74
|
def size
|
73
75
|
@columns.size
|
74
76
|
end
|
75
77
|
|
76
|
-
|
77
|
-
cells.compact.max
|
78
|
-
end
|
79
|
-
|
78
|
+
# Renderer for Column +key+. Default to Table#renderer.
|
80
79
|
def renderer(key)
|
81
80
|
renderers[key] || @renderer || Renderer
|
82
81
|
end
|
83
82
|
|
83
|
+
# List of Renderers
|
84
84
|
def renderers
|
85
85
|
@renderers ||= {}
|
86
86
|
end
|
data/lib/tabular/keys.rb
CHANGED
data/lib/tabular/renderer.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
module Tabular
|
2
|
+
# Custom display of cells. By default, return to_s.
|
3
|
+
#
|
4
|
+
# Create your own Renders by implementing a class that responds to render(column, row) for cells
|
5
|
+
# and/or render_header(column) for Column headers.
|
2
6
|
class Renderer
|
3
7
|
def self.render(column, row)
|
4
8
|
row[column.key]
|
data/lib/tabular/row.rb
CHANGED
@@ -56,6 +56,7 @@ module Tabular
|
|
56
56
|
hash.each(&block)
|
57
57
|
end
|
58
58
|
|
59
|
+
# Keys for all columns
|
59
60
|
def keys
|
60
61
|
hash.keys
|
61
62
|
end
|
@@ -70,16 +71,19 @@ module Tabular
|
|
70
71
|
hash.delete key
|
71
72
|
end
|
72
73
|
|
74
|
+
# Previous Row
|
73
75
|
def previous
|
74
76
|
if index > 0
|
75
77
|
@table.rows[index - 1]
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
81
|
+
# Tabluar::Columns
|
79
82
|
def columns
|
80
83
|
@table.columns
|
81
84
|
end
|
82
85
|
|
86
|
+
# By default, return self[key]. Customize by setting Table#renderer or Column#renderers[key]
|
83
87
|
def render(key)
|
84
88
|
column = columns[key]
|
85
89
|
column.renderer.render column, self
|
data/lib/tabular/table.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Tabular
|
2
|
-
# Simple Enumerable list of Hashes. Use Table.read(file_path) to read file.
|
2
|
+
# Simple Enumerable list of Hashes. Use Table.read(file_path) to read file. Can also create a Table with Table.new. Either
|
3
|
+
# pass in data or set options and then call row=.
|
3
4
|
class Table
|
4
5
|
include Tabular::Keys
|
5
6
|
|
@@ -63,6 +64,8 @@ module Tabular
|
|
63
64
|
#
|
64
65
|
# Options:
|
65
66
|
# :columns => { :original_name => :preferred_name, :column_name => { :column_type => :boolean } }
|
67
|
+
#
|
68
|
+
# The :columns option will likely be deprecated and options for mappers and renderers added
|
66
69
|
def initialize(rows = [], *options)
|
67
70
|
@options = Table.extract_options(options)
|
68
71
|
self.rows = rows
|
@@ -72,6 +75,7 @@ module Tabular
|
|
72
75
|
@rows ||= []
|
73
76
|
end
|
74
77
|
|
78
|
+
# Set table rows. Calls row <<, which creates columns and links the source rows to Row#source.
|
75
79
|
def rows=(source_rows = [])
|
76
80
|
return [] unless source_rows
|
77
81
|
|
@@ -87,6 +91,9 @@ module Tabular
|
|
87
91
|
rows[index]
|
88
92
|
end
|
89
93
|
|
94
|
+
# Add row to end of table. Create missing columns and link the source row to Row#source.
|
95
|
+
# To control how source data is added to the Table, use Table#mapper= to set a class that
|
96
|
+
# implements map(row) and returns a Hash.
|
90
97
|
def <<(row)
|
91
98
|
if row_mapper
|
92
99
|
cells = row_mapper.map(row)
|
@@ -111,10 +118,12 @@ module Tabular
|
|
111
118
|
rows.map { |row| row.join(",") }.join("\n")
|
112
119
|
end
|
113
120
|
|
121
|
+
# Instance of Tabular::Columns
|
114
122
|
def columns
|
115
123
|
@columns ||= Tabular::Columns.new(self, [])
|
116
124
|
end
|
117
125
|
|
126
|
+
# Remove all columns that only contain a blank string, zero, or nil
|
118
127
|
def delete_blank_columns!
|
119
128
|
columns.map(&:key).each do |key|
|
120
129
|
if rows.all? { |row| row[key].blank? || row[key].zero? }
|
@@ -123,6 +132,7 @@ module Tabular
|
|
123
132
|
end
|
124
133
|
end
|
125
134
|
|
135
|
+
# Remove all columns that contain the same value in all rows
|
126
136
|
def delete_homogenous_columns!
|
127
137
|
return if rows.size < 2
|
128
138
|
|
@@ -134,6 +144,8 @@ module Tabular
|
|
134
144
|
end
|
135
145
|
end
|
136
146
|
|
147
|
+
# Remove preceding and trailing whitespace from all cells. By default, Table does not
|
148
|
+
# strip whitespace from cells.
|
137
149
|
def strip!
|
138
150
|
rows.each do |row|
|
139
151
|
columns.each do |column|
|
@@ -152,10 +164,12 @@ module Tabular
|
|
152
164
|
columns.delete key
|
153
165
|
end
|
154
166
|
|
167
|
+
# Set default Renderer. If present, will be used for all cells and Column headers.
|
155
168
|
def renderer=(value)
|
156
169
|
columns.renderer = value
|
157
170
|
end
|
158
171
|
|
172
|
+
# List of Renderers
|
159
173
|
def renderers
|
160
174
|
columns.renderers
|
161
175
|
end
|
data/tabular.gemspec
CHANGED
data/test/columns_test.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: tabular
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Scott Willson
|
@@ -105,7 +105,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
105
|
requirements:
|
106
106
|
- - ! '>='
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
hash: -
|
108
|
+
hash: -2217103212522653909
|
109
109
|
segments:
|
110
110
|
- 0
|
111
111
|
version: '0'
|