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 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
@@ -1,5 +1,5 @@
1
1
  ---
2
- :patch: 0
2
+ :minor: 3
3
+ :patch: 1
3
4
  :build:
4
5
  :major: 0
5
- :minor: 3
@@ -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">&nbsp;</a>
41
- <h1>TableFu <small>&ndash; Version: <%=
40
+ <h1>TableFu <small>&ndash; 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">&nbsp;</a>
13
+ <h1>TableFu <small>&ndash; 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> &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>
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>&lt;&lt;-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">=&gt;</span> {'order' <span class="PunctuationSeparator">=&gt;</span> 'ascending'}}
27
+ <span class="Keyword">end</span>
28
+ </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;]]
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>&lt;&lt;-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">=&gt;</span> {'order' <span class="PunctuationSeparator">=&gt;</span> 'ascending'}}
66
+ <span class="Keyword">end</span>
67
+ </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;]]
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> [&quot;Best Book&quot;<span class="PunctuationSeparator">,</span> &quot;Author&quot;]
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">[&quot;Malone Muert&quot;<span class="PunctuationSeparator">,</span> &quot;Samuel Beckett&quot;]
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> [&quot;Best Book&quot;<span class="PunctuationSeparator">,</span> &quot;Author&quot;]
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">&quot;Modernism&quot;
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">{&quot;Column Name&quot; <span class="PunctuationSeparator">=&gt;</span> 'Formatting Method Name'}
94
+
95
+ <span class="Comment"><span class="Comment">#</span> or</span>
96
+
97
+ {&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']}}
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> {&quot;Author&quot; <span class="PunctuationSeparator">=&gt;</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">&quot;Beckett&quot;
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> &quot;Style&quot;
124
+ </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;]]
125
+ 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;]]
126
+ 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;]]
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">[[&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;]]
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">=&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;]]
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">=&gt;</span> {&quot;order&quot; <span class="PunctuationSeparator">=&gt;</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">[[&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;]]
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>
@@ -1,5 +1,9 @@
1
- require 'rubygems'
2
- require 'fastercsv'
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
@@ -1,6 +1,5 @@
1
1
  require 'spec'
2
- require 'spec/spec_helper'
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
@@ -1,4 +1,3 @@
1
- $:.unshift File.expand_path(File.join(File.dirname(__FILE__)))
2
-
1
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
+ require 'rubygems'
3
3
  require 'lib/table_fu'
4
- require 'rubygems'
@@ -1,6 +1,5 @@
1
1
  require 'spec'
2
- require 'spec/spec_helper'
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] = {'State', 'Party', 'Total Appropriations', 'URL'}
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
 
@@ -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.0"
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-05-26}
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: 19
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 0
10
- version: 0.3.0
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-05-26 00:00:00 -04:00
19
+ date: 2010-11-19 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency