ruport 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +4 -0
- data/CHANGELOG +10 -1
- data/Rakefile +1 -1
- data/examples/simple_table_interface.rb +20 -0
- data/lib/ruport.rb +87 -69
- data/lib/ruport/attempt.rb +1 -1
- data/lib/ruport/config.rb +198 -166
- data/lib/ruport/data.rb +6 -1
- data/lib/ruport/data/collection.rb +15 -8
- data/lib/ruport/data/groupable.rb +68 -6
- data/lib/ruport/data/record.rb +73 -34
- data/lib/ruport/data/record.rb~ +236 -0
- data/lib/ruport/data/set.rb +48 -13
- data/lib/ruport/data/table.rb +164 -74
- data/lib/ruport/data/table.rb.rej +67 -0
- data/lib/ruport/data/table.rb~ +153 -68
- data/lib/ruport/data/taggable.rb +37 -9
- data/lib/ruport/format.rb +1 -1
- data/lib/ruport/mailer.rb +41 -27
- data/lib/ruport/meta_tools.rb +26 -11
- data/lib/ruport/query.rb +102 -68
- data/lib/ruport/query/sql_split.rb +1 -1
- data/lib/ruport/report.rb +84 -58
- data/lib/ruport/report/graph.rb +1 -1
- data/lib/ruport/report/invoice.rb +1 -1
- data/test/test_query.rb +305 -48
- data/test/test_query.rb.rej +161 -0
- data/test/test_query.rb~ +337 -0
- data/test/test_record.rb +6 -0
- data/test/test_table.rb +18 -0
- data/test/test_table.rb~ +336 -0
- data/test/unit.log +180 -6
- metadata +8 -2
data/lib/ruport/report.rb
CHANGED
@@ -29,7 +29,7 @@ module Ruport
|
|
29
29
|
# require "ruport"
|
30
30
|
# require "fileutils"
|
31
31
|
# class MyReport < Ruport::Report
|
32
|
-
# prepare
|
32
|
+
# def prepare
|
33
33
|
# log_file "f.log"
|
34
34
|
# log "preparing report", :status => :info
|
35
35
|
# source :default,
|
@@ -40,12 +40,12 @@ module Ruport
|
|
40
40
|
# :address => "gregory.t.brown@gmail.com"
|
41
41
|
# end
|
42
42
|
#
|
43
|
-
# generate
|
43
|
+
# def generate
|
44
44
|
# log "generated csv from query", :status => :info
|
45
45
|
# query "select * from bar", :as => :csv
|
46
46
|
# end
|
47
47
|
#
|
48
|
-
# cleanup
|
48
|
+
# def cleanup
|
49
49
|
# log "removing foo.csv", :status => :info
|
50
50
|
# FileUtils.rm("foo.csv")
|
51
51
|
# end
|
@@ -63,24 +63,26 @@ module Ruport
|
|
63
63
|
# }
|
64
64
|
#
|
65
65
|
#
|
66
|
-
# This class can also be used to run templates and process text filters
|
66
|
+
# This class can also be used to run templates and process text filters.
|
67
67
|
#
|
68
68
|
# See the examples in the documentation below to see how to use these
|
69
|
-
# features
|
70
|
-
# Report#eval_template
|
69
|
+
# features (namely Report#process_text , Report#text_processor, and
|
70
|
+
# Report#eval_template).
|
71
71
|
#
|
72
72
|
class Report
|
73
73
|
extend Forwardable
|
74
74
|
|
75
75
|
include Ruport::Data::TableHelper
|
76
|
+
#
|
76
77
|
# When initializing a report, you can provide a default mailer and source by
|
77
78
|
# giving a name of a valid source or mailer you've defined via
|
78
|
-
# Ruport::Config
|
79
|
+
# Ruport::Config.
|
79
80
|
#
|
80
81
|
# If your report does not need any sort of specialized information, you can
|
81
|
-
# simply use Report.run (Or MyReportName.run if you've inherited)
|
82
|
+
# simply use Report.run (Or MyReportName.run if you've inherited).
|
82
83
|
#
|
83
84
|
# This will auto-initialize a report.
|
85
|
+
#
|
84
86
|
def initialize( source_name=:default, mailer_name=:default )
|
85
87
|
use_source source_name
|
86
88
|
use_mailer mailer_name
|
@@ -89,46 +91,49 @@ module Ruport
|
|
89
91
|
@file = nil
|
90
92
|
end
|
91
93
|
|
92
|
-
#
|
94
|
+
# By default, this file will be used by Report#write.
|
93
95
|
attr_accessor :file
|
94
96
|
|
95
|
-
#
|
96
|
-
#
|
97
|
+
#
|
98
|
+
# This attribute will get the results of Report#generate when the report is
|
99
|
+
# run.
|
100
|
+
#
|
97
101
|
attr_accessor :results
|
98
102
|
|
99
|
-
#
|
103
|
+
# This is a simplified interface to Ruport::Query.
|
100
104
|
#
|
101
|
-
#
|
105
|
+
# You can use it to read SQL statements from file or string:
|
102
106
|
#
|
103
|
-
#
|
104
|
-
#
|
107
|
+
# #from string
|
108
|
+
# result = query "select * from foo"
|
105
109
|
#
|
106
|
-
#
|
107
|
-
#
|
110
|
+
# #from file
|
111
|
+
# result = query "my_query.sql", :origin => :file
|
108
112
|
#
|
109
|
-
#
|
113
|
+
# You can use multistatement SQL:
|
110
114
|
#
|
111
|
-
#
|
112
|
-
#
|
115
|
+
# # will return the value of the last statement, "select * from foo"
|
116
|
+
# result = query "insert into foo values(1,2); select * from foo"
|
113
117
|
#
|
114
|
-
#
|
118
|
+
# You can iterate by row or return the entire set:
|
115
119
|
#
|
116
|
-
#
|
120
|
+
# query("select * from foo", :yield_type => :by_row) { |r|
|
117
121
|
# #do something with the rows here
|
118
|
-
#
|
122
|
+
# }
|
119
123
|
#
|
120
|
-
#
|
124
|
+
# query() can return raw DBI:Row objects or Ruport's data structures:
|
121
125
|
#
|
122
|
-
#
|
123
|
-
#
|
126
|
+
# # will return an Array of DBI::Row objects
|
127
|
+
# result = query "select * from foo", :raw_data => true
|
124
128
|
#
|
125
|
-
#
|
129
|
+
# You can quickly output in a number of formats:
|
126
130
|
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
131
|
+
# result = query "select * from foo", :as => :csv
|
132
|
+
# result = query "select * from foo", :as => :html
|
133
|
+
# result = query "select * from foo", :as => :pdf
|
134
|
+
#
|
135
|
+
# See Ruport::Query for details.
|
130
136
|
#
|
131
|
-
# See source of this function and methods of Ruport::Query for details.
|
132
137
|
def query(sql, options={})
|
133
138
|
options[:origin] ||= :string
|
134
139
|
options[:source] ||= @source
|
@@ -143,25 +148,28 @@ module Ruport
|
|
143
148
|
end
|
144
149
|
end
|
145
150
|
|
146
|
-
# Evaluates _code_ from _filename_ as pure ruby code for files ending in
|
147
|
-
# .rb, and as ERb templates for anything else.
|
148
151
|
#
|
149
|
-
#
|
150
|
-
#
|
152
|
+
# Evaluates <tt>code</tt> from <tt>filename</tt> as pure ruby code for
|
153
|
+
# files ending in .rb, and as ERb templates for anything else.
|
154
|
+
#
|
155
|
+
# This code will be evaluated in the context of the instance on which it
|
156
|
+
# is called.
|
157
|
+
#
|
151
158
|
def eval_template( code, filename=nil )
|
152
159
|
filename =~ /\.rb/ ? eval(code) : ERB.new(code, 0, "%").result(binding)
|
153
160
|
end
|
154
161
|
|
155
|
-
#
|
162
|
+
# Sets the active source to the Ruport::Config source requested by <tt>label</tt>.
|
156
163
|
def use_source(label)
|
157
164
|
@source = label
|
158
165
|
end
|
159
166
|
|
160
|
-
#
|
167
|
+
# Sets the active mailer to the Ruport::Config source requested by <tt>label</tt>.
|
161
168
|
def use_mailer(label)
|
162
169
|
@mailer = label
|
163
170
|
end
|
164
171
|
|
172
|
+
#
|
165
173
|
# Provides a nice way to execute templates and filters.
|
166
174
|
#
|
167
175
|
# Example:
|
@@ -170,6 +178,7 @@ module Ruport
|
|
170
178
|
#
|
171
179
|
# This method automatically passes a binding into the filters, so you are
|
172
180
|
# free to access data from your Report instance in your templates.
|
181
|
+
#
|
173
182
|
def process_text(string, options)
|
174
183
|
options[:filters].each do |f|
|
175
184
|
format = Format.new(binding)
|
@@ -179,60 +188,70 @@ module Ruport
|
|
179
188
|
string
|
180
189
|
end
|
181
190
|
|
182
|
-
#
|
191
|
+
#
|
192
|
+
# This allows you to create filters to be used by process_text.
|
183
193
|
#
|
184
194
|
# The block is evaluated in the context of the instance.
|
185
195
|
#
|
186
|
-
#
|
196
|
+
# Example:
|
187
197
|
#
|
188
198
|
# text_processor(:unix_newlines) { |r| r.gsub(/\r\n/,"\n") }
|
199
|
+
#
|
189
200
|
def text_processor(label,&block)
|
190
201
|
Format.register_filter(label, &block)
|
191
202
|
end
|
192
203
|
|
193
|
-
|
194
|
-
# Writes the contents of <tt>results</tt> to file. If a filename is
|
204
|
+
#
|
205
|
+
# Writes the contents of <tt>results</tt> to a file. If a filename is
|
195
206
|
# specified, it will use it. Otherwise, it will try to write to the file
|
196
207
|
# specified by the <tt>file</tt> attribute.
|
208
|
+
#
|
197
209
|
def write(my_file=file,my_results=results)
|
198
210
|
File.open(my_file,"w") { |f| f << my_results }
|
199
211
|
end
|
200
212
|
|
213
|
+
#
|
201
214
|
# Like Report#write, but will append to a file rather than overwrite it if
|
202
|
-
# the file already exists
|
215
|
+
# the file already exists.
|
216
|
+
#
|
203
217
|
def append(my_file=file)
|
204
218
|
File.open(my_file,"a") { |f| f << results }
|
205
219
|
end
|
206
220
|
|
207
221
|
class << self
|
208
222
|
|
223
|
+
#
|
209
224
|
# Defines an instance method which will be run before the
|
210
|
-
# <tt>generate</tt> method when Ruport.run is executed
|
225
|
+
# <tt>generate</tt> method when Ruport.run is executed.
|
211
226
|
#
|
212
|
-
# Good for setting config info and perhaps files and/or loggers
|
227
|
+
# Good for setting config info and perhaps files and/or loggers.
|
213
228
|
#
|
214
229
|
def prepare(&block); define_method(:prepare,&block) end
|
215
230
|
|
216
|
-
#
|
231
|
+
#
|
232
|
+
# Defines an instance method which will be executed by Report.run.
|
217
233
|
#
|
218
234
|
# The return value of this method is assigned to the <tt>results</tt>
|
219
|
-
# attribute
|
235
|
+
# attribute.
|
220
236
|
#
|
221
237
|
def generate(&block); define_method(:generate,&block) end
|
222
238
|
|
239
|
+
#
|
223
240
|
# Defines an instance method which will be executed after the object is
|
224
|
-
# yielded in Report.run
|
241
|
+
# yielded in Report.run.
|
225
242
|
#
|
226
243
|
def cleanup(&block); define_method(:cleanup,&block) end
|
227
244
|
|
245
|
+
#
|
228
246
|
# Runs the reports specified. If no reports are specified, then it
|
229
|
-
# creates a new instance via <tt>self.new</tt
|
247
|
+
# creates a new instance via <tt>self.new</tt>.
|
230
248
|
#
|
231
249
|
# Tries to execute the prepare instance method, then runs generate.
|
232
250
|
# It then yields the object so that you may do something with it
|
233
|
-
# (print something out, write to file, email, etc)
|
251
|
+
# (print something out, write to file, email, etc.).
|
234
252
|
#
|
235
253
|
# Finally, it tries to call cleanup.
|
254
|
+
#
|
236
255
|
def run(options={})
|
237
256
|
options[:reports] ||= [self.new]
|
238
257
|
|
@@ -260,23 +279,26 @@ module Ruport
|
|
260
279
|
|
261
280
|
end
|
262
281
|
|
263
|
-
#
|
282
|
+
#
|
283
|
+
# This method passes <tt>self</tt> to Report.run.
|
264
284
|
#
|
265
285
|
# Please see the class method for details.
|
286
|
+
#
|
266
287
|
def run(options={},&block)
|
267
288
|
options[:reports] ||= [self]
|
268
289
|
self.class.run(options,&block)
|
269
290
|
end
|
270
291
|
|
271
|
-
|
272
|
-
# loads a CSV in from file.
|
273
292
|
#
|
274
|
-
#
|
293
|
+
# Loads a CSV in from a file.
|
294
|
+
#
|
295
|
+
# Example:
|
296
|
+
#
|
297
|
+
# my_table = load_csv "foo.csv" #=> Data::Table
|
298
|
+
# my_array = load_csv "foo.csv", :as => :array #=> Array
|
275
299
|
#
|
276
|
-
#
|
277
|
-
# my_array = load_csv "foo.csv", :as => :array #=> Array
|
300
|
+
# See also Ruport::Data::Table.load
|
278
301
|
#
|
279
|
-
# See also, Ruport::Data::Table.load
|
280
302
|
def load_csv(file,options={})
|
281
303
|
case options[:as]
|
282
304
|
when :array
|
@@ -287,11 +309,15 @@ module Ruport
|
|
287
309
|
end
|
288
310
|
end
|
289
311
|
|
290
|
-
#
|
312
|
+
#
|
313
|
+
# Allows logging and other fun stuff.
|
314
|
+
# See also Ruport.log
|
315
|
+
#
|
291
316
|
def log(*args); Ruport.log(*args) end
|
292
317
|
|
318
|
+
#
|
293
319
|
# Creates a new Mailer and sets the <tt>to</tt> attribute to the addresses
|
294
|
-
# specified.
|
320
|
+
# specified. Yields a Mailer object, which can be modified before delivery.
|
295
321
|
#
|
296
322
|
def send_to(adds)
|
297
323
|
m = Mailer.new
|
data/lib/ruport/report/graph.rb
CHANGED
data/test/test_query.rb
CHANGED
@@ -1,80 +1,337 @@
|
|
1
1
|
require "test/unit"
|
2
2
|
require "ruport"
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'mocha'
|
6
|
+
require 'stubba'
|
7
|
+
require 'dbi'
|
8
|
+
rescue LoadError
|
9
|
+
$stderr.puts "Warning: Mocha not found -- skipping some Query tests"
|
10
|
+
end
|
5
11
|
|
12
|
+
class TestQuery < Test::Unit::TestCase
|
6
13
|
def setup
|
7
|
-
|
8
|
-
:
|
14
|
+
@sources = {
|
15
|
+
:default => {
|
16
|
+
:dsn => 'ruport:test', :user => 'greg', :password => 'apple' },
|
17
|
+
:alternative => {
|
18
|
+
:dsn => "ruport:test2", :user => "sandal", :password => "harmonix" },
|
19
|
+
}
|
20
|
+
Ruport::Config.source :default, @sources[:default]
|
21
|
+
Ruport::Config.source :alternative, @sources[:alternative]
|
22
|
+
|
23
|
+
@columns = %w(a b c)
|
24
|
+
@data = [ [[1,2,3],[4,5,6],[7,8,9]],
|
25
|
+
[[9,8,7],[6,5,4],[3,2,1]],
|
26
|
+
[[7,8,9],[4,5,6],[1,2,3]], ]
|
27
|
+
@datasets = @data.dup
|
28
|
+
|
29
|
+
@sql = [ "select * from foo", "create table foo ..." ]
|
30
|
+
@sql << @sql.values_at(0, 0).join(";\n")
|
31
|
+
@sql << @sql.values_at(1, 0).join(";\n")
|
32
|
+
@query = {
|
33
|
+
:plain => Ruport::Query.new(@sql[0]),
|
34
|
+
:sourced => Ruport::Query.new(@sql[0], :source => :alternative),
|
35
|
+
:paramed => Ruport::Query.new(@sql[0], :params => [ 42 ]),
|
36
|
+
:cached => Ruport::Query.new(@sql[0], :cache_enabled => true),
|
37
|
+
:uncached => Ruport::Query.new(@sql[0], :cache_enabled => false),
|
38
|
+
:precached => Ruport::Query.new(@sql[0], :cache_enabled => true),
|
39
|
+
:raw => Ruport::Query.new(@sql[0], :raw_data => true),
|
40
|
+
:unraw => Ruport::Query.new(@sql[0], :raw_data => false),
|
41
|
+
:resultless => Ruport::Query.new(@sql[1]),
|
42
|
+
:multi => Ruport::Query.new(@sql[2]),
|
43
|
+
:mixed => Ruport::Query.new(@sql[3]),
|
44
|
+
}
|
45
|
+
@query[:precached].cached_data = @data[0]
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_execute
|
49
|
+
return unless Object.const_defined? :Mocha
|
50
|
+
query = @query[:uncached]
|
51
|
+
setup_mock_dbi(1)
|
9
52
|
|
10
|
-
|
11
|
-
|
53
|
+
assert_equal nil, query.execute
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_execute_sourced
|
57
|
+
return unless Object.const_defined? :Mocha
|
58
|
+
query = @query[:sourced]
|
59
|
+
setup_mock_dbi(1, :source => :alternative)
|
60
|
+
|
61
|
+
assert_equal nil, query.execute
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_execute_paramed
|
65
|
+
return unless Object.const_defined? :Mocha
|
66
|
+
query = @query[:paramed]
|
67
|
+
setup_mock_dbi(1, :params => [ 42 ])
|
68
|
+
|
69
|
+
assert_equal nil, query.execute
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_result_cache_disabled
|
73
|
+
return unless Object.const_defined? :Mocha
|
74
|
+
query = @query[:uncached]
|
75
|
+
setup_mock_dbi(3)
|
12
76
|
|
13
|
-
|
14
|
-
@
|
77
|
+
assert_nothing_raised { query.result }
|
78
|
+
assert_equal @data[1], get_raw(query.result)
|
79
|
+
assert_equal @data[2], get_raw(query.result)
|
15
80
|
end
|
16
81
|
|
82
|
+
def test_result_cache_enabled
|
83
|
+
return unless Object.const_defined? :Mocha
|
84
|
+
query = @query[:cached]
|
85
|
+
setup_mock_dbi(1)
|
86
|
+
|
87
|
+
assert_nothing_raised { query.result }
|
88
|
+
assert_equal @data[0], get_raw(query.result)
|
89
|
+
assert_equal @data[0], get_raw(query.result)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_result_resultless
|
93
|
+
return unless Object.const_defined? :Mocha
|
94
|
+
query = @query[:resultless]
|
95
|
+
setup_mock_dbi(1, :resultless => true, :sql => @sql[1])
|
96
|
+
|
97
|
+
assert_equal nil, query.result
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_result_multi
|
101
|
+
return unless Object.const_defined? :Mocha
|
102
|
+
query = @query[:multi]
|
103
|
+
setup_mock_dbi(2)
|
104
|
+
|
105
|
+
assert_equal @data[1], get_raw(query.result)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_result_raw_disabled
|
109
|
+
return unless Object.const_defined? :Mocha
|
110
|
+
query = @query[:unraw]
|
111
|
+
setup_mock_dbi(1)
|
112
|
+
|
113
|
+
assert_equal @data[0].to_table(@columns), query.result
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_result_raw_enabled
|
117
|
+
return unless Object.const_defined? :Mocha
|
118
|
+
query = @query[:raw]
|
119
|
+
setup_mock_dbi(1)
|
120
|
+
|
121
|
+
assert_equal @data[0], query.result
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_update_cache
|
125
|
+
return unless Object.const_defined? :Mocha
|
126
|
+
query = @query[:cached]
|
127
|
+
setup_mock_dbi(2)
|
128
|
+
|
129
|
+
assert_equal @data[0], get_raw(query.result)
|
130
|
+
query.update_cache
|
131
|
+
assert_equal @data[1], get_raw(query.cached_data)
|
132
|
+
assert_equal @data[1], get_raw(query.result)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_clear_cache
|
136
|
+
return unless Object.const_defined? :Mocha
|
137
|
+
query = @query[:cached]
|
138
|
+
setup_mock_dbi(2)
|
139
|
+
|
140
|
+
assert_equal @data[0], get_raw(query.result)
|
141
|
+
query.clear_cache
|
142
|
+
assert_equal nil, query.cached_data
|
143
|
+
assert_equal @data[1], get_raw(query.result)
|
144
|
+
end
|
17
145
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
146
|
+
def test_disable_caching
|
147
|
+
return unless Object.const_defined? :Mocha
|
148
|
+
query = @query[:cached]
|
149
|
+
setup_mock_dbi(3)
|
150
|
+
|
151
|
+
assert_equal @data[0], get_raw(query.result)
|
152
|
+
assert_equal @data[0], get_raw(query.result)
|
153
|
+
query.disable_caching
|
154
|
+
assert_equal @data[1], get_raw(query.result)
|
155
|
+
assert_equal @data[2], get_raw(query.result)
|
21
156
|
end
|
22
157
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
158
|
+
def test_enable_caching
|
159
|
+
return unless Object.const_defined? :Mocha
|
160
|
+
query = @query[:uncached]
|
161
|
+
setup_mock_dbi(3)
|
162
|
+
|
163
|
+
assert_equal @data[0], get_raw(query.result)
|
164
|
+
assert_equal @data[1], get_raw(query.result)
|
165
|
+
query.enable_caching
|
166
|
+
assert_equal @data[2], get_raw(query.result)
|
167
|
+
assert_equal @data[2], get_raw(query.result)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_load_file
|
171
|
+
return unless Object.const_defined? :Mocha
|
172
|
+
File.expects(:read).
|
173
|
+
with("query_test.sql").
|
174
|
+
returns("select * from foo\n")
|
175
|
+
|
176
|
+
query = Ruport::Query.new "query_test.sql"
|
177
|
+
assert_equal "select * from foo", query.sql
|
26
178
|
end
|
27
179
|
|
28
|
-
def
|
180
|
+
def test_load_file_erb
|
181
|
+
return unless Object.const_defined? :Mocha
|
29
182
|
@table = 'bar'
|
30
|
-
|
31
|
-
|
183
|
+
File.expects(:read).
|
184
|
+
with("query_test.sql").
|
185
|
+
returns("select * from <%= @table %>\n")
|
186
|
+
|
187
|
+
query = Ruport::Query.new "query_test.sql", :binding => binding
|
188
|
+
assert_equal "select * from bar", query.sql
|
32
189
|
end
|
33
190
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
191
|
+
def test_load_file_not_found
|
192
|
+
return unless Object.const_defined? :Mocha
|
193
|
+
File.expects(:read).
|
194
|
+
with("query_test.sql").
|
195
|
+
raises(Errno::ENOENT)
|
196
|
+
Ruport.expects(:log).
|
197
|
+
with("Could not open query_test.sql",
|
198
|
+
:status => :fatal, :exception => LoadError).
|
199
|
+
raises(LoadError)
|
200
|
+
|
201
|
+
assert_raises LoadError do
|
202
|
+
query = Ruport::Query.new "query_test.sql"
|
42
203
|
end
|
43
|
-
assert_raise (LocalJumpError) { @query1.each }
|
44
204
|
end
|
45
205
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
assert_equal( "apple", @query1.instance_eval("@password") )
|
206
|
+
def test_each_cache_disabled
|
207
|
+
return unless Object.const_defined? :Mocha
|
208
|
+
query = @query[:uncached]
|
209
|
+
setup_mock_dbi(2)
|
51
210
|
|
52
|
-
|
211
|
+
result = []; query.each { |r| result << r.to_a }
|
212
|
+
assert_equal @data[0], result
|
213
|
+
|
214
|
+
result = []; query.each { |r| result << r.to_a }
|
215
|
+
assert_equal @data[1], result
|
216
|
+
end
|
53
217
|
|
54
|
-
|
55
|
-
|
56
|
-
|
218
|
+
def test_each_cache_enabled
|
219
|
+
return unless Object.const_defined? :Mocha
|
220
|
+
query = @query[:cached]
|
221
|
+
setup_mock_dbi(1)
|
57
222
|
|
58
|
-
|
223
|
+
result = []; query.each { |r| result << r.to_a }
|
224
|
+
assert_equal @data[0], result
|
225
|
+
|
226
|
+
result = []; query.each { |r| result << r.to_a }
|
227
|
+
assert_equal @data[0], result
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_each_multi
|
231
|
+
return unless Object.const_defined? :Mocha
|
232
|
+
query = @query[:multi]
|
233
|
+
setup_mock_dbi(2)
|
59
234
|
|
60
|
-
|
61
|
-
assert_equal
|
62
|
-
|
63
|
-
|
235
|
+
result = []; query.each { |r| result << r.to_a }
|
236
|
+
assert_equal @data[1], result
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_each_without_block
|
240
|
+
assert_raise (LocalJumpError) { @query[:precached].each }
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_select_source
|
244
|
+
query = @query[:precached]
|
245
|
+
assert_equal @sources[:default], get_query_source(query)
|
246
|
+
|
247
|
+
query.select_source :alternative
|
248
|
+
assert_equal @sources[:alternative], get_query_source(query)
|
249
|
+
|
250
|
+
query.select_source :default
|
251
|
+
assert_equal @sources[:default], get_query_source(query)
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_initialize_source_temporary
|
255
|
+
query = Ruport::Query.new "<unused>", @sources[:alternative]
|
256
|
+
assert_equal @sources[:alternative], get_query_source(query)
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_initialize_source_temporary_multiple
|
260
|
+
query1 = Ruport::Query.new "<unused>", @sources[:default]
|
261
|
+
query2 = Ruport::Query.new "<unused>", @sources[:alternative]
|
262
|
+
|
263
|
+
assert_equal @sources[:default], get_query_source(query1)
|
264
|
+
assert_equal @sources[:alternative], get_query_source(query2)
|
64
265
|
end
|
65
266
|
|
66
267
|
def test_generator
|
67
|
-
|
68
|
-
gen =
|
69
|
-
assert_equal [
|
70
|
-
assert_equal [
|
71
|
-
assert_equal [
|
268
|
+
query = @query[:precached]
|
269
|
+
gen = query.generator
|
270
|
+
assert_equal @data[0][0], gen.next
|
271
|
+
assert_equal @data[0][1], gen.next
|
272
|
+
assert_equal @data[0][2], gen.next
|
72
273
|
assert_raise(EOFError) { gen.next }
|
73
274
|
end
|
74
275
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
276
|
+
def test_to_table
|
277
|
+
return unless Object.const_defined? :Mocha
|
278
|
+
query = @query[:raw]
|
279
|
+
setup_mock_dbi(3, :returns => @data[0])
|
280
|
+
|
281
|
+
assert_equal @data[0], query.result
|
282
|
+
assert_equal @data[0].to_table(@columns), query.to_table
|
283
|
+
assert_equal @data[0], query.result
|
78
284
|
end
|
79
285
|
|
286
|
+
def test_to_csv
|
287
|
+
return unless Object.const_defined? :Mocha
|
288
|
+
query = @query[:plain]
|
289
|
+
setup_mock_dbi(1)
|
290
|
+
|
291
|
+
csv = @data[0].to_table(@columns).as(:csv)
|
292
|
+
assert_equal csv, query.to_csv
|
293
|
+
end
|
294
|
+
|
295
|
+
private
|
296
|
+
def setup_mock_dbi(count, options={})
|
297
|
+
sql = options[:sql] || @sql[0]
|
298
|
+
source = options[:source] || :default
|
299
|
+
returns = options[:returns] || Proc.new { @datasets.shift }
|
300
|
+
resultless = options[:resultless]
|
301
|
+
params = options[:params] || []
|
302
|
+
|
303
|
+
@dbh = mock("database_handle")
|
304
|
+
@sth = mock("statement_handle")
|
305
|
+
def @dbh.execute(*a, &b); execute__(*a, &b); ensure; sth__.finish if b; end
|
306
|
+
def @sth.each; data__.each { |x| yield(x) }; end
|
307
|
+
def @sth.fetch_all; data__; end
|
308
|
+
|
309
|
+
DBI.expects(:connect).
|
310
|
+
with(*@sources[source].values_at(:dsn, :user, :password)).
|
311
|
+
yields(@dbh).times(count)
|
312
|
+
@dbh.expects(:execute__).with(sql, *params).
|
313
|
+
yields(@sth).returns(@sth).times(count)
|
314
|
+
@dbh.stubs(:sth__).returns(@sth)
|
315
|
+
@sth.expects(:finish).with().times(count)
|
316
|
+
unless resultless
|
317
|
+
@sth.stubs(:fetchable?).returns(true)
|
318
|
+
@sth.stubs(:column_names).returns(@columns)
|
319
|
+
@sth.expects(:data__).returns(returns).times(count)
|
320
|
+
else
|
321
|
+
@sth.stubs(:fetchable?).returns(false)
|
322
|
+
@sth.stubs(:column_names).returns([])
|
323
|
+
@sth.stubs(:cancel)
|
324
|
+
@sth.expects(:data__).times(0)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def get_query_source(query)
|
329
|
+
[ :dsn, :user, :password ].inject({}) do |memo, var|
|
330
|
+
memo.update var => query.instance_variable_get("@#{var}")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def get_raw(table)
|
335
|
+
table.collect { |row| row.to_a }
|
336
|
+
end
|
80
337
|
end
|