ruport 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +4 -2
- data/README +4 -3
- data/Rakefile +1 -1
- data/lib/ruport.rb +1 -4
- data/lib/ruport/config.rb +6 -11
- data/lib/ruport/data/collection.rb +8 -2
- data/lib/ruport/data/groupable.rb +0 -2
- data/lib/ruport/data/record.rb +0 -13
- data/lib/ruport/data/set.rb +0 -8
- data/lib/ruport/data/table.rb +1 -18
- data/lib/ruport/data/taggable.rb +1 -6
- data/lib/ruport/format/latex.rb +5 -8
- data/lib/ruport/format/pdf.rb +56 -0
- data/lib/ruport/format/plugin.rb +5 -0
- data/lib/ruport/format/svg.rb +26 -4
- data/lib/ruport/format/text.rb +25 -2
- data/lib/ruport/format/xml.rb +1 -1
- data/lib/ruport/generator.rb +1 -1
- data/lib/ruport/mailer.rb +1 -4
- data/lib/ruport/query.rb +0 -9
- data/lib/ruport/renderer.rb +15 -1
- data/lib/ruport/report.rb +5 -22
- data/test/test_mailer.rb +86 -24
- data/test/test_report.rb +72 -1
- data/test/test_table.rb +15 -0
- data/test/unit.log +7 -277
- metadata +34 -44
- data/lib/ruport.rb~ +0 -69
- data/lib/ruport/data.rb.rej +0 -5
- data/lib/ruport/data.rb~ +0 -1
- data/lib/ruport/data/record.rb~ +0 -236
- data/lib/ruport/data/table.rb.rej +0 -67
- data/lib/ruport/data/table.rb~ +0 -414
- data/test/test_query.rb.rej +0 -161
- data/test/test_query.rb~ +0 -337
- data/test/test_record.rb.rej +0 -46
- data/test/test_table.rb~ +0 -336
data/lib/ruport/renderer.rb
CHANGED
@@ -33,7 +33,8 @@ class Ruport::Renderer
|
|
33
33
|
plugin.send something if plugin.respond_to? something
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
|
+
# Allows you to register a format with the renderer.
|
37
38
|
#
|
38
39
|
# example:
|
39
40
|
#
|
@@ -44,9 +45,11 @@ class Ruport::Renderer
|
|
44
45
|
# SomeRenderer.add_format self, :my_plugin
|
45
46
|
#
|
46
47
|
# end
|
48
|
+
#
|
47
49
|
def self.add_format(format,name=nil)
|
48
50
|
return formats[name] = format if name
|
49
51
|
|
52
|
+
# NOTE: MEANT FOR INTERNAL USE
|
50
53
|
add_core_format(format)
|
51
54
|
end
|
52
55
|
|
@@ -58,6 +61,7 @@ class Ruport::Renderer
|
|
58
61
|
|
59
62
|
# same as Renderer#layout, but can be used to specify a default layout object
|
60
63
|
# for the entire class.
|
64
|
+
#
|
61
65
|
def self.layout
|
62
66
|
@layout ||= Ruport::Layout::Component.new
|
63
67
|
yield(@layout) if block_given?
|
@@ -72,6 +76,7 @@ class Ruport::Renderer
|
|
72
76
|
# The run() method is then called on the renderer method.
|
73
77
|
#
|
74
78
|
# Finally, the value of the plugin's output accessor is returned
|
79
|
+
#
|
75
80
|
def self.render(format,&block)
|
76
81
|
rend = build format, &block
|
77
82
|
rend.run
|
@@ -84,6 +89,7 @@ class Ruport::Renderer
|
|
84
89
|
# yielded.
|
85
90
|
#
|
86
91
|
# Returns the renderer instance.
|
92
|
+
#
|
87
93
|
def self.build(format)
|
88
94
|
rend = self.new
|
89
95
|
|
@@ -108,6 +114,7 @@ class Ruport::Renderer
|
|
108
114
|
end
|
109
115
|
|
110
116
|
# sets +data+ attribute on both the renderer and any active plugin
|
117
|
+
#
|
111
118
|
def data=(val)
|
112
119
|
@data = val.dup
|
113
120
|
plugin.data = @data if plugin
|
@@ -115,6 +122,7 @@ class Ruport::Renderer
|
|
115
122
|
|
116
123
|
# General purpose openstruct which is shared with the current formatting
|
117
124
|
# plugin.
|
125
|
+
#
|
118
126
|
def options
|
119
127
|
yield(plugin.options) if block_given?
|
120
128
|
plugin.options
|
@@ -127,6 +135,7 @@ class Ruport::Renderer
|
|
127
135
|
#
|
128
136
|
# when a block is given without block variables, instance_evals the block
|
129
137
|
# within the context of the plugin
|
138
|
+
#
|
130
139
|
def plugin(&block)
|
131
140
|
if block.nil?
|
132
141
|
return @plugin
|
@@ -150,6 +159,7 @@ class Ruport::Renderer
|
|
150
159
|
|
151
160
|
# tries to autoload and register a format which is part of the Ruport::Format
|
152
161
|
# module. For internal use only.
|
162
|
+
#
|
153
163
|
def self.add_core_format(format)
|
154
164
|
try_require(format)
|
155
165
|
|
@@ -160,12 +170,14 @@ class Ruport::Renderer
|
|
160
170
|
end
|
161
171
|
|
162
172
|
# internal shortcut for format registering
|
173
|
+
#
|
163
174
|
def self.add_formats(*formats)
|
164
175
|
formats.each { |f| add_format f }
|
165
176
|
end
|
166
177
|
|
167
178
|
# Trys to autoload a given format,
|
168
179
|
# silently fails
|
180
|
+
#
|
169
181
|
def self.try_require(format)
|
170
182
|
begin
|
171
183
|
require "ruport/format/#{format}"
|
@@ -175,12 +187,14 @@ class Ruport::Renderer
|
|
175
187
|
end
|
176
188
|
|
177
189
|
# selects a plugin for use by format name
|
190
|
+
#
|
178
191
|
def use_plugin(format)
|
179
192
|
self.plugin = self.class.formats[format].new
|
180
193
|
end
|
181
194
|
|
182
195
|
# provides a shortcut to render() to allow
|
183
196
|
# render(:csv) to become render_csv
|
197
|
+
#
|
184
198
|
def self.method_missing(id,*args,&block)
|
185
199
|
id.to_s =~ /^render_(.*)/
|
186
200
|
$1 ? render($1.to_sym,&block) : super
|
data/lib/ruport/report.rb
CHANGED
@@ -63,16 +63,9 @@ module Ruport
|
|
63
63
|
# }
|
64
64
|
#
|
65
65
|
#
|
66
|
-
# This class can also be used to run templates and process text filters.
|
67
|
-
#
|
68
|
-
# See the examples in the documentation below to see how to use these
|
69
|
-
# features (namely Report#process_text , Report#text_processor, and
|
70
|
-
# Report#eval_template).
|
71
|
-
#
|
72
66
|
class Report
|
73
67
|
extend Forwardable
|
74
68
|
|
75
|
-
#
|
76
69
|
# When initializing a report, you can provide a default mailer and source by
|
77
70
|
# giving a name of a valid source or mailer you've defined via
|
78
71
|
# Ruport::Config.
|
@@ -93,7 +86,6 @@ module Ruport
|
|
93
86
|
# By default, this file will be used by Report#write.
|
94
87
|
attr_accessor :file
|
95
88
|
|
96
|
-
#
|
97
89
|
# This attribute will get the results of Report#generate when the report is
|
98
90
|
# run.
|
99
91
|
#
|
@@ -114,9 +106,9 @@ module Ruport
|
|
114
106
|
# # will return the value of the last statement, "select * from foo"
|
115
107
|
# result = query "insert into foo values(1,2); select * from foo"
|
116
108
|
#
|
117
|
-
# You can iterate by row
|
109
|
+
# You can iterate by row:
|
118
110
|
#
|
119
|
-
# query("select * from foo"
|
111
|
+
# query("select * from foo") { |r|
|
120
112
|
# #do something with the rows here
|
121
113
|
# }
|
122
114
|
#
|
@@ -165,7 +157,6 @@ module Ruport
|
|
165
157
|
File.open(my_file,"w") { |f| f << my_results }
|
166
158
|
end
|
167
159
|
|
168
|
-
#
|
169
160
|
# Like Report#write, but will append to a file rather than overwrite it if
|
170
161
|
# the file already exists.
|
171
162
|
#
|
@@ -182,7 +173,6 @@ module Ruport
|
|
182
173
|
self.class.run(options,&block)
|
183
174
|
end
|
184
175
|
|
185
|
-
#
|
186
176
|
# Loads a CSV in from a file.
|
187
177
|
#
|
188
178
|
# Example:
|
@@ -202,7 +192,6 @@ module Ruport
|
|
202
192
|
end
|
203
193
|
end
|
204
194
|
|
205
|
-
#
|
206
195
|
# Executes an erb template. If a filename is given which matches the
|
207
196
|
# pattern /\.r\w+$/ (eg foo.rhtml, bar.rtxt, etc),
|
208
197
|
# it will be loaded and evaluated. Otherwise, the string will be processed
|
@@ -234,13 +223,11 @@ module Ruport
|
|
234
223
|
RedCloth.new(s).to_html
|
235
224
|
end
|
236
225
|
|
237
|
-
#
|
238
226
|
# Allows logging and other fun stuff.
|
239
227
|
# See also Ruport.log
|
240
228
|
#
|
241
229
|
def log(*args); Ruport.log(*args) end
|
242
230
|
|
243
|
-
#
|
244
231
|
# Creates a new Mailer and sets the <tt>to</tt> attribute to the addresses
|
245
232
|
# specified. Yields a Mailer object, which can be modified before delivery.
|
246
233
|
#
|
@@ -256,7 +243,6 @@ module Ruport
|
|
256
243
|
|
257
244
|
class << self
|
258
245
|
|
259
|
-
#
|
260
246
|
# Defines an instance method which will be run before the
|
261
247
|
# <tt>generate</tt> method when Ruport.run is executed.
|
262
248
|
#
|
@@ -264,7 +250,6 @@ module Ruport
|
|
264
250
|
#
|
265
251
|
def prepare(&block); define_method(:prepare,&block) end
|
266
252
|
|
267
|
-
#
|
268
253
|
# Defines an instance method which will be executed by Report.run.
|
269
254
|
#
|
270
255
|
# The return value of this method is assigned to the <tt>results</tt>
|
@@ -272,13 +257,13 @@ module Ruport
|
|
272
257
|
#
|
273
258
|
def generate(&block); define_method(:generate,&block) end
|
274
259
|
|
275
|
-
#
|
276
260
|
# Defines an instance method which will be executed after the object is
|
277
261
|
# yielded in Report.run.
|
278
262
|
#
|
279
263
|
def cleanup(&block); define_method(:cleanup,&block) end
|
264
|
+
|
265
|
+
private :prepare, :generate, :cleanup
|
280
266
|
|
281
|
-
#
|
282
267
|
# Runs the reports specified. If no reports are specified, then it
|
283
268
|
# creates a new instance via <tt>self.new</tt>.
|
284
269
|
#
|
@@ -290,9 +275,7 @@ module Ruport
|
|
290
275
|
#
|
291
276
|
# This method will return the contents of Report#results, as a single
|
292
277
|
# value for single reports, and an array of outputs for multiple reports.
|
293
|
-
|
294
|
-
private :prepare, :generate, :cleanup
|
295
|
-
|
278
|
+
#
|
296
279
|
def run(options={})
|
297
280
|
options[:reports] ||= [self.new]
|
298
281
|
|
data/test/test_mailer.rb
CHANGED
@@ -2,6 +2,14 @@ require "test/unit"
|
|
2
2
|
require "ruport"
|
3
3
|
begin; require "rubygems"; rescue LoadError; nil end
|
4
4
|
|
5
|
+
begin
|
6
|
+
require 'mocha'
|
7
|
+
require 'stubba'
|
8
|
+
require 'net/smtp'
|
9
|
+
rescue LoadError
|
10
|
+
$stderr.puts "Warning: Mocha not found -- skipping some Mailer tests"
|
11
|
+
end
|
12
|
+
|
5
13
|
class TestMailer < Test::Unit::TestCase
|
6
14
|
|
7
15
|
def setup
|
@@ -40,7 +48,12 @@ class TestMailer < Test::Unit::TestCase
|
|
40
48
|
def test_constructor_with_mailer_label
|
41
49
|
assert_mailer_equal @other_opts, @other_mailer
|
42
50
|
end
|
43
|
-
|
51
|
+
|
52
|
+
def test_constructor_without_mailer
|
53
|
+
Ruport::Config.mailers[:default] = nil
|
54
|
+
assert_raise(RuntimeError) { Ruport::Mailer.new }
|
55
|
+
end
|
56
|
+
|
44
57
|
def test_select_mailer
|
45
58
|
mailer = Ruport::Mailer.new :default
|
46
59
|
assert_mailer_equal @default_opts, mailer
|
@@ -79,30 +92,79 @@ class TestMailer < Test::Unit::TestCase
|
|
79
92
|
assert_equal ['RuportDay!'], @default_mailer.subject
|
80
93
|
end
|
81
94
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
def
|
103
|
-
|
104
|
-
|
95
|
+
def test_send_mail_with_default
|
96
|
+
return unless Object.const_defined? :Mocha
|
97
|
+
setup_mock_mailer(1)
|
98
|
+
assert_equal "250 ok",
|
99
|
+
@default_mailer.deliver(:to => "clyde@example.com",
|
100
|
+
:from => "sue@example.com",
|
101
|
+
:subject => "Hello",
|
102
|
+
:text => "This is a test.")
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_send_mail_with_other
|
106
|
+
return unless Object.const_defined? :Mocha
|
107
|
+
setup_mock_mailer(1, @other_mailer)
|
108
|
+
assert_equal "250 ok",
|
109
|
+
@other_mailer.deliver(:to => "sue@example.com",
|
110
|
+
:from => "clyde@example.com",
|
111
|
+
:subject => "Hello",
|
112
|
+
:text => "This is a test.")
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_send_mail_without_to
|
116
|
+
return unless Object.const_defined? :Mocha
|
117
|
+
setup_mock_mailer(1)
|
118
|
+
assert_raise(Net::SMTPSyntaxError) {
|
119
|
+
@default_mailer.deliver(:from => "sue@example.com",
|
120
|
+
:subject => "Hello",
|
121
|
+
:text => "This is a test.")
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_send_html_mail
|
126
|
+
return unless Object.const_defined? :Mocha
|
127
|
+
setup_mock_mailer(1)
|
128
|
+
assert_equal "250 ok",
|
129
|
+
@default_mailer.deliver(:to => "clyde@example.com",
|
130
|
+
:from => "sue@example.com",
|
131
|
+
:subject => "Hello",
|
132
|
+
:html => "<p>This is a test.</p>")
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_send_mail_with_attachment
|
136
|
+
return unless Object.const_defined? :Mocha
|
137
|
+
setup_mock_mailer(1)
|
138
|
+
@default_mailer.attach 'test/samples/data.csv'
|
139
|
+
assert_equal "250 ok",
|
140
|
+
@default_mailer.deliver(:to => "clyde@example.com",
|
141
|
+
:from => "sue@example.com",
|
142
|
+
:subject => "Hello",
|
143
|
+
:text => "This is a test.")
|
105
144
|
end
|
106
145
|
|
146
|
+
private
|
147
|
+
|
148
|
+
def setup_mock_mailer(count, mailer=@default_mailer)
|
149
|
+
host = mailer.instance_variable_get(:@host)
|
150
|
+
port = mailer.instance_variable_get(:@port)
|
151
|
+
user = mailer.instance_variable_get(:@user)
|
152
|
+
password = mailer.instance_variable_get(:@password)
|
153
|
+
auth = mailer.instance_variable_get(:@auth)
|
154
|
+
|
155
|
+
@smtp = mock('smtp')
|
156
|
+
|
157
|
+
Net::SMTP.expects(:start).
|
158
|
+
with(host,port,host,user,password,auth).
|
159
|
+
yields(@smtp).
|
160
|
+
returns("250 ok").times(count)
|
161
|
+
@smtp.stubs(:send_message).
|
162
|
+
with {|*params| !params[2].nil? }.
|
163
|
+
returns("250 ok")
|
164
|
+
@smtp.stubs(:send_message).
|
165
|
+
with {|*params| params[2].nil? }.
|
166
|
+
raises(Net::SMTPSyntaxError)
|
167
|
+
end
|
168
|
+
|
107
169
|
end
|
108
170
|
|
data/test/test_report.rb
CHANGED
@@ -6,12 +6,22 @@
|
|
6
6
|
require "test/unit"
|
7
7
|
require "ruport"
|
8
8
|
begin; require "rubygems"; rescue LoadError; nil; end
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'mocha'
|
12
|
+
require 'stubba'
|
13
|
+
require 'net/smtp'
|
14
|
+
rescue LoadError
|
15
|
+
$stderr.puts "Warning: Mocha not found -- skipping some Report tests"
|
16
|
+
end
|
17
|
+
|
9
18
|
class TestReport < Test::Unit::TestCase
|
10
19
|
include Ruport
|
11
20
|
|
12
21
|
def setup
|
13
22
|
@report = Report.new
|
14
|
-
Ruport::Config.source :default, :dsn => "ruport:test",
|
23
|
+
Ruport::Config.source :default, :dsn => "ruport:test",
|
24
|
+
:user => "foo", :password => "bar"
|
15
25
|
@query1 = Ruport::Query.new "select * from foo", :cache_enabled => true
|
16
26
|
@query1.cached_data = [[1,2,3],[4,5,6],[7,8,9]].to_table(%w[a b c])
|
17
27
|
end
|
@@ -106,5 +116,66 @@ class TestReport < Test::Unit::TestCase
|
|
106
116
|
assert_equal ["hello dolly", "hello dolly"],
|
107
117
|
rep_klass.run(:reports => [rep_klass.new,rep_klass.new])
|
108
118
|
end
|
119
|
+
|
120
|
+
def test_send_to
|
121
|
+
return unless Object.const_defined? :Mocha
|
122
|
+
setup_mock_mailer
|
123
|
+
@report = Report.new
|
124
|
+
assert_equal "250 ok", @report.send_to("clyde@example.com") { |mail|
|
125
|
+
mail.subject = "Test Report"
|
126
|
+
mail.text = "Test"
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_write_to_file
|
131
|
+
return unless Object.const_defined? :Mocha
|
132
|
+
setup_mock_file
|
133
|
+
@report = Report.new
|
134
|
+
assert @report.write("foo.csv")
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_append_to_file
|
138
|
+
return unless Object.const_defined? :Mocha
|
139
|
+
setup_mock_file
|
140
|
+
@report = Report.new
|
141
|
+
assert @report.append("foo.csv")
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_load_csv
|
145
|
+
expected = [%w[a b c],['d', nil, 'e']].to_table(%w[col1 col2 col3])
|
146
|
+
|
147
|
+
@report = Report.new
|
148
|
+
table = @report.load_csv("test/samples/data.csv")
|
149
|
+
|
150
|
+
assert_equal expected, table
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_load_csv_as_array
|
154
|
+
expected = [%w[a b c],['d', nil, 'e']]
|
155
|
+
|
156
|
+
@report = Report.new
|
157
|
+
array = @report.load_csv("test/samples/data.csv", :as => :array)
|
158
|
+
|
159
|
+
assert_equal expected, array
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def setup_mock_mailer
|
165
|
+
@smtp = mock('smtp')
|
166
|
+
|
167
|
+
Net::SMTP.expects(:start).
|
168
|
+
yields(@smtp).
|
169
|
+
returns("250 ok").at_least_once
|
170
|
+
@smtp.stubs(:send_message).
|
171
|
+
returns("250 ok")
|
172
|
+
end
|
173
|
+
|
174
|
+
def setup_mock_file
|
175
|
+
@file = mock("file")
|
176
|
+
|
177
|
+
File.expects(:open).yields(@file).returns(@file).at_least_once
|
178
|
+
@file.expects(:<<).returns(@file).at_least_once
|
179
|
+
end
|
109
180
|
|
110
181
|
end
|
data/test/test_table.rb
CHANGED
@@ -294,6 +294,21 @@ class TestTable < Test::Unit::TestCase
|
|
294
294
|
|
295
295
|
end
|
296
296
|
|
297
|
+
|
298
|
+
#Ticket #142
|
299
|
+
def test_ensure_constructor_dups_record_tags
|
300
|
+
a = [[1,2,3],[4,5,6],[7,8,9]].to_table(%w[a b c])
|
301
|
+
b = a.dup
|
302
|
+
|
303
|
+
a[0].tag :foo
|
304
|
+
assert_equal [], b[0].tags
|
305
|
+
assert_equal [:foo],a[0].tags
|
306
|
+
|
307
|
+
b[1].tag :bar
|
308
|
+
assert_equal [], a[1].tags
|
309
|
+
assert_equal [:bar], b[1].tags
|
310
|
+
end
|
311
|
+
|
297
312
|
def test_setting_column_names_changes_record_attributes
|
298
313
|
table = Ruport::Data::Table.new :column_names => %w[a b c],
|
299
314
|
:data => [[1,2,3],[4,5,6]]
|