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