ruport 0.4.19 → 0.4.21
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/CHANGELOG +19 -2
- data/Rakefile +10 -5
- data/examples/new_plugin.rb +2 -2
- data/lib/ruport.rb +2 -2
- data/lib/ruport/data.rb +1 -1
- data/lib/ruport/data/collection.rb +8 -0
- data/lib/ruport/data/record.rb +15 -2
- data/lib/ruport/data/set.rb +42 -0
- data/lib/ruport/data/table.rb +20 -0
- data/lib/ruport/format.rb +0 -6
- data/lib/ruport/format/engine.rb +18 -1
- data/lib/ruport/format/plugin.rb +84 -6
- data/lib/ruport/query.rb +5 -5
- data/lib/ruport/rails/reportable.rb +11 -14
- data/lib/ruport/report.rb +2 -8
- data/test/tc_database.rb +1 -1
- data/test/tc_format_engine.rb +5 -5
- data/test/tc_plugin.rb +12 -12
- data/test/tc_record.rb +32 -1
- data/test/tc_set.rb +93 -0
- data/test/tc_table.rb +27 -0
- data/test/ts_all.rb +3 -2
- data/test/unit.log +428 -0
- metadata +4 -4
- data/lib/ruport/data_row.rb +0 -187
- data/lib/ruport/data_set.rb +0 -308
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruport
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.4.
|
7
|
-
date: 2006-07
|
6
|
+
version: 0.4.21
|
7
|
+
date: 2006-08-07 00:00:00 -04:00
|
8
8
|
summary: A generalized Ruby report generation and templating engine.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -44,8 +44,6 @@ files:
|
|
44
44
|
- lib/ruport/format
|
45
45
|
- lib/ruport/rails
|
46
46
|
- lib/ruport/data
|
47
|
-
- lib/ruport/data_row.rb
|
48
|
-
- lib/ruport/data_set.rb
|
49
47
|
- lib/ruport/system_extensions.rb
|
50
48
|
- lib/ruport/config.rb
|
51
49
|
- lib/ruport/query.rb
|
@@ -65,6 +63,7 @@ files:
|
|
65
63
|
- lib/ruport/data/taggable.rb
|
66
64
|
- lib/ruport/data/record.rb
|
67
65
|
- lib/ruport/data/collection.rb
|
66
|
+
- lib/ruport/data/set.rb
|
68
67
|
- test/samples
|
69
68
|
- test/tc_element.rb
|
70
69
|
- test/tc_format.rb
|
@@ -87,6 +86,7 @@ files:
|
|
87
86
|
- test/tc_taggable.rb
|
88
87
|
- test/tc_record.rb
|
89
88
|
- test/tc_table.rb
|
89
|
+
- test/tc_set.rb
|
90
90
|
- test/samples/ruport_test.sql
|
91
91
|
- test/samples/test.yaml
|
92
92
|
- test/samples/data.csv
|
data/lib/ruport/data_row.rb
DELETED
@@ -1,187 +0,0 @@
|
|
1
|
-
# --
|
2
|
-
# data_row.rb : Ruby Reports row abstraction
|
3
|
-
#
|
4
|
-
# Author: Gregory T. Brown (gregory.t.brown at gmail dot com)
|
5
|
-
#
|
6
|
-
# Copyright (c) 2006, All Rights Reserved.
|
7
|
-
#
|
8
|
-
# This is free software. You may modify and redistribute this freely under
|
9
|
-
# your choice of the GNU General Public License or the Ruby License.
|
10
|
-
#
|
11
|
-
# See LICENSE and COPYING for details
|
12
|
-
# ++
|
13
|
-
module Ruport
|
14
|
-
|
15
|
-
# DataRows are Enumerable lists which can be accessed by field name or
|
16
|
-
# ordinal position.
|
17
|
-
#
|
18
|
-
# They feature a tagging system, allowing them to be easily
|
19
|
-
# compared or recalled.
|
20
|
-
#
|
21
|
-
# DataRows form the elements of DataSets
|
22
|
-
#
|
23
|
-
class DataRow
|
24
|
-
|
25
|
-
include Enumerable
|
26
|
-
|
27
|
-
# Takes field names as well as some optional parameters and
|
28
|
-
# constructs a DataRow.
|
29
|
-
#
|
30
|
-
# Options:
|
31
|
-
# <tt>:data</tt>:: can be specified in Hash, Array, or DataRow form
|
32
|
-
# <tt>:default</tt>:: The default value for empty fields
|
33
|
-
# <tt>:tags</tt>:: an initial set of tags for the row
|
34
|
-
#
|
35
|
-
#
|
36
|
-
# Examples:
|
37
|
-
# >> Ruport::DataRow.new [:a,:b,:c,:d,:e], :data => [1,2,3,4,5]
|
38
|
-
# :tags => %w[cat dog]
|
39
|
-
# => #<Ruport::DataRow:0xb77e4b04 @fields=[:a, :b, :c, :d, :e],
|
40
|
-
# @data=[1, 2, 3, 4, 5], @tags=["cat", "dog"]>
|
41
|
-
#
|
42
|
-
# >> Ruport::DataRow.new([:a,:b,:c,:d,:e],
|
43
|
-
# :data => { :a => 'moo', :c => 'caw'} ,
|
44
|
-
# :tags => %w[cat dog])
|
45
|
-
# => #<Ruport::DataRow:0xb77c298c @fields=[:a, :b, :c, :d, :e],
|
46
|
-
# @data=["moo", nil, "caw", nil, nil], @tags=["cat", "dog"]>
|
47
|
-
#
|
48
|
-
# >> Ruport::DataRow.new [:a,:b,:c,:d,:e], :data => [1,2,3],
|
49
|
-
# :tags => %w[cat dog], :default => 0
|
50
|
-
# => #<Ruport::DataRow:0xb77bb4d4 @fields=[:a, :b, :c, :d, :e],
|
51
|
-
# @data=[1, 2, 3, 0, 0], @tags=["cat", "dog"]>
|
52
|
-
#
|
53
|
-
def initialize(fields=nil, options={})
|
54
|
-
|
55
|
-
#checks to ensure data is convertable
|
56
|
-
verify options[:data]
|
57
|
-
data = options[:data].dup
|
58
|
-
|
59
|
-
@fields = fields ? fields.dup : ( 0...data.length ).to_a
|
60
|
-
@tags = (options[:tags] || {}).dup
|
61
|
-
@data = []
|
62
|
-
|
63
|
-
nr_action = case(data)
|
64
|
-
when Array
|
65
|
-
lambda {|key, index| @data[index] = data.shift || options[:default]}
|
66
|
-
when DataRow
|
67
|
-
lambda {|key, index| @data = data.to_a}
|
68
|
-
else
|
69
|
-
lambda {|key, index| @data[index] = data[key] || options[:default]}
|
70
|
-
end
|
71
|
-
@fields.each_with_index {|key, index| nr_action.call(key,index)}
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
attr_accessor :fields, :tags
|
76
|
-
alias_method :column_names, :fields
|
77
|
-
alias_method :attributes, :fields
|
78
|
-
# Returns a new DataRow
|
79
|
-
def +(other)
|
80
|
-
DataRow.new @fields + other.fields, :data => (@data + other.to_a)
|
81
|
-
end
|
82
|
-
|
83
|
-
# Lets you access individual fields
|
84
|
-
#
|
85
|
-
# i.e. row["phone"] or row[4]
|
86
|
-
def [](key)
|
87
|
-
case(key)
|
88
|
-
when Fixnum
|
89
|
-
@data[key]
|
90
|
-
when Symbol
|
91
|
-
@data[@fields.index(key.to_s)] rescue nil
|
92
|
-
else
|
93
|
-
@data[@fields.index(key)] rescue nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# Lets you set field values
|
98
|
-
#
|
99
|
-
# i.e. row["phone"] = '2038291203', row[7] = "allen"
|
100
|
-
def []=(key,value)
|
101
|
-
case(key)
|
102
|
-
when Fixnum
|
103
|
-
@data[key] = value
|
104
|
-
when Symbol
|
105
|
-
@data[@fields.index(key.to_s)] = value
|
106
|
-
else
|
107
|
-
@data[@fields.index(key)] = value
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# Converts the DataRow to a plain old Array
|
112
|
-
def to_a
|
113
|
-
@data.clone
|
114
|
-
end
|
115
|
-
|
116
|
-
def to_h
|
117
|
-
a = Hash.new
|
118
|
-
@fields.each { |f| a[f] = self[f] }; a
|
119
|
-
end
|
120
|
-
|
121
|
-
# Converts the DataRow to a string representation
|
122
|
-
# for outputting to screen.
|
123
|
-
def to_s
|
124
|
-
"[" + @data.join(",") + "]"
|
125
|
-
end
|
126
|
-
|
127
|
-
# Checks to see row includes the tag given.
|
128
|
-
#
|
129
|
-
# Example:
|
130
|
-
#
|
131
|
-
# >> row.has_tag? :running_balance
|
132
|
-
# => true
|
133
|
-
#
|
134
|
-
def has_tag?(tag)
|
135
|
-
@tags.include?(tag)
|
136
|
-
end
|
137
|
-
|
138
|
-
# Iterates through DataRow elements. Accepts a block.
|
139
|
-
def each(&action)
|
140
|
-
@data.each(&action)
|
141
|
-
end
|
142
|
-
|
143
|
-
# Allows you to add a tag to a row.
|
144
|
-
#
|
145
|
-
# Examples:
|
146
|
-
#
|
147
|
-
# row.tag_as(:jay_cross) if row["product"].eql?("im_courier")
|
148
|
-
# row.tag_as(:running_balance) if row.fields.include?("RB")
|
149
|
-
#
|
150
|
-
def tag_as(something)
|
151
|
-
@tags[something] = true
|
152
|
-
end
|
153
|
-
|
154
|
-
# Compares two DataRow objects. If values and fields are the same
|
155
|
-
# (and in the correct order) returns true. Otherwise returns false.
|
156
|
-
def ==(other)
|
157
|
-
self.to_a.eql?(other.to_a) && @fields.eql?(other.fields)
|
158
|
-
end
|
159
|
-
|
160
|
-
# Synonym for DataRow#==
|
161
|
-
def eql?(other)
|
162
|
-
self == other
|
163
|
-
end
|
164
|
-
|
165
|
-
def clone
|
166
|
-
self.class.new @fields, :data => @data, :tags => @tags
|
167
|
-
end
|
168
|
-
|
169
|
-
alias_method :dup, :clone
|
170
|
-
|
171
|
-
private
|
172
|
-
|
173
|
-
def verify(data)
|
174
|
-
if data.kind_of? String or
|
175
|
-
data.kind_of? Integer or not data.respond_to?(:[])
|
176
|
-
Ruport.complain "Cannot convert data to DataRow",
|
177
|
-
:status => :fatal, :exception => ArgumentError, :level => :log_only
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
def method_missing(id,*args)
|
182
|
-
f = id.to_s.gsub(/=$/,'')
|
183
|
-
return super unless fields.include?(f)
|
184
|
-
args.empty? ? self[f] : self[f] = args[0]
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
data/lib/ruport/data_set.rb
DELETED
@@ -1,308 +0,0 @@
|
|
1
|
-
# data_set.rb : Ruby Reports core datastructure.
|
2
|
-
#
|
3
|
-
# Author: Gregory T. Brown (gregory.t.brown at gmail dot com)
|
4
|
-
# Copyright (c) 2006, All Rights Reserved.
|
5
|
-
#
|
6
|
-
# Pseudo keyword argument support, improved <<, and set operations submitted by
|
7
|
-
# Dudley Flanders
|
8
|
-
#
|
9
|
-
# This is free software. You may modify and redistribute this freely under
|
10
|
-
# your choice of the GNU General Public License or the Ruby License.
|
11
|
-
#
|
12
|
-
# See LICENSE and COPYING for details
|
13
|
-
module Ruport
|
14
|
-
|
15
|
-
# The DataSet is the core datastructure for Ruport. It provides methods that
|
16
|
-
# allow you to compare and combine query results, data loaded in from CSVs,
|
17
|
-
# and user-defined sets of data.
|
18
|
-
#
|
19
|
-
# It is tightly integrated with Ruport's formatting and query systems, so if
|
20
|
-
# you'd like to take advantage of these models, you will probably find
|
21
|
-
# DataSet useful.
|
22
|
-
class DataSet
|
23
|
-
#FIXME: Add logging to this class
|
24
|
-
include Enumerable
|
25
|
-
extend Forwardable
|
26
|
-
# DataSets must be given a set of fields to be defined.
|
27
|
-
#
|
28
|
-
# These field names will define the columns for the DataSet and how you
|
29
|
-
# access them.
|
30
|
-
#
|
31
|
-
# data = Ruport::DataSet.new %w[ id name phone ]
|
32
|
-
#
|
33
|
-
# Options:
|
34
|
-
# * <tt>:data</tt> - An Enumerable with the content for this DataSet
|
35
|
-
# * <tt>:default</tt> - The default value for empty cells
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# DataSet supports the following Array methods through delegators
|
39
|
-
# length, empty?, delete_at, first, last, pop
|
40
|
-
#
|
41
|
-
def initialize(fields=nil, options={})
|
42
|
-
@fields = fields.dup if fields
|
43
|
-
@default = options[:default] || default
|
44
|
-
@data = []
|
45
|
-
options[:data].each { |r| self << r } if options[:data]
|
46
|
-
end
|
47
|
-
|
48
|
-
#an array which contains column names
|
49
|
-
attr_accessor :fields
|
50
|
-
alias_method :column_names, :fields
|
51
|
-
alias_method :column_names=, :fields=
|
52
|
-
#the default value to fill empty cells with
|
53
|
-
attr_accessor :default
|
54
|
-
|
55
|
-
#data holds the elements of the Row
|
56
|
-
attr_reader :data
|
57
|
-
|
58
|
-
def_delegators :@data, :length, :[], :empty?,
|
59
|
-
:delete_at, :first, :last, :pop,
|
60
|
-
:each, :reverse_each, :at, :clear
|
61
|
-
|
62
|
-
def delete_if(&block)
|
63
|
-
@data.delete_if █ self
|
64
|
-
end
|
65
|
-
|
66
|
-
#provides a deep copy of the DataSet.
|
67
|
-
def clone
|
68
|
-
self.class.new(@fields, :data => @data)
|
69
|
-
end
|
70
|
-
|
71
|
-
alias_method :dup, :clone
|
72
|
-
|
73
|
-
# Creates a new DataSet with the same shape as this one, but empty.
|
74
|
-
def empty_clone
|
75
|
-
self.class.new(@fields)
|
76
|
-
end
|
77
|
-
|
78
|
-
#allows setting of rows
|
79
|
-
def []=(index,data)
|
80
|
-
@data[index] = DataRow.new @fields, :data => data
|
81
|
-
end
|
82
|
-
|
83
|
-
def [](index)
|
84
|
-
case(index)
|
85
|
-
when Range
|
86
|
-
self.class.new @fields, :data => @data[index]
|
87
|
-
else
|
88
|
-
@data[index]
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# Appends a row to the DataSet
|
93
|
-
# Can be added as an array, an array of DataRows, a DataRow, or a keyed
|
94
|
-
# hash-like object.
|
95
|
-
#
|
96
|
-
# Columns left undefined will be filled with DataSet#default values.
|
97
|
-
#
|
98
|
-
# data << [ 1, 2, 3 ]
|
99
|
-
# data << { :some_field_name => 3, :other => 2, :another => 1 }
|
100
|
-
#
|
101
|
-
# FIXME: Appending a datarow is wonky.
|
102
|
-
def << ( stuff, filler=@default )
|
103
|
-
if stuff.kind_of?(DataRow)
|
104
|
-
@data << stuff.clone
|
105
|
-
elsif stuff.kind_of?(Array) && stuff[0].kind_of?(DataRow)
|
106
|
-
@data.concat(stuff)
|
107
|
-
else
|
108
|
-
@data << DataRow.new(@fields, :data => stuff.clone,:default => filler)
|
109
|
-
end
|
110
|
-
return self
|
111
|
-
end
|
112
|
-
alias_method :push, :<<
|
113
|
-
|
114
|
-
# checks if one dataset equals another
|
115
|
-
# FIXME: expand this doc.
|
116
|
-
def eql?(data2)
|
117
|
-
return false unless ( @data.length == data2.data.length and
|
118
|
-
@fields.eql?(data2.fields) )
|
119
|
-
@data.each_with_index do |row, r_index|
|
120
|
-
row.each_with_index do |field, f_index|
|
121
|
-
return false unless field.eql?(data2[r_index][f_index])
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
return true
|
126
|
-
end
|
127
|
-
|
128
|
-
# checks if one dataset equals another
|
129
|
-
def ==(data2)
|
130
|
-
eql?(data2)
|
131
|
-
end
|
132
|
-
|
133
|
-
# Set union - returns a DataSet with the elements that are contained in
|
134
|
-
# in either of the two given sets, with no duplicates.
|
135
|
-
def |(other)
|
136
|
-
clone << other.reject { |x| self.include? x }
|
137
|
-
end
|
138
|
-
alias_method :union, :|
|
139
|
-
|
140
|
-
# Set intersection
|
141
|
-
def &(other)
|
142
|
-
empty_clone << select { |x| other.include? x }
|
143
|
-
end
|
144
|
-
alias_method :intersection, :&
|
145
|
-
|
146
|
-
# Set difference
|
147
|
-
def -(other)
|
148
|
-
empty_clone << reject { |x| other.include? x }
|
149
|
-
end
|
150
|
-
alias_method :difference, :-
|
151
|
-
|
152
|
-
# Checks if one DataSet has the same set of fields as another
|
153
|
-
def shaped_like?(other)
|
154
|
-
return true if @fields.eql?(other.fields)
|
155
|
-
end
|
156
|
-
|
157
|
-
# Concatenates one DataSet onto another if they have the same shape
|
158
|
-
def concat(other)
|
159
|
-
if other.shaped_like?(self)
|
160
|
-
@data.concat(other.data)
|
161
|
-
return self
|
162
|
-
end
|
163
|
-
end
|
164
|
-
alias_method :+, :concat
|
165
|
-
|
166
|
-
# Allows loading of CSV files or YAML dumps. Returns a DataSet
|
167
|
-
#
|
168
|
-
# FasterCSV will be used if it is installed.
|
169
|
-
#
|
170
|
-
# my_data = Ruport::DataSet.load("foo.csv")
|
171
|
-
# my_data = Ruport::DataSet.load("foo.yaml")
|
172
|
-
# my_data = Ruport::DataSet.load("foo.yml")
|
173
|
-
def self.load ( source, options={}, &block)
|
174
|
-
options = {:has_names => true}.merge(options)
|
175
|
-
case source
|
176
|
-
when /\.(yaml|yml)/
|
177
|
-
return YAML.load(File.open(source))
|
178
|
-
when /\.csv/
|
179
|
-
require "fastercsv"
|
180
|
-
input = FasterCSV.read(source) if source =~ /\.csv/
|
181
|
-
loaded_data = self.new
|
182
|
-
|
183
|
-
action = if block
|
184
|
-
lambda { |r| block[loaded_data,r] }
|
185
|
-
else
|
186
|
-
lambda { |r| loaded_data << r }
|
187
|
-
end
|
188
|
-
|
189
|
-
if options[:has_names]
|
190
|
-
loaded_data.fields = input[0] ; input = input[1..-1]
|
191
|
-
end
|
192
|
-
|
193
|
-
loaded_data.default = options[:default]
|
194
|
-
input.each { |row| action[row] }
|
195
|
-
return loaded_data
|
196
|
-
else
|
197
|
-
raise "Invalid file type"
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
|
202
|
-
# Returns a new DataSet composed of the fields specified.
|
203
|
-
def select_columns(*fields)
|
204
|
-
fields = get_field_names(fields)
|
205
|
-
rows = fields.inject([]) { |s,e| s + [map { |row| row[e] }] }.transpose
|
206
|
-
my_data = DataSet.new(fields, :data => rows)
|
207
|
-
end
|
208
|
-
|
209
|
-
# Prunes the dataset to contain only the fields specified. (DESTRUCTIVE)
|
210
|
-
def select_columns!(*fields)
|
211
|
-
a = select_columns(*fields)
|
212
|
-
@fields = a.fields; @data = a.data
|
213
|
-
end
|
214
|
-
|
215
|
-
#Creates a new dataset with additional columns appending to it
|
216
|
-
def add_columns(*fields)
|
217
|
-
select_columns *(@fields + fields)
|
218
|
-
end
|
219
|
-
|
220
|
-
def add_columns!(*fields)
|
221
|
-
select_columns! *(@fields + fields)
|
222
|
-
end
|
223
|
-
|
224
|
-
# Returns a new DataSet with the specified fields removed
|
225
|
-
def remove_columns(*fields)
|
226
|
-
fields = get_field_names(fields)
|
227
|
-
select_columns(*(@fields-fields))
|
228
|
-
end
|
229
|
-
|
230
|
-
# removes the specified fields from this DataSet (DESTRUCTIVE!)
|
231
|
-
def remove_columns!(*fields)
|
232
|
-
d = remove_columns(*fields)
|
233
|
-
@data = d.data
|
234
|
-
@fields = d.fields
|
235
|
-
end
|
236
|
-
|
237
|
-
def rename_columns(cols)
|
238
|
-
if cols.kind_of?(Array)
|
239
|
-
cols.each_with_index { |c,i| fields[i] = c }
|
240
|
-
else
|
241
|
-
cols.map { |k,v| fields[fields.index(k)] = v }
|
242
|
-
end
|
243
|
-
@data.each { |r| r.fields = fields }
|
244
|
-
end
|
245
|
-
# uses Format::Builder to render DataSets in various ready to output
|
246
|
-
# formats.
|
247
|
-
#
|
248
|
-
# To add new formats to this function, simply re-open Format::Builder
|
249
|
-
# and add methods like <tt>render_my_format_name</tt>.
|
250
|
-
#
|
251
|
-
# This will enable <tt>data.as(:my_format_name)</tt>
|
252
|
-
def as(format)
|
253
|
-
t = Format.table_object(:data => self, :plugin => format)
|
254
|
-
yield(t) if block_given?
|
255
|
-
t.render
|
256
|
-
end
|
257
|
-
|
258
|
-
# Will iterate row by row yielding each row
|
259
|
-
# The result of the block will be added to a running total
|
260
|
-
#
|
261
|
-
# Only works with blocks resulting in numeric values.
|
262
|
-
#
|
263
|
-
# Also allows summing up a specific column, e.g.
|
264
|
-
#
|
265
|
-
# my_set.sigma("col1")
|
266
|
-
def sigma(f = nil)
|
267
|
-
if f
|
268
|
-
inject(0) { |s,r| s + (r[f] || 0) }
|
269
|
-
else
|
270
|
-
inject(0) { |s,r| s + (yield(r) || 0) }
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
alias_method :sum, :sigma
|
275
|
-
|
276
|
-
# Converts a DataSet to an array of arrays
|
277
|
-
def to_a
|
278
|
-
@data.map {|x| x.to_a }
|
279
|
-
end
|
280
|
-
|
281
|
-
# Converts a DataSet to CSV
|
282
|
-
def to_csv; as(:csv) end
|
283
|
-
|
284
|
-
# Converts a Dataset to html
|
285
|
-
def to_html; as(:html) end
|
286
|
-
|
287
|
-
# Readable string representation of the DataSet
|
288
|
-
def to_s; as(:text) end
|
289
|
-
|
290
|
-
private
|
291
|
-
|
292
|
-
def get_field_names(f)
|
293
|
-
f.all? { |e| e.kind_of? Integer } &&
|
294
|
-
f.inject([]) { |s,e| s + [@fields[e]] } || f
|
295
|
-
end
|
296
|
-
|
297
|
-
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
class Array
|
302
|
-
|
303
|
-
# Will convert Arrays of Enumerable objects to DataSets.
|
304
|
-
# May have dragons.
|
305
|
-
def to_ds(fields,options={})
|
306
|
-
Ruport::DataSet.new fields, :data => to_a, :default => options[:default]
|
307
|
-
end
|
308
|
-
end
|