ruport 0.6.0 → 0.6.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.
@@ -0,0 +1,67 @@
1
+ ***************
2
+ *** 287,294 ****
3
+ # # pass in FasterCSV options, such as column separators
4
+ # table = Table.load('mydata.csv',:csv_opts => { :col_sep => "\t" })
5
+ #
6
+ - def self.load(csv_file, options={})
7
+ - get_table_from_csv(:foreach, csv_file, options)
8
+ end
9
+
10
+ #
11
+ --- 287,294 ----
12
+ # # pass in FasterCSV options, such as column separators
13
+ # table = Table.load('mydata.csv',:csv_opts => { :col_sep => "\t" })
14
+ #
15
+ + def self.load(csv_file, options={},&block)
16
+ + get_table_from_csv(:foreach, csv_file, options,&block)
17
+ end
18
+
19
+ #
20
+ ***************
21
+ *** 297,307 ****
22
+ #
23
+ # table = Table.parse("a,b,c\n1,2,3\n4,5,6\n")
24
+ #
25
+ - def self.parse(string, options={})
26
+ - get_table_from_csv(:parse,string,options)
27
+ end
28
+
29
+ - def self.get_table_from_csv(msg,param,options={}) #:nodoc:
30
+ options = {:has_names => true,
31
+ :csv_options => {} }.merge(options)
32
+ require "fastercsv"
33
+ --- 297,307 ----
34
+ #
35
+ # table = Table.parse("a,b,c\n1,2,3\n4,5,6\n")
36
+ #
37
+ + def self.parse(string, options={},&block)
38
+ + get_table_from_csv(:parse,string,options,&block)
39
+ end
40
+
41
+ + def self.get_table_from_csv(msg,param,options={},&block) #:nodoc:
42
+ options = {:has_names => true,
43
+ :csv_options => {} }.merge(options)
44
+ require "fastercsv"
45
+ ***************
46
+ *** 312,321 ****
47
+ if first_line && options[:has_names]
48
+ loaded_data.column_names = row
49
+ first_line = false
50
+ - elsif !block_given?
51
+ loaded_data << row
52
+ else
53
+ - yield(loaded_data,row)
54
+ end
55
+ end ; loaded_data
56
+ end
57
+ --- 312,321 ----
58
+ if first_line && options[:has_names]
59
+ loaded_data.column_names = row
60
+ first_line = false
61
+ + elsif !block
62
+ loaded_data << row
63
+ else
64
+ + block[loaded_data,row]
65
+ end
66
+ end ; loaded_data
67
+ end
@@ -5,10 +5,14 @@
5
5
  # Copyright 2006 by respective content owners, all rights reserved.
6
6
 
7
7
  class Array
8
+
9
+ #
8
10
  # Converts an array to a Ruport::Data::Table object, ready to
9
11
  # use in your reports.
10
12
  #
13
+ # Example:
11
14
  # [[1,2],[3,4]].to_table(%w[a b])
15
+ #
12
16
  def to_table(options={})
13
17
  options = { :column_names => options } if options.kind_of? Array
14
18
  Ruport::Data::Table.new({:data => self}.merge(options))
@@ -16,7 +20,10 @@ class Array
16
20
  end
17
21
 
18
22
  module Ruport::Data
19
-
23
+
24
+ #
25
+ # === Overview
26
+ #
20
27
  # This class is one of the core classes for building and working with data
21
28
  # in Ruport. The idea is to get your data into a standard form, regardless
22
29
  # of its source (a database, manual arrays, ActiveRecord, CSVs, etc.).
@@ -28,17 +35,21 @@ module Ruport::Data
28
35
  # Once your data is in a Ruport::Data::Table object, it can be manipulated
29
36
  # to suit your needs, then used to build a report.
30
37
  #
31
- # Included in this class are methods to create Tables manually and from CSV
32
- # files.
33
- #
34
- # For building a table using ActiveRecord, have a look at Ruport::Reportable.
35
38
  class Table < Collection
36
-
39
+ include Groupable
40
+
41
+ #
37
42
  # Creates a new table based on the supplied options.
38
- # Valid options are :data and :column_names.
43
+ # Valid options:
44
+ # <b><tt>:data</tt></b>:: An Array of Arrays representing the
45
+ # records in this Table
46
+ # <b><tt>:column_names</tt></b>:: An Array containing the column names
47
+ # for this Table.
48
+ # Example:
49
+ #
50
+ # table = Table.new :data => [[1,2,3], [3,4,5]],
51
+ # :column_names => %w[a b c]
39
52
  #
40
- # table = Table.new({:data => [1,2,3], [3,4,5],
41
- # :column_names => %w[a b c]})
42
53
  def initialize(options={})
43
54
  @column_names = options[:column_names] ? options[:column_names].dup : []
44
55
  @data = []
@@ -52,44 +63,70 @@ module Ruport::Data
52
63
  end
53
64
  end
54
65
 
66
+ # This Table's column names.
55
67
  attr_reader :column_names
56
68
  def_delegator :@data, :[]
57
- # Sets the column names for this table. The single parameter should be
58
- # an array listing the names of the columns.
69
+
70
+ #
71
+ # Sets the column names for this table. <tt>new_column_names</tt> should
72
+ # be an array listing the names of the columns.
59
73
  #
60
- # tbl = Table.new({:data => [1,2,3], [3,4,5], :column_names => %w[a b c]})
61
- # tbl.column_names = %w[e f g]
62
- def column_names=(other)
74
+ # Example:
75
+ #
76
+ # table = Table.new :data => [1,2,3], [3,4,5],
77
+ # :column_names => %w[a b c]
78
+ #
79
+ # table.column_names = %w[e f g]
80
+ #
81
+ def column_names=(new_column_names)
63
82
  @column_names.replace(other.dup)
64
83
  end
65
84
 
66
- # Compares this table to another table and returns true if
67
- # both the data and column names are equal
68
85
  #
69
- # one = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
70
- # two = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
86
+ # Compares this Table to another Table and returns <tt>true</tt> if
87
+ # both the <tt>data</tt> and <tt>column_names</tt> are equal.
88
+ #
89
+ # Example:
90
+ #
91
+ # one = Table.new :data => [1,2], [3,4],
92
+ # :column_names => %w[a b]
93
+ #
94
+ # two = Table.new :data => [1,2], [3,4],
95
+ # :column_names => %w[a b]
96
+ #
71
97
  # one.eql?(two) #=> true
98
+ #
72
99
  def eql?(other)
73
100
  data.eql?(other.data) && column_names.eql?(other.column_names)
74
101
  end
75
102
 
76
103
  alias_method :==, :eql?
77
104
 
78
- # Uses Ruport's built-in text plugin to render this table into a string
105
+ #
106
+ # Uses Ruport's built-in text plugin to render this Table into a String
107
+ #
108
+ # Example:
79
109
  #
80
- # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
110
+ # data = Table.new :data => [1,2], [3,4],
111
+ # :column_names => %w[a b]
81
112
  # puts data.to_s
113
+ #
82
114
  def to_s
83
115
  as(:text)
84
116
  end
85
117
 
86
- # Used to add extra data to the table. The single parameter can be an
87
- # Array, Hash or Ruport::Data::Record.
88
118
  #
89
- # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
119
+ # Used to add extra data to the Table. <tt>other</tt> can be an Array,
120
+ # Hash or Record.
121
+ #
122
+ # Example:
123
+ #
124
+ # data = Table.new :data => [1,2], [3,4],
125
+ # :column_names => %w[a b]
90
126
  # data << [8,9]
91
127
  # data << { :a => 4, :b => 5}
92
- # data << Ruport::Data::Record.new [5,6], :attributes => %w[a b]
128
+ # data << Record.new [5,6], :attributes => %w[a b]
129
+ #
93
130
  def <<(other)
94
131
  case other
95
132
  when Array
@@ -108,24 +145,37 @@ module Ruport::Data
108
145
  self
