ruport 0.8.14 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +42 -107
- data/Rakefile +29 -32
- data/examples/centered_pdf_text_box.rb +13 -19
- data/examples/example.csv +3 -0
- data/examples/line_plotter.rb +15 -15
- data/examples/pdf_complex_report.rb +10 -23
- data/examples/pdf_table_with_title.rb +12 -12
- data/examples/rope_examples/itunes/Rakefile +22 -1
- data/examples/rope_examples/itunes/config/environment.rb +4 -0
- data/examples/rope_examples/itunes/lib/init.rb +32 -2
- data/examples/rope_examples/itunes/util/build +50 -16
- data/examples/rope_examples/sales_report/README +1 -1
- data/examples/rope_examples/sales_report/Rakefile +22 -1
- data/examples/rope_examples/sales_report/config/environment.rb +4 -0
- data/examples/rope_examples/sales_report/lib/init.rb +32 -2
- data/examples/rope_examples/sales_report/lib/reports/sales.rb +10 -16
- data/examples/rope_examples/sales_report/util/build +50 -16
- data/examples/row_renderer.rb +39 -0
- data/examples/ruport_list/png_embed.rb +61 -0
- data/examples/ruport_list/roadmap.png +0 -0
- data/examples/sample.rb +16 -0
- data/examples/simple_pdf_lines.rb +24 -0
- data/lib/ruport.rb +143 -57
- data/lib/ruport/acts_as_reportable.rb +246 -0
- data/lib/ruport/data.rb +1 -2
- data/lib/ruport/data/grouping.rb +311 -0
- data/lib/ruport/data/record.rb +113 -84
- data/lib/ruport/data/table.rb +275 -174
- data/lib/ruport/formatter.rb +149 -0
- data/lib/ruport/formatter/csv.rb +87 -0
- data/lib/ruport/formatter/html.rb +89 -0
- data/lib/ruport/formatter/pdf.rb +357 -0
- data/lib/ruport/formatter/text.rb +151 -0
- data/lib/ruport/generator.rb +127 -30
- data/lib/ruport/query.rb +46 -99
- data/lib/ruport/renderer.rb +238 -194
- data/lib/ruport/renderer/grouping.rb +67 -0
- data/lib/ruport/renderer/table.rb +25 -98
- data/lib/ruport/report.rb +45 -96
- data/test/acts_as_reportable_test.rb +229 -0
- data/test/csv_formatter_test.rb +97 -0
- data/test/{_test_database.rb → database_test_.rb} +0 -0
- data/test/grouping_test.rb +305 -0
- data/test/html_formatter_test.rb +104 -0
- data/test/pdf_formatter_test.rb +25 -0
- data/test/{test_query.rb → query_test.rb} +32 -121
- data/test/{test_record.rb → record_test.rb} +40 -23
- data/test/renderer_test.rb +344 -0
- data/test/{test_report.rb → report_test.rb} +74 -44
- data/test/samples/ticket_count.csv +124 -0
- data/test/{test_sql_split.rb → sql_split_test.rb} +0 -0
- data/test/{test_table.rb → table_test.rb} +255 -44
- data/test/text_formatter_test.rb +144 -0
- data/util/bench/data/record/bench_as_vs_to.rb +17 -0
- data/util/bench/data/record/bench_constructor.rb +46 -0
- data/util/bench/data/record/bench_indexing.rb +65 -0
- data/util/bench/data/record/bench_reorder.rb +35 -0
- data/util/bench/data/record/bench_to_a.rb +19 -0
- data/util/bench/data/table/bench_column_manip.rb +103 -0
- data/util/bench/data/table/bench_dup.rb +24 -0
- data/util/bench/data/table/bench_init.rb +67 -0
- data/util/bench/data/table/bench_manip.rb +125 -0
- data/util/bench/formatter/bench_csv.rb +14 -0
- data/util/bench/formatter/bench_html.rb +14 -0
- data/util/bench/formatter/bench_pdf.rb +14 -0
- data/util/bench/formatter/bench_text.rb +14 -0
- data/util/bench/samples/tattle.csv +1237 -0
- metadata +121 -143
- data/TODO +0 -21
- data/examples/invoice.rb +0 -142
- data/examples/invoice_report.rb +0 -29
- data/examples/line_graph.rb +0 -38
- data/examples/rope_examples/itunes/config/ruport_config.rb +0 -8
- data/examples/rope_examples/sales_report/config/ruport_config.rb +0 -8
- data/lib/ruport/attempt.rb +0 -63
- data/lib/ruport/config.rb +0 -204
- data/lib/ruport/data/groupable.rb +0 -93
- data/lib/ruport/data/taggable.rb +0 -80
- data/lib/ruport/format.rb +0 -1
- data/lib/ruport/format/csv.rb +0 -29
- data/lib/ruport/format/html.rb +0 -42
- data/lib/ruport/format/latex.rb +0 -47
- data/lib/ruport/format/pdf.rb +0 -233
- data/lib/ruport/format/plugin.rb +0 -31
- data/lib/ruport/format/svg.rb +0 -60
- data/lib/ruport/format/text.rb +0 -103
- data/lib/ruport/format/xml.rb +0 -32
- data/lib/ruport/layout.rb +0 -1
- data/lib/ruport/layout/component.rb +0 -7
- data/lib/ruport/mailer.rb +0 -99
- data/lib/ruport/renderer/graph.rb +0 -46
- data/lib/ruport/report/graph.rb +0 -14
- data/lib/ruport/system_extensions.rb +0 -71
- data/test/test_config.rb +0 -88
- data/test/test_format_text.rb +0 -63
- data/test/test_graph_renderer.rb +0 -97
- data/test/test_groupable.rb +0 -56
- data/test/test_mailer.rb +0 -170
- data/test/test_renderer.rb +0 -151
- data/test/test_ruport.rb +0 -58
- data/test/test_table_renderer.rb +0 -141
- data/test/test_taggable.rb +0 -52
@@ -0,0 +1,67 @@
|
|
1
|
+
module Ruport
|
2
|
+
|
3
|
+
# This class implements the basic renderer for a single group of data.
|
4
|
+
#
|
5
|
+
# == Supported Formatters
|
6
|
+
#
|
7
|
+
# * Formatter::CSV
|
8
|
+
# * Formatter::Text
|
9
|
+
# * Formatter::HTML
|
10
|
+
# * Formatter::PDF
|
11
|
+
#
|
12
|
+
# == Default layout options
|
13
|
+
#
|
14
|
+
# * <tt>show_table_headers</tt> #=> true
|
15
|
+
#
|
16
|
+
# == Formatter hooks called (in order)
|
17
|
+
#
|
18
|
+
# * build_group_header
|
19
|
+
# * build_group_body
|
20
|
+
# * build_group_footer
|
21
|
+
#
|
22
|
+
class Renderer::Group < Renderer
|
23
|
+
|
24
|
+
option :show_table_headers
|
25
|
+
|
26
|
+
options { |o| o.show_table_headers = true }
|
27
|
+
|
28
|
+
stage :group_header, :group_body, :group_footer
|
29
|
+
end
|
30
|
+
|
31
|
+
# This class implements the basic renderer for data groupings in Ruport
|
32
|
+
# (a collection of Groups).
|
33
|
+
#
|
34
|
+
# == Supported Formatters
|
35
|
+
#
|
36
|
+
# * Formatter::CSV
|
37
|
+
# * Formatter::Text
|
38
|
+
# * Formatter::HTML
|
39
|
+
# * Formatter::PDF
|
40
|
+
#
|
41
|
+
# == Default layout options
|
42
|
+
#
|
43
|
+
# * <tt>show_group_headers</tt> #=> true
|
44
|
+
# * <tt>style</tt> #=> :inline
|
45
|
+
#
|
46
|
+
# == Formatter hooks called (in order)
|
47
|
+
#
|
48
|
+
# * build_grouping_header
|
49
|
+
# * build_grouping_body
|
50
|
+
# * build_grouping_footer
|
51
|
+
# * finalize_grouping
|
52
|
+
#
|
53
|
+
class Renderer::Grouping < Renderer
|
54
|
+
|
55
|
+
option :show_group_headers, :style
|
56
|
+
|
57
|
+
options do |o|
|
58
|
+
o.show_group_headers = true
|
59
|
+
o.style = :inline
|
60
|
+
end
|
61
|
+
|
62
|
+
stage :grouping_header, :grouping_body, :grouping_footer
|
63
|
+
|
64
|
+
finalize :grouping
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -4,107 +4,38 @@
|
|
4
4
|
# This is Free Software, please see LICENSE and COPYING for details.
|
5
5
|
|
6
6
|
module Ruport
|
7
|
+
|
8
|
+
# This class implements the basic renderer for table rows.
|
7
9
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
+
# == Supported Formatters
|
11
|
+
#
|
12
|
+
# * Formatter::CSV
|
13
|
+
# * Formatter::Text
|
14
|
+
# * Formatter::HTML
|
10
15
|
#
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# Example:
|
19
|
-
#
|
20
|
-
# table.as(:text){ |r| r.rewrite_column("col1") { |a| a[0] + 5 }
|
21
|
-
# table.as(:csv) { |r| r.rewrite_column(2) { |a| a.capitalize }
|
22
|
-
def rewrite_column(key,&block)
|
23
|
-
data.to_a.each { |r| r[key] = block[r] }
|
24
|
-
end
|
25
|
-
|
26
|
-
# Gets the number of columns in a table. Useful in formatting plugins.
|
27
|
-
def num_cols
|
28
|
-
data[0].to_a.length
|
29
|
-
end
|
30
|
-
|
31
|
-
# Allows you to remove duplicates from data tables.
|
32
|
-
#
|
33
|
-
# By default, it will try to prune the entire table, but you may provide a
|
34
|
-
# limit of how many columns in it should work.
|
35
|
-
#
|
36
|
-
# Examples:
|
37
|
-
#
|
38
|
-
# irb(main):014:0> puts a
|
39
|
-
# +-----------+
|
40
|
-
# | a | b | c |
|
41
|
-
# +-----------+
|
42
|
-
# | 1 | 2 | 3 |
|
43
|
-
# | 1 | 2 | 2 |
|
44
|
-
# | 1 | 3 | 5 |
|
45
|
-
# | 2 | 7 | 9 |
|
46
|
-
# | 2 | 8 | 3 |
|
47
|
-
# | 2 | 7 | 1 |
|
48
|
-
# | 1 | 7 | 9 |
|
49
|
-
# +-----------+
|
50
|
-
# => nil
|
51
|
-
# irb(main):015:0> puts a.as(:text) { |e| e.prune(2) }
|
52
|
-
# +-----------+
|
53
|
-
# | a | b | c |
|
54
|
-
# +-----------+
|
55
|
-
# | 1 | 2 | 3 |
|
56
|
-
# | | | 2 |
|
57
|
-
# | | 3 | 5 |
|
58
|
-
# | 2 | 7 | 9 |
|
59
|
-
# | | 8 | 3 |
|
60
|
-
# | | 7 | 1 |
|
61
|
-
# | 1 | 7 | 9 |
|
62
|
-
# +-----------+
|
63
|
-
# => nil
|
64
|
-
# irb(main):016:0> puts a.as(:text) { |e| e.prune(1) }
|
65
|
-
# +-----------+
|
66
|
-
# | a | b | c |
|
67
|
-
# +-----------+
|
68
|
-
# | 1 | 2 | 3 |
|
69
|
-
# | | 2 | 2 |
|
70
|
-
# | | 3 | 5 |
|
71
|
-
# | 2 | 7 | 9 |
|
72
|
-
# | | 8 | 3 |
|
73
|
-
# | | 7 | 1 |
|
74
|
-
# | 1 | 7 | 9 |
|
75
|
-
# +-----------+
|
76
|
-
def prune(limit=data[0].length)
|
77
|
-
require "enumerator"
|
78
|
-
limit.times do |field|
|
79
|
-
last = ""
|
80
|
-
data.each_cons(2) { |l,e|
|
81
|
-
next if field.nonzero? && e[field-1]
|
82
|
-
last = l[field] if l[field]
|
83
|
-
e[field] = nil if e[field] == last
|
84
|
-
}
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
16
|
+
# == Formatter hooks called (in order)
|
17
|
+
#
|
18
|
+
# * build_row
|
19
|
+
#
|
20
|
+
class Renderer::Row < Renderer
|
21
|
+
option :format_options
|
22
|
+
stage :row
|
88
23
|
end
|
89
|
-
|
24
|
+
|
90
25
|
# This class implements the basic tabular data renderer for Ruport.
|
91
26
|
#
|
92
|
-
#
|
93
|
-
# see the included TableHelpers module
|
94
|
-
#
|
95
|
-
# == Supported Format Plugins
|
27
|
+
# == Supported Formatters
|
96
28
|
#
|
97
|
-
# *
|
98
|
-
# *
|
99
|
-
# *
|
100
|
-
# *
|
101
|
-
# * Format::PDF
|
29
|
+
# * Formatter::CSV
|
30
|
+
# * Formatter::Text
|
31
|
+
# * Formatter::HTML
|
32
|
+
# * Formatter::PDF
|
102
33
|
#
|
103
34
|
# == Default layout options
|
104
35
|
#
|
105
36
|
# * <tt>show_table_headers</tt> #=> true
|
106
37
|
#
|
107
|
-
# ==
|
38
|
+
# == Formatter hooks called (in order)
|
108
39
|
#
|
109
40
|
# * prepare_table
|
110
41
|
# * build_table_header
|
@@ -113,18 +44,14 @@ module Ruport
|
|
113
44
|
# * finalize_table
|
114
45
|
#
|
115
46
|
class Renderer::Table < Renderer
|
116
|
-
include TableHelpers
|
117
|
-
include Renderer::Helpers
|
118
|
-
|
119
|
-
add_formats :csv, :text, :html, :latex, :pdf
|
120
47
|
|
121
|
-
|
48
|
+
option :show_table_headers, :format_options
|
49
|
+
|
50
|
+
options { |o| o.show_table_headers = true }
|
122
51
|
|
123
52
|
prepare :table
|
124
53
|
|
125
|
-
stage :table_header
|
126
|
-
stage :table_body
|
127
|
-
stage :table_footer
|
54
|
+
stage :table_header, :table_body, :table_footer
|
128
55
|
|
129
56
|
finalize :table
|
130
57
|
end
|
data/lib/ruport/report.rb
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
|
8
8
|
#load the needed standard libraries.
|
9
9
|
%w[erb yaml date logger fileutils].each { |lib| require lib }
|
10
|
-
%w[graph].each { |lib| require "ruport/report/"+lib }
|
11
10
|
require "forwardable"
|
12
11
|
|
13
12
|
module Ruport
|
@@ -20,64 +19,19 @@ module Ruport
|
|
20
19
|
# individual classes of the library, but if they are fairly simple, you may be
|
21
20
|
# able to get away using this class alone.
|
22
21
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# Here is a simple example of using the Report class to run a simple query and
|
26
|
-
# then email the results as a CSV file, deleting the file from the local
|
27
|
-
# machine after it has been emailed:
|
28
|
-
#
|
29
|
-
# require "ruport"
|
30
|
-
# require "fileutils"
|
31
|
-
# class MyReport < Ruport::Report
|
32
|
-
# def prepare
|
33
|
-
# log_file "f.log"
|
34
|
-
# log "preparing report", :status => :info
|
35
|
-
# source :default,
|
36
|
-
# :dsn => "dbi:mysql:foo",
|
37
|
-
# :user => "root"
|
38
|
-
# mailer :default,
|
39
|
-
# :host => "mail.adelphia.net",
|
40
|
-
# :address => "gregory.t.brown@gmail.com"
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# def generate
|
44
|
-
# log "generated csv from query", :status => :info
|
45
|
-
# query "select * from bar", :as => :csv
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# def cleanup
|
49
|
-
# log "removing foo.csv", :status => :info
|
50
|
-
# FileUtils.rm("foo.csv")
|
51
|
-
# end
|
52
|
-
# end
|
53
|
-
#
|
54
|
-
# MyReport.run { |res|
|
55
|
-
# res.write "foo.csv";
|
56
|
-
# res.send_to("greg7224@gmail.com") do |mail|
|
57
|
-
# mail.subject = "Sample report"
|
58
|
-
# mail.attach "foo.csv"
|
59
|
-
# mail.text = <<-EOS
|
60
|
-
# this is a sample of sending an emailed report from within Ruport.
|
61
|
-
# EOS
|
62
|
-
# end
|
63
|
-
# }
|
64
|
-
#
|
65
|
-
#
|
22
|
+
# FIXME: New example
|
66
23
|
class Report
|
67
24
|
extend Forwardable
|
25
|
+
include Renderer::Hooks
|
68
26
|
|
69
|
-
# When initializing a report, you can provide a default mailer and source by
|
70
|
-
# giving a name of a valid source or mailer you've defined via
|
71
|
-
# Ruport::Config.
|
72
|
-
#
|
73
27
|
# If your report does not need any sort of specialized information, you can
|
74
28
|
# simply use Report.run (Or MyReportName.run if you've inherited).
|
75
29
|
#
|
76
30
|
# This will auto-initialize a report.
|
77
31
|
#
|
78
|
-
def initialize(
|
79
|
-
use_source
|
80
|
-
|
32
|
+
def initialize( format=nil, options={} )
|
33
|
+
use_source :default
|
34
|
+
@format = format
|
81
35
|
@report_name = ""
|
82
36
|
@results = ""
|
83
37
|
@file = nil
|
@@ -91,6 +45,8 @@ module Ruport
|
|
91
45
|
#
|
92
46
|
attr_accessor :results
|
93
47
|
|
48
|
+
attr_accessor :format
|
49
|
+
|
94
50
|
# This is a simplified interface to Ruport::Query.
|
95
51
|
#
|
96
52
|
# You can use it to read SQL statements from file or string:
|
@@ -128,7 +84,6 @@ module Ruport
|
|
128
84
|
def query(sql, options={})
|
129
85
|
options[:origin] ||= :string
|
130
86
|
options[:source] ||= @source
|
131
|
-
options[:binding] ||= binding
|
132
87
|
q = options[:query_obj] || Query.new(sql, options)
|
133
88
|
if block_given?
|
134
89
|
q.each { |r| yield(r) }
|
@@ -139,27 +94,15 @@ module Ruport
|
|
139
94
|
end
|
140
95
|
end
|
141
96
|
|
142
|
-
# Sets the active source to the Ruport::
|
97
|
+
# Sets the active source to the Ruport::Query source requested by <tt>label</tt>.
|
143
98
|
def use_source(label)
|
144
99
|
@source = label
|
145
100
|
end
|
146
101
|
|
147
|
-
# Sets the active mailer to the Ruport::Config source requested by <tt>label</tt>.
|
148
|
-
def use_mailer(label)
|
149
|
-
@mailer = label
|
150
|
-
end
|
151
|
-
|
152
|
-
# Writes the contents of <tt>results</tt> to a file. If a filename is
|
153
|
-
# specified, it will use it. Otherwise, it will try to write to the file
|
154
|
-
# specified by the <tt>file</tt> attribute.
|
155
|
-
#
|
156
102
|
def write(my_file=file,my_results=results)
|
157
103
|
File.open(my_file,"w") { |f| f << my_results }
|
158
104
|
end
|
159
105
|
|
160
|
-
# Like Report#write, but will append to a file rather than overwrite it if
|
161
|
-
# the file already exists.
|
162
|
-
#
|
163
106
|
def append(my_file=file,my_results=results)
|
164
107
|
File.open(my_file,"a") { |f| f << my_results }
|
165
108
|
end
|
@@ -173,6 +116,16 @@ module Ruport
|
|
173
116
|
self.class.run(options,&block)
|
174
117
|
end
|
175
118
|
|
119
|
+
def as(format,*args)
|
120
|
+
self.format = format
|
121
|
+
run(*args)
|
122
|
+
end
|
123
|
+
|
124
|
+
def method_missing(id,*args)
|
125
|
+
id.to_s =~ /^to_(.*)/
|
126
|
+
$1 ? as($1.to_sym,*args) : super
|
127
|
+
end
|
128
|
+
|
176
129
|
# Loads a CSV in from a file.
|
177
130
|
#
|
178
131
|
# Example:
|
@@ -212,37 +165,18 @@ module Ruport
|
|
212
165
|
end
|
213
166
|
end
|
214
167
|
|
215
|
-
# uses RedCloth to turn a string containing textile markup into HTML.
|
216
|
-
#
|
217
|
-
# Example:
|
218
|
-
#
|
219
|
-
# textile "*bar*" #=> "<p><strong>foo</strong></p>"
|
220
|
-
#
|
221
|
-
def textile(s)
|
222
|
-
require "redcloth"
|
223
|
-
RedCloth.new(s).to_html
|
224
|
-
end
|
225
|
-
|
226
|
-
# Allows logging and other fun stuff.
|
227
|
-
# See also Ruport.log
|
228
|
-
#
|
229
|
-
def log(*args); Ruport.log(*args) end
|
230
|
-
|
231
|
-
# Creates a new Mailer and sets the <tt>to</tt> attribute to the addresses
|
232
|
-
# specified. Yields a Mailer object, which can be modified before delivery.
|
233
|
-
#
|
234
|
-
def send_to(adds)
|
235
|
-
m = Mailer.new
|
236
|
-
m.to = adds
|
237
|
-
yield(m)
|
238
|
-
m.send(:select_mailer,@mailer)
|
239
|
-
m.deliver :from => m.from, :to => m.to
|
240
|
-
end
|
241
|
-
|
242
|
-
def_delegators Ruport::Config, :source, :mailer, :log_file, :log_file=
|
243
|
-
|
244
168
|
class << self
|
245
169
|
|
170
|
+
def as(format,options={})
|
171
|
+
report = new(format)
|
172
|
+
report.run(rendering_options.merge(options))
|
173
|
+
end
|
174
|
+
|
175
|
+
def method_missing(id,*args)
|
176
|
+
id.to_s =~ /^to_(.*)/
|
177
|
+
$1 ? as($1.to_sym,*args) : super
|
178
|
+
end
|
179
|
+
|
246
180
|
# Defines an instance method which will be run before the
|
247
181
|
# <tt>generate</tt> method when Ruport.run is executed.
|
248
182
|
#
|
@@ -263,7 +197,7 @@ module Ruport
|
|
263
197
|
def cleanup(&block); define_method(:cleanup,&block) end
|
264
198
|
|
265
199
|
private :prepare, :generate, :cleanup
|
266
|
-
|
200
|
+
|
267
201
|
# Runs the reports specified. If no reports are specified, then it
|
268
202
|
# creates a new instance via <tt>self.new</tt>.
|
269
203
|
#
|
@@ -279,10 +213,26 @@ module Ruport
|
|
279
213
|
def run(options={})
|
280
214
|
options[:reports] ||= [self.new]
|
281
215
|
|
216
|
+
formatting_options = ( options.keys -
|
217
|
+
[:reports,:tries,:timeout,:interval])
|
218
|
+
|
219
|
+
fopts = formatting_options.inject({}) { |s,k|
|
220
|
+
s.merge( k => options[k] )
|
221
|
+
}
|
222
|
+
|
223
|
+
|
282
224
|
process = lambda do
|
283
225
|
options[:reports].each { |rep|
|
284
226
|
rep.prepare if rep.respond_to? :prepare
|
285
227
|
rep.results = rep.generate
|
228
|
+
|
229
|
+
if renderer
|
230
|
+
rep.results =
|
231
|
+
renderer.render(rep.format,rendering_options.merge(fopts)) { |r|
|
232
|
+
r.data = rep.results
|
233
|
+
}
|
234
|
+
end
|
235
|
+
|
286
236
|
yield(rep) if block_given?
|
287
237
|
rep.cleanup if rep.respond_to? :cleanup
|
288
238
|
}
|
@@ -293,7 +243,6 @@ module Ruport
|
|
293
243
|
a.tries = options[:tries]
|
294
244
|
a.interval = options[:interval] if options[:interval]
|
295
245
|
a.timeout = options[:timeout] if options[:timeout]
|
296
|
-
a.log_level = options[:log_level]
|
297
246
|
}
|
298
247
|
code.attempt(&process)
|
299
248
|
else
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require "ruport"
|
2
|
+
require "test/unit"
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "rubygems"
|
6
|
+
rescue LoadError
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'mocha'
|
13
|
+
require 'stubba'
|
14
|
+
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
|
+
|
40
|
+
class PersonalTrainer < ActiveRecord::Base
|
41
|
+
acts_as_reportable
|
42
|
+
has_one :team
|
43
|
+
has_many :players
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class TestActsAsReportable < Test::Unit::TestCase
|
49
|
+
Column = ActiveRecord::ConnectionAdapters::Column
|
50
|
+
PersonalTrainer = SomeModule::PersonalTrainer
|
51
|
+
|
52
|
+
def setup
|
53
|
+
setup_column_stubs
|
54
|
+
|
55
|
+
@trainers = []
|
56
|
+
@trainers << PersonalTrainer.new(:name => "Trainer 1")
|
57
|
+
@trainers << PersonalTrainer.new(:name => "Trainer 2")
|
58
|
+
@teams = []
|
59
|
+
@teams << Team.new( :name => "Testers",
|
60
|
+
:league => "My League")
|
61
|
+
@teams << Team.new( :name => "Others",
|
62
|
+
:league => "Other League")
|
63
|
+
@players = []
|
64
|
+
@players << Player.new( :team_id => 1,
|
65
|
+
:name => "Player 1",
|
66
|
+
:personal_trainer_id => 1)
|
67
|
+
@players << Player.new( :team_id => 1,
|
68
|
+
:name => "Player 2",
|
69
|
+
:personal_trainer_id => 2)
|
70
|
+
|
71
|
+
setup_find_stubs
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_options_set
|
75
|
+
assert_equal({:except => 'id', :include => :players}, Team.aar_options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_basic_report_table
|
79
|
+
actual = Player.report_table
|
80
|
+
expected = [[1, "Player 1", 1],
|
81
|
+
[1, "Player 2", 2]].to_table(%w[team_id name personal_trainer_id])
|
82
|
+
assert_equal expected, actual
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_only
|
86
|
+
actual = Player.report_table(:all, :only => 'name')
|
87
|
+
expected = [["Player 1"],["Player 2"]].to_table(%w[name])
|
88
|
+
assert_equal expected, actual
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_except
|
92
|
+
actual = Player.report_table(:all, :except => 'personal_trainer_id')
|
93
|
+
expected = [[1, "Player 1"],[1, "Player 2"]].to_table(%w[team_id name])
|
94
|
+
assert_equal expected, actual
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_methods
|
98
|
+
actual = Player.report_table(:all, :only => 'name', :methods => :stats)
|
99
|
+
expected = [["Player 1", "Player 1 stats"],
|
100
|
+
["Player 2", "Player 2 stats"]].to_table(%w[name stats])
|
101
|
+
assert_equal expected, actual
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_include
|
105
|
+
actual = Player.report_table(:all, :only => 'name',
|
106
|
+
:include => :personal_trainer)
|
107
|
+
expected = [["Player 1", "Trainer 1"],
|
108
|
+
["Player 2", "Trainer 2"]].to_table(%w[name personal_trainer.name])
|
109
|
+
assert_equal expected, actual
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_include_with_options
|
113
|
+
actual = Team.report_table(:all, :only => 'name',
|
114
|
+
:include => { :players => { :only => 'name' } })
|
115
|
+
expected = [["Testers", "Player 1"],
|
116
|
+
["Testers", "Player 2"],
|
117
|
+
["Others", nil]].to_table(%w[name player.name])
|
118
|
+
assert_equal expected, actual
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_get_include_for_find
|
122
|
+
assert_equal :players, Team.send(:get_include_for_find, nil)
|
123
|
+
assert_equal nil, Player.send(:get_include_for_find, nil)
|
124
|
+
assert_equal :team, Player.send(:get_include_for_find, :team)
|
125
|
+
assert_equal [:team],
|
126
|
+
Player.send(:get_include_for_find, {:team => {:except => 'id'}})
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_reportable_data
|
130
|
+
actual = @players[0].reportable_data
|
131
|
+
expected = [{ 'team_id' => 1,
|
132
|
+
'name' => "Player 1",
|
133
|
+
'personal_trainer_id' => 1 }]
|
134
|
+
assert_equal expected, actual
|
135
|
+
|
136
|
+
actual = @teams[0].reportable_data(:include =>
|
137
|
+
{ :players => { :only => 'name' } })
|
138
|
+
expected = [{ 'name' => "Testers",
|
139
|
+
'league' => "My League",
|
140
|
+
'player.name' => "Player 1" },
|
141
|
+
{ 'name' => "Testers",
|
142
|
+
'league' => "My League",
|
143
|
+
'player.name' => "Player 2" }]
|
144
|
+
assert_equal expected, actual
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_add_includes
|
148
|
+
actual = @players[0].send(:add_includes,
|
149
|
+
[{ 'name' => "Player 1" }], :personal_trainer)
|
150
|
+
expected = [{ 'name' => "Player 1",
|
151
|
+
'some_module/personal_trainer.name' => "Trainer 1" }]
|
152
|
+
assert_equal expected, actual
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_has_report_options
|
156
|
+
assert @teams[0].send(:has_report_options?, { :only => 'name' })
|
157
|
+
assert @teams[0].send(:has_report_options?, { :except => 'name' })
|
158
|
+
assert @teams[0].send(:has_report_options?, { :methods => 'name' })
|
159
|
+
assert @teams[0].send(:has_report_options?, { :include => 'name' })
|
160
|
+
assert !@teams[0].send(:has_report_options?, { :foo => 'name' })
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_preserve_namespace_option
|
164
|
+
actual = Player.report_table(:all, :only => 'name',
|
165
|
+
:include => :personal_trainer, :preserve_namespace => true)
|
166
|
+
expected = [["Player 1", "Trainer 1"],
|
167
|
+
["Player 2", "Trainer 2"]].to_table(%w[name
|
168
|
+
some_module/personal_trainer.name])
|
169
|
+
assert_equal expected, actual
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_get_attributes_with_options
|
173
|
+
actual = @players[0].send(:get_attributes_with_options)
|
174
|
+
expected = { 'team_id' => 1,
|
175
|
+
'name' => "Player 1",
|
176
|
+
'personal_trainer_id' => 1 }
|
177
|
+
assert_equal expected, actual
|
178
|
+
|
179
|
+
actual = @players[0].send(:get_attributes_with_options,
|
180
|
+
{ :only => 'name' })
|
181
|
+
expected = { 'name' => "Player 1" }
|
182
|
+
assert_equal expected, actual
|
183
|
+
|
184
|
+
actual = @players[0].send(:get_attributes_with_options,
|
185
|
+
{ :except => 'personal_trainer_id' })
|
186
|
+
expected = { 'team_id' => 1,
|
187
|
+
'name' => "Player 1" }
|
188
|
+
assert_equal expected, actual
|
189
|
+
|
190
|
+
actual = @players[0].send(:get_attributes_with_options,
|
191
|
+
{ :only => 'name', :qualify_attribute_names => true })
|
192
|
+
expected = { 'player.name' => "Player 1" }
|
193
|
+
assert_equal expected, actual
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def setup_column_stubs
|
199
|
+
PersonalTrainer.stubs(:columns).returns([
|
200
|
+
Column.new("id", nil, "integer", false),
|
201
|
+
Column.new("name", nil, "string", false)])
|
202
|
+
Team.stubs(:columns).returns([Column.new("id", nil, "integer", false),
|
203
|
+
Column.new("name", nil, "string", false),
|
204
|
+
Column.new("league", nil, "string", true)])
|
205
|
+
Player.stubs(:columns).returns([Column.new("id", nil, "integer", false),
|
206
|
+
Column.new("team_id", nil, "integer", true),
|
207
|
+
Column.new("name", nil, "string", false),
|
208
|
+
Column.new("personal_trainer_id", nil, "integer", true)])
|
209
|
+
end
|
210
|
+
|
211
|
+
def setup_find_stubs
|
212
|
+
PersonalTrainer.stubs(:find).returns(@trainers)
|
213
|
+
@trainers[0].stubs(:players).returns([@players[0]])
|
214
|
+
@trainers[1].stubs(:players).returns([@players[1]])
|
215
|
+
Team.stubs(:find).returns(@teams)
|
216
|
+
@teams[0].stubs(:players).returns(@players)
|
217
|
+
@teams[1].stubs(:players).returns([])
|
218
|
+
Player.stubs(:find).returns(@players)
|
219
|
+
@players[0].stubs(:team).returns(@teams[0])
|
220
|
+
@players[1].stubs(:team).returns(@teams[0])
|
221
|
+
@players[0].stubs(:personal_trainer).returns(@trainers[0])
|
222
|
+
@players[1].stubs(:personal_trainer).returns(@trainers[1])
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
else
|
228
|
+
$stderr.puts "Warning: Mocha and/or ActiveRecord not found -- skipping AAR tests"
|
229
|
+
end
|