ruport-util 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ end
18
18
 
19
19
  spec = Gem::Specification.new do |spec|
20
20
  spec.name = "ruport-util"
21
- spec.version = "0.3.0"
21
+ spec.version = "0.4.0"
22
22
  spec.platform = Gem::Platform::RUBY
23
23
  spec.summary = "A set of tools and helper libs for Ruby Reports"
24
24
  spec.files = Dir.glob("{example,lib,test,bin}/**/**/*") +
@@ -28,6 +28,7 @@ spec = Gem::Specification.new do |spec|
28
28
 
29
29
  spec.test_files = Dir[ "test/test_*.rb" ]
30
30
  spec.bindir = "bin"
31
+ spec.executables = FileList["rope"]
31
32
  spec.has_rdoc = true
32
33
  spec.extra_rdoc_files = %w{}
33
34
  spec.rdoc_options << '--title' << 'Ruport Documentation' #<<
data/bin/rope ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+ require "ruport/util/generator"
4
+ include FileUtils
5
+
6
+ if ARGV.empty?
7
+ puts "Usage: rope project_name"
8
+ exit
9
+ end
10
+ project = ARGV[0]
11
+
12
+ Ruport::Generator.build(ARGV[0])
@@ -0,0 +1,280 @@
1
+ module Ruport
2
+ class Generator
3
+ extend FileUtils
4
+
5
+ module Helpers
6
+ def format_class_name(string)
7
+ string.downcase.split("_").map { |s| s.capitalize }.join
8
+ end
9
+
10
+ def check_for_files
11
+ if File.exist? "lib/reports/#{ARGV[1]}.rb"
12
+ raise "Report #{ARGV[1]} exists!"
13
+ end
14
+
15
+ if File.exist? "lib/renderers/#{ARGV[1]}.rb"
16
+ raise "Renderer #{ARGV[1]} exists!"
17
+ end
18
+ end
19
+ end
20
+
21
+ begin
22
+ require "rubygems"
23
+ rescue LoadError
24
+ nil
25
+ end
26
+ require "ruport"
27
+ require "ruport/util"
28
+
29
+ def self.build(proj)
30
+ @project = proj
31
+ build_directory_structure
32
+ build_init
33
+ build_config
34
+ build_utils
35
+ build_rakefile
36
+ puts "\nSuccessfully generated project: #{proj}"
37
+ end
38
+
39
+
40
+ def self.build_init
41
+ m = "#{project}/lib/init.rb"
42
+ puts " #{m}"
43
+ File.open(m,"w") { |f| f << INIT }
44
+ end
45
+
46
+ # Generates a trivial rakefile for use with Ruport.
47
+ def self.build_rakefile
48
+ m = "#{project}/Rakefile"
49
+ puts " #{m}"
50
+ File.open(m,"w") { |f| f << RAKEFILE }
51
+ end
52
+
53
+ # Generates the build.rb and sql_exec.rb utilities
54
+ def self.build_utils
55
+
56
+ m = "#{project}/util/build"
57
+ puts " #{m}"
58
+ File.open(m,"w") { |f| f << BUILD }
59
+ chmod(0755, m)
60
+
61
+ m = "#{project}/util/sql_exec"
62
+ puts " #{m}"
63
+ File.open(m,"w") { |f| f << SQL_EXEC }
64
+ chmod(0755, m)
65
+ end
66
+
67
+ # sets up the basic directory layout for a Ruport application
68
+ def self.build_directory_structure
69
+ mkdir project
70
+ puts "creating directories.."
71
+ %w[ test config output data lib lib/reports
72
+ lib/renderers templates sql log util].each do |d|
73
+ m="#{project}/#{d}"
74
+ puts " #{m}"
75
+ mkdir(m)
76
+ end
77
+
78
+ puts "creating files.."
79
+ %w[reports helpers renderers].each { |f|
80
+ m = "#{project}/lib/#{f}.rb"
81
+ puts " #{m}"
82
+ touch(m)
83
+ }
84
+ end
85
+
86
+ def self.build_config
87
+ m = "#{project}/config/environment.rb"
88
+ puts " #{m}"
89
+ File.open(m,"w") { |f| f << CONFIG }
90
+ end
91
+
92
+ # returns the project's name
93
+ def self.project; @project; end
94
+
95
+ RAKEFILE = <<'END_RAKEFILE'
96
+ begin; require "rubygems"; rescue LoadError; end
97
+ require "rake/testtask"
98
+
99
+ task :default => [:test]
100
+
101
+ Rake::TestTask.new do |test|
102
+ test.libs << "test"
103
+ test.pattern = 'test/**/test_*.rb'
104
+ test.verbose = true
105
+ end
106
+
107
+ task :build do
108
+ if ENV['report']
109
+ sh "ruby util/build report #{ENV['report']}"
110
+ elsif ENV['renderer']
111
+ sh "ruby util/build renderer #{ENV['renderer']}"
112
+ end
113
+ end
114
+
115
+ task :run do
116
+ sh "ruby lib/reports/#{ENV['report']}.rb"
117
+ end
118
+ END_RAKEFILE
119
+
120
+ CONFIG = <<END_CONFIG
121
+ require "ruport"
122
+
123
+ Ruport::Query.add_source :default, :user => "root",
124
+ :dsn => "dbi:mysql:mydb"
125
+ END_CONFIG
126
+
127
+ BUILD = <<'END_BUILD'
128
+ #!/usr/bin/env ruby
129
+
130
+ require 'fileutils'
131
+ require 'lib/init.rb'
132
+ require "ruport/util"
133
+ include FileUtils
134
+ include Ruport::Generator::Helpers
135
+
136
+ unless ARGV.length > 1
137
+ puts "usage: build [command] [options]"
138
+ exit
139
+ end
140
+
141
+ class_name = format_class_name(ARGV[1])
142
+
143
+ if ARGV[0].eql? "report"
144
+ check_for_files
145
+ File.open("lib/reports.rb", "a") { |f|
146
+ f.puts("require \"lib/reports/#{ARGV[1]}\"")
147
+ }
148
+ REP = <<EOR
149
+ require "lib/init"
150
+ class #{class_name} < Ruport::Report
151
+
152
+ def generate
153
+
154
+ end
155
+
156
+ end
157
+
158
+ if __FILE__ == $0
159
+ puts #{class_name}.run
160
+ end
161
+ EOR
162
+
163
+ TEST = <<EOR
164
+ require "test/unit"
165
+ require "lib/reports/#{ARGV[1]}"
166
+
167
+ class Test#{class_name} < Test::Unit::TestCase
168
+ def test_flunk
169
+ flunk "Write your real tests here or in any test/test_* file"
170
+ end
171
+ end
172
+ EOR
173
+
174
+ File.open("lib/reports/#{ARGV[1]}.rb", "w") { |f| f << REP }
175
+ puts "reports file: lib/reports/#{ARGV[1]}.rb"
176
+ puts "test file: test/test_#{ARGV[1]}.rb"
177
+ puts "class name: #{class_name}"
178
+ File.open("test/test_#{ARGV[1]}.rb","w") { |f| f << TEST }
179
+
180
+ elsif ARGV[0].eql? "renderer"
181
+
182
+ check_for_files
183
+ File.open("lib/renderers.rb","a") { |f|
184
+ f.puts("require \"lib/renderers/#{ARGV[1]}\"")
185
+ }
186
+ REP = <<EOR
187
+ require "lib/init"
188
+
189
+ class #{class_name} < Ruport::Renderer
190
+ stage :#{class_name.downcase}
191
+ end
192
+
193
+ class #{class_name}Formatter < Ruport::Formatter
194
+
195
+ # change to your format name, or add additional formats
196
+ renders :my_format, :for => #{class_name}
197
+
198
+ def build_#{class_name.downcase}
199
+
200
+ end
201
+
202
+ end
203
+ EOR
204
+
205
+ TEST = <<EOR
206
+ require "test/unit"
207
+ require "lib/renderers/#{ARGV[1]}"
208
+
209
+ class Test#{class_name} < Test::Unit::TestCase
210
+ def test_flunk
211
+ flunk "Write your real tests here or in any test/test_* file"
212
+ end
213
+ end
214
+ EOR
215
+ puts "renderer file: lib/renderers/#{ARGV[1]}.rb"
216
+ File.open("lib/renderers/#{ARGV[1]}.rb", "w") { |f| f << REP }
217
+ puts "test file: test/test_#{ARGV[1]}.rb"
218
+
219
+ puts "class name: #{class_name}"
220
+ File.open("test/test_#{ARGV[1]}.rb","w") { |f| f << TEST }
221
+ else
222
+ puts "Incorrect usage."
223
+ end
224
+ END_BUILD
225
+
226
+ SQL_EXEC = <<'END_SQL'
227
+ #!/usr/bin/env ruby
228
+
229
+ require "lib/init"
230
+
231
+ puts Ruport::Query.new(ARGF.read).result
232
+ END_SQL
233
+
234
+ INIT = <<END_INIT
235
+ begin
236
+ require "rubygems"
237
+ gem "ruport","=#{Ruport::VERSION}"
238
+ gem "ruport-util","=#{Ruport::Util::VERSION}"
239
+ rescue LoadError
240
+ nil
241
+ end
242
+ require "ruport"
243
+ require "ruport/util"
244
+ require "lib/helpers"
245
+ require "config/environment"
246
+
247
+ class String
248
+ def /(other)
249
+ self + "/" + other
250
+ end
251
+ end
252
+
253
+ class Ruport::Report
254
+
255
+ def output_dir
256
+ config.output_dir or dir('output')
257
+ end
258
+
259
+ def data_dir
260
+ config.data_dir or dir('data')
261
+ end
262
+
263
+ def query_dir
264
+ config.query_dir or dir('sql')
265
+ end
266
+
267
+ def template_dir
268
+ config.template_dir or dir('templates')
269
+ end
270
+
271
+ private
272
+ def dir(name)
273
+ "#{FileUtils.pwd}/#{ARGV[0]}/\#{name}"
274
+ end
275
+ end
276
+ END_INIT
277
+
278
+
279
+ end
280
+ end
@@ -6,6 +6,7 @@
6
6
  # See LICENSE for details
