table_fu 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +4 -1
- data/VERSION.yml +2 -2
- data/documentation/index.html.erb +6 -7
- data/index.html +196 -0
- data/lib/table_fu.rb +66 -62
- data/spec/readme_example_spec.rb +5 -6
- data/spec/spec_helper.rb +2 -3
- data/spec/table_fu_spec.rb +21 -22
- data/table_fu.gemspec +2 -2
- metadata +4 -4
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__))
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
require 'rake'
|
3
5
|
|
@@ -37,6 +39,7 @@ task :default => :spec
|
|
37
39
|
require 'rake/rdoctask'
|
38
40
|
Rake::RDocTask.new do |rdoc|
|
39
41
|
if File.exist?('VERSION.yml')
|
42
|
+
require 'yaml'
|
40
43
|
config = YAML.load(File.read('VERSION.yml'))
|
41
44
|
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
42
45
|
else
|
@@ -50,7 +53,7 @@ Rake::RDocTask.new do |rdoc|
|
|
50
53
|
end
|
51
54
|
|
52
55
|
desc "render documentation for gh-pages"
|
53
|
-
task :gh do
|
56
|
+
task :gh do
|
54
57
|
require 'erb'
|
55
58
|
File.open("index.html", "w") do |f|
|
56
59
|
f.write ERB.new(File.open("documentation/index.html.erb").read).result
|
data/VERSION.yml
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
<%
|
2
2
|
$:.unshift File.expand_path(File.dirname(__FILE__), "/../lib/table_fu")
|
3
|
-
|
3
|
+
require 'rubygems'
|
4
4
|
require 'uv'
|
5
|
-
require 'FasterCSV'
|
6
5
|
require 'table_fu'
|
7
6
|
|
8
7
|
def code_for(file, output=true)
|
@@ -35,10 +34,10 @@ end %>
|
|
35
34
|
<link rel="stylesheet" type="text/css" href="documentation/css/styles.css" />
|
36
35
|
<link rel="stylesheet" type="text/css" href="documentation/css/dawn.css" />
|
37
36
|
</head>
|
38
|
-
|
37
|
+
|
39
38
|
<body>
|
40
39
|
<a href="http://www.propublica.org" class="propublica"> </a>
|
41
|
-
<h1>TableFu <small>– Version: <%=
|
40
|
+
<h1>TableFu <small>– Version: <%=
|
42
41
|
config = YAML.load(File.read('VERSION.yml'))
|
43
42
|
"#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
44
43
|
%></small></h1>
|
@@ -85,10 +84,10 @@ end %>
|
|
85
84
|
Note that the columns are still accessible directly even if they're not in the columns array.
|
86
85
|
<%= code_for "columns_hidden" %>
|
87
86
|
</p>
|
88
|
-
|
87
|
+
|
89
88
|
<h2><a id="macros" href="#toc">Macros / Formatting</a></h2>
|
90
89
|
<p><strong>TableFu</strong> allows you to format columns of cells through the use of macros. See <a href="http://github.com/propublica/table-fu/blob/master/lib/table_fu/formatting.rb"><strong>TableFu::Formatting</strong></a> for the predefined macros available. </p>
|
91
|
-
<p>The <strong>formatting</strong> attribute should be a hash of the form:
|
90
|
+
<p>The <strong>formatting</strong> attribute should be a hash of the form:
|
92
91
|
<%= code_for "formatting_options", false %>
|
93
92
|
which will call the macro on the column name with the arguments if specified.
|
94
93
|
</p>
|
@@ -99,7 +98,7 @@ end %>
|
|
99
98
|
<p>Of course, you can provide your own macros by patching <a href="http://github.com/propublica/table-fu/blob/master/lib/table_fu/formatting.rb">TableFu::Formatting</a>. <a href="http://www.github.com/propublica/table-setter">TableSetter</a> includes rails view helpers directly in <strong>TableFu::Formatting</strong>.
|
100
99
|
<%= code_for "rails_helpers", false %>
|
101
100
|
</p>
|
102
|
-
|
101
|
+
|
103
102
|
<h2><a id="faceting" href="#toc">Faceting</a></h2>
|
104
103
|
<p>Faceting provides a way to group rows together using a cell value they share in common. Calling <strong>TableFu#faceted_by</strong> returns an array of table fu instances each with a <strong>faceted_on</strong> attribute and with only the rows where that value appears.
|
105
104
|
</p>
|
data/index.html
CHANGED
@@ -0,0 +1,196 @@
|
|
1
|
+
|
2
|
+
<!DOCTYPE html>
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
6
|
+
<title>TableFu</title>
|
7
|
+
<link rel="stylesheet" type="text/css" href="documentation/css/styles.css" />
|
8
|
+
<link rel="stylesheet" type="text/css" href="documentation/css/dawn.css" />
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body>
|
12
|
+
<a href="http://www.propublica.org" class="propublica"> </a>
|
13
|
+
<h1>TableFu <small>– Version: 0.3.1</small></h1>
|
14
|
+
|
15
|
+
<p><a href="http://github.com/propublica/table-fu">TableFu</a> is a ruby gem for spreadsheet-style handling of arrays (e.g. filtering, formatting, and sorting by "column" or "row"). In addition, it has the ability to <a href="#facet">facet</a> — or group — rows according to cell value. It was developed as a backend for its companion project <a href="http://www.github.com/propublica/table-setter">TableSetter</a>.</p>
|
16
|
+
<p>For example, <strong>TableFu</strong> can consume a csv file and sort on a column:
|
17
|
+
<pre class="dawn">csv <span class="Keyword">=</span><<-CSV
|
18
|
+
Author,Best Book,Number of Pages,Style
|
19
|
+
Samuel Beckett,Malone Muert,120,Modernism
|
20
|
+
James Joyce,Ulysses,644,Modernism
|
21
|
+
Nicholson Baker,Mezannine,150,Minimalism
|
22
|
+
Vladimir Sorokin,The Queue,263,Satire
|
23
|
+
CSV
|
24
|
+
|
25
|
+
spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
26
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">sorted_by</span> <span class="Keyword">=</span> {'Best Book' <span class="PunctuationSeparator">=></span> {'order' <span class="PunctuationSeparator">=></span> 'ascending'}}
|
27
|
+
<span class="Keyword">end</span>
|
28
|
+
</pre><em>Returns:</em><pre class="dawn">[["Samuel Beckett"<span class="PunctuationSeparator">,</span> "Malone Muert"<span class="PunctuationSeparator">,</span> "120"<span class="PunctuationSeparator">,</span> "Modernism"]<span class="PunctuationSeparator">,</span> ["Nicholson Baker"<span class="PunctuationSeparator">,</span> "Mezannine"<span class="PunctuationSeparator">,</span> "150"<span class="PunctuationSeparator">,</span> "Minimalism"]<span class="PunctuationSeparator">,</span> ["Vladimir Sorokin"<span class="PunctuationSeparator">,</span> "The Queue"<span class="PunctuationSeparator">,</span> "263"<span class="PunctuationSeparator">,</span> "Satire"]<span class="PunctuationSeparator">,</span> ["James Joyce"<span class="PunctuationSeparator">,</span> "Ulysses"<span class="PunctuationSeparator">,</span> "644"<span class="PunctuationSeparator">,</span> "Modernism"]]
|
29
|
+
</pre>
|
30
|
+
</p>
|
31
|
+
<h2><a id="toc">Table of Contents</a></h2>
|
32
|
+
<ul>
|
33
|
+
<li><a href="#installation">Installation</a></li>
|
34
|
+
<li><a href="#usage">Usage</a></li>
|
35
|
+
<li><a href="#macros">Macros / Formatting</a></li>
|
36
|
+
<li><a href="#faceting">Faceting</a></li>
|
37
|
+
<li><a href="#manipulation">Manipulation</a></li>
|
38
|
+
<li><a href="#links">Links</a></li>
|
39
|
+
<li><a href="#credits">Credits</a></li>
|
40
|
+
<li><a href="#license">License</a></li>
|
41
|
+
</ul>
|
42
|
+
<h2><a id="installation" href="#toc">Installation</a></h2>
|
43
|
+
<p><strong>TableFu</strong> is available as a rubygem:
|
44
|
+
<pre class="dawn">
|
45
|
+
gem install table_fu</pre>
|
46
|
+
or from the actual source:
|
47
|
+
<pre class="dawn">
|
48
|
+
git clone git://github.com/propublica/table-fu.git
|
49
|
+
cd table-fu
|
50
|
+
rake install</pre>
|
51
|
+
</p>
|
52
|
+
<h2><a id="usage" href="#toc">Usage</a></h2>
|
53
|
+
<p>
|
54
|
+
The <strong>TableFu</strong> constructor takes two arguments; a 2 dimensional array or csv (file object or string) and a hash of column options or a block. TableFu will assume that the first row of the array contains the column headers. The simple options are:</p>
|
55
|
+
<p><strong>sorted_by:</strong> the column to sort by, it defaults to no sorting at all.
|
56
|
+
<pre class="dawn">csv <span class="Keyword">=</span><<-CSV
|
57
|
+
Author,Best Book,Number of Pages,Style
|
58
|
+
Samuel Beckett,Malone Muert,120,Modernism
|
59
|
+
James Joyce,Ulysses,644,Modernism
|
60
|
+
Nicholson Baker,Mezannine,150,Minimalism
|
61
|
+
Vladimir Sorokin,The Queue,263,Satire
|
62
|
+
CSV
|
63
|
+
|
64
|
+
spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
65
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">sorted_by</span> <span class="Keyword">=</span> {'Best Book' <span class="PunctuationSeparator">=></span> {'order' <span class="PunctuationSeparator">=></span> 'ascending'}}
|
66
|
+
<span class="Keyword">end</span>
|
67
|
+
</pre><em>Returns:</em><pre class="dawn">[["Samuel Beckett"<span class="PunctuationSeparator">,</span> "Malone Muert"<span class="PunctuationSeparator">,</span> "120"<span class="PunctuationSeparator">,</span> "Modernism"]<span class="PunctuationSeparator">,</span> ["Nicholson Baker"<span class="PunctuationSeparator">,</span> "Mezannine"<span class="PunctuationSeparator">,</span> "150"<span class="PunctuationSeparator">,</span> "Minimalism"]<span class="PunctuationSeparator">,</span> ["Vladimir Sorokin"<span class="PunctuationSeparator">,</span> "The Queue"<span class="PunctuationSeparator">,</span> "263"<span class="PunctuationSeparator">,</span> "Satire"]<span class="PunctuationSeparator">,</span> ["James Joyce"<span class="PunctuationSeparator">,</span> "Ulysses"<span class="PunctuationSeparator">,</span> "644"<span class="PunctuationSeparator">,</span> "Modernism"]]
|
68
|
+
</pre>
|
69
|
+
</p>
|
70
|
+
<p><strong>columns:</strong> the columns to include in the table, useful when reordering and filtering extraneous columns. If no arguments are provided, <strong>TableFu</strong> will include all columns by default.
|
71
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
72
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">columns</span> <span class="Keyword">=</span> ["Best Book"<span class="PunctuationSeparator">,</span> "Author"]
|
73
|
+
<span class="Keyword">end</span>
|
74
|
+
|
75
|
+
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">columns</span><span class="PunctuationSeparator">.</span><span class="Entity">map</span> <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">column</span><span class="PunctuationSeparator">|</span>
|
76
|
+
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">rows</span>[<span class="Constant">0</span>]<span class="PunctuationSeparator">.</span><span class="Entity">column_for</span>(column)<span class="PunctuationSeparator">.</span><span class="Entity">to_s</span>
|
77
|
+
<span class="Keyword">end</span>
|
78
|
+
</pre><em>Returns:</em><pre class="dawn">["Malone Muert"<span class="PunctuationSeparator">,</span> "Samuel Beckett"]
|
79
|
+
</pre>
|
80
|
+
Note that the columns are still accessible directly even if they're not in the columns array.
|
81
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
82
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">columns</span> <span class="Keyword">=</span> ["Best Book"<span class="PunctuationSeparator">,</span> "Author"]
|
83
|
+
<span class="Keyword">end</span>
|
84
|
+
|
85
|
+
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">rows</span>[<span class="Constant">0</span>]['Style']<span class="PunctuationSeparator">.</span>to_s
|
86
|
+
</pre><em>Returns:</em><pre class="dawn">"Modernism"
|
87
|
+
</pre>
|
88
|
+
</p>
|
89
|
+
|
90
|
+
<h2><a id="macros" href="#toc">Macros / Formatting</a></h2>
|
91
|
+
<p><strong>TableFu</strong> allows you to format columns of cells through the use of macros. See <a href="http://github.com/propublica/table-fu/blob/master/lib/table_fu/formatting.rb"><strong>TableFu::Formatting</strong></a> for the predefined macros available. </p>
|
92
|
+
<p>The <strong>formatting</strong> attribute should be a hash of the form:
|
93
|
+
<pre class="dawn">{"Column Name" <span class="PunctuationSeparator">=></span> 'Formatting Method Name'}
|
94
|
+
|
95
|
+
<span class="Comment"><span class="Comment">#</span> or</span>
|
96
|
+
|
97
|
+
{"Meta Column Name" <span class="PunctuationSeparator">=></span> {"method" <span class="PunctuationSeparator">=></span> "Method Name"<span class="PunctuationSeparator">,</span> "arguments" <span class="PunctuationSeparator">=></span> ['Column 1'<span class="PunctuationSeparator">,</span> 'Column 2' <span class="PunctuationSeparator">.</span><span class="PunctuationSeparator">.</span><span class="PunctuationSeparator">.</span> 'Column N']}}
|
98
|
+
|
99
|
+
</pre>
|
100
|
+
which will call the macro on the column name with the arguments if specified.
|
101
|
+
</p>
|
102
|
+
<p>For example, you can use the <strong>last_name</strong> formatter to extract the last name of a cell containing a person's name:
|
103
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
104
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">formatting</span> <span class="Keyword">=</span> {"Author" <span class="PunctuationSeparator">=></span> 'last_name'}
|
105
|
+
<span class="Keyword">end</span>
|
106
|
+
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">rows</span>[<span class="Constant">0</span>]<span class="PunctuationSeparator">.</span><span class="Entity">column_for</span>('Author')<span class="PunctuationSeparator">.</span>to_s
|
107
|
+
</pre><em>Returns:</em><pre class="dawn">"Beckett"
|
108
|
+
</pre>
|
109
|
+
</p>
|
110
|
+
|
111
|
+
<p>Of course, you can provide your own macros by patching <a href="http://github.com/propublica/table-fu/blob/master/lib/table_fu/formatting.rb">TableFu::Formatting</a>. <a href="http://www.github.com/propublica/table-setter">TableSetter</a> includes rails view helpers directly in <strong>TableFu::Formatting</strong>.
|
112
|
+
<pre class="dawn"><span class="Keyword">class</span> <span class="Entity">TableFu::Formatting</span>
|
113
|
+
<span class="Keyword">extend</span> <span class="Support">ActionView</span><span class="PunctuationSeparator">::</span><span class="Entity">Helpers</span><span class="PunctuationSeparator">::</span><span class="Entity">NumberHelper</span>
|
114
|
+
<span class="Keyword">end</span>
|
115
|
+
</pre>
|
116
|
+
</p>
|
117
|
+
|
118
|
+
<h2><a id="faceting" href="#toc">Faceting</a></h2>
|
119
|
+
<p>Faceting provides a way to group rows together using a cell value they share in common. Calling <strong>TableFu#faceted_by</strong> returns an array of table fu instances each with a <strong>faceted_on</strong> attribute and with only the rows where that value appears.
|
120
|
+
</p>
|
121
|
+
<p>In this example there are 2 rows where "Modernism" appears in the style column, so calling <strong>faceted_on</strong> with the argument <strong>"Style"</strong> returns a <strong>TableFu</strong> instance with those rows grouped together:
|
122
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv)
|
123
|
+
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">faceted_by</span> "Style"
|
124
|
+
</pre><em>Returns:</em><pre class="dawn">table<span class="PunctuationSeparator">.</span><span class="Entity">faceted_on</span> <span class="PunctuationSeparator">=></span> <span class="Variable">Minimalism</span><span class="PunctuationSeparator">,</span> table<span class="PunctuationSeparator">.</span><span class="Entity">rows</span> <span class="PunctuationSeparator">=></span> [["Nicholson Baker"<span class="PunctuationSeparator">,</span> "Mezannine"<span class="PunctuationSeparator">,</span> "150"<span class="PunctuationSeparator">,</span> "Minimalism"]]
|
125
|
+
table<span class="PunctuationSeparator">.</span><span class="Entity">faceted_on</span> <span class="PunctuationSeparator">=></span> <span class="Variable">Modernism</span><span class="PunctuationSeparator">,</span> table<span class="PunctuationSeparator">.</span><span class="Entity">rows</span> <span class="PunctuationSeparator">=></span> [["Samuel Beckett"<span class="PunctuationSeparator">,</span> "Malone Muert"<span class="PunctuationSeparator">,</span> "120"<span class="PunctuationSeparator">,</span> "Modernism"]<span class="PunctuationSeparator">,</span> ["James Joyce"<span class="PunctuationSeparator">,</span> "Ulysses"<span class="PunctuationSeparator">,</span> "644"<span class="PunctuationSeparator">,</span> "Modernism"]]
|
126
|
+
table<span class="PunctuationSeparator">.</span><span class="Entity">faceted_on</span> <span class="PunctuationSeparator">=></span> <span class="Variable">Satire</span><span class="PunctuationSeparator">,</span> table<span class="PunctuationSeparator">.</span><span class="Entity">rows</span> <span class="PunctuationSeparator">=></span> [["Vladimir Sorokin"<span class="PunctuationSeparator">,</span> "The Queue"<span class="PunctuationSeparator">,</span> "263"<span class="PunctuationSeparator">,</span> "Satire"]]
|
127
|
+
</pre>
|
128
|
+
</p>
|
129
|
+
<h2><a id="manipulation" href="#toc">Manipulation / Output</a></h2>
|
130
|
+
<h3>Deleting Rows</h3>
|
131
|
+
<p>In addition to hiding columns and faceting <strong>TableFu</strong> can delete rows from the csv. Let's get rid of James Joyce (no one ever finished <em>Ulysses</em> anyway):
|
132
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
133
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">delete_rows!</span> [<span class="Constant">1</span>]
|
134
|
+
<span class="Keyword">end</span>
|
135
|
+
</pre><em>Returns:</em><pre class="dawn">[["Samuel Beckett"<span class="PunctuationSeparator">,</span> "Malone Muert"<span class="PunctuationSeparator">,</span> "120"<span class="PunctuationSeparator">,</span> "Modernism"]<span class="PunctuationSeparator">,</span> ["Nicholson Baker"<span class="PunctuationSeparator">,</span> "Mezannine"<span class="PunctuationSeparator">,</span> "150"<span class="PunctuationSeparator">,</span> "Minimalism"]<span class="PunctuationSeparator">,</span> ["Vladimir Sorokin"<span class="PunctuationSeparator">,</span> "The Queue"<span class="PunctuationSeparator">,</span> "263"<span class="PunctuationSeparator">,</span> "Satire"]]
|
136
|
+
</pre>
|
137
|
+
The deleted rows are still available in <strong>@deleted_rows</strong> for later access:
|
138
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
139
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">delete_rows!</span> [<span class="Constant">1</span>]
|
140
|
+
<span class="Keyword">end</span>
|
141
|
+
</pre><em>Returns:</em><pre class="dawn">table<span class="PunctuationSeparator">.</span><span class="Entity">deleted_rows</span> <span class="PunctuationSeparator">=></span> [["James Joyce"<span class="PunctuationSeparator">,</span> "Ulysses"<span class="PunctuationSeparator">,</span> "644"<span class="PunctuationSeparator">,</span> "Modernism"]]
|
142
|
+
</pre>
|
143
|
+
</p>
|
144
|
+
<h3>Pagination</h3>
|
145
|
+
<p>If you want only a chunk of the data, say to paginate your table, you can call <strong>only!</strong> with the range of values you want to keep:
|
146
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv) <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">s</span><span class="PunctuationSeparator">|</span>
|
147
|
+
s<span class="PunctuationSeparator">.</span><span class="Entity">sorted_by</span> <span class="Keyword">=</span> {'Style' <span class="PunctuationSeparator">=></span> {"order" <span class="PunctuationSeparator">=></span> 'ascending'}}
|
148
|
+
<span class="Keyword">end</span>
|
149
|
+
|
150
|
+
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">only!</span>(<span class="Constant">2</span><span class="PunctuationSeparator">.</span><span class="PunctuationSeparator">.</span><span class="Constant">4</span>)
|
151
|
+
spreadsheet<span class="PunctuationSeparator">.</span>rows
|
152
|
+
</pre><em>Returns:</em><pre class="dawn">[["Nicholson Baker"<span class="PunctuationSeparator">,</span> "Mezannine"<span class="PunctuationSeparator">,</span> "150"<span class="PunctuationSeparator">,</span> "Minimalism"]<span class="PunctuationSeparator">,</span> ["Vladimir Sorokin"<span class="PunctuationSeparator">,</span> "The Queue"<span class="PunctuationSeparator">,</span> "263"<span class="PunctuationSeparator">,</span> "Satire"]]
|
153
|
+
</pre>
|
154
|
+
</p>
|
155
|
+
<h3>Sum</h3>
|
156
|
+
<p>TableFu can also sum a column of values:
|
157
|
+
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv)
|
158
|
+
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">total_for</span>('Number of Pages')<span class="PunctuationSeparator">.</span>to_s
|
159
|
+
</pre><em>Returns:</em><pre class="dawn"><span class="Constant">1177</span>
|
160
|
+
</pre>
|
161
|
+
</p>
|
162
|
+
<h2><a id="links" href="#toc">Links</a></h2>
|
163
|
+
<ul>
|
164
|
+
<li><a href="http://github.com/propublica/table-setter">TableSetter</a><br>A Sinatra app that uses <strong>TableFu</strong> to render public Google Spreadsheets in custom HTML.</li>
|
165
|
+
<li><a href="http://github.com/propublica/table-setter-generator">TableSetter Generator</a><br>
|
166
|
+
A rails generator that allows you to create a rails app like TableSetter.
|
167
|
+
</li>
|
168
|
+
<li><a href="http://github.com/propublica/table-fu/issues">Issues</a><br>Post bug reports and feature requests here.</li>
|
169
|
+
<li><a href="doc/index.html">API Docs</a></li>
|
170
|
+
</ul>
|
171
|
+
<h2><a id="credits" href="#toc">Credits</a></h2>
|
172
|
+
<p><a href="http://github.com/thejefflarson">Jeff Larson</a> (Maintainer), <a href="http://github.com/brianboyer/">Brian Boyer</a>, <a href="http://github.com/kleinmatic">Scott Klein</a>, <a href="http://github.com/markpercival">Mark Percival</a>, and <a href="http://github.com/seebq">Charles Brian Quinn</a>.</p>
|
173
|
+
<h2><a id="license" href="#toc">License</a></h2>
|
174
|
+
<pre>Copyright (c) 2010 ProPublica
|
175
|
+
|
176
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
177
|
+
a copy of this software and associated documentation files (the
|
178
|
+
"Software"), to deal in the Software without restriction, including
|
179
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
180
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
181
|
+
permit persons to whom the Software is furnished to do so, subject to
|
182
|
+
the following conditions:
|
183
|
+
|
184
|
+
The above copyright notice and this permission notice shall be
|
185
|
+
included in all copies or substantial portions of the Software.
|
186
|
+
|
187
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
188
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
189
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
190
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
191
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
192
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
193
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
194
|
+
</pre>
|
195
|
+
</body>
|
196
|
+
</html>
|
data/lib/table_fu.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
if RUBY_VERSION > "1.9"
|
2
|
+
require 'csv'
|
3
|
+
::FasterCSV = CSV
|
4
|
+
else
|
5
|
+
require 'fastercsv'
|
6
|
+
end
|
3
7
|
|
4
8
|
|
5
9
|
# TableFu turns a matric array(from a csv file for example) into a spreadsheet.
|
@@ -9,10 +13,10 @@ require 'fastercsv'
|
|
9
13
|
# Documentation:
|
10
14
|
# http://propublica.github.com/table-fu
|
11
15
|
class TableFu
|
12
|
-
|
16
|
+
|
13
17
|
attr_reader :deleted_rows, :table, :totals, :column_headers
|
14
18
|
attr_accessor :faceted_on, :col_opts
|
15
|
-
|
19
|
+
|
16
20
|
# Should be initialized with a matrix array or a string containing a csv, and expects the first
|
17
21
|
# array in the matrix to be column headers.
|
18
22
|
def initialize(table, column_opts = {})
|
@@ -28,11 +32,11 @@ class TableFu
|
|
28
32
|
end
|
29
33
|
|
30
34
|
|
31
|
-
|
35
|
+
|
32
36
|
# Pass it an array and it will delete it from the table, but save the data in
|
33
37
|
# @deleted_rows@ for later perusal.
|
34
|
-
#
|
35
|
-
# Returns:
|
38
|
+
#
|
39
|
+
# Returns:
|
36
40
|
# nothing
|
37
41
|
def delete_rows!(arr)
|
38
42
|
@deleted_rows ||= []
|
@@ -42,8 +46,8 @@ class TableFu
|
|
42
46
|
end
|
43
47
|
@table.compact!
|
44
48
|
end
|
45
|
-
|
46
|
-
|
49
|
+
|
50
|
+
|
47
51
|
# Inverse slice: Only keep the rows in the range after sorting
|
48
52
|
def only!(range)
|
49
53
|
rows_to_exclude = rows.map do |row|
|
@@ -56,7 +60,7 @@ class TableFu
|
|
56
60
|
def row_at(row_num)
|
57
61
|
TableFu::Row.new(@table[row_num], row_num, self)
|
58
62
|
end
|
59
|
-
|
63
|
+
|
60
64
|
# Returns all the Row objects for this object as a collection
|
61
65
|
def rows
|
62
66
|
all_rows = []
|
@@ -65,13 +69,13 @@ class TableFu
|
|
65
69
|
end
|
66
70
|
all_rows.sort
|
67
71
|
end
|
68
|
-
|
72
|
+
|
69
73
|
# Return the headers defined in column headers or cherry picked from @col_opts
|
70
74
|
def columns
|
71
75
|
@col_opts[:columns] || column_headers
|
72
76
|
end
|
73
|
-
|
74
|
-
# Return the headers of the array
|
77
|
+
|
78
|
+
# Return the headers of the array
|
75
79
|
def headers
|
76
80
|
all_columns = []
|
77
81
|
columns.each do |header|
|
@@ -79,18 +83,18 @@ class TableFu
|
|
79
83
|
end
|
80
84
|
all_columns
|
81
85
|
end
|
82
|
-
|
86
|
+
|
83
87
|
# Sum the values of a particular column
|
84
88
|
def sum_totals_for(column)
|
85
89
|
@totals[column.to_s] = rows.inject(0) { |sum, r| to_numeric(r.datum_for(column).value) + sum }
|
86
90
|
end
|
87
|
-
|
91
|
+
|
88
92
|
# Sum the values of a particular column and return a Datum
|
89
93
|
def total_for(column)
|
90
94
|
sum_totals_for(column)
|
91
95
|
Datum.new(@totals[column.to_s], column, nil, self)
|
92
96
|
end
|
93
|
-
|
97
|
+
|
94
98
|
# Return an array of TableFu instances grouped by a column.
|
95
99
|
def faceted_by(column, opts = {})
|
96
100
|
faceted_spreadsheets = {}
|
@@ -100,7 +104,7 @@ class TableFu
|
|
100
104
|
faceted_spreadsheets[row.column_for(column).value] << row
|
101
105
|
end
|
102
106
|
end
|
103
|
-
|
107
|
+
|
104
108
|
# Create new table_fu instances for each facet
|
105
109
|
tables = []
|
106
110
|
faceted_spreadsheets.each do |key,value|
|
@@ -110,11 +114,11 @@ class TableFu
|
|
110
114
|
table.col_opts = @col_opts #formatting should be carried through
|
111
115
|
tables << table
|
112
116
|
end
|
113
|
-
|
117
|
+
|
114
118
|
tables.sort! do |a,b|
|
115
119
|
a.faceted_on <=> b.faceted_on
|
116
120
|
end
|
117
|
-
|
121
|
+
|
118
122
|
if opts[:total]
|
119
123
|
opts[:total].each do |c|
|
120
124
|
tables.each do |f|
|
@@ -122,10 +126,10 @@ class TableFu
|
|
122
126
|
end
|
123
127
|
end
|
124
128
|
end
|
125
|
-
|
129
|
+
|
126
130
|
tables
|
127
131
|
end
|
128
|
-
|
132
|
+
|
129
133
|
# Return a numeric instance for a string number, or if it's a string we
|
130
134
|
# return 1, this way if we total up a series of strings it's a count
|
131
135
|
def to_numeric(num)
|
@@ -137,70 +141,70 @@ class TableFu
|
|
137
141
|
1 # We count each instance of a string this way
|
138
142
|
end
|
139
143
|
end
|
140
|
-
|
144
|
+
|
141
145
|
# Return true if this table is faceted
|
142
146
|
def faceted?
|
143
147
|
not faceted_on.nil?
|
144
148
|
end
|
145
|
-
|
149
|
+
|
146
150
|
# Return the sorted_by column
|
147
151
|
def sorted_by
|
148
152
|
@col_opts[:sorted_by]
|
149
153
|
end
|
150
|
-
|
154
|
+
|
151
155
|
# Set the sorted_by column
|
152
156
|
def sorted_by=(header)
|
153
157
|
@col_opts[:sorted_by] = header
|
154
158
|
end
|
155
|
-
|
159
|
+
|
156
160
|
# Return the formatting hash
|
157
161
|
def formatting
|
158
162
|
@col_opts[:formatting]
|
159
163
|
end
|
160
|
-
|
164
|
+
|
161
165
|
# Set the formatting hash
|
162
166
|
def formatting=(headers)
|
163
167
|
@col_opts[:formatting] = headers
|
164
168
|
end
|
165
|
-
|
169
|
+
|
166
170
|
# Set up the cherry picked columns
|
167
171
|
def columns=(array)
|
168
172
|
@col_opts[:columns] = array
|
169
173
|
end
|
170
|
-
|
171
174
|
|
172
|
-
|
175
|
+
|
176
|
+
|
173
177
|
end
|
174
178
|
|
175
179
|
class TableFu
|
176
180
|
# TableFu::Row adds functionality to an row array in a TableFu instance
|
177
181
|
class Row < Array
|
178
|
-
|
182
|
+
|
179
183
|
attr_reader :row_num
|
180
|
-
|
184
|
+
|
181
185
|
def initialize(row, row_num, spreadsheet)
|
182
186
|
self.replace row
|
183
187
|
@row_num = row_num
|
184
188
|
@spreadsheet = spreadsheet
|
185
189
|
end
|
186
|
-
|
190
|
+
|
187
191
|
def columns
|
188
192
|
all_cols = []
|
189
193
|
@spreadsheet.columns.each do |column|
|
190
|
-
all_cols << datum_for(column)
|
191
|
-
end
|
194
|
+
all_cols << datum_for(column)
|
195
|
+
end
|
192
196
|
all_cols
|
193
197
|
end
|
194
|
-
|
198
|
+
|
195
199
|
# This returns a Datum object for a header name. Will return a nil Datum object
|
196
200
|
# for nonexistant column names
|
197
|
-
#
|
201
|
+
#
|
198
202
|
# Parameters:
|
199
203
|
# header name
|
200
|
-
#
|
204
|
+
#
|
201
205
|
# Returns:
|
202
206
|
# Datum object
|
203
|
-
#
|
207
|
+
#
|
204
208
|
def datum_for(col_name)
|
205
209
|
if col_num = @spreadsheet.column_headers.index(col_name)
|
206
210
|
TableFu::Datum.new(self[col_num], col_name, self, @spreadsheet)
|
@@ -209,7 +213,7 @@ class TableFu
|
|
209
213
|
end
|
210
214
|
end
|
211
215
|
alias_method :column_for, :datum_for
|
212
|
-
|
216
|
+
|
213
217
|
# sugar
|
214
218
|
def [](col)
|
215
219
|
if col.is_a?(String)
|
@@ -218,7 +222,7 @@ class TableFu
|
|
218
222
|
super(col)
|
219
223
|
end
|
220
224
|
end
|
221
|
-
|
225
|
+
|
222
226
|
# Comparator for sorting a spreadsheet row.
|
223
227
|
#
|
224
228
|
def <=>(b)
|
@@ -228,25 +232,25 @@ class TableFu
|
|
228
232
|
format = @spreadsheet.sorted_by[column]["format"]
|
229
233
|
a = column_for(column).value || ''
|
230
234
|
b = b.column_for(column).value || ''
|
231
|
-
if format
|
235
|
+
if format
|
232
236
|
a = TableFu::Formatting.send(format, a) || ''
|
233
237
|
b = TableFu::Formatting.send(format, b) || ''
|
234
238
|
end
|
235
239
|
result = a <=> b
|
236
240
|
result = -1 if result.nil?
|
237
|
-
result = result * -1 if order == 'descending'
|
241
|
+
result = result * -1 if order == 'descending'
|
238
242
|
result
|
239
243
|
else
|
240
244
|
-1
|
241
245
|
end
|
242
246
|
end
|
243
|
-
|
247
|
+
|
244
248
|
end
|
245
249
|
# A Datum is an individual cell in the TableFu::Row
|
246
250
|
class Datum
|
247
251
|
|
248
252
|
attr_reader :options, :column_name
|
249
|
-
|
253
|
+
|
250
254
|
# Each piece of datum should know where it is by column and row number, along
|
251
255
|
# with the spreadsheet it's apart of. There's probably a better way to go
|
252
256
|
# about doing this. Subclass?
|
@@ -256,7 +260,7 @@ class TableFu
|
|
256
260
|
@row = row
|
257
261
|
@spreadsheet = spreadsheet
|
258
262
|
end
|
259
|
-
|
263
|
+
|
260
264
|
# Our standard formatter for the datum
|
261
265
|
#
|
262
266
|
# Returns:
|
@@ -264,7 +268,7 @@ class TableFu
|
|
264
268
|
#
|
265
269
|
# First we test to see if this Datum has a macro attached to it. If so
|
266
270
|
# we let the macro method do it's magic
|
267
|
-
#
|
271
|
+
#
|
268
272
|
# Then we test for a simple formatter method.
|
269
273
|
#
|
270
274
|
# And finally we return a empty string object or the value.
|
@@ -278,8 +282,8 @@ class TableFu
|
|
278
282
|
@datum || ''
|
279
283
|
end
|
280
284
|
end
|
281
|
-
|
282
|
-
# Returns the macro'd format if there is one
|
285
|
+
|
286
|
+
# Returns the macro'd format if there is one
|
283
287
|
#
|
284
288
|
# Returns:
|
285
289
|
# The macro value if it exists, otherwise nil
|
@@ -288,26 +292,26 @@ class TableFu
|
|
288
292
|
# Then get a array of the values in the columns listed as arguments
|
289
293
|
# Splat the arguments to the macro method.
|
290
294
|
# Example:
|
291
|
-
# @spreadsheet.col_opts[:formatting] =
|
295
|
+
# @spreadsheet.col_opts[:formatting] =
|
292
296
|
# {'Total Appropriation' => :currency,
|
293
297
|
# 'AppendedColumn' => {'method' => 'append', 'arguments' => ['Projects','State']}}
|
294
|
-
#
|
298
|
+
#
|
295
299
|
# in the above case we handle the AppendedColumn in this method
|
296
300
|
|
297
301
|
if @spreadsheet.formatting && @spreadsheet.formatting[@column_name].is_a?(Hash)
|
298
302
|
method = @spreadsheet.formatting[@column_name]['method']
|
299
303
|
arguments = @spreadsheet.formatting[@column_name]['arguments'].inject([]) do |arr,arg|
|
300
|
-
arr << @row.column_for(arg)
|
304
|
+
arr << @row.column_for(arg)
|
301
305
|
arr
|
302
306
|
end
|
303
307
|
TableFu::Formatting.send(method, *arguments)
|
304
308
|
end
|
305
309
|
end
|
306
|
-
|
307
|
-
# Returns the raw value of a datum
|
310
|
+
|
311
|
+
# Returns the raw value of a datum
|
308
312
|
#
|
309
313
|
# Returns:
|
310
|
-
# raw value of the datum, could be nil
|
314
|
+
# raw value of the datum, could be nil
|
311
315
|
def value
|
312
316
|
if @datum =~ /[0-9]+/
|
313
317
|
@datum.to_i
|
@@ -320,21 +324,21 @@ class TableFu
|
|
320
324
|
#
|
321
325
|
# First Option
|
322
326
|
# We have a column option by that method name and it applies to this column
|
323
|
-
# Example -
|
327
|
+
# Example -
|
324
328
|
# >> @data.column_name
|
325
329
|
# => 'Total'
|
326
330
|
# >> @datum.style
|
327
331
|
# Finds col_opt[:style] = {'Total' => 'text-align:left;'}
|
328
332
|
# => 'text-align:left;'
|
329
|
-
#
|
333
|
+
#
|
330
334
|
# Second Option
|
331
335
|
# We have a column option by that method name, but no attribute
|
332
336
|
# >> @data.column_name
|
333
337
|
# => 'Total'
|
334
|
-
# >> @datum.style
|
338
|
+
# >> @datum.style
|
335
339
|
# Finds col_opt[:style] = {'State' => 'text-align:left;'}
|
336
340
|
# => ''
|
337
|
-
#
|
341
|
+
#
|
338
342
|
# Third Option
|
339
343
|
# The boolean
|
340
344
|
# >> @data.invisible?
|
@@ -361,7 +365,7 @@ class TableFu
|
|
361
365
|
super
|
362
366
|
end
|
363
367
|
end
|
364
|
-
|
368
|
+
|
365
369
|
private
|
366
370
|
|
367
371
|
# Enable string or symbol key access to col_opts
|
@@ -378,7 +382,7 @@ class TableFu
|
|
378
382
|
Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
|
379
383
|
end
|
380
384
|
end
|
381
|
-
|
385
|
+
|
382
386
|
# A header object needs to be a special kind of Datum, and
|
383
387
|
# we may want to extend this further, but currently we just
|
384
388
|
# need to ensure that when to_s is called on a @Header@ object
|
@@ -388,9 +392,9 @@ class TableFu
|
|
388
392
|
def to_s
|
389
393
|
@datum
|
390
394
|
end
|
391
|
-
|
395
|
+
|
392
396
|
end
|
393
|
-
|
397
|
+
|
394
398
|
end
|
395
399
|
|
396
400
|
$:.unshift(File.dirname(__FILE__)) unless
|
data/spec/readme_example_spec.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'spec'
|
2
|
-
require '
|
3
|
-
require 'fastercsv'
|
2
|
+
require 'spec_helper.rb'
|
4
3
|
|
5
4
|
|
6
5
|
describe TableFu do
|
@@ -17,19 +16,19 @@ CSV
|
|
17
16
|
s.formatting = {'Cost' => 'currency'}
|
18
17
|
s.sorted_by = {'Project' => {'order' => 'descending'}}
|
19
18
|
s.columns = ['Date', 'Project', 'Cost']
|
20
|
-
end
|
21
|
-
|
19
|
+
end
|
20
|
+
|
22
21
|
end
|
23
22
|
|
24
23
|
it "should just work" do
|
25
24
|
@spreadsheet.rows[0].column_for('Cost').to_s.should == '$45.00'
|
26
25
|
@spreadsheet.rows[0].columns[1].to_s.should == 'Motorized Bar Stool'
|
27
26
|
end
|
28
|
-
|
27
|
+
|
29
28
|
it 'should open a file if passed one' do
|
30
29
|
@spreadsheet = TableFu.new(File.open('spec/assets/test.csv')).rows[0].column_for('State').to_s.should eql "Alabama"
|
31
30
|
end
|
32
|
-
|
31
|
+
|
33
32
|
it "should populate headers if we don't tell it which headers to use" do
|
34
33
|
TableFu.new(@csv).headers.should_not be_nil
|
35
34
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/table_fu_spec.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'spec'
|
2
|
-
require '
|
3
|
-
require 'fastercsv'
|
2
|
+
require 'spec_helper'
|
4
3
|
|
5
4
|
|
6
5
|
describe TableFu do
|
@@ -19,7 +18,7 @@ describe TableFu do
|
|
19
18
|
it 'should give me back a column by it\'s header name' do
|
20
19
|
@spreadsheet.rows[0].column_for("State").to_s.should == "Alabama"
|
21
20
|
end
|
22
|
-
|
21
|
+
|
23
22
|
it 'should sort rows' do
|
24
23
|
@spreadsheet.sorted_by = {'State' => {"order" => 'descending'}}
|
25
24
|
@spreadsheet.rows[0].column_for("State").to_s.should eql "Wyoming"
|
@@ -28,8 +27,8 @@ describe TableFu do
|
|
28
27
|
@spreadsheet.sorted_by = {'Representative' => {"order" => 'ascending', "format" => 'last_name'}}
|
29
28
|
@spreadsheet.rows[2].column_for("Representative").to_s.should eql "Jo Bonner"
|
30
29
|
|
31
|
-
|
32
|
-
@spreadsheet.col_opts[:columns] =
|
30
|
+
|
31
|
+
@spreadsheet.col_opts[:columns] = ['State', 'Party', 'Total Appropriations', 'URL']
|
33
32
|
@spreadsheet.rows.each do |row|
|
34
33
|
row.columns.each do |column|
|
35
34
|
if column.column_name == 'URL'
|
@@ -40,9 +39,9 @@ describe TableFu do
|
|
40
39
|
column.style.should_not be_nil
|
41
40
|
end
|
42
41
|
end
|
43
|
-
|
42
|
+
|
44
43
|
end
|
45
|
-
|
44
|
+
|
46
45
|
it 'should sort rows with numerals' do
|
47
46
|
@spreadsheet.sorted_by = {'Projects' => {"order" => 'ascending'}}
|
48
47
|
sorted = @spreadsheet.rows.map do |row|
|
@@ -50,7 +49,7 @@ describe TableFu do
|
|
50
49
|
end
|
51
50
|
sorted.should eql [4, 5, 10, 12, 20, 49, nil]
|
52
51
|
end
|
53
|
-
|
52
|
+
|
54
53
|
it 'should be able to contain only the rows I want, after sorting' do
|
55
54
|
@spreadsheet.sorted_by = {'State' => {"order" => 'ascending'}}
|
56
55
|
@spreadsheet.only!(1..2)
|
@@ -66,7 +65,7 @@ describe TableFu, 'with a complicated setup' do
|
|
66
65
|
before :all do
|
67
66
|
csv = FasterCSV.parse(File.open('spec/assets/test.csv'))
|
68
67
|
@spreadsheet = TableFu.new(csv)
|
69
|
-
@spreadsheet.col_opts[:formatting] = {'Total Appropriation' => :currency,
|
68
|
+
@spreadsheet.col_opts[:formatting] = {'Total Appropriation' => :currency,
|
70
69
|
"Representative" => :last_name_first_name}
|
71
70
|
@spreadsheet.col_opts[:style] = {'Leadership' => "text-align: left;", 'URL' => 'text-align: right;'}
|
72
71
|
@spreadsheet.col_opts[:invisible] = ['URL']
|
@@ -95,12 +94,12 @@ describe TableFu, 'with a complicated setup' do
|
|
95
94
|
@spreadsheet.rows[2].column_for('State').to_s.should eql "New Jersey"
|
96
95
|
@spreadsheet.rows[0].column_for('State').to_s.should eql "Wyoming"
|
97
96
|
end
|
98
|
-
|
97
|
+
|
99
98
|
it 'should have some sugar' do
|
100
99
|
@spreadsheet.rows[3]['State'].to_s.should eql "Georgia"
|
101
|
-
|
100
|
+
|
102
101
|
end
|
103
|
-
|
102
|
+
|
104
103
|
it 'should total a column' do
|
105
104
|
@spreadsheet.total_for("Total Appropriation").value.should eql 16640189309
|
106
105
|
@spreadsheet.total_for("Total Appropriation").to_s.should eql "$16,640,189,309"
|
@@ -111,12 +110,12 @@ describe TableFu, 'with a complicated setup' do
|
|
111
110
|
@spreadsheet.rows[0].column_for("Total Appropriation").value.should eql 138526141
|
112
111
|
@spreadsheet.rows[4].column_for("Representative").to_s.should eql "Nunes, Devin"
|
113
112
|
end
|
114
|
-
|
113
|
+
|
115
114
|
it 'should format a header' do
|
116
115
|
@spreadsheet.headers[1].style.should eql 'text-align: left;'
|
117
116
|
@spreadsheet.headers[4].style.should eql 'text-align: right;'
|
118
117
|
end
|
119
|
-
|
118
|
+
|
120
119
|
it 'should not care what kind of keys the hash has' do
|
121
120
|
@spreadsheet = TableFu.new(File.open('spec/assets/test.csv'))
|
122
121
|
@spreadsheet.col_opts["style"] = {'Leadership' => "text-align: left;", 'URL' => 'text-align: right;'}
|
@@ -124,7 +123,7 @@ describe TableFu, 'with a complicated setup' do
|
|
124
123
|
@spreadsheet.rows[0].column_for('Leadership').style.should ==
|
125
124
|
@spreadsheet.col_opts["style"]['Leadership']
|
126
125
|
end
|
127
|
-
|
126
|
+
|
128
127
|
|
129
128
|
|
130
129
|
end
|
@@ -163,7 +162,7 @@ describe TableFu, "with faceting" do
|
|
163
162
|
end
|
164
163
|
|
165
164
|
it "should keep the formatting" do
|
166
|
-
|
165
|
+
|
167
166
|
@faceted_spreadsheets[1].rows[1].column_for('Total Appropriation').to_s.should eql "$25,320,127"
|
168
167
|
@faceted_spreadsheets[1].rows[1].column_for('Projects').style.should eql "text-align:left;"
|
169
168
|
end
|
@@ -174,15 +173,15 @@ end
|
|
174
173
|
describe TableFu, 'with macro columns' do
|
175
174
|
|
176
175
|
class TableFu::Formatting
|
177
|
-
|
176
|
+
|
178
177
|
class<<self
|
179
178
|
|
180
179
|
def append(first, second)
|
181
180
|
"#{first}#{second}"
|
182
181
|
end
|
183
|
-
|
182
|
+
|
184
183
|
end
|
185
|
-
|
184
|
+
|
186
185
|
end
|
187
186
|
|
188
187
|
|
@@ -195,13 +194,13 @@ describe TableFu, 'with macro columns' do
|
|
195
194
|
@spreadsheet.sorted_by = {'Projects' => {'order' => 'descending'}}
|
196
195
|
@spreadsheet.col_opts[:columns] = ['State', 'Total Appropriation', 'Projects', 'MacroColumn']
|
197
196
|
end
|
198
|
-
|
197
|
+
|
199
198
|
it "should let us specify a macro for a column" do
|
200
199
|
@spreadsheet.rows[1].column_for('MacroColumn').to_s.should eql '20Arizona'
|
201
200
|
end
|
202
|
-
|
201
|
+
|
203
202
|
it "should keep the rows in order" do
|
204
|
-
@spreadsheet.rows[0].column_for('Projects').value.should eql 49
|
203
|
+
@spreadsheet.rows[0].column_for('Projects').value.should eql 49
|
205
204
|
@spreadsheet.rows[1].column_for('Total Appropriation').to_s.should eql '$42,367,198'
|
206
205
|
end
|
207
206
|
|
data/table_fu.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{table_fu}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Mark Percival", "Jeff Larson"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-11-19}
|
13
13
|
s.description = %q{A library for manipulating tables as arrays}
|
14
14
|
s.email = %q{jeff.larson@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: table_fu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 1
|
10
|
+
version: 0.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Mark Percival
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-
|
19
|
+
date: 2010-11-19 00:00:00 -05:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|