tabular 0.0.7 → 0.2.0

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/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "ruby-ole", :git => "git://github.com/scottwillson/ruby-ole.git"
4
+ gem "spreadsheet", :git => "git://github.com/scottwillson/spreadsheet.git"
5
+ gem "jeweler"
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 'rake/rdoctask'
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.7
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/column.rb"
6
- require "tabular/columns.rb"
7
- require "tabular/row.rb"
8
- require "tabular/table.rb"
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"
@@ -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
@@ -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(data, columns_map = {})
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 = data.map do |column|
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
- private
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.to_sym] = value
96
+ normalized_columns_map[key_to_sym(key)] = value
67
97
  else
68
- normalized_columns_map[key.to_sym] = value.to_sym
98
+ normalized_columns_map[key_to_sym(key)] = value.to_sym
69
99
  end
70
100
  end
71
101
  normalized_columns_map
@@ -0,0 +1,14 @@
1
+ module Tabular
2
+ module Keys
3
+ def key_to_sym(key)
4
+ _key = case key
5
+ when Column
6
+ key.key
7
+ when String
8
+ key.to_sym
9
+ else
10
+ key
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Tabular
2
+ class Renderer
3
+ def self.render(column, row)
4
+ row[column.key]
5
+ end
6
+
7
+ def self.render_header(column)
8
+ column.to_s
9
+ end
10
+ end
11
+ end
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
- # +cell+ -- array (not neccessarily Strings)
12
- def initialize(table, cells = [])
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
- @array = cells
15
- @hash = nil
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