Skip to content

Instantly share code, notes, and snippets.

@eiriks
Created November 21, 2012 12:25
Show Gist options
  • Save eiriks/4124620 to your computer and use it in GitHub Desktop.
Save eiriks/4124620 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>TableFu</title>
<link rel="stylesheet" type="text/css" href="documentation/css/styles.css" />
<link rel="stylesheet" type="text/css" href="documentation/css/dawn.css" />
</head>
<body>
<a href="http://www.propublica.org" class="propublica">&nbsp;</a>
<h1>TableFu <small>&ndash; Version: 0.3.4</small></h1>
<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> &mdash; or group &mdash; 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>
<p>For example, <strong>TableFu</strong> can consume a csv file and sort on a column:
<pre class="dawn">csv <span class="Keyword">=</span>&lt;&lt;-CSV
Author,Best Book,Number of Pages,Style
Samuel Beckett,Malone Muert,120,Modernism
James Joyce,Ulysses,644,Modernism
Nicholson Baker,Mezannine,150,Minimalism
Vladimir Sorokin,The Queue,263,Satire
CSV
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>
s<span class="PunctuationSeparator">.</span><span class="Entity">sorted_by</span> <span class="Keyword">=</span> {'Best Book' <span class="PunctuationSeparator">=&gt;</span> {'order' <span class="PunctuationSeparator">=&gt;</span> 'ascending'}}
<span class="Keyword">end</span>
</pre><em>Returns:</em><pre class="dawn">[[&quot;Samuel Beckett&quot;<span class="PunctuationSeparator">,</span> &quot;Malone Muert&quot;<span class="PunctuationSeparator">,</span> &quot;120&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]<span class="PunctuationSeparator">,</span> [&quot;Nicholson Baker&quot;<span class="PunctuationSeparator">,</span> &quot;Mezannine&quot;<span class="PunctuationSeparator">,</span> &quot;150&quot;<span class="PunctuationSeparator">,</span> &quot;Minimalism&quot;]<span class="PunctuationSeparator">,</span> [&quot;Vladimir Sorokin&quot;<span class="PunctuationSeparator">,</span> &quot;The Queue&quot;<span class="PunctuationSeparator">,</span> &quot;263&quot;<span class="PunctuationSeparator">,</span> &quot;Satire&quot;]<span class="PunctuationSeparator">,</span> [&quot;James Joyce&quot;<span class="PunctuationSeparator">,</span> &quot;Ulysses&quot;<span class="PunctuationSeparator">,</span> &quot;644&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]]
</pre>
</p>
<h2><a id="toc">Table of Contents</a></h2>
<ul>
<li><a href="#installation">Installation</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#macros">Macros / Formatting</a></li>
<li><a href="#faceting">Faceting</a></li>
<li><a href="#manipulation">Manipulation</a></li>
<li><a href="#links">Links</a></li>
<li><a href="#credits">Credits</a></li>
<li><a href="#license">License</a></li>
</ul>
<h2><a id="installation" href="#toc">Installation</a></h2>
<p><strong>TableFu</strong> is available as a rubygem:
<pre class="dawn">
gem install table_fu</pre>
or from the actual source:
<pre class="dawn">
git clone git://github.com/propublica/table-fu.git
cd table-fu
rake install</pre>
</p>
<h2><a id="usage" href="#toc">Usage</a></h2>
<p>
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>
<p><strong>sorted_by:</strong> the column to sort by, it defaults to no sorting at all.
<pre class="dawn">csv <span class="Keyword">=</span>&lt;&lt;-CSV
Author,Best Book,Number of Pages,Style
Samuel Beckett,Malone Muert,120,Modernism
James Joyce,Ulysses,644,Modernism
Nicholson Baker,Mezannine,150,Minimalism
Vladimir Sorokin,The Queue,263,Satire
CSV
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>
s<span class="PunctuationSeparator">.</span><span class="Entity">sorted_by</span> <span class="Keyword">=</span> {'Best Book' <span class="PunctuationSeparator">=&gt;</span> {'order' <span class="PunctuationSeparator">=&gt;</span> 'ascending'}}
<span class="Keyword">end</span>
</pre><em>Returns:</em><pre class="dawn">[[&quot;Samuel Beckett&quot;<span class="PunctuationSeparator">,</span> &quot;Malone Muert&quot;<span class="PunctuationSeparator">,</span> &quot;120&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]<span class="PunctuationSeparator">,</span> [&quot;Nicholson Baker&quot;<span class="PunctuationSeparator">,</span> &quot;Mezannine&quot;<span class="PunctuationSeparator">,</span> &quot;150&quot;<span class="PunctuationSeparator">,</span> &quot;Minimalism&quot;]<span class="PunctuationSeparator">,</span> [&quot;Vladimir Sorokin&quot;<span class="PunctuationSeparator">,</span> &quot;The Queue&quot;<span class="PunctuationSeparator">,</span> &quot;263&quot;<span class="PunctuationSeparator">,</span> &quot;Satire&quot;]<span class="PunctuationSeparator">,</span> [&quot;James Joyce&quot;<span class="PunctuationSeparator">,</span> &quot;Ulysses&quot;<span class="PunctuationSeparator">,</span> &quot;644&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]]
</pre>
</p>
<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.
<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>
s<span class="PunctuationSeparator">.</span><span class="Entity">columns</span> <span class="Keyword">=</span> [&quot;Best Book&quot;<span class="PunctuationSeparator">,</span> &quot;Author&quot;]
<span class="Keyword">end</span>
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>
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>
<span class="Keyword">end</span>
</pre><em>Returns:</em><pre class="dawn">[&quot;Malone Muert&quot;<span class="PunctuationSeparator">,</span> &quot;Samuel Beckett&quot;]
</pre>
Note that the columns are still accessible directly even if they're not in the columns array.
<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>
s<span class="PunctuationSeparator">.</span><span class="Entity">columns</span> <span class="Keyword">=</span> [&quot;Best Book&quot;<span class="PunctuationSeparator">,</span> &quot;Author&quot;]
<span class="Keyword">end</span>
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">rows</span>[<span class="Constant">0</span>]['Style']<span class="PunctuationSeparator">.</span>to_s
</pre><em>Returns:</em><pre class="dawn">&quot;Modernism&quot;
</pre>
</p>
<h2><a id="macros" href="#toc">Macros / Formatting</a></h2>
<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>
<p>The <strong>formatting</strong> attribute should be a hash of the form:
<pre class="dawn">{&quot;Column Name&quot; <span class="PunctuationSeparator">=&gt;</span> 'Formatting Method Name'}
<span class="Comment"><span class="Comment">#</span> or</span>
{&quot;Meta Column Name&quot; <span class="PunctuationSeparator">=&gt;</span> {&quot;method&quot; <span class="PunctuationSeparator">=&gt;</span> &quot;Method Name&quot;<span class="PunctuationSeparator">,</span> &quot;arguments&quot; <span class="PunctuationSeparator">=&gt;</span> ['Column 1'<span class="PunctuationSeparator">,</span> 'Column 2' <span class="PunctuationSeparator">.</span><span class="PunctuationSeparator">.</span><span class="PunctuationSeparator">.</span> 'Column N']}}
</pre>
which will call the macro on the column name with the arguments if specified.
</p>
<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:
<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>
s<span class="PunctuationSeparator">.</span><span class="Entity">formatting</span> <span class="Keyword">=</span> {&quot;Author&quot; <span class="PunctuationSeparator">=&gt;</span> 'last_name'}
<span class="Keyword">end</span>
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
</pre><em>Returns:</em><pre class="dawn">&quot;Beckett&quot;
</pre>
</p>
<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>.
<pre class="dawn"><span class="Keyword">class</span> <span class="Entity">TableFu::Formatting</span>
<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>
<span class="Keyword">end</span>
</pre>
</p>
<h2><a id="faceting" href="#toc">Faceting</a></h2>
<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.
</p>
<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:
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv)
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">faceted_by</span> &quot;Style&quot;
</pre><em>Returns:</em><pre class="dawn">table<span class="PunctuationSeparator">.</span><span class="Entity">faceted_on</span> <span class="PunctuationSeparator">=&gt;</span> <span class="Variable">Minimalism</span><span class="PunctuationSeparator">,</span> table<span class="PunctuationSeparator">.</span><span class="Entity">rows</span> <span class="PunctuationSeparator">=&gt;</span> [[&quot;Nicholson Baker&quot;<span class="PunctuationSeparator">,</span> &quot;Mezannine&quot;<span class="PunctuationSeparator">,</span> &quot;150&quot;<span class="PunctuationSeparator">,</span> &quot;Minimalism&quot;]]
table<span class="PunctuationSeparator">.</span><span class="Entity">faceted_on</span> <span class="PunctuationSeparator">=&gt;</span> <span class="Variable">Modernism</span><span class="PunctuationSeparator">,</span> table<span class="PunctuationSeparator">.</span><span class="Entity">rows</span> <span class="PunctuationSeparator">=&gt;</span> [[&quot;Samuel Beckett&quot;<span class="PunctuationSeparator">,</span> &quot;Malone Muert&quot;<span class="PunctuationSeparator">,</span> &quot;120&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]<span class="PunctuationSeparator">,</span> [&quot;James Joyce&quot;<span class="PunctuationSeparator">,</span> &quot;Ulysses&quot;<span class="PunctuationSeparator">,</span> &quot;644&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]]
table<span class="PunctuationSeparator">.</span><span class="Entity">faceted_on</span> <span class="PunctuationSeparator">=&gt;</span> <span class="Variable">Satire</span><span class="PunctuationSeparator">,</span> table<span class="PunctuationSeparator">.</span><span class="Entity">rows</span> <span class="PunctuationSeparator">=&gt;</span> [[&quot;Vladimir Sorokin&quot;<span class="PunctuationSeparator">,</span> &quot;The Queue&quot;<span class="PunctuationSeparator">,</span> &quot;263&quot;<span class="PunctuationSeparator">,</span> &quot;Satire&quot;]]
</pre>
</p>
<h2><a id="manipulation" href="#toc">Manipulation / Output</a></h2>
<h3>Deleting Rows</h3>
<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):
<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>
s<span class="PunctuationSeparator">.</span><span class="Entity">delete_rows!</span> [<span class="Constant">1</span>]
<span class="Keyword">end</span>
</pre><em>Returns:</em><pre class="dawn">[[&quot;Samuel Beckett&quot;<span class="PunctuationSeparator">,</span> &quot;Malone Muert&quot;<span class="PunctuationSeparator">,</span> &quot;120&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]<span class="PunctuationSeparator">,</span> [&quot;Nicholson Baker&quot;<span class="PunctuationSeparator">,</span> &quot;Mezannine&quot;<span class="PunctuationSeparator">,</span> &quot;150&quot;<span class="PunctuationSeparator">,</span> &quot;Minimalism&quot;]<span class="PunctuationSeparator">,</span> [&quot;Vladimir Sorokin&quot;<span class="PunctuationSeparator">,</span> &quot;The Queue&quot;<span class="PunctuationSeparator">,</span> &quot;263&quot;<span class="PunctuationSeparator">,</span> &quot;Satire&quot;]]
</pre>
The deleted rows are still available in <strong>@deleted_rows</strong> for later access:
<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>
s<span class="PunctuationSeparator">.</span><span class="Entity">delete_rows!</span> [<span class="Constant">1</span>]
<span class="Keyword">end</span>
</pre><em>Returns:</em><pre class="dawn">table<span class="PunctuationSeparator">.</span><span class="Entity">deleted_rows</span> <span class="PunctuationSeparator">=&gt;</span> [[&quot;James Joyce&quot;<span class="PunctuationSeparator">,</span> &quot;Ulysses&quot;<span class="PunctuationSeparator">,</span> &quot;644&quot;<span class="PunctuationSeparator">,</span> &quot;Modernism&quot;]]
</pre>
</p>
<h3>Pagination</h3>
<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:
<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>
s<span class="PunctuationSeparator">.</span><span class="Entity">sorted_by</span> <span class="Keyword">=</span> {'Style' <span class="PunctuationSeparator">=&gt;</span> {&quot;order&quot; <span class="PunctuationSeparator">=&gt;</span> 'ascending'}}
<span class="Keyword">end</span>
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>)
spreadsheet<span class="PunctuationSeparator">.</span>rows
</pre><em>Returns:</em><pre class="dawn">[[&quot;Nicholson Baker&quot;<span class="PunctuationSeparator">,</span> &quot;Mezannine&quot;<span class="PunctuationSeparator">,</span> &quot;150&quot;<span class="PunctuationSeparator">,</span> &quot;Minimalism&quot;]<span class="PunctuationSeparator">,</span> [&quot;Vladimir Sorokin&quot;<span class="PunctuationSeparator">,</span> &quot;The Queue&quot;<span class="PunctuationSeparator">,</span> &quot;263&quot;<span class="PunctuationSeparator">,</span> &quot;Satire&quot;]]
</pre>
</p>
<h3>Sum</h3>
<p>TableFu can also sum a column of values:
<pre class="dawn">spreadsheet <span class="Keyword">=</span> <span class="Support">TableFu</span><span class="PunctuationSeparator">.</span><span class="Entity">new</span>(csv)
spreadsheet<span class="PunctuationSeparator">.</span><span class="Entity">total_for</span>('Number of Pages')<span class="PunctuationSeparator">.</span>to_s
</pre><em>Returns:</em><pre class="dawn"><span class="Constant">1177</span>
</pre>
</p>
<h2><a id="links" href="#toc">Links</a></h2>
<ul>
<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>
<li><a href="http://github.com/propublica/table-setter-generator">TableSetter Generator</a><br>
A rails generator that allows you to create a rails app like TableSetter.
</li>
<li><a href="http://github.com/propublica/table-fu/issues">Issues</a><br>Post bug reports and feature requests here.</li>
<li><a href="doc/index.html">API Docs</a></li>
</ul>
<h2><a id="credits" href="#toc">Credits</a></h2>
<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>,
<a href="http://github.com/seebq">Charles Brian Quinn</a>, and
<a href="http://github.com/jpmckinney">James McKinney</a>.</p>.</p>
<h2><a id="license" href="#toc">License</a></h2>
<pre>Copyright (c) 2010 ProPublica
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment