derencius-acts_as_reportable 1.1.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 +63 -0
- data/lib/ruport/acts_as_reportable.rb +385 -0
- data/test/acts_as_reportable_test.rb +286 -0
- data/test/helpers.rb +8 -0
- metadata +66 -0
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require "rake/rdoctask"
|
2
|
+
require "rake/testtask"
|
3
|
+
require "rake/gempackagetask"
|
4
|
+
|
5
|
+
AAR_VERSION = "1.1.1"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require "rubygems"
|
9
|
+
rescue LoadError
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => [:test]
|
14
|
+
|
15
|
+
Rake::TestTask.new do |test|
|
16
|
+
test.libs << "test"
|
17
|
+
test.test_files = Dir[ "test/*_test.rb" ]
|
18
|
+
test.verbose = true
|
19
|
+
end
|
20
|
+
|
21
|
+
spec = Gem::Specification.new do |spec|
|
22
|
+
spec.name = "acts_as_reportable"
|
23
|
+
spec.version = AAR_VERSION
|
24
|
+
spec.platform = Gem::Platform::RUBY
|
25
|
+
spec.summary = "ActiveRecord support for Ruby Reports"
|
26
|
+
spec.files = Dir.glob("{lib,test}/**/**/*") +
|
27
|
+
["Rakefile"]
|
28
|
+
spec.require_path = "lib"
|
29
|
+
|
30
|
+
spec.test_files = Dir[ "test/*_test.rb" ]
|
31
|
+
spec.has_rdoc = true
|
32
|
+
#spec.extra_rdoc_files = %w{README LICENSE AUTHORS}
|
33
|
+
spec.rdoc_options << '--title' << 'Ruport Documentation'
|
34
|
+
spec.add_dependency('ruport', '>= 1.6.0')
|
35
|
+
spec.author = "Michael Milner"
|
36
|
+
spec.email = "mikem836@gmail.com"
|
37
|
+
spec.rubyforge_project = "ruport"
|
38
|
+
spec.homepage = "http://rubyreports.org"
|
39
|
+
spec.description = <<END_DESC
|
40
|
+
acts_as_reportable provides ActiveRecord support for Ruby Reports
|
41
|
+
END_DESC
|
42
|
+
end
|
43
|
+
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
rdoc.rdoc_files.include( "lib/" )
|
46
|
+
rdoc.main = "README"
|
47
|
+
rdoc.rdoc_dir = "doc/html"
|
48
|
+
rdoc.title = "acts_as_reportable Documentation"
|
49
|
+
end
|
50
|
+
|
51
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
52
|
+
pkg.need_zip = true
|
53
|
+
pkg.need_tar = true
|
54
|
+
end
|
55
|
+
|
56
|
+
begin
|
57
|
+
require 'rcov/rcovtask'
|
58
|
+
Rcov::RcovTask.new do |t|
|
59
|
+
t.test_files = Dir[ "test/*_test.rb" ]
|
60
|
+
end
|
61
|
+
rescue LoadError
|
62
|
+
nil
|
63
|
+
end
|
@@ -0,0 +1,385 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# acts_as_reportable.rb provides ActiveRecord integration for Ruport.
|
4
|
+
#
|
5
|
+
# Originally created by Dudley Flanders, 2006
|
6
|
+
# Revised and updated by Michael Milner, 2007
|
7
|
+
# Copyright (C) 2006-2007 Dudley Flanders / Michael Milner, All Rights Reserved.
|
8
|
+
#
|
9
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
10
|
+
# See LICENSE and COPYING for details.
|
11
|
+
#
|
12
|
+
require "ruport"
|
13
|
+
Ruport.quiet { require "active_record" }
|
14
|
+
|
15
|
+
module Ruport
|
16
|
+
|
17
|
+
# === Overview
|
18
|
+
#
|
19
|
+
# This module is designed to allow an ActiveRecord model to be converted to
|
20
|
+
# Ruport's data structures. If ActiveRecord is available when Ruport is
|
21
|
+
# loaded, this module will be automatically mixed into ActiveRecord::Base.
|
22
|
+
#
|
23
|
+
# Add the acts_as_reportable call to the model class that you want to
|
24
|
+
# integrate with Ruport:
|
25
|
+
#
|
26
|
+
# class Book < ActiveRecord::Base
|
27
|
+
# acts_as_reportable
|
28
|
+
# belongs_to :author
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Then you can use the <tt>report_table</tt> method to get data from the
|
32
|
+
# model using ActiveRecord.
|
33
|
+
#
|
34
|
+
# Book.report_table(:all, :include => :author)
|
35
|
+
#
|
36
|
+
module Reportable
|
37
|
+
|
38
|
+
def self.included(base) #:nodoc:
|
39
|
+
base.extend ClassMethods
|
40
|
+
end
|
41
|
+
|
42
|
+
# === Overview
|
43
|
+
#
|
44
|
+
# This module contains class methods that will automatically be available
|
45
|
+
# to ActiveRecord models.
|
46
|
+
#
|
47
|
+
module ClassMethods
|
48
|
+
|
49
|
+
# In the ActiveRecord model you wish to integrate with Ruport, add the
|
50
|
+
# following line just below the class definition:
|
51
|
+
#
|
52
|
+
# acts_as_reportable
|
53
|
+
#
|
54
|
+
# Available options:
|
55
|
+
#
|
56
|
+
# <b><tt>:only</tt></b>:: an attribute name or array of attribute
|
57
|
+
# names to include in the results, other
|
58
|
+
# attributes will be excuded.
|
59
|
+
# <b><tt>:except</tt></b>:: an attribute name or array of attribute
|
60
|
+
# names to exclude from the results.
|
61
|
+
# <b><tt>:methods</tt></b>:: a method name or array of method names
|
62
|
+
# whose result(s) will be included in the
|
63
|
+
# table.
|
64
|
+
# <b><tt>:include</tt></b>:: an associated model or array of associated
|
65
|
+
# models to include in the results.
|
66
|
+
#
|
67
|
+
# Example:
|
68
|
+
#
|
69
|
+
# class Book < ActiveRecord::Base
|
70
|
+
# acts_as_reportable, :only => 'title', :include => :author
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
def acts_as_reportable(options = {})
|
74
|
+
cattr_accessor :aar_options, :aar_columns
|
75
|
+
|
76
|
+
self.aar_options = options
|
77
|
+
|
78
|
+
include Ruport::Reportable::InstanceMethods
|
79
|
+
extend Ruport::Reportable::SingletonMethods
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# === Overview
|
84
|
+
#
|
85
|
+
# This module contains methods that will be made available as singleton
|
86
|
+
# class methods to any ActiveRecord model that calls
|
87
|
+
# <tt>acts_as_reportable</tt>.
|
88
|
+
#
|
89
|
+
module SingletonMethods
|
90
|
+
|
91
|
+
# Creates a Ruport::Data::Table from an ActiveRecord find. Takes
|
92
|
+
# parameters just like a regular find.
|
93
|
+
#
|
94
|
+
# Additional options include:
|
95
|
+
#
|
96
|
+
# <b><tt>:only</tt></b>:: An attribute name or array of attribute
|
97
|
+
# names to include in the results, other
|
98
|
+
# attributes will be excuded.
|
99
|
+
# <b><tt>:except</tt></b>:: An attribute name or array of attribute
|
100
|
+
# names to exclude from the results.
|
101
|
+
# <b><tt>:methods</tt></b>:: A method name or array of method names
|
102
|
+
# whose result(s) will be included in the
|
103
|
+
# table.
|
104
|
+
# <b><tt>:include</tt></b>:: An associated model or array of associated
|
105
|
+
# models to include in the results.
|
106
|
+
# <b><tt>:filters</tt></b>:: A proc or array of procs that set up
|
107
|
+
# conditions to filter the data being added
|
108
|
+
# to the table.
|
109
|
+
# <b><tt>:transforms</tt></b>:: A proc or array of procs that perform
|
110
|
+
# transformations on the data being added
|
111
|
+
# to the table.
|
112
|
+
# <b><tt>:record_class</tt></b>:: Specify the class of the table's
|
113
|
+
# records.
|
114
|
+
# <b><tt>:eager_loading</tt></b>:: Set to false if you don't want to
|
115
|
+
# eager load included associations.
|
116
|
+
#
|
117
|
+
# The :only, :except, :methods, and :include options may also be passed
|
118
|
+
# to the :include option in order to specify the output for any
|
119
|
+
# associated models. In this case, the :include option must be a hash,
|
120
|
+
# where the keys are the names of the associations and the values
|
121
|
+
# are hashes of options.
|
122
|
+
#
|
123
|
+
# Any options passed to report_table will disable the options set by
|
124
|
+
# the acts_as_reportable class method.
|
125
|
+
#
|
126
|
+
# Example:
|
127
|
+
#
|
128
|
+
# class Book < ActiveRecord::Base
|
129
|
+
# belongs_to :author
|
130
|
+
# acts_as_reportable
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# Book.report_table(:all, :only => ['title'],
|
134
|
+
# :include => { :author => { :only => 'name' } }).as(:html)
|
135
|
+
#
|
136
|
+
# Returns:
|
137
|
+
#
|
138
|
+
# an html version of the table with two columns, title from
|
139
|
+
# the book, and name from the associated author.
|
140
|
+
#
|
141
|
+
# Example:
|
142
|
+
#
|
143
|
+
# Book.report_table(:all, :include => :author).as(:html)
|
144
|
+
#
|
145
|
+
# Returns:
|
146
|
+
#
|
147
|
+
# an html version of the table with all columns from books and authors.
|
148
|
+
#
|
149
|
+
# Note: column names for attributes of included models will be qualified
|
150
|
+
# with the name of the association.
|
151
|
+
#
|
152
|
+
def report_table(number = :all, options = {})
|
153
|
+
only = options.delete(:only)
|
154
|
+
except = options.delete(:except)
|
155
|
+
methods = options.delete(:methods)
|
156
|
+
includes = options.delete(:include)
|
157
|
+
filters = options.delete(:filters)
|
158
|
+
transforms = options.delete(:transforms)
|
159
|
+
record_class = options.delete(:record_class) || Ruport::Data::Record
|
160
|
+
self.aar_columns = []
|
161
|
+
|
162
|
+
unless options.delete(:eager_loading) == false
|
163
|
+
options[:include] = get_include_for_find(includes)
|
164
|
+
end
|
165
|
+
|
166
|
+
data = [find(number, options)].flatten
|
167
|
+
data = data.map {|r| r.reportable_data(:include => includes,
|
168
|
+
:only => only,
|
169
|
+
:except => except,
|
170
|
+
:methods => methods) }.flatten
|
171
|
+
|
172
|
+
table = Ruport::Data::Table.new(:data => data,
|
173
|
+
:column_names => aar_columns,
|
174
|
+
:record_class => record_class,
|
175
|
+
:filters => filters,
|
176
|
+
:transforms => transforms )
|
177
|
+
end
|
178
|
+
|
179
|
+
# Creates a Ruport::Data::Table from an ActiveRecord find_by_sql.
|
180
|
+
#
|
181
|
+
# Additional options include:
|
182
|
+
#
|
183
|
+
# <b><tt>:filters</tt></b>:: A proc or array of procs that set up
|
184
|
+
# conditions to filter the data being added
|
185
|
+
# to the table.
|
186
|
+
# <b><tt>:transforms</tt></b>:: A proc or array of procs that perform
|
187
|
+
# transformations on the data being added
|
188
|
+
# to the table.
|
189
|
+
# <b><tt>:record_class</tt></b>:: Specify the class of the table's
|
190
|
+
# records.
|
191
|
+
#
|
192
|
+
# Example:
|
193
|
+
#
|
194
|
+
# class Book < ActiveRecord::Base
|
195
|
+
# belongs_to :author
|
196
|
+
# acts_as_reportable
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# Book.report_table_by_sql("SELECT * FROM books")
|
200
|
+
#
|
201
|
+
def report_table_by_sql(sql, options = {})
|
202
|
+
record_class = options.delete(:record_class) || Ruport::Data::Record
|
203
|
+
filters = options.delete(:filters)
|
204
|
+
transforms = options.delete(:transforms)
|
205
|
+
self.aar_columns = []
|
206
|
+
|
207
|
+
data = find_by_sql(sql)
|
208
|
+
data = data.map {|r| r.reportable_data }.flatten
|
209
|
+
|
210
|
+
table = Ruport::Data::Table.new(:data => data,
|
211
|
+
:column_names => aar_columns,
|
212
|
+
:record_class => record_class,
|
213
|
+
:filters => filters,
|
214
|
+
:transforms => transforms)
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def get_include_for_find(report_option)
|
220
|
+
includes = report_option.blank? ? aar_options[:include] : report_option
|
221
|
+
if includes.is_a?(Hash)
|
222
|
+
result = {}
|
223
|
+
includes.each do |k,v|
|
224
|
+
if v.empty? || !v[:include]
|
225
|
+
result.merge!(k => {})
|
226
|
+
else
|
227
|
+
result.merge!(k => get_include_for_find(v[:include]))
|
228
|
+
end
|
229
|
+
end
|
230
|
+
result
|
231
|
+
elsif includes.is_a?(Array)
|
232
|
+
result = {}
|
233
|
+
includes.each {|i| result.merge!(i => {}) }
|
234
|
+
result
|
235
|
+
else
|
236
|
+
includes
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# === Overview
|
242
|
+
#
|
243
|
+
# This module contains methods that will be made available as instance
|
244
|
+
# methods to any ActiveRecord model that calls <tt>acts_as_reportable</tt>.
|
245
|
+
#
|
246
|
+
module InstanceMethods
|
247
|
+
|
248
|
+
# Grabs all of the object's attributes and the attributes of the
|
249
|
+
# associated objects and returns them as an array of record hashes.
|
250
|
+
#
|
251
|
+
# Associated object attributes are stored in the record with
|
252
|
+
# "association.attribute" keys.
|
253
|
+
#
|
254
|
+
# Passing :only as an option will only get those attributes.
|
255
|
+
# Passing :except as an option will exclude those attributes.
|
256
|
+
# Must pass :include as an option to access associations. Options
|
257
|
+
# may be passed to the included associations by providing the :include
|
258
|
+
# option as a hash.
|
259
|
+
# Passing :methods as an option will include any methods on the object.
|
260
|
+
#
|
261
|
+
# Example:
|
262
|
+
#
|
263
|
+
# class Book < ActiveRecord::Base
|
264
|
+
# belongs_to :author
|
265
|
+
# acts_as_reportable
|
266
|
+
# end
|
267
|
+
#
|
268
|
+
# abook.reportable_data(:only => ['title'], :include => [:author])
|
269
|
+
#
|
270
|
+
# Returns:
|
271
|
+
#
|
272
|
+
# [{'title' => 'book title',
|
273
|
+
# 'author.id' => 'author id',
|
274
|
+
# 'author.name' => 'author name' }]
|
275
|
+
#
|
276
|
+
# NOTE: title will only be returned if the value exists in the table.
|
277
|
+
# If the books table does not have a title column, it will not be
|
278
|
+
# returned.
|
279
|
+
#
|
280
|
+
# Example:
|
281
|
+
#
|
282
|
+
# abook.reportable_data(:only => ['title'],
|
283
|
+
# :include => { :author => { :only => ['name'] } })
|
284
|
+
#
|
285
|
+
# Returns:
|
286
|
+
#
|
287
|
+
# [{'title' => 'book title',
|
288
|
+
# 'author.name' => 'author name' }]
|
289
|
+
#
|
290
|
+
def reportable_data(options = {})
|
291
|
+
options = options.merge(self.class.aar_options) unless
|
292
|
+
has_report_options?(options)
|
293
|
+
|
294
|
+
data_records = [get_attributes_with_options(options)]
|
295
|
+
Array(options[:methods]).each do |method|
|
296
|
+
if options[:qualify_attribute_names]
|
297
|
+
m = "#{options[:qualify_attribute_names]}.#{method}"
|
298
|
+
else
|
299
|
+
m = "#{method}"
|
300
|
+
end
|
301
|
+
data_records.first[m] = send(method)
|
302
|
+
end
|
303
|
+
|
304
|
+
# Reorder columns to match options[:only]
|
305
|
+
if Array === options[:only]
|
306
|
+
cols = options[:only].map {|c| c.to_s }
|
307
|
+
self.class.aar_columns = cols
|
308
|
+
end
|
309
|
+
|
310
|
+
self.class.aar_columns |= data_records.first.keys
|
311
|
+
|
312
|
+
data_records =
|
313
|
+
add_includes(data_records, options[:include]) if options[:include]
|
314
|
+
|
315
|
+
data_records
|
316
|
+
end
|
317
|
+
|
318
|
+
private
|
319
|
+
|
320
|
+
# Add data for all included associations
|
321
|
+
#
|
322
|
+
def add_includes(data_records, includes)
|
323
|
+
include_has_options = includes.is_a?(Hash)
|
324
|
+
associations = include_has_options ? includes.keys : Array(includes)
|
325
|
+
|
326
|
+
associations.each do |association|
|
327
|
+
existing_records = data_records.dup
|
328
|
+
data_records = []
|
329
|
+
|
330
|
+
if include_has_options
|
331
|
+
assoc_options = includes[association].merge({
|
332
|
+
:qualify_attribute_names => association })
|
333
|
+
else
|
334
|
+
assoc_options = { :qualify_attribute_names => association }
|
335
|
+
end
|
336
|
+
|
337
|
+
association_objects = [send(association)].flatten.compact
|
338
|
+
|
339
|
+
existing_records.each do |existing_record|
|
340
|
+
if association_objects.empty?
|
341
|
+
data_records << existing_record
|
342
|
+
else
|
343
|
+
association_objects.each do |obj|
|
344
|
+
association_records = obj.reportable_data(assoc_options)
|
345
|
+
association_records.each do |assoc_record|
|
346
|
+
data_records << existing_record.merge(assoc_record)
|
347
|
+
end
|
348
|
+
self.class.aar_columns |= data_records.last.keys
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
data_records
|
354
|
+
end
|
355
|
+
|
356
|
+
# Check if the options hash has any report options
|
357
|
+
# (:only, :except, :methods, or :include).
|
358
|
+
#
|
359
|
+
def has_report_options?(options)
|
360
|
+
options[:only] || options[:except] || options[:methods] ||
|
361
|
+
options[:include]
|
362
|
+
end
|
363
|
+
|
364
|
+
# Get the object's attributes using the supplied options.
|
365
|
+
#
|
366
|
+
# Use the :only or :except options to limit the attributes returned.
|
367
|
+
#
|
368
|
+
# Use the :qualify_attribute_names option to append the association
|
369
|
+
# name to the attribute name as association.attribute
|
370
|
+
#
|
371
|
+
def get_attributes_with_options(options = {})
|
372
|
+
attrs = attributes
|
373
|
+
attrs.delete_if {|key, value| [*options[:except]].collect{|o| o.to_s}.include?( key.to_s) } if options[:except]
|
374
|
+
attrs.delete_if {|key, value| ![*options[:only]].collect{|o| o.to_s}.include?( key.to_s) } if options[:only]
|
375
|
+
|
376
|
+
attrs = attrs.inject({}) {|h,(k,v)|
|
377
|
+
h["#{options[:qualify_attribute_names]}.#{k}"] = v; h
|
378
|
+
} if options[:qualify_attribute_names]
|
379
|
+
attrs
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
ActiveRecord::Base.send :include, Ruport::Reportable
|
@@ -0,0 +1,286 @@
|
|
1
|
+
class Array
|
2
|
+
def to_table(columns)
|
3
|
+
Table(columns) { |t| each { |r| t << r } }
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
#!/usr/bin/env ruby -w
|
9
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "helpers")
|
10
|
+
|
11
|
+
begin
|
12
|
+
require "mocha"
|
13
|
+
Ruport.quiet { require "active_record" }
|
14
|
+
rescue LoadError
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
if Object.const_defined?(:ActiveRecord) && Object.const_defined?(:Mocha)
|
19
|
+
|
20
|
+
require "ruport/acts_as_reportable"
|
21
|
+
|
22
|
+
class Team < ActiveRecord::Base
|
23
|
+
acts_as_reportable :except => 'id', :include => :players
|
24
|
+
has_many :players
|
25
|
+
end
|
26
|
+
|
27
|
+
class Player < ActiveRecord::Base
|
28
|
+
acts_as_reportable
|
29
|
+
belongs_to :team
|
30
|
+
belongs_to :personal_trainer
|
31
|
+
|
32
|
+
def stats
|
33
|
+
"#{name} stats"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module SomeModule
|
38
|
+
class PersonalTrainer < ActiveRecord::Base
|
39
|
+
acts_as_reportable
|
40
|
+
has_one :team
|
41
|
+
has_many :players
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module ModelStubsSetup
|
46
|
+
Column = ActiveRecord::ConnectionAdapters::Column
|
47
|
+
PersonalTrainer = SomeModule::PersonalTrainer
|
48
|
+
|
49
|
+
def setup
|
50
|
+
setup_column_stubs
|
51
|
+
|
52
|
+
@trainers = []
|
53
|
+
@trainers << PersonalTrainer.new(:name => "Trainer 1")
|
54
|
+
@trainers << PersonalTrainer.new(:name => "Trainer 2")
|
55
|
+
@teams = []
|
56
|
+
@teams << Team.new( :name => "Testers",
|
57
|
+
:league => "My League")
|
58
|
+
@teams << Team.new( :name => "Others",
|
59
|
+
:league => "Other League")
|
60
|
+
@players = []
|
61
|
+
@players << Player.new( :team_id => 1,
|
62
|
+
:name => "Player 1",
|
63
|
+
:personal_trainer_id => 1)
|
64
|
+
@players << Player.new( :team_id => 1,
|
65
|
+
:name => "Player 2",
|
66
|
+
:personal_trainer_id => 2)
|
67
|
+
|
68
|
+
setup_find_stubs
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def setup_column_stubs
|
74
|
+
PersonalTrainer.stubs(:columns).returns([
|
75
|
+
Column.new("id", nil, "integer", false),
|
76
|
+
Column.new("name", nil, "string", false)])
|
77
|
+
Team.stubs(:columns).returns([Column.new("id", nil, "integer", false),
|
78
|
+
Column.new("name", nil, "string", false),
|
79
|
+
Column.new("league", nil, "string", true)])
|
80
|
+
Player.stubs(:columns).returns([Column.new("id", nil, "integer", false),
|
81
|
+
Column.new("team_id", nil, "integer", true),
|
82
|
+
Column.new("name", nil, "string", false),
|
83
|
+
Column.new("personal_trainer_id", nil, "integer", true)])
|
84
|
+
end
|
85
|
+
|
86
|
+
def setup_find_stubs
|
87
|
+
PersonalTrainer.stubs(:find).returns(@trainers)
|
88
|
+
@trainers[0].stubs(:players).returns([@players[0]])
|
89
|
+
@trainers[1].stubs(:players).returns([@players[1]])
|
90
|
+
Team.stubs(:find).returns(@teams)
|
91
|
+
@teams[0].stubs(:players).returns(@players)
|
92
|
+
@teams[1].stubs(:players).returns([])
|
93
|
+
Player.stubs(:find).returns(@players)
|
94
|
+
Player.stubs(:find_by_sql).returns(@players)
|
95
|
+
@players[0].stubs(:team).returns(@teams[0])
|
96
|
+
@players[1].stubs(:team).returns(@teams[0])
|
97
|
+
@players[0].stubs(:personal_trainer).returns(@trainers[0])
|
98
|
+
@players[1].stubs(:personal_trainer).returns(@trainers[1])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
class TestActsAsReportableClassMethods < Test::Unit::TestCase
|
104
|
+
|
105
|
+
def test_aar_options_set
|
106
|
+
assert_equal({:except => 'id', :include => :players}, Team.aar_options)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class TestActsAsReportableSingletonMethods < Test::Unit::TestCase
|
111
|
+
include ModelStubsSetup
|
112
|
+
|
113
|
+
def test_basic_report_table
|
114
|
+
actual = Player.report_table
|
115
|
+
expected = [[1, "Player 1", 1],
|
116
|
+
[1, "Player 2", 2]].to_table(%w[team_id name personal_trainer_id])
|
117
|
+
assert_equal expected, actual
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_report_table_by_sql
|
121
|
+
actual = Player.report_table_by_sql("SELECT * FROM players")
|
122
|
+
expected = [[1, "Player 1", 1],
|
123
|
+
[1, "Player 2", 2]].to_table(%w[team_id name personal_trainer_id])
|
124
|
+
assert_equal expected, actual
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_only_option
|
128
|
+
actual = Player.report_table(:all, :only => 'name')
|
129
|
+
expected = [["Player 1"],["Player 2"]].to_table(%w[name])
|
130
|
+
assert_equal expected, actual
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_only_option_preserves_column_sort_order
|
134
|
+
column_order = %w[name personal_trainer_id team_id]
|
135
|
+
actual = Player.report_table(:all, :only => column_order)
|
136
|
+
expected = [["Player 1", 1, 1],
|
137
|
+
["Player 2", 2, 1]].to_table(column_order)
|
138
|
+
assert_equal expected, actual
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_only_option_allows_symbols
|
142
|
+
column_order = [:name, :personal_trainer_id, :team_id]
|
143
|
+
actual = Player.report_table(:all, :only => column_order)
|
144
|
+
expected = [["Player 1", 1, 1],
|
145
|
+
["Player 2", 2, 1]].to_table(%w[name personal_trainer_id team_id])
|
146
|
+
assert_equal expected, actual
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_except_option
|
150
|
+
actual = Player.report_table(:all, :except => 'personal_trainer_id')
|
151
|
+
expected = [[1, "Player 1"],[1, "Player 2"]].to_table(%w[team_id name])
|
152
|
+
assert_equal expected, actual
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_methods_option
|
156
|
+
actual = Player.report_table(:all, :only => 'name', :methods => :stats)
|
157
|
+
expected = [["Player 1", "Player 1 stats"],
|
158
|
+
["Player 2", "Player 2 stats"]].to_table(%w[name stats])
|
159
|
+
assert_equal expected, actual
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_include_option
|
163
|
+
actual = Player.report_table(:all, :only => 'name',
|
164
|
+
:include => :personal_trainer)
|
165
|
+
expected = [["Player 1", "Trainer 1"],
|
166
|
+
["Player 2", "Trainer 2"]].to_table(%w[name personal_trainer.name])
|
167
|
+
assert_equal expected, actual
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_column_sorting_works_with_include_option
|
171
|
+
actual = Player.report_table(:all,
|
172
|
+
:only => %w[name personal_trainer.name],
|
173
|
+
:include => { :personal_trainer => { :only => %w[name] } })
|
174
|
+
expected = [["Player 1", "Trainer 1"],
|
175
|
+
["Player 2", "Trainer 2"]].to_table(%w[name personal_trainer.name])
|
176
|
+
assert_equal expected, actual
|
177
|
+
|
178
|
+
actual = Player.report_table(:all,
|
179
|
+
:only => %w[personal_trainer.name name],
|
180
|
+
:include => { :personal_trainer => { :only => %w[name] } })
|
181
|
+
expected = [["Trainer 1", "Player 1"],
|
182
|
+
["Trainer 2", "Player 2"]].to_table(%w[personal_trainer.name name])
|
183
|
+
assert_equal expected, actual
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_include_has_options
|
187
|
+
actual = Team.report_table(:all, :only => 'name',
|
188
|
+
:include => { :players => { :only => 'name' } })
|
189
|
+
expected = [["Testers", "Player 1"],
|
190
|
+
["Testers", "Player 2"],
|
191
|
+
["Others", nil]].to_table(%w[name players.name])
|
192
|
+
assert_equal expected, actual
|
193
|
+
end
|
194
|
+
|
195
|
+
class CustomRecord < Ruport::Data::Record; end
|
196
|
+
|
197
|
+
def test_record_class_option
|
198
|
+
actual = Player.report_table(:all, :record_class => CustomRecord)
|
199
|
+
actual.each { |r| assert_equal CustomRecord, r.class }
|
200
|
+
|
201
|
+
actual = Player.report_table_by_sql("SELECT * FROM players",
|
202
|
+
:record_class => CustomRecord)
|
203
|
+
actual.each { |r| assert_equal CustomRecord, r.class }
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_get_include_for_find
|
207
|
+
assert_equal :players, Team.send(:get_include_for_find, nil)
|
208
|
+
assert_equal nil, Player.send(:get_include_for_find, nil)
|
209
|
+
assert_equal :team, Player.send(:get_include_for_find, :team)
|
210
|
+
expected = {:team => {}}
|
211
|
+
assert_equal expected,
|
212
|
+
Player.send(:get_include_for_find, {:team => {:except => 'id'}})
|
213
|
+
expected = {:team => {:a => {}, :b => {}},
|
214
|
+
:c => {:d => {:e => {}, :f => {}}},
|
215
|
+
:g => {}}
|
216
|
+
assert_equal expected,
|
217
|
+
Player.send(:get_include_for_find, {:team => {:include => [:a,:b]},
|
218
|
+
:c => {:include => {:d => {:include => [:e,:f]}}}, :g => {}})
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
class TestActsAsReportableInstanceMethods < Test::Unit::TestCase
|
223
|
+
include ModelStubsSetup
|
224
|
+
|
225
|
+
def test_reportable_data
|
226
|
+
actual = @players[0].reportable_data
|
227
|
+
expected = [{ 'team_id' => 1,
|
228
|
+
'name' => "Player 1",
|
229
|
+
'personal_trainer_id' => 1 }]
|
230
|
+
assert_equal expected, actual
|
231
|
+
|
232
|
+
actual = @teams[0].reportable_data(:include =>
|
233
|
+
{ :players => { :only => 'name' } })
|
234
|
+
expected = [{ 'name' => "Testers",
|
235
|
+
'league' => "My League",
|
236
|
+
'players.name' => "Player 1" },
|
237
|
+
{ 'name' => "Testers",
|
238
|
+
'league' => "My League",
|
239
|
+
'players.name' => "Player 2" }]
|
240
|
+
assert_equal expected, actual
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_add_includes
|
244
|
+
actual = @players[0].send(:add_includes,
|
245
|
+
[{ 'name' => "Player 1" }], :personal_trainer)
|
246
|
+
expected = [{ 'name' => "Player 1",
|
247
|
+
'personal_trainer.name' => "Trainer 1" }]
|
248
|
+
assert_equal expected, actual
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_has_report_options
|
252
|
+
assert @teams[0].send(:has_report_options?, { :only => 'name' })
|
253
|
+
assert @teams[0].send(:has_report_options?, { :except => 'name' })
|
254
|
+
assert @teams[0].send(:has_report_options?, { :methods => 'name' })
|
255
|
+
assert @teams[0].send(:has_report_options?, { :include => 'name' })
|
256
|
+
assert !@teams[0].send(:has_report_options?, { :foo => 'name' })
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_get_attributes_with_options
|
260
|
+
actual = @players[0].send(:get_attributes_with_options)
|
261
|
+
expected = { 'team_id' => 1,
|
262
|
+
'name' => "Player 1",
|
263
|
+
'personal_trainer_id' => 1 }
|
264
|
+
assert_equal expected, actual
|
265
|
+
|
266
|
+
actual = @players[0].send(:get_attributes_with_options,
|
267
|
+
{ :only => 'name' })
|
268
|
+
expected = { 'name' => "Player 1" }
|
269
|
+
assert_equal expected, actual
|
270
|
+
|
271
|
+
actual = @players[0].send(:get_attributes_with_options,
|
272
|
+
{ :except => 'personal_trainer_id' })
|
273
|
+
expected = { 'team_id' => 1,
|
274
|
+
'name' => "Player 1" }
|
275
|
+
assert_equal expected, actual
|
276
|
+
|
277
|
+
actual = @players[0].send(:get_attributes_with_options,
|
278
|
+
{ :only => 'name', :qualify_attribute_names => :players })
|
279
|
+
expected = { 'players.name' => "Player 1" }
|
280
|
+
assert_equal expected, actual
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
else
|
285
|
+
$stderr.puts "Warning: Mocha and/or ActiveRecord not found -- skipping AAR tests"
|
286
|
+
end
|
data/test/helpers.rb
ADDED
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: derencius-acts_as_reportable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Milner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-08 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: ruport
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.6.0
|
23
|
+
version:
|
24
|
+
description: acts_as_reportable provides ActiveRecord support for Ruby Reports
|
25
|
+
email: mikem836@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- lib/ruport
|
34
|
+
- lib/ruport/acts_as_reportable.rb
|
35
|
+
- test/acts_as_reportable_test.rb
|
36
|
+
- test/helpers.rb
|
37
|
+
- Rakefile
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://rubyreports.org
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --title
|
43
|
+
- Ruport Documentation
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project: ruport
|
61
|
+
rubygems_version: 1.2.0
|
62
|
+
signing_key:
|
63
|
+
specification_version: 2
|
64
|
+
summary: ActiveRecord support for Ruby Reports
|
65
|
+
test_files:
|
66
|
+
- test/acts_as_reportable_test.rb
|