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 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.0
1
+ 0.2.1
@@ -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
@@ -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
- def max
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
@@ -1,5 +1,6 @@
1
1
  module Tabular
2
2
  module Keys
3
+ # Return Symbol for +key+. Translate Column and String. Return +key+ unmodified for anything else.
3
4
  def key_to_sym(key)
4
5
  _key = case key
5
6
  when Column
@@ -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]
@@ -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
@@ -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
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "tabular"
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
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"]
@@ -33,7 +33,7 @@ module Tabular
33
33
  end
34
34
 
35
35
  def test_render
36
- columns = Columns.new(nil, ["date", "first name", "LastName"])
36
+ columns = Columns.new(Table.new, ["date", "first name", "LastName"])
37
37
  assert_equal "date", columns.first.render
38
38
  end
39
39
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: tabular
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.0
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: -1721544850789134153
108
+ hash: -2217103212522653909
109
109
  segments:
110
110
  - 0
111
111
  version: '0'