7
7
  require "net/smtp"
8
8
  require "forwardable"
9
+ require "ruport/util/report"
9
10
 
10
11
  module Ruport
11
12
 
@@ -0,0 +1,405 @@
1
+ # report.rb : High Level Interface to Ruport
2
+ #
3
+ # Author: Gregory Brown
4
+ # Copyright 2006, All Rights Reserved
5
+ #
6
+ # This is Free Software. See LICENSE and COPYING files for details.
7
+
8
+ #load the needed standard libraries.
9
+ %w[erb yaml date logger fileutils].each { |lib| require lib }
10
+ require "forwardable"
11
+
12
+ module Ruport
13
+
14
+ require 'timeout'
15
+
16
+ class Attempt # :nodoc:
17
+ VERSION = '0.1.0 (vendored)'
18
+
19
+ # Number of attempts to make before failing. The default is 3.
20
+ attr_accessor :tries
21
+
22
+ # Number of seconds to wait between attempts. The default is 60.
23
+ attr_accessor :interval
24
+
25
+ # a level which ruport understands.
26
+ attr_accessor :log_level
27
+
28
+ # If set, this increments the interval with each failed attempt by that
29
+ # number of seconds.
30
+ attr_accessor :increment
31
+
32
+ # If set, the code block is further wrapped in a timeout block.
33
+ attr_accessor :timeout
34
+
35
+ # Determines which exception level to check when looking for errors to
36
+ # retry. The default is 'Exception' (i.e. all errors).
37
+ attr_accessor :level
38
+
39
+ # :call-seq:
40
+ # Attempt.new{ |a| ... }
41
+ #
42
+ # Creates and returns a new +Attempt+ object. Use a block to set the
43
+ # accessors.
44
+ #
45
+ def initialize
46
+ @tries = 3 # Reasonable default
47
+ @interval = 60 # Reasonable default
48
+ @increment = nil # Should be an int, if provided
49
+ @timeout = nil # Wrap the code in a timeout block if provided
50
+ @level = Exception # Level of exception to be caught
51
+
52
+ yield self if block_given?
53
+ end
54
+
55
+ def attempt
56
+ count = 1
57
+ begin
58
+ if @timeout
59
+ Timeout.timeout(@timeout){ yield }
60
+ else
61
+ yield
62
+ end
63
+ rescue @level => error
64
+ @tries -= 1
65
+ if @tries > 0
66
+ msg = "Error on attempt # #{count}: #{error}; retrying"
67
+ count += 1
68
+ @interval += @increment if @increment
69
+ sleep @interval
70
+ retry
71
+ end
72
+ raise
73
+ end
74
+ end
75
+ end
76
+
77
+
78
+
79
+ # === Overview
80
+ #
81
+ # The Ruport::Report class provides a high level interface to much of Ruport's
82
+ # functionality. It is designed to allow you to build and run reports easily.
83
+ # If your needs are complicated, you will probably need to take a look at the
84
+ # individual classes of the library, but if they are fairly simple, you may be
85
+ # able to get away using this class alone.
86
+ #
87
+ # Ruport::Report is primarily meant to be used with Ruport's code generator,
88
+ # rope, and is less useful when integrated within another system, such as
89
+ # Rails or Camping.
90
+ #
91
+ # Below is a simple example of loading a report in from a CSV, performing a
92
+ # grouping operation, and then rendering the resulting PDF to file.
93
+ #
94
+ # require "rubygems"
95
+ # require "ruport"
96
+ # class MyReport < Ruport::Report
97
+ #
98
+ # renders_as_grouping(:style => :inline)
99
+ #
100
+ # def generate
101
+ # table = load_csv "foo.csv"
102
+ # Grouping(table, :by => "username")
103
+ # end
104
+ #
105
+ # end
106
+ #
107
+ # report = MyReport.new(:pdf)
108
+ # report.run { |results| results.write("bar.pdf") }
109
+ #
110
+ class Report
111
+ extend Forwardable
112
+ include Renderer::Hooks
113
+
114
+ # Builds a report instance. If provided a format parameter,
115
+ # this format will be used by default when rendering the report.
116
+ #
117
+ def initialize( format=nil )
118
+ use_source :default
119
+ @format = format
120
+ @report_name = ""
121
+ @results = ""
122
+ @file = nil
123
+ end
124
+
125
+ # By default, this file will be used by Report#write.
126
+ attr_accessor :file
127
+
128
+ # This attribute will get the results of Report#generate when the report is
129
+ # run.
130
+ #
131
+ attr_accessor :results
132
+
133
+ # This attribute defines which format the Report will render in by default.
134
+ attr_accessor :format
135
+
136
+ # This is a simplified interface to Ruport::Query.
137
+ #
138
+ # You can use it to read SQL statements from file or string:
139
+ #
140
+ # #from string
141
+ # result = query "select * from foo"
142
+ #
143
+ # #from file
144
+ # result = query "my_query.sql", :origin => :file
145
+ #
146
+ # You can use multistatement SQL:
147
+ #
148
+ # # will return the value of the last statement, "select * from foo"
149
+ # result = query "insert into foo values(1,2); select * from foo"
150
+ #
151
+ # You can iterate by row:
152
+ #
153
+ # query("select * from foo") { |r|
154
+ # #do something with the rows here
155
+ # }
156
+ #
157
+ # query() can return raw DBI:Row objects or Ruport's data structures:
158
+ #
159
+ # # will return an Array of DBI::Row objects
160
+ # result = query "select * from foo", :raw_data => true
161
+ #
162
+ # You can quickly output in a number of formats:
163
+ #
164
+ # result = query "select * from foo", :as => :csv
165
+ # result = query "select * from foo", :as => :html
166
+ # result = query "select * from foo", :as => :pdf
167
+ #
168
+ # See Ruport::Query for details.
169
+ #
170
+ def query(sql, options={})
171
+ options[:origin] ||= :string
172
+ options[:source] ||= @source
173
+ q = options[:query_obj] || Query.new(sql, options)
174
+ if block_given?
175
+ q.each { |r| yield(r) }
176
+ elsif options[:as]
177
+ q.result.as(options[:as])
178
+ else
179
+ q.result
180
+ end
181
+ end
182
+
183
+ # Sets the active source to the Ruport::Query source requested by
184
+ # <tt>label</tt>.
185
+ #
186
+ # For example, if you have a data source :test, which is defined as such:
187
+ #
188
+ # Ruport::Query.add_source(:test, :dsn => "dbi:mysql:test",
189
+ # :user => "root" )
190
+ #
191
+ #
192
+ # The following report would use that data source rather than the
193
+ # <tt>:default</tt> source:
194
+ #
195
+ # class MyReport < Ruport::Report
196
+ #
197
+ # renders_as_table
198
+ #
199
+ # def generate
200
+ # use_source :test
201
+ # query "select * from foo"
202
+ # end
203
+ #
204
+ # end
205
+ def use_source(label)
206
+ @source = label
207
+ end
208
+
209
+ # Writes the contents of Report#results to file.
210
+ # If given a string as a second argument, writes that to file, instead.
211
+ #
212
+ # Examples:
213
+ #
214
+ # # write the results of the report to a file
215
+ # Report.run { |r| r.write("foo.txt") }
216
+ #
217
+ # # write the results in reverse
218
+ # Report.run { |r| r.write("foo.txt",r.results.reverse) }
219
+ #
220
+ def write(my_file=file,my_results=results)
221
+ File.open(my_file,"w") { |f| f << my_results }
222
+ end
223
+
224
+ # Behaves the same way as Report#write, but will append to a file rather
225
+ # than create a new file if it already exists.
226
+ #
227
+ def append(my_file=file,my_results=results)
228
+ File.open(my_file,"a") { |f| f << my_results }
229
+ end
230
+
231
+ # This method passes <tt>self</tt> to Report.run.
232
+ #
233
+ # Please see the class method for details.
234
+ #
235
+ def run(options={},&block)
236
+ options[:reports] ||= [self]
237
+ self.class.run(options,&block)
238
+ end
239
+
240
+ # Allows you to override the default format.
241
+ #
242
+ # Example:
243
+ #
244
+ # my_report.as(:csv)
245
+ #
246
+ def as(format,*args)
247
+ self.format,old = format, self.format
248
+ results = run(*args)
249
+ self.format = old
250
+ return results
251
+ end
252
+
253
+ # Provides syntactic sugar, allowing to_foo in place of as(:foo)
254
+ def method_missing(id,*args)
255
+ id.to_s =~ /^to_(.*)/
256
+ $1 ? as($1.to_sym,*args) : super
257
+ end
258
+
259
+ # Loads a CSV in from a file.
260
+ #
261
+ # Example:
262
+ #
263
+ # my_table = load_csv "foo.csv" #=> Data::Table
264
+ # my_array = load_csv "foo.csv", :as => :array #=> Array
265
+ #
266
+ # See also Ruport::Data::Table.load and Table()
267
+ #
268
+ def load_csv(file,options={})
269
+ case options[:as]
270
+ when :array
271
+ a = []
272
+ Data::Table.load(file,options) { |s,r| a << r } ; a
273
+ else
274
+ Data::Table.load(file,options)
275
+ end
276
+ end
277
+
278
+ # Executes an erb template. If a filename is given which matches the
279
+ # pattern /\.r\w+$/ (eg foo.rhtml, bar.rtxt, etc),
280
+ # it will be loaded and evaluated. Otherwise, the string will be processed
281
+ # directly.
282
+ #
283
+ # Examples:
284
+ #
285
+ # @foo = 'greg'
286
+ # erb "My name is <%= @foo %>" #=> "My name is greg"
287
+ #
288
+ # erb "foo.rhtml" #=> contents of evaluated text in foo.rhtml
289
+ #
290
+ def erb(s)
291
+ if s =~ /\.r\w+$/
292
+ ERB.new(File.read(s)).result(binding)
293
+ else
294
+ ERB.new(s).result(binding)
295
+ end
296
+ end
297
+
298
+ class << self
299
+
300
+ # Allows you to override the default format.
301
+ #
302
+ # Example:
303
+ #
304
+ # my_report.as(:csv)
305
+ #
306
+ def as(format,options={})
307
+ report = new(format)
308
+ report.run(rendering_options.merge(options))
309
+ end
310
+
311
+ # Provides syntactic sugar, allowing to_foo in place of as(:foo)
312
+ def method_missing(id,*args)
313
+ id.to_s =~ /^to_(.*)/
314
+ $1 ? as($1.to_sym,*args) : super
315
+ end
316
+
317
+ # Defines an instance method which will be run before the
318
+ # <tt>generate</tt> method when Ruport.run is executed.
319
+ #
320
+ # Good for setting config info and perhaps files and/or loggers.
321
+ #
322
+ def prepare(&block); define_method(:prepare,&block) end
323
+
324
+ # Defines an instance method which will be executed by Report.run.
325
+ #
326
+ # The return value of this method is assigned to the <tt>results</tt>
327
+ # attribute.
328
+ #
329
+ def generate(&block); define_method(:generate,&block) end
330
+
331
+ # Defines an instance method which will be executed after the object is
332
+ # yielded in Report.run.
333
+ #
334
+ def cleanup(&block); define_method(:cleanup,&block) end
335
+
336
+ private :prepare, :generate, :cleanup
337
+
338
+ # Runs the reports specified. If no reports are specified, then it
339
+ # creates a new instance via <tt>self.new</tt>.
340
+ #
341
+ # Hooks called, in order:
342
+ # * Report#prepare
343
+ # * Report#generate #=> return value stored in @results
344
+ # * yields self to block, if given
345
+ # * if a renderer is specified, passes along @results and options
346
+ # * Report#cleanup
347
+ #
348
+ # Options:
349
+ # :reports: A list of reports to run, defaults to a single generic
350
+ # instance of the current report (self.new).
351
+ #
352
+ # :tries:, :timeout:, :interval: Wrappers on attempt.rb
353
+ #
354
+ # all other options will be forwarded to a renderer if one is specified
355
+ # via the Renderer::Hooks methods
356
+ def run(options={})
357
+ options[:reports] ||= [self.new]
358
+
359
+ formatting_options = ( options.keys -
360
+ [:reports,:tries,:timeout,:interval])
361
+
362
+ fopts = formatting_options.inject({}) { |s,k|
363
+ s.merge( k => options[k] )
364
+ }
365
+
366
+
367
+ process = lambda do
368
+ options[:reports].each { |rep|
369
+ rep.prepare if rep.respond_to? :prepare
370
+ rep.results = rep.generate
371
+
372
+ if renderer
373
+ rep.results =
374
+ renderer.render(rep.format,rendering_options.merge(fopts)) { |r|
375
+ r.data = rep.results
376
+ }
377
+ end
378
+
379
+ yield(rep) if block_given?
380
+ rep.cleanup if rep.respond_to? :cleanup
381
+ }
382
+ end
383
+
384
+ if options[:tries] && (options[:interval] || options[:timeout])
385
+ code = Attempt.new { |a|
386
+ a.tries = options[:tries]
387
+ a.interval = options[:interval] if options[:interval]
388
+ a.timeout = options[:timeout] if options[:timeout]
389
+ }
390
+ code.attempt(&process)
391
+ else
392
+ process.call
393
+ end
394
+
395
+ outs = options[:reports].map { |r| r.results }
396
+ if outs.length == 1
397
+ outs.last
398
+ else
399
+ outs
400
+ end
401
+
402
+ end
403
+ end
404
+ end
405
+ end
data/lib/ruport/util.rb CHANGED
@@ -1,5 +1,12 @@
1
+ module Ruport
2
+ module Util
3
+ VERSION = "0.4.0"
4
+ end
5
+ end
6
+ require "ruport/util/report"
1
7
  require "ruport/util/graph"
