tabular 0.0.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/Gemfile.lock +34 -0
- data/Rakefile +1 -3
- data/VERSION +1 -1
- data/lib/tabular.rb +8 -4
- data/lib/tabular/column.rb +35 -8
- data/lib/tabular/columns.rb +49 -19
- data/lib/tabular/keys.rb +14 -0
- data/lib/tabular/renderer.rb +11 -0
- data/lib/tabular/row.rb +53 -20
- data/lib/tabular/support/zero.rb +29 -0
- data/lib/tabular/table.rb +94 -24
- data/tabular.gemspec +46 -41
- data/test/column_test.rb +59 -18
- data/test/columns_test.rb +39 -14
- data/test/row_test.rb +72 -13
- data/test/table_test.rb +140 -6
- data/test/zero_test.rb +21 -0
- metadata +82 -47
- data/.gitignore +0 -2
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/scottwillson/ruby-ole.git
|
3
|
+
revision: 6b9d2530b12259ca21af75ed2dcb26ba745a6115
|
4
|
+
specs:
|
5
|
+
ruby-ole (1.2.11.3)
|
6
|
+
|
7
|
+
GIT
|
8
|
+
remote: git://github.com/scottwillson/spreadsheet.git
|
9
|
+
revision: e5d97bc43f3db66600a70ace5de638f41a4a700b
|
10
|
+
specs:
|
11
|
+
spreadsheet (0.6.6)
|
12
|
+
ruby-ole
|
13
|
+
|
14
|
+
GEM
|
15
|
+
remote: https://rubygems.org/
|
16
|
+
specs:
|
17
|
+
git (1.2.5)
|
18
|
+
jeweler (1.8.4)
|
19
|
+
bundler (~> 1.0)
|
20
|
+
git (>= 1.2.5)
|
21
|
+
rake
|
22
|
+
rdoc
|
23
|
+
json (1.7.7)
|
24
|
+
rake (10.0.4)
|
25
|
+
rdoc (4.0.1)
|
26
|
+
json (~> 1.4)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
jeweler
|
33
|
+
ruby-ole!
|
34
|
+
spreadsheet!
|
data/Rakefile
CHANGED
@@ -23,11 +23,9 @@ Rake::TestTask.new(:test) do |test|
|
|
23
23
|
test.verbose = true
|
24
24
|
end
|
25
25
|
|
26
|
-
task :test => :check_dependencies
|
27
|
-
|
28
26
|
task :default => :test
|
29
27
|
|
30
|
-
require '
|
28
|
+
require 'rdoc/task'
|
31
29
|
Rake::RDocTask.new do |rdoc|
|
32
30
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
33
31
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.2.0
|
data/lib/tabular.rb
CHANGED
@@ -2,9 +2,13 @@ require "rubygems"
|
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib")
|
4
4
|
|
5
|
-
require "tabular/
|
6
|
-
|
7
|
-
require "tabular/
|
8
|
-
require "tabular/
|
5
|
+
require "tabular/keys"
|
6
|
+
|
7
|
+
require "tabular/column"
|
8
|
+
require "tabular/columns"
|
9
|
+
require "tabular/renderer"
|
10
|
+
require "tabular/row"
|
11
|
+
require "tabular/table"
|
9
12
|
|
10
13
|
require "tabular/support/object"
|
14
|
+
require "tabular/support/zero"
|
data/lib/tabular/column.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
module Tabular
|
2
2
|
class Column
|
3
3
|
attr_reader :key, :column_type
|
4
|
-
|
5
|
-
def initialize(key = nil, columns_map = {})
|
4
|
+
|
5
|
+
def initialize(table, columns, key = nil, columns_map = {})
|
6
|
+
@columns = columns
|
7
|
+
@table = table
|
8
|
+
|
6
9
|
key = symbolize(key)
|
7
10
|
columns_map = columns_map || {}
|
8
11
|
map_for_key = columns_map[key]
|
9
|
-
|
12
|
+
|
10
13
|
@column_type = :string
|
11
14
|
case map_for_key
|
12
15
|
when nil
|
@@ -17,7 +20,7 @@ module Tabular
|
|
17
20
|
@column_type = :date if key == :date
|
18
21
|
when Hash
|
19
22
|
@key = key
|
20
|
-
@column_type = map_for_key[:column_type]
|
23
|
+
@column_type = map_for_key[:column_type]
|
21
24
|
else
|
22
25
|
raise "Expected Symbol or Hash, but was #{map_for_key.class}"
|
23
26
|
end
|
@@ -25,7 +28,7 @@ module Tabular
|
|
25
28
|
|
26
29
|
def symbolize(key)
|
27
30
|
return nil if key.blank?
|
28
|
-
|
31
|
+
|
29
32
|
begin
|
30
33
|
key.to_s.strip.gsub(/::/, '/').
|
31
34
|
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
@@ -38,13 +41,37 @@ module Tabular
|
|
38
41
|
nil
|
39
42
|
end
|
40
43
|
end
|
41
|
-
|
44
|
+
|
45
|
+
def rows
|
46
|
+
@table.rows
|
47
|
+
end
|
48
|
+
|
49
|
+
def cells
|
50
|
+
rows.map { |r| r[key] }
|
51
|
+
end
|
52
|
+
|
53
|
+
def max
|
54
|
+
cells.compact.max
|
55
|
+
end
|
56
|
+
|
57
|
+
def precision
|
58
|
+
@precision || cells.map(&:to_f).map {|n| n.round(3) }.map {|n| n.to_s.split(".").last.gsub(/0+$/, "").length }.max
|
59
|
+
end
|
60
|
+
|
61
|
+
def render
|
62
|
+
renderer.render_header self
|
63
|
+
end
|
64
|
+
|
65
|
+
def renderer
|
66
|
+
@columns.renderer(key)
|
67
|
+
end
|
68
|
+
|
42
69
|
def inspect
|
43
70
|
"#<Tabular::Column #{key} #{column_type}>"
|
44
71
|
end
|
45
|
-
|
72
|
+
|
46
73
|
def to_s
|
47
|
-
key
|
74
|
+
key.to_s
|
48
75
|
end
|
49
76
|
end
|
50
77
|
end
|
data/lib/tabular/columns.rb
CHANGED
@@ -2,18 +2,22 @@ module Tabular
|
|
2
2
|
# The Table's header: a list of Columns.
|
3
3
|
class Columns
|
4
4
|
include Enumerable
|
5
|
-
|
5
|
+
include Tabular::Keys
|
6
|
+
|
7
|
+
attr_accessor :renderer
|
8
|
+
|
6
9
|
# +data+ -- array of header names
|
7
10
|
# +columns_map+ -- see Table. Maps column names and type conversion.
|
8
|
-
def initialize(
|
11
|
+
def initialize(table, names, columns_map = {})
|
12
|
+
@table = table
|
9
13
|
columns_map ||= {}
|
10
14
|
@columns_map = normalize_columns_map(columns_map)
|
11
15
|
@column_indexes = {}
|
12
16
|
@columns_by_key = {}
|
13
17
|
index = 0
|
14
18
|
@columns = nil
|
15
|
-
@columns =
|
16
|
-
new_column = Tabular::Column.new(column, @columns_map)
|
19
|
+
@columns = names.map do |column|
|
20
|
+
new_column = Tabular::Column.new(table, self, column, @columns_map)
|
17
21
|
unless new_column.key.blank?
|
18
22
|
@column_indexes[new_column.key] = index
|
19
23
|
@columns_by_key[new_column.key] = new_column
|
@@ -22,50 +26,76 @@ module Tabular
|
|
22
26
|
new_column
|
23
27
|
end
|
24
28
|
end
|
25
|
-
|
29
|
+
|
26
30
|
# Is the a Column with this key? Keys are lower-case, underscore symbols.
|
27
31
|
# Example: :postal_code
|
28
32
|
def has_key?(key)
|
29
33
|
@columns.any? { |column| column.key == key }
|
30
34
|
end
|
31
|
-
|
35
|
+
|
32
36
|
# Column for +key+
|
33
37
|
def [](key)
|
34
|
-
@columns_by_key[key]
|
38
|
+
@columns_by_key[key_to_sym(key)]
|
35
39
|
end
|
36
|
-
|
40
|
+
|
37
41
|
# Zero-based index of Column for +key+
|
38
42
|
def index(key)
|
39
43
|
@column_indexes[key]
|
40
44
|
end
|
41
|
-
|
45
|
+
|
42
46
|
# Call +block+ for each Column
|
43
47
|
def each(&block)
|
44
48
|
@columns.each(&block)
|
45
49
|
end
|
46
|
-
|
50
|
+
|
47
51
|
# Add a new Column with +key+
|
48
52
|
def <<(key)
|
49
|
-
column = Column.new(key, @columns_map)
|
50
|
-
unless column.key.blank?
|
53
|
+
column = Column.new(@table, self, key, @columns_map)
|
54
|
+
unless column.key.blank? || has_key?(key)
|
51
55
|
@column_indexes[column.key] = @columns.size
|
52
56
|
@column_indexes[@columns.size] = column
|
53
57
|
@columns_by_key[column.key] = column
|
58
|
+
@columns << column
|
54
59
|
end
|
55
|
-
@columns << column
|
56
60
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
+
|
62
|
+
def delete(key)
|
63
|
+
@columns.delete_if { |column| column.key == key }
|
64
|
+
@columns_by_key.delete key
|
65
|
+
@column_indexes.delete key
|
66
|
+
|
67
|
+
@columns.each.with_index do |column, index|
|
68
|
+
@column_indexes[column.key] = index
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def size
|
73
|
+
@columns.size
|
74
|
+
end
|
75
|
+
|
76
|
+
def max
|
77
|
+
cells.compact.max
|
78
|
+
end
|
79
|
+
|
80
|
+
def renderer(key)
|
81
|
+
renderers[key] || @renderer || Renderer
|
82
|
+
end
|
83
|
+
|
84
|
+
def renderers
|
85
|
+
@renderers ||= {}
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
private
|
90
|
+
|
61
91
|
def normalize_columns_map(columns_map)
|
62
92
|
normalized_columns_map = {}
|
63
93
|
columns_map.each do |key, value|
|
64
94
|
case value
|
65
95
|
when Hash, Symbol
|
66
|
-
normalized_columns_map[key
|
96
|
+
normalized_columns_map[key_to_sym(key)] = value
|
67
97
|
else
|
68
|
-
normalized_columns_map[key
|
98
|
+
normalized_columns_map[key_to_sym(key)] = value.to_sym
|
69
99
|
end
|
70
100
|
end
|
71
101
|
normalized_columns_map
|
data/lib/tabular/keys.rb
ADDED
data/lib/tabular/row.rb
CHANGED
@@ -4,23 +4,37 @@ module Tabular
|
|
4
4
|
# Associate list of cells. Each Table has a list of Rows. Access Row cells via symbols. Ex: row[:city]
|
5
5
|
class Row
|
6
6
|
include Enumerable
|
7
|
-
|
7
|
+
include Tabular::Keys
|
8
|
+
|
8
9
|
attr_reader :index
|
9
|
-
|
10
|
+
attr_reader :source
|
11
|
+
|
10
12
|
# +table+ -- Table
|
11
|
-
# +
|
12
|
-
|
13
|
+
# +cells+ -- array (not neccessarily Strings)
|
14
|
+
# +source+ -- original data before mapped to Hash or Array (optional)
|
15
|
+
def initialize(table, cells = [], source = nil)
|
13
16
|
@table = table
|
14
|
-
@
|
15
|
-
|
17
|
+
@source = source || cells
|
18
|
+
|
19
|
+
if cells.respond_to?(:keys)
|
20
|
+
@array = cells.values
|
21
|
+
@hash = {}
|
22
|
+
cells.each do |key, value|
|
23
|
+
@hash[key_to_sym(key)] = value
|
24
|
+
end
|
25
|
+
else
|
26
|
+
@array = cells
|
27
|
+
@hash = nil
|
28
|
+
end
|
29
|
+
|
16
30
|
@index = table.rows.size
|
17
31
|
end
|
18
|
-
|
32
|
+
|
19
33
|
# Cell value by symbol. E.g., row[:phone_number]
|
20
34
|
def [](key)
|
21
35
|
hash[key]
|
22
36
|
end
|
23
|
-
|
37
|
+
|
24
38
|
# Set cell value. Adds cell to end of Row and adds new Column if there is no Column for +key_
|
25
39
|
def []=(key, value)
|
26
40
|
if columns.has_key?(key)
|
@@ -31,42 +45,61 @@ module Tabular
|
|
31
45
|
end
|
32
46
|
hash[key] = value
|
33
47
|
end
|
34
|
-
|
48
|
+
|
35
49
|
# Call +block+ for each cell
|
36
50
|
def each(&block)
|
37
51
|
@array.each(&block)
|
38
52
|
end
|
39
53
|
|
54
|
+
# Call +block+ for each cell
|
55
|
+
def each_with_key(&block)
|
56
|
+
hash.each(&block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def keys
|
60
|
+
hash.keys
|
61
|
+
end
|
62
|
+
|
40
63
|
# For pretty-printing cell values
|
41
64
|
def join(sep = nil)
|
42
65
|
@array.join(sep)
|
43
66
|
end
|
44
|
-
|
67
|
+
|
68
|
+
def delete(key)
|
69
|
+
@array.delete key
|
70
|
+
hash.delete key
|
71
|
+
end
|
72
|
+
|
45
73
|
def previous
|
46
74
|
if index > 0
|
47
75
|
@table.rows[index - 1]
|
48
76
|
end
|
49
77
|
end
|
50
|
-
|
78
|
+
|
51
79
|
def columns
|
52
80
|
@table.columns
|
53
81
|
end
|
54
|
-
|
82
|
+
|
83
|
+
def render(key)
|
84
|
+
column = columns[key]
|
85
|
+
column.renderer.render column, self
|
86
|
+
end
|
87
|
+
|
55
88
|
def to_hash
|
56
89
|
hash.dup
|
57
90
|
end
|
58
|
-
|
91
|
+
|
59
92
|
def inspect
|
60
93
|
hash.inspect
|
61
94
|
end
|
62
|
-
|
95
|
+
|
63
96
|
def to_s
|
64
97
|
@array.join(", ").to_s
|
65
98
|
end
|
66
99
|
|
67
100
|
|
68
101
|
protected
|
69
|
-
|
102
|
+
|
70
103
|
def hash #:nodoc:
|
71
104
|
unless @hash
|
72
105
|
@hash = Hash.new
|
@@ -103,14 +136,14 @@ module Tabular
|
|
103
136
|
end
|
104
137
|
@hash
|
105
138
|
end
|
106
|
-
|
107
|
-
|
139
|
+
|
140
|
+
|
108
141
|
private
|
109
|
-
|
142
|
+
|
110
143
|
# Handle common m/d/yy case that Date.parse dislikes
|
111
144
|
def parse_invalid_date(value)
|
112
145
|
return unless value
|
113
|
-
|
146
|
+
|
114
147
|
parts = value.split("/")
|
115
148
|
return unless parts.size == 3
|
116
149
|
|
@@ -128,7 +161,7 @@ module Tabular
|
|
128
161
|
elsif year < 1900 || year > 2050
|
129
162
|
return nil
|
130
163
|
end
|
131
|
-
|
164
|
+
|
132
165
|
Date.new(year, month, day)
|
133
166
|
end
|
134
167
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Object
|
2
|
+
def zero?
|
3
|
+
false
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class NilClass #:nodoc:
|
8
|
+
def zero?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class FalseClass #:nodoc:
|
14
|
+
def zero?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class TrueClass #:nodoc:
|
20
|
+
def zero?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class String #:nodoc:
|
26
|
+
def zero?
|
27
|
+
self == "0" || self[/^0+\.0+$/]
|
28
|
+
end
|
29
|
+
end
|