tabular 0.2.0 → 0.2.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/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'
|