hirb 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +9 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +231 -0
- data/Rakefile +49 -0
- data/VERSION.yml +4 -0
- data/lib/hirb.rb +31 -0
- data/lib/hirb/console.rb +17 -0
- data/lib/hirb/hash_struct.rb +17 -0
- data/lib/hirb/helpers.rb +7 -0
- data/lib/hirb/helpers/active_record_table.rb +17 -0
- data/lib/hirb/helpers/auto_table.rb +14 -0
- data/lib/hirb/helpers/object_table.rb +15 -0
- data/lib/hirb/helpers/parent_child_tree.rb +22 -0
- data/lib/hirb/helpers/table.rb +175 -0
- data/lib/hirb/helpers/tree.rb +177 -0
- data/lib/hirb/import_object.rb +10 -0
- data/lib/hirb/util.rb +29 -0
- data/lib/hirb/view.rb +201 -0
- data/lib/hirb/views/activerecord_base.rb +9 -0
- data/test/hirb_test.rb +23 -0
- data/test/import_test.rb +9 -0
- data/test/table_test.rb +263 -0
- data/test/test_helper.rb +17 -0
- data/test/tree_test.rb +167 -0
- data/test/util_test.rb +21 -0
- data/test/view_test.rb +169 -0
- metadata +83 -0
data/CHANGELOG.rdoc
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2009 Gabriel Horner
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
== Description
|
2
|
+
|
3
|
+
Hirb currently provides a mini view framework for console applications, designed with irb in mind.
|
4
|
+
Given the output of a console application, it renders a view if there is one configured, based on
|
5
|
+
the output's class. The framework encourages reusing views by letting you package them in classes
|
6
|
+
and associate them with any number of output classes. Hirb comes with tree views (see
|
7
|
+
Hirb::Helpers::Tree) and table views (see Hirb::Helpers::Table). By default Hirb displays Rails'
|
8
|
+
model classes as tables.
|
9
|
+
|
10
|
+
== Install
|
11
|
+
|
12
|
+
Install the gem with:
|
13
|
+
|
14
|
+
sudo gem install cldwalker-hirb --source http://gems.github.com
|
15
|
+
|
16
|
+
== Rails Example
|
17
|
+
|
18
|
+
Let's load and enable the view framework:
|
19
|
+
bash> script/console
|
20
|
+
Loading local environment (Rails 2.2.2)
|
21
|
+
irb>> require 'hirb'
|
22
|
+
=> true
|
23
|
+
irb>> Hirb::View.enable
|
24
|
+
=> nil
|
25
|
+
|
26
|
+
The default configuration provides table views for ActiveRecord::Base descendants.
|
27
|
+
If a class isn't configured, Hirb reverts to irb's default echo mode.
|
28
|
+
irb>> Hirb::View.output_config
|
29
|
+
=> {"ActiveRecord::Base"=>{:class=>"Hirb::Views::ActiveRecord_Base", :ancestor=>true}}
|
30
|
+
|
31
|
+
# Tag is a model class and descendant of ActiveRecord::Base
|
32
|
+
irb>> Tag.last
|
33
|
+
+-----+-------------------------+-------------+---------------+-----------+-----------+-------+
|
34
|
+
| id | created_at | description | name | namespace | predicate | value |
|
35
|
+
+-----+-------------------------+-------------+---------------+-----------+-----------+-------+
|
36
|
+
| 907 | 2009-03-06 21:10:41 UTC | | gem:tags=yaml | gem | tags | yaml |
|
37
|
+
+-----+-------------------------+-------------+---------------+-----------+-----------+-------+
|
38
|
+
1 row in set
|
39
|
+
|
40
|
+
irb>> 'plain ol irb'
|
41
|
+
=> 'plain ol irb'
|
42
|
+
irb>> :blah
|
43
|
+
=> :blah
|
44
|
+
|
45
|
+
From above you can see there were no views configured for a String or a Symbol so Hirb defaulted to
|
46
|
+
irb's echo mode. Also note that Tag was able to inherit its view from the ActiveRecord::Base config
|
47
|
+
because it had an :ancestor option.
|
48
|
+
|
49
|
+
Now that you understand that Hirb displays views based on an output object's class,
|
50
|
+
you may appreciate it also detects configured output objects in an array:
|
51
|
+
|
52
|
+
irb>> Tag.all :limit=>3, :order=>"id DESC"
|
53
|
+
+-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
|
54
|
+
| id | created_at | description | name | namespace | predicate | value |
|
55
|
+
+-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
|
56
|
+
| 907 | 2009-03-06 21:10:41 UTC | | gem:tags=yaml | gem | tags | yaml |
|
57
|
+
| 906 | 2009-03-06 08:47:04 UTC | | gem:tags=nomonkey | gem | tags | nomonkey |
|
58
|
+
| 905 | 2009-03-04 00:30:10 UTC | | article:tags=ruby | article | tags | ruby |
|
59
|
+
+-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
|
60
|
+
3 rows in set
|
61
|
+
|
62
|
+
At any time you can disable Hirb if you really like irb's lovely echo mode:
|
63
|
+
irb>> Hirb::View.disable
|
64
|
+
=> nil
|
65
|
+
irb>> Tag.all :limit=>3, :order=>"id DESC"
|
66
|
+
=> [#<Tag id: 907, name: "gem:tags=yaml", description: nil, created_at: "2009-03-06 21:10:41",
|
67
|
+
namespace: "gem", predicate: "tags", value: "yaml">, #<Tag id: 906, name: "gem:tags=nomonkey",
|
68
|
+
description: nil, created_at: "2009-03-06 08:47:04", namespace: "gem", predicate: "tags", value:
|
69
|
+
"nomonkey">, #<Tag id: 905, name: "article:tags=ruby", description: nil, created_at: "2009-03-04
|
70
|
+
00:30:10", namespace: "article", predicate: "tags", value: "ruby">]
|
71
|
+
|
72
|
+
== Views: Anytime, Anywhere
|
73
|
+
While preconfigured tables are great for database records, sometimes you just want to create
|
74
|
+
tables/views for any output object:
|
75
|
+
|
76
|
+
#These examples don't need to have Hirb::View enabled.
|
77
|
+
irb>>Hirb::View.disable
|
78
|
+
=>nil
|
79
|
+
|
80
|
+
# Imports table() and view()
|
81
|
+
irb>>extend Hirb::Console
|
82
|
+
=>main
|
83
|
+
|
84
|
+
# Create a table of Dates comparing them with different formats.
|
85
|
+
irb>> table [Date.today, Date.today.next_month], :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
|
86
|
+
+------------+--------+-----------+-------+--------------------------+
|
87
|
+
| to_s | ld | ajd | amjd | asctime |
|
88
|
+
+------------+--------+-----------+-------+--------------------------+
|
89
|
+
| 2009-03-11 | 155742 | 4909803/2 | 54901 | Wed Mar 11 00:00:00 2009 |
|
90
|
+
| 2009-04-11 | 155773 | 4909865/2 | 54932 | Sat Apr 11 00:00:00 2009 |
|
91
|
+
+------------+--------+-----------+-------+--------------------------+
|
92
|
+
2 rows in set
|
93
|
+
|
94
|
+
# Same table as the previous method. However view() will be able to call any view created.
|
95
|
+
irb>> view [Date.today, Date.today.next_month], :class=>Hirb::Helpers::ObjectTable,
|
96
|
+
:fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
|
97
|
+
|
98
|
+
If these console methods weren't convenient enough, try:
|
99
|
+
|
100
|
+
# Imports view() to all objects.
|
101
|
+
irb>> require 'hirb/import_object'
|
102
|
+
=>true
|
103
|
+
# Yields same table as above examples.
|
104
|
+
irb>> [Date.today, Date.today.next_month].view :class=>Hirb::Helpers::ObjectTable,
|
105
|
+
:fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
|
106
|
+
|
107
|
+
Although views by default are printed to STDOUT, they can be easily modified to write anywhere:
|
108
|
+
# Setup views to write to file 'console.log'.
|
109
|
+
irb>> Hirb::View.render_method = lambda {|output| File.open("console.log", 'w') {|f| f.write(output) } }
|
110
|
+
|
111
|
+
# Writes to file with same table output as above example.
|
112
|
+
irb>> view [Date.today, Date.today.next_month], :class=>Hirb::Helpers::ObjectTable,
|
113
|
+
:fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
|
114
|
+
|
115
|
+
# Doesn't write to file because Symbol isn't configured to use Hirb::View and thus defaults to irb's echo mode.
|
116
|
+
irb>> :blah
|
117
|
+
=>:blah
|
118
|
+
|
119
|
+
# Go back to printing Hirb views to STDOUT.
|
120
|
+
irb>> Hirb::View.reset_render_method
|
121
|
+
|
122
|
+
== Create and Configure Views
|
123
|
+
Let's create a simple view and configure it in different ways to be Hash's default view:
|
124
|
+
|
125
|
+
=== Setup
|
126
|
+
irb>> require 'hirb'
|
127
|
+
=>true
|
128
|
+
irb>> Hirb::View.enable
|
129
|
+
=>nil
|
130
|
+
irb>> require 'yaml'
|
131
|
+
=>true
|
132
|
+
|
133
|
+
=== Configure As View Method
|
134
|
+
A view method is the smallest reuseable view.
|
135
|
+
# Create yaml view method
|
136
|
+
irb>> def yaml(output); output.to_yaml; end
|
137
|
+
=>nil
|
138
|
+
|
139
|
+
# Configure view and reload it
|
140
|
+
irb>>Hirb::View.output_config = {"Hash"=>{:method=>:yaml}}
|
141
|
+
=>{"Hash"=>{:method=>:yaml}}
|
142
|
+
irb>>Hash::View.reload_config
|
143
|
+
=>true
|
144
|
+
|
145
|
+
# Hashes now appear as yaml
|
146
|
+
irb>>{:a=>1, :b=>{:c=>3}}
|
147
|
+
---
|
148
|
+
:a : 1
|
149
|
+
:b :
|
150
|
+
:c : 3
|
151
|
+
=> true
|
152
|
+
|
153
|
+
=== Configure As View Class
|
154
|
+
A view class is suited for more complex views. View classes can be under any namespace
|
155
|
+
and are expected to provide a render method. However, if a class is under the Hirb::Views namespace,
|
156
|
+
it will be automatically loaded with no configuration. Something to think about when
|
157
|
+
sharing views with others.
|
158
|
+
|
159
|
+
# Create yaml view class
|
160
|
+
irb>> class Hirb::Views::Hash; def self.render(output, options={}); output.to_yaml; end ;end
|
161
|
+
=>nil
|
162
|
+
# Just reload since no configuration is necessary
|
163
|
+
irb>>Hirb::View.reload_config
|
164
|
+
|
165
|
+
# Hashes now appear as yaml ...
|
166
|
+
|
167
|
+
Although the Hirb::Views namespace is great for quick classes that just plug and play, you
|
168
|
+
often want view classes that can be reused with multiple outputs. For this case, it's recommended to
|
169
|
+
use the Hirb::Helpers namespace.
|
170
|
+
|
171
|
+
# Create yaml view class
|
172
|
+
irb>> class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
|
173
|
+
=>nil
|
174
|
+
|
175
|
+
# Configure view and reload it
|
176
|
+
irb>>Hirb::View.output_config = {"Hash"=>{:class=>"Hirb::Helpers::Yaml"}}
|
177
|
+
=>{"Hash"=>{:class=>"Hirb::Helpers::Yaml"}}
|
178
|
+
irb>>Hirb::View.reload_config
|
179
|
+
|
180
|
+
# Hashes now appear as yaml ...
|
181
|
+
|
182
|
+
=== Configure At Startup
|
183
|
+
Once you know what views are associated with what output classes, you can configure
|
184
|
+
them at startup by passing Hirb::View.enable a block:
|
185
|
+
# In .irbrc
|
186
|
+
require 'hirb'
|
187
|
+
# View class needs to come before enable()
|
188
|
+
class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
|
189
|
+
Hirb::View.enable {|conf| conf.output = {"Hash"=>{:class=>"Hirb::Helpers::Yaml"}} }
|
190
|
+
|
191
|
+
Or by creating a config file at config/hirb.yml or ~/.hirb.yml:
|
192
|
+
# The config file for the yaml example would look like:
|
193
|
+
# ---
|
194
|
+
# :view :
|
195
|
+
# :output :
|
196
|
+
# Hash :
|
197
|
+
# :class : Hirb::Helpers::Yaml
|
198
|
+
|
199
|
+
# In .irbrc
|
200
|
+
require 'hirb'
|
201
|
+
# View class needs to come before enable()
|
202
|
+
class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
|
203
|
+
Hirb::View.enable
|
204
|
+
|
205
|
+
== Contributing Views
|
206
|
+
If you have views of your own you'd like to share, fork Hirb and put your views under
|
207
|
+
the Hirb::Helpers namespace and the view files under lib/hirb/helpers/.
|
208
|
+
|
209
|
+
== Limitations
|
210
|
+
Although Hirb preserves Wirble colorizing irb's default echo mode, it doesn't colorize its own views.
|
211
|
+
This is mainly because colorizing caused table classes to render incorrectly. If you can get tables
|
212
|
+
and colors to work nicely, please fork. To colorize your Hirb output:
|
213
|
+
Hirb::View.render_method = lambda {|output| puts Wirble::Colorize.colorize(output) }
|
214
|
+
|
215
|
+
== Motivation
|
216
|
+
Table code from http://gist.github.com/72234 and {my console
|
217
|
+
app's needs}[http://github.com/cldwalker/tag-tree].
|
218
|
+
|
219
|
+
== Bugs
|
220
|
+
Please report them as tickets here: http://cldwalker.lighthouseapp.com/projects/27735-hirb/tickets
|
221
|
+
|
222
|
+
== Links
|
223
|
+
* http://tagaholic.me/2009/03/13/hirb-irb-on-the-good-stuff.html
|
224
|
+
* http://tagaholic.me/2009/03/18/ruby-class-trees-rails-plugin-trees-with-hirb.html
|
225
|
+
|
226
|
+
== Todo
|
227
|
+
* Configurable max height, which if exceeded activates a pager.
|
228
|
+
* Possibly add non-view irb goodies ie command manager.
|
229
|
+
* Consider applying multiple views/filters to output.
|
230
|
+
* Provides helper methods to all view classes.
|
231
|
+
* Consider adding a template system as needed.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
begin
|
5
|
+
require 'rcov/rcovtask'
|
6
|
+
|
7
|
+
Rcov::RcovTask.new do |t|
|
8
|
+
t.libs << 'test'
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
10
|
+
t.rcov_opts = ["-T -x '/Library/Ruby/*'"]
|
11
|
+
t.verbose = true
|
12
|
+
end
|
13
|
+
rescue LoadError
|
14
|
+
puts "Rcov not available. Install it for rcov-related tasks with: sudo gem install rcov"
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'jeweler'
|
19
|
+
Jeweler::Tasks.new do |s|
|
20
|
+
s.name = "hirb"
|
21
|
+
s.description = "A mini view framework for console/irb that's easy to use, even while under its influence."
|
22
|
+
s.summary = s.description
|
23
|
+
s.email = "gabriel.horner@gmail.com"
|
24
|
+
s.homepage = "http://github.com/cldwalker/hirb"
|
25
|
+
s.authors = ["Gabriel Horner"]
|
26
|
+
s.has_rdoc = true
|
27
|
+
s.extra_rdoc_files = ["README.rdoc", "LICENSE.txt"]
|
28
|
+
s.files = FileList["[A-Z]*", "{bin,lib,test}/**/*"]
|
29
|
+
end
|
30
|
+
|
31
|
+
rescue LoadError
|
32
|
+
puts "Jeweler not available. Install it for jeweler-related tasks with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
33
|
+
end
|
34
|
+
|
35
|
+
Rake::TestTask.new do |t|
|
36
|
+
t.libs << 'lib'
|
37
|
+
t.pattern = 'test/**/*_test.rb'
|
38
|
+
t.verbose = false
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::RDocTask.new do |rdoc|
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = 'test'
|
44
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
48
|
+
|
49
|
+
task :default => :test
|
data/VERSION.yml
ADDED
data/lib/hirb.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
current_dir = File.dirname(__FILE__)
|
2
|
+
$:.unshift(current_dir) unless $:.include?(current_dir) || $:.include?(File.expand_path(current_dir))
|
3
|
+
require 'hirb/util'
|
4
|
+
require 'hirb/hash_struct'
|
5
|
+
require 'hirb/helpers'
|
6
|
+
require 'hirb/view'
|
7
|
+
require 'hirb/views/activerecord_base'
|
8
|
+
require 'hirb/console'
|
9
|
+
|
10
|
+
# Most of Hirb's functionality currently resides in Hirb::View.
|
11
|
+
# Hirb has an optional yaml config file defined by config_file. This config file
|
12
|
+
# has the following top level keys:
|
13
|
+
# [:view] See Hirb::View for the value of this entry.
|
14
|
+
module Hirb
|
15
|
+
class <<self
|
16
|
+
# Default is config/hirb.yml or ~/hirb.yml in that order.
|
17
|
+
def config_file
|
18
|
+
File.exists?('config/hirb.yml') ? 'config/hirb.yml' : File.expand_path(File.join("~",".hirb.yml"))
|
19
|
+
end
|
20
|
+
|
21
|
+
#:stopdoc:
|
22
|
+
def read_config_file(file=config_file)
|
23
|
+
File.exists?(file) ? YAML::load_file(file) : {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def config(reload=false)
|
27
|
+
@config = (@config.nil? || reload) ? read_config_file : @config
|
28
|
+
end
|
29
|
+
#:startdoc:
|
30
|
+
end
|
31
|
+
end
|
data/lib/hirb/console.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Hirb
|
2
|
+
# This class is meant to be extended to provide methods for use in a console/irb shell.
|
3
|
+
# For example:
|
4
|
+
# irb>> extend Hirb::Console
|
5
|
+
# irb>> view 'some string', :class=>Some::String::Formatter
|
6
|
+
# irb>> table [[:row1], [:row2]]
|
7
|
+
module Console
|
8
|
+
# Renders a table for the given object. Takes same options as Hirb::Helpers::Table.render.
|
9
|
+
def table(output, options={})
|
10
|
+
Hirb::View.console_render_output(output, options.merge(:class=>"Hirb::Helpers::AutoTable"))
|
11
|
+
end
|
12
|
+
# Renders any specified view for the given object. Takes same options as Hirb::View.console_render_output.
|
13
|
+
def view(*args)
|
14
|
+
Hirb::View.console_render_output(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/hirb/helpers.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Hirb::Helpers::ActiveRecordTable < Hirb::Helpers::ObjectTable
|
2
|
+
# Rows are Rails' ActiveRecord::Base objects.
|
3
|
+
# Takes same options as Hirb::Helpers::Table.render except as noted below.
|
4
|
+
#
|
5
|
+
# Options:
|
6
|
+
# :fields- Can be any attribute, column or not. If not given, this defaults to the database table's columns.
|
7
|
+
def self.render(rows, options={})
|
8
|
+
rows = [rows] unless rows.is_a?(Array)
|
9
|
+
options[:fields] ||=
|
10
|
+
begin
|
11
|
+
fields = rows.first.attribute_names
|
12
|
+
fields.unshift(fields.delete('id')) if fields.include?('id')
|
13
|
+
fields.map {|e| e.to_sym }
|
14
|
+
end
|
15
|
+
super(rows, options)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Attempts to autodetect the table class the output represents and delegates rendering to it.
|
2
|
+
class Hirb::Helpers::AutoTable
|
3
|
+
# Same options as Hirb::Helpers::Table.render.
|
4
|
+
def self.render(output, options={})
|
5
|
+
klass = if ((output.is_a?(Array) && output[0].is_a?(ActiveRecord::Base)) or output.is_a?(ActiveRecord::Base) rescue false)
|
6
|
+
Hirb::Helpers::ActiveRecordTable
|
7
|
+
elsif options[:fields]
|
8
|
+
Hirb::Helpers::ObjectTable
|
9
|
+
else
|
10
|
+
Hirb::Helpers::Table
|
11
|
+
end
|
12
|
+
klass.render(output, options)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Hirb::Helpers::ObjectTable < Hirb::Helpers::Table
|
2
|
+
# Rows are any ruby objects. Takes same options as Hirb::Helpers::Table.render except as noted below.
|
3
|
+
#
|
4
|
+
# Options:
|
5
|
+
# :fields- Methods of the object which are represented as columns in the table. Required option.
|
6
|
+
# All method values are converted to strings via to_s.
|
7
|
+
def self.render(rows, options ={})
|
8
|
+
raise(ArgumentError, "Option 'fields' is required.") unless options[:fields]
|
9
|
+
rows = [rows] unless rows.is_a?(Array)
|
10
|
+
item_hashes = rows.inject([]) {|t,item|
|
11
|
+
t << options[:fields].inject({}) {|h,f| h[f] = item.send(f).to_s; h}
|
12
|
+
}
|
13
|
+
super(item_hashes, options)
|
14
|
+
end
|
15
|
+
end
|