109
146
  end
110
147
 
111
- # Used to combine two tables. Throws an ArgumentError if the tables don't
148
+ #
149
+ # Used to combine two Tables. Throws an ArgumentError if the Tables don't
112
150
  # have identical columns.
113
151
  #
114
- # inky = Table.new(:data => [[1,2], [3,4]], :column_names => %w[a b])
115
- # blinky = Table.new(:data => [[5,6]], :column_names => %w[a b])
152
+ # Example:
153
+ #
154
+ # inky = Table.new :data => [[1,2], [3,4]],
155
+ # :column_names => %w[a b]
156
+ #
157
+ # blinky = Table.new :data => [[5,6]],
158
+ # :column_names => %w[a b]
159
+ #
116
160
  # sue = inky + blinky
117
161
  # sue.data #=> [[1,2],[3,4],[5,6]]
118
-
162
+ #
119
163
  def +(other)
120
164
  raise ArgumentError unless other.column_names == @column_names
121
165
  Table.new(:column_names => @column_names, :data => @data + other.data)
122
166
  end
123
167
 
124
- # Reorders the columns that exist in the table. Operates directly
125
- # on this table.
126
168
  #
127
- # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
169
+ # Reorders the columns that exist in the Table. Modifies this Table
170
+ # in-place.
171
+ #
172
+ # Example:
173
+ #
174
+ # data = Table.new :data => [1,2], [3,4],
175
+ # :column_names => %w[a b]
176
+ #
128
177
  # data.reorder!([1,0])
178
+ #
129
179
  def reorder!(*indices)
130
180
  indices = indices[0] if indices[0].kind_of? Array
131
181
  if @column_names && !@column_names.empty?
@@ -142,21 +192,34 @@ module Ruport::Data
142
192
  }; self
143
193
  end
144
194
 
145
- # Returns a copy of the table with its columns in the requested order.
146
195
  #
147
- # one = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
196
+ # Returns a copy of the Table with its columns in the requested order.
197
+ #
198
+ # Example:
199
+ #
200
+ # one = Table.new :data => [1,2], [3,4],
201
+ # :column_names => %w[a b]
202
+ #
148
203
  # two = one.reorder!([1,0])
204
+ #
149
205
  def reorder(*indices)
150
206
  dup.reorder!(*indices)
151
207
  end
152
208
 
153
- # Adds an extra column to the table. Accepts an options Hash as its
154
- # only parameter which should contain 2 keys - :name and :fill.
155
- # :name specifies the new columns name, and :fill the default value to
156
- # use for the column in existing rows.
209
+ #
210
+ # Adds an extra column to the Table. Required options:
211
+ #
212
+ # <b><tt>:name</tt></b>:: The new column's name
213
+ # <b><tt>:fill</tt></b>:: The default value to use for the column in
214
+ # existing rows.
157
215
  #
158
- # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
159
- # data.append_column({:name => 'new_column', :fill => 1)
216
+ # Example:
217
+ #
218
+ # data = Table.new :data => [1,2], [3,4],
219
+ # :column_names => %w[a b]
220
+ #
221
+ # data.append_column :name => 'new_column', :fill => 1
222
+ #
160
223
  def append_column(options={})
161
224
  self.column_names += [options[:name]] if options[:name]
162
225
  if block_given?
@@ -166,17 +229,21 @@ module Ruport::Data
166
229
  end; self
167
230
  end
168
231
 
169
- # Removes a column from the table. Any values in the specified column are
232
+ #
233
+ # Removes a column from the Table. Any values in the specified column are
170
234
  # lost.
171
- # data = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
172
- # data.append_column({:name => 'new_column', :fill => 1)
173
- # data.remove_column({:name => 'new_column')
174
- # data == Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
175
- # #=> true
176
- #
235
+ #
236
+ # Example:
237
+ #
238
+ # data = Table.new :data => [[1,2], [3,4]], :column_names => %w[a b]
239
+ # data.append_column :name => 'new_column', :fill => 1
240
+ # data.remove_column :name => 'new_column'
241
+ # data == Table.new :data => [[1,2], [3,4]],
242
+ # :column_names => %w[a b] #=> true
177
243
  # data = [[1,2],[3,4]].to_table