2
8
  require "ruport/util/invoice"
3
9
  require "ruport/util/report_manager"
4
10
  require "ruport/util/mailer"
5
11
  require "ruport/util/bench"
12
+ require "ruport/util/generator"
@@ -0,0 +1,3 @@
1
+ <%= @results %>
2
+ <%= 2 + 2 %>
3
+ ---
@@ -0,0 +1,218 @@
1
+ #tc_report.rb
2
+ #
3
+ # Created by Gregory Thomas Brown on 2005-08-09
4
+ # Copyright 2005 (Gregory Brown) All rights reserved.
5
+
6
+ require "test/unit"
7
+ begin; require "rubygems"; rescue LoadError; nil; end
8
+ require "ruport"
9
+ require "ruport/util/report"
10
+
11
+ begin
12
+ require 'mocha'
13
+ require 'stubba'
14
+ require 'net/smtp'
15
+ rescue LoadError
16
+ $stderr.puts "Warning: Mocha not found -- skipping some Report tests"
17
+ end
18
+
19
+ class SampleReport < Ruport::Report
20
+ renders_with Ruport::Renderer::Table
21
+
22
+ def generate
23
+ Table(%w[not abc]) << %w[o r] << %w[one two] << %w[thr ee]
24
+ end
25
+ end
26
+
27
+ class TestReport < Test::Unit::TestCase
28
+ include Ruport
29
+
30
+ def setup
31
+ @report = Report.new
32
+ end
33
+
34
+ def test_renders_with_shortcuts
35
+ a = SampleReport.new(:csv)
36
+ assert_equal("not,abc\no,r\none,two\nthr,ee\n",a.run)
37
+ assert_equal("not,abc\no,r\none,two\nthr,ee\n",SampleReport.as(:csv))
38
+ assert_equal("not,abc\no,r\none,two\nthr,ee\n",SampleReport.to_csv)
39
+ assert_equal("not,abc\no,r\none,two\nthr,ee\n",a.to_csv)
40
+ a = SampleReport.new
41
+ assert_equal("not,abc\no,r\none,two\nthr,ee\n",a.to_csv)
42
+
43
+ assert_nil nil, a.format
44
+ a.to_text
45
+
46
+ assert_nil a.format
47
+ end
48
+
49
+ def test_erb
50
+ @report = Report.new
51
+ @report.results = "foo"
52
+ assert_equal "foo", @report.erb("<%= @results %>")
53
+ assert_equal "foo\n4\n---\n", @report.erb("test/samples/foo.rtxt")
54
+ end
55
+
56
+ class MyReport < Report; end
57
+
58
+ def test_klass_methods
59
+ rep_klass = MyReport.dup
60
+ rep_klass.send(:prepare) { self.file = "foo.csv" }
61
+ rep_klass.send(:generate) { "hello dolly" }
62
+ rep_klass.send(:cleanup) { @foo = "bar" }
63
+ report = rep_klass.new
64
+ report.run { |rep|
65
+ assert_equal("foo.csv",rep.file)
66
+ assert_equal("hello dolly",rep.results)
67
+ assert_equal(nil,rep.instance_eval("@foo"))
68
+ }
69
+ assert_equal("bar",report.instance_eval("@foo"))
70
+ end
71
+
72
+ def test_multi_reports
73
+ rep_klass = MyReport.dup
74
+
75
+ report1 = rep_klass.new
76
+ report2 = rep_klass.new
77
+
78
+ report1.file = "foo"
79
+ report2.file = "bar"
80
+
81
+ rep_klass.send(:generate) { file }
82
+
83
+ expected = %w[foo bar]
84
+
85
+ rep_klass.run :reports => [report1,report2] do |rep|
86
+ assert_equal expected.shift, rep.results
87
+ end
88
+
89
+ end
90
+
91
+
92
+ def test_timeout
93
+ rep_klass = MyReport.dup
94
+ rep_klass.send(:generate) { raise }
95
+
96
+ assert_raises(RuntimeError){
97
+ rep_klass.run(:tries => 3, :interval => 1)
98
+ }
99
+
100
+ rep_klass.send(:generate) { sleep 1.1 }
101
+
102
+ assert_raises(Timeout::Error) {
103
+ rep_klass.run( :tries => 2,
104
+ :timeout => 1,
105
+ :interval => 1,
106
+ :log_level => :log_only)
107
+ }
108
+
109
+ end
110
+
111
+ def test_return_value
112
+ rep_klass = MyReport.dup
113
+ rep_klass.send(:generate) { "hello dolly" }
114
+
115
+ # single report
116
+ assert_equal "hello dolly", rep_klass.run
117
+
118
+ # multiple reports
119
+ assert_equal ["hello dolly", "hello dolly"],
120
+ rep_klass.run(:reports => [rep_klass.new,rep_klass.new])
121
+ end
122
+
123
+ def test_write_to_file
124
+ return unless Object.const_defined? :Mocha
125
+ file = mock("file")
126
+
127
+ File.expects(:open).
128
+ with("foo.csv","w").yields(file).returns(file).at_least_once
129
+
130
+ file.expects(:<<).
131
+ with("results").returns(file).at_least_once
132
+
133
+ @report = Report.new
134
+ assert @report.write("foo.csv", "results")
135
+ end
136
+
137
+ def test_append_to_file
138
+ return unless Object.const_defined? :Mocha
139
+ file = mock("file")
140
+
141
+ File.expects(:open).
142
+ with("foo.csv","a").yields(file).returns(file).at_least_once
143
+
144
+ file.expects(:<<).
145
+ with("results").returns(file).at_least_once
146
+
147
+ @report = Report.new
148
+ assert @report.append("foo.csv", "results")
149
+ end
150
+
151
+ def test_load_csv
152
+ expected = [%w[a b c],['d', nil, 'e']].to_table(%w[col1 col2 col3])
153
+
154
+ @report = Report.new
155
+ table = @report.load_csv("test/samples/data.csv")
156
+
157
+ assert_equal expected, table
158
+ end
159
+
160
+ def test_load_csv_as_array
161
+ expected = [%w[a b c],['d', nil, 'e']]
162
+
163
+ @report = Report.new
164
+ array = @report.load_csv("test/samples/data.csv", :as => :array)
165
+
166
+ assert_equal expected, array
167
+ end
168
+
169
+ def test_renders_with
170
+ klass = MyReport.dup
171
+ klass.renders_with Ruport::Renderer::Table
172
+ klass.send(:generate) { [[1,2,3],[4,5,6]].to_table(%w[a b c]) }
173
+ a = klass.new(:csv)
174
+ assert_equal "a,b,c\n1,2,3\n4,5,6\n", a.run
175
+
176
+ klass.renders_with Ruport::Renderer::Table, :show_table_headers => false
177
+ a = klass.new(:csv)
178
+ assert_equal "1,2,3\n4,5,6\n", a.run
179
+ assert_equal "a,b,c\n1,2,3\n4,5,6\n", a.run(:show_table_headers => true)
180
+
181
+
182
+ end
183
+
184
+ def test_renders_as_table
185
+ klass = MyReport.dup
186
+ klass.renders_as_table
187
+ klass.send(:generate) { [[1,2,3],[4,5,6]].to_table(%w[a b c]) }
188
+ a = klass.new(:csv)
189
+ assert_equal "a,b,c\n1,2,3\n4,5,6\n", a.run
190
+ end
191
+
192
+ def test_renders_as_row
193
+ klass = MyReport.dup
194
+ klass.renders_as_row
195
+ klass.send(:generate) { [[1,2,3]].to_table(%w[a b c])[0] }
196
+ a = klass.new(:csv)
197
+ assert_equal "1,2,3\n", a.run
198
+ end
199
+
200
+ def test_renders_as_group
201
+ klass = MyReport.dup
202
+ klass.renders_as_group
203
+ klass.send(:generate) { [[1,2,3]].to_table(%w[a b c]).to_group("foo") }
204
+ a = klass.new(:csv)
205
+ assert_equal "foo\n\na,b,c\n1,2,3\n", a.run
206
+ end
207
+
208
+ def test_renders_as_grouping
209
+ klass = MyReport.dup
210
+ klass.renders_as_grouping
211
+ klass.send(:generate) {
212
+ Grouping([[1,2,3],[4,5,6]].to_table(%w[a b c]),:by => "a")
213
+ }
214
+ a = klass.new(:csv)
215
+ assert_equal "1\n\nb,c\n2,3\n\n4\n\nb,c\n5,6\n\n", a.run
216
+ end
217
+
218
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: ruport-util
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.0
7
- date: 2007-04-22 00:00:00 -04:00
6
+ version: 0.4.0
7
+ date: 2007-05-01 00:00:00 -04:00
8
8
  summary: A set of tools and helper libs for Ruby Reports
