ruport 0.8.14 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/README +42 -107
  2. data/Rakefile +29 -32
  3. data/examples/centered_pdf_text_box.rb +13 -19
  4. data/examples/example.csv +3 -0
  5. data/examples/line_plotter.rb +15 -15
  6. data/examples/pdf_complex_report.rb +10 -23
  7. data/examples/pdf_table_with_title.rb +12 -12
  8. data/examples/rope_examples/itunes/Rakefile +22 -1
  9. data/examples/rope_examples/itunes/config/environment.rb +4 -0
  10. data/examples/rope_examples/itunes/lib/init.rb +32 -2
  11. data/examples/rope_examples/itunes/util/build +50 -16
  12. data/examples/rope_examples/sales_report/README +1 -1
  13. data/examples/rope_examples/sales_report/Rakefile +22 -1
  14. data/examples/rope_examples/sales_report/config/environment.rb +4 -0
  15. data/examples/rope_examples/sales_report/lib/init.rb +32 -2
  16. data/examples/rope_examples/sales_report/lib/reports/sales.rb +10 -16
  17. data/examples/rope_examples/sales_report/util/build +50 -16
  18. data/examples/row_renderer.rb +39 -0
  19. data/examples/ruport_list/png_embed.rb +61 -0
  20. data/examples/ruport_list/roadmap.png +0 -0
  21. data/examples/sample.rb +16 -0
  22. data/examples/simple_pdf_lines.rb +24 -0
  23. data/lib/ruport.rb +143 -57
  24. data/lib/ruport/acts_as_reportable.rb +246 -0
  25. data/lib/ruport/data.rb +1 -2
  26. data/lib/ruport/data/grouping.rb +311 -0
  27. data/lib/ruport/data/record.rb +113 -84
  28. data/lib/ruport/data/table.rb +275 -174
  29. data/lib/ruport/formatter.rb +149 -0
  30. data/lib/ruport/formatter/csv.rb +87 -0
  31. data/lib/ruport/formatter/html.rb +89 -0
  32. data/lib/ruport/formatter/pdf.rb +357 -0
  33. data/lib/ruport/formatter/text.rb +151 -0
  34. data/lib/ruport/generator.rb +127 -30
  35. data/lib/ruport/query.rb +46 -99
  36. data/lib/ruport/renderer.rb +238 -194
  37. data/lib/ruport/renderer/grouping.rb +67 -0
  38. data/lib/ruport/renderer/table.rb +25 -98
  39. data/lib/ruport/report.rb +45 -96
  40. data/test/acts_as_reportable_test.rb +229 -0
  41. data/test/csv_formatter_test.rb +97 -0
  42. data/test/{_test_database.rb → database_test_.rb} +0 -0
  43. data/test/grouping_test.rb +305 -0
  44. data/test/html_formatter_test.rb +104 -0
  45. data/test/pdf_formatter_test.rb +25 -0
  46. data/test/{test_query.rb → query_test.rb} +32 -121
  47. data/test/{test_record.rb → record_test.rb} +40 -23
  48. data/test/renderer_test.rb +344 -0
  49. data/test/{test_report.rb → report_test.rb} +74 -44
  50. data/test/samples/ticket_count.csv +124 -0
  51. data/test/{test_sql_split.rb → sql_split_test.rb} +0 -0
  52. data/test/{test_table.rb → table_test.rb} +255 -44
  53. data/test/text_formatter_test.rb +144 -0
  54. data/util/bench/data/record/bench_as_vs_to.rb +17 -0
  55. data/util/bench/data/record/bench_constructor.rb +46 -0
  56. data/util/bench/data/record/bench_indexing.rb +65 -0
  57. data/util/bench/data/record/bench_reorder.rb +35 -0
  58. data/util/bench/data/record/bench_to_a.rb +19 -0
  59. data/util/bench/data/table/bench_column_manip.rb +103 -0
  60. data/util/bench/data/table/bench_dup.rb +24 -0
  61. data/util/bench/data/table/bench_init.rb +67 -0
  62. data/util/bench/data/table/bench_manip.rb +125 -0
  63. data/util/bench/formatter/bench_csv.rb +14 -0
  64. data/util/bench/formatter/bench_html.rb +14 -0
  65. data/util/bench/formatter/bench_pdf.rb +14 -0
  66. data/util/bench/formatter/bench_text.rb +14 -0
  67. data/util/bench/samples/tattle.csv +1237 -0
  68. metadata +121 -143
  69. data/TODO +0 -21
  70. data/examples/invoice.rb +0 -142
  71. data/examples/invoice_report.rb +0 -29
  72. data/examples/line_graph.rb +0 -38
  73. data/examples/rope_examples/itunes/config/ruport_config.rb +0 -8
  74. data/examples/rope_examples/sales_report/config/ruport_config.rb +0 -8
  75. data/lib/ruport/attempt.rb +0 -63
  76. data/lib/ruport/config.rb +0 -204
  77. data/lib/ruport/data/groupable.rb +0 -93
  78. data/lib/ruport/data/taggable.rb +0 -80
  79. data/lib/ruport/format.rb +0 -1
  80. data/lib/ruport/format/csv.rb +0 -29
  81. data/lib/ruport/format/html.rb +0 -42
  82. data/lib/ruport/format/latex.rb +0 -47
  83. data/lib/ruport/format/pdf.rb +0 -233
  84. data/lib/ruport/format/plugin.rb +0 -31
  85. data/lib/ruport/format/svg.rb +0 -60
  86. data/lib/ruport/format/text.rb +0 -103
  87. data/lib/ruport/format/xml.rb +0 -32
  88. data/lib/ruport/layout.rb +0 -1
  89. data/lib/ruport/layout/component.rb +0 -7
  90. data/lib/ruport/mailer.rb +0 -99
  91. data/lib/ruport/renderer/graph.rb +0 -46
  92. data/lib/ruport/report/graph.rb +0 -14
  93. data/lib/ruport/system_extensions.rb +0 -71
  94. data/test/test_config.rb +0 -88
  95. data/test/test_format_text.rb +0 -63
  96. data/test/test_graph_renderer.rb +0 -97
  97. data/test/test_groupable.rb +0 -56
  98. data/test/test_mailer.rb +0 -170
  99. data/test/test_renderer.rb +0 -151
  100. data/test/test_ruport.rb +0 -58
  101. data/test/test_table_renderer.rb +0 -141
  102. 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
- # This module provides some additional methods for Renderer::Table that may be
9
- # helpful when rendering tabular data.
10
+ # == Supported Formatters
11
+ #
12
+ # * Formatter::CSV
13
+ # * Formatter::Text
14
+ # * Formatter::HTML
10
15
  #
11
- # These methods assume you are working with Data::Table objects
12
- module Renderer::TableHelpers
13
-
14
- # Allows you to modify a column at rendering time based on a block.
15
- # This will not effect the original data object you provided to the table
16
- # renderer
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
- # For a set of methods that might be helpful while working with this class,
93
- # see the included TableHelpers module
94
- #
95
- # == Supported Format Plugins
27
+ # == Supported Formatters
96
28
  #
97
- # * Format::CSV
98
- # * Format::Text
99
- # * Format::HTML
100
- # * Format::Latex
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
- # == Plugin hooks called (in order)
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
- layout { |lay| lay.show_table_headers = true }
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
- # === Example
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( source_name=:default, mailer_name=:default )
79
- use_source source_name
80
- use_mailer mailer_name
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::Config source requested by <tt>label</tt>.
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