178
244
  # data.remove_column(1)
179
245
  # data.eql? [[1],[3]].to_table %w[a] #=> true
246
+ #
180
247
  def remove_column(options={})
181
248
  if options.kind_of? Integer
182
249
  return reorder!((0...data[0].length).to_a - [options])
@@ -190,29 +257,38 @@ module Ruport::Data
190
257
  reorder! column_names - [name]
191
258
  end
192
259
 
193
- # Create a shallow copy of the table: the same data elements are referenced
194
- # by both the old and new table.
195
260
  #
196
- # one = Table.new({:data => [1,2], [3,4], :column_names => %w[a b]})
261
+ # Create a shallow copy of the Table: the same data elements are referenced
262
+ # by both the old and new Table.
263
+ #
264
+ # Example:
265
+ #
266
+ # one = Table.new :data => [1,2], [3,4],
267
+ # :column_names => %w[a b]
197
268
  # two = one.dup
269
+ #
198
270
  def dup
199
271
  a = self.class.new(:data => @data, :column_names => @column_names)
200
272
  a.tags = tags.dup
201
273
  return a
202
274
  end
203
275
 
204
- # Loads a CSV file directly into a table using the fasterCSV library.
276
+ #
277
+ # Loads a CSV file directly into a Table using the FasterCSV library.
278
+ #
279
+ # Example:
205
280
  #
206
- # data = Table.load('mydata.csv')
281
+ # table = Table.load('mydata.csv')
282
+ #
207
283
  def self.load(csv_file, options={})
208
284
  get_table_from_csv(:foreach, csv_file, options)
209
285
  end
210
-
211
- def self.parse(string, options={})
286
+
287
+ def self.parse(string, options={}) #:nodoc:
212
288
  get_table_from_csv(:parse,string,options)
213
289
  end
214
290
 
215
- def self.get_table_from_csv(msg,param,options={})
291
+ def self.get_table_from_csv(msg,param,options={}) #:nodoc:
216
292
  options = {:has_names => true,
217
293
  :csv_options => {} }.merge(options)
218
294
  require "fastercsv"
@@ -231,7 +307,8 @@ module Ruport::Data
231
307
  end ; loaded_data
232
308
  end
233
309
 
234
- # Allows you to split tables into multiple tables for grouping.
310
+ #
311
+ # Allows you to split Tables into multiple Tables for grouping.
235
312
  #
236
313
  # Example:
237
314
  #
@@ -246,8 +323,8 @@ module Ruport::Data
246
323
  # b.greg.eql? [[1,2,3],[7,8,9]].to_table(%w[a b c]) #=> true
247
324
  # b["joe"].eql? [[2,3,4],[1,2,3]].to_table(%w[a b c]) #=> true
248
325
  #
249
- # You can also pass an array to :group, and the resulting attributes in
250
- # the group will be joined by an underscore.
326
+ # You can also pass an Array to <tt>:group</tt>, and the resulting
327
+ # attributes in the group will be joined by an underscore.
251
328
  #
252
329
  # Example:
253
330
  #
@@ -260,6 +337,7 @@ module Ruport::Data
260
337
  # a.greg_brown.length #=> 2
261
338
  # a["greg_gibson"].length #=> 1
262
339
  # a.greg_brown[0].x #=> "foo"
340
+ #
263
341
  def split(options={})
264
342
  if options[:group].kind_of? Array
265
343
  group = map { |r| options[:group].map { |e| r[e] } }.uniq
@@ -292,23 +370,22 @@ module Ruport::Data
292
370
  end; rec
293
371
  end
294
372
 
295
- # Calculates sums. If a column name or index is given, it will try to
373
+ #
374
+ # Calculates sums. If a column name or index is given, it will try to
296
375
  # convert each element of that column to an integer or float