9
9
  require_paths:
10
10
  - lib
@@ -29,38 +29,44 @@ post_install_message:
29
29
  authors:
30
30
  - Gregory Brown
31
31
  files:
32
+ - example/graph_report.rb
32
33
  - example/invoice_report.rb
33
- - example/managed_report.rb
34
34
  - example/mailer.rb
35
- - example/graph_report.rb
35
+ - example/managed_report.rb
36
36
  - lib/ruport
37
37
  - lib/ruport/util
38
38
  - lib/ruport/util.rb
39
- - lib/ruport/util/mailer.rb
40
39
  - lib/ruport/util/bench.rb
40
+ - lib/ruport/util/generator.rb
41
41
  - lib/ruport/util/graph.rb
42
- - lib/ruport/util/report_manager.rb
43
42
  - lib/ruport/util/invoice.rb
44
- - test/samples
43
+ - lib/ruport/util/mailer.rb
44
+ - lib/ruport/util/report.rb
45
+ - lib/ruport/util/report_manager.rb
45
46
  - test/init.rb
46
- - test/test_report_manager.rb
47
+ - test/samples
47
48
  - test/test_graph_renderer.rb
48
- - test/test_mailer.rb
49
49
  - test/test_invoice.rb
50
+ - test/test_mailer.rb
51
+ - test/test_report.rb
52
+ - test/test_report_manager.rb
50
53
  - test/samples/data.csv
54
+ - test/samples/foo.rtxt
55
+ - bin/rope
51
56
  - Rakefile
52
57
  test_files:
53
- - test/test_report_manager.rb
54
58
  - test/test_graph_renderer.rb
55
- - test/test_mailer.rb
56
59
  - test/test_invoice.rb
60
+ - test/test_mailer.rb
61
+ - test/test_report.rb
62
+ - test/test_report_manager.rb
57
63
  rdoc_options:
58
64
  - --title
59
65
  - Ruport Documentation
60
66
  extra_rdoc_files: []
61
67
 
62
- executables: []
63
-
68
+ executables:
69
+ - rope
64
70
  extensions: []
65
71
 
66
72
  requirements: []