ruport-util 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile 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: []