297
- # and add it together
298
- #
299
- # If a block is given, yields each Record so that you can do a calculation.
376
+ # and add them together.
300
377
  #
378
+ # If a block is given, it yields each Record so that you can do your own
379
+ # calculation.
301
380
  #
302
381
  # Example:
303
382
  #
383
+ # table = [[1,2],[3,4],[5,6]].to_table(%w[col1 col2])
384
+ # table.sigma("col1") #=> 9
385
+ # table.sigma(0) #=> 9
386
+ # table.sigma { |r| r.col1 + r.col2 } #=> 21
387
+ # table.sigma { |r| r.col2 + 1 } #=> 15
304
388
  #
305
- # table = [[1,2],[3,4],[5,6]].to_table(%w[col1 col2])
306
- # table.sigma("col1") #=> 9
307
- # table.sigma(0) #=> 9
308
- # table.sigma { |r| r.col1 + r.col2 } #=> 21
309
- # table.sigma { |r| r.col2 + 1 } #=> 15
310
- #
311
- # For the non-mathy, this has been aliased as Table#sum
312
389
  def sigma(column=nil)
313
390
  inject(0) { |s,r|
314
391
  if column
@@ -326,4 +403,12 @@ module Ruport::Data
326
403
  alias_method :sum, :sigma
327
404
 
328
405
  end
406
+
407
+ end
408
+
409
+ module Ruport::Data::TableHelper #:nodoc:
410
+ def table(names=[])
411
+ t = [].to_table(names)
412
+ yield(t) if block_given?; t
413
+ end
329
414
  end
@@ -5,38 +5,66 @@
5
5
  # Copyright 2006 by respective content owners, all rights reserved.
6
6
  module Ruport::Data
7
7
 
8
- # This module provides a simple mechanism for tagging arbitrary objects. This
9
- # provides the necessary methods to set and retrieve tags which can consist of
10
- # any Ruby object. This is used by Data::Record and the Ruport Data
11
- # Collections.
8
+ #
9
+ # === Overview
10
+ #
11
+ # This module provides a simple mechanism for tagging arbitrary objects.
12
+ # It provides the necessary methods to set and retrieve tags which can
13
+ # consist of any Ruby object.
14
+ #
12
15
  module Taggable
13
16
 
14
- # Adds a tag to the object
17
+ #
18
+ # Adds a tag to the object.
19
+ #
20
+ # Example:
21
+ #
15
22
  # taggable_obj.tag :spiffy
23
+ #
16
24
  def tag(tag_name)
17
25
  tags << tag_name unless has_tag? tag_name
18
26
  end
19
27
 
20
- # Removes a tag
28
+ #
29
+ # Removes a tag from the object.
30
+ #
31
+ # Example:
32
+ #
21
33
  # taggable_obj.delete_tag :not_so_spiffy
34
+ #
22
35
  def delete_tag(tag_name)
23
36
  tags.delete tag_name
24
37
  end
25
38
 
26
- # Checks to see if a tag is present
39
+ #
40
+ # Checks to see if a tag is present.
41
+ #
42
+ # Example:
43
+ #
27
44
  # taggable_obj.has_tag? :spiffy #=> true
45
+ #
28
46
  def has_tag?(tag_name)
29
47
  tags.include? tag_name
30
48
  end
31
49
 
32
- # Returns an array of tags.
50
+ #
51
+ # Returns an Array of the object's tags.
52
+ #
53
+ # Example:
54
+ #
33
55
  # taggable_obj.tags #=> [:spiffy, :kind_of_spiffy]
56
+ #
34
57
  def tags
35
58
  @ruport_tags ||= []
36
59
  end
37
60
 
38
- # Sets the tags to some array
61
+ #
62
+ # Sets the tags to some Array.
63
+ #
64
+ # Example:
65
+ #
39
66
  # taggable_obj.tags = [:really_dang_spiffy, :the_most_spiffy]
67
+ #
40
68
  def tags=(tags_list)
41
69
  @ruport_tags = tags_list
42
70
  end