ruport 0.7.1 → 0.7.2
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/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]]
|