table_fu 0.3.0 → 0.3.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/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
|