jzimmek-reportme 0.2.2 → 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/VERSION +1 -1
- data/lib/reportme.rb +28 -2
- data/lib/reportme/report.rb +18 -3
- data/lib/reportme/report_factory.rb +201 -83
- data/test/reportme_test.rb +196 -59
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/reportme.rb
CHANGED
@@ -2,5 +2,31 @@ require 'rubygems'
|
|
2
2
|
require 'activerecord'
|
3
3
|
require "actionmailer"
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
class Object
|
6
|
+
|
7
|
+
def self.dsl_attr(name, opts={})
|
8
|
+
|
9
|
+
self.class.send(:define_method, name) do |value|
|
10
|
+
key = "@@#{name}".to_sym
|
11
|
+
class_variable_set(key, value)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
self.class.send(:define_method, "#{name}_value".to_sym) do
|
16
|
+
class_variable_get("@@#{name}".to_sym)
|
17
|
+
end
|
18
|
+
|
19
|
+
self.class.send(:define_method, "#{name}_reset".to_sym) do
|
20
|
+
default = opts[:default].try(:call)
|
21
|
+
class_variable_set("@@#{name}".to_sym, default)
|
22
|
+
end
|
23
|
+
|
24
|
+
default = opts[:default].try(:call)
|
25
|
+
send(name, default)
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'reportme/report_factory'
|
32
|
+
|
data/lib/reportme/report.rb
CHANGED
@@ -2,17 +2,31 @@ module Reportme
|
|
2
2
|
class Report
|
3
3
|
|
4
4
|
attr_reader :name
|
5
|
-
|
6
|
-
def initialize(report_factory, name)
|
5
|
+
|
6
|
+
def initialize(report_factory, name, temporary=false)
|
7
7
|
@report_factory = report_factory
|
8
8
|
@name = name
|
9
9
|
@periods = [:today, :day, :week, :calendar_week, :month, :calendar_month]
|
10
|
+
@depends_on = []
|
11
|
+
@temporary = temporary
|
10
12
|
end
|
11
13
|
|
14
|
+
def temporary?
|
15
|
+
@temporary
|
16
|
+
end
|
17
|
+
|
12
18
|
def source(&block)
|
13
19
|
@source = block
|
14
20
|
end
|
15
21
|
|
22
|
+
def depends_on(dependencies=[])
|
23
|
+
@depends_on += dependencies
|
24
|
+
end
|
25
|
+
|
26
|
+
def dependencies
|
27
|
+
@depends_on
|
28
|
+
end
|
29
|
+
|
16
30
|
def periods(wanted_periods=[])
|
17
31
|
unless wanted_periods.blank?
|
18
32
|
@periods.clear
|
@@ -31,7 +45,8 @@ module Reportme
|
|
31
45
|
end
|
32
46
|
|
33
47
|
def table_name(period)
|
34
|
-
"
|
48
|
+
prefix = temporary? ? "tmp_" : ""
|
49
|
+
"#{prefix}#{name}_#{period}"
|
35
50
|
end
|
36
51
|
|
37
52
|
def table_exist?(period)
|
@@ -3,51 +3,42 @@ require 'reportme/mailer'
|
|
3
3
|
|
4
4
|
module Reportme
|
5
5
|
class ReportFactory
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
6
|
+
|
7
|
+
dsl_attr :reports, :default => lambda{ [] }
|
8
|
+
dsl_attr :subscribtions, :default => lambda{ {} }
|
9
|
+
dsl_attr :properties, :default => lambda{ {} }
|
10
|
+
dsl_attr :init
|
12
11
|
|
13
12
|
def initialize
|
14
|
-
@reports = []
|
15
|
-
@subscribtions = {}
|
16
13
|
@report_exists_cache = []
|
17
14
|
end
|
18
15
|
|
19
|
-
def connection(properties)
|
20
|
-
|
21
|
-
ActiveRecord::Base.establish_connection(@properties)
|
16
|
+
def self.connection(properties)
|
17
|
+
ActiveRecord::Base.establish_connection(@@properties = properties)
|
22
18
|
end
|
23
19
|
|
24
|
-
def smtp(settings)
|
20
|
+
def self.smtp(settings)
|
25
21
|
ActionMailer::Base.smtp_settings = settings
|
26
22
|
end
|
27
23
|
|
28
|
-
def mail(from, recipients, subject, body, attachments=[])
|
24
|
+
def self.mail(from, recipients, subject, body, attachments=[])
|
29
25
|
Mailer.deliver_message(from, recipients, subject, body, attachments)
|
30
26
|
end
|
31
27
|
|
32
|
-
def
|
33
|
-
raise "
|
34
|
-
|
35
|
-
|
36
|
-
@since = since.to_date
|
37
|
-
end
|
38
|
-
|
39
|
-
def init(&block)
|
40
|
-
raise "only one init block allowed" if @init
|
41
|
-
@init = block;
|
28
|
+
def self.init(&block)
|
29
|
+
raise "only one init block allowed" if @@init
|
30
|
+
@@init = block;
|
42
31
|
end
|
43
32
|
|
44
33
|
def self.periods(today)
|
45
34
|
|
35
|
+
today = today.to_date
|
36
|
+
|
46
37
|
r = []
|
47
38
|
p = []
|
48
39
|
|
49
40
|
# period "today" will never be generated for previous days
|
50
|
-
p << :today if today
|
41
|
+
p << :today if today == Date.today
|
51
42
|
p += [:day, :week, :calendar_week, :month, :calendar_month]
|
52
43
|
|
53
44
|
p.each do |period|
|
@@ -100,13 +91,17 @@ module Reportme
|
|
100
91
|
exists
|
101
92
|
end
|
102
93
|
|
103
|
-
def schema_name
|
104
|
-
schema =
|
94
|
+
def self.schema_name
|
95
|
+
schema = @@properties[:database]
|
105
96
|
raise "missing :database in connection properties" unless schema
|
106
97
|
schema
|
107
98
|
end
|
108
|
-
|
99
|
+
|
109
100
|
def columns(table_name)
|
101
|
+
self.class.columns(table_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.columns(table_name)
|
110
105
|
sql = <<-SQL
|
111
106
|
select
|
112
107
|
column_name
|
@@ -120,23 +115,17 @@ module Reportme
|
|
120
115
|
select_values(sql)
|
121
116
|
end
|
122
117
|
|
123
|
-
def
|
124
|
-
@report_exists_cache.clear
|
125
|
-
exec("drop table if exists #{report_information_table_name};")
|
118
|
+
def ensure_report_tables_exist(report)
|
126
119
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
def ensure_report_table_exist(report, period)
|
135
|
-
unless report.table_exist?(period)
|
136
|
-
table_name = report.table_name(period)
|
137
|
-
sql = report.sql('0000-00-00 00:00:00', '0000-00-00 00:00:00', period)
|
120
|
+
[:today, :day, :week, :calendar_week, :month, :calendar_month].each do |period|
|
121
|
+
next unless report.wants_period?(period)
|
122
|
+
|
123
|
+
unless report.table_exist?(period)
|
124
|
+
table_name = report.table_name(period)
|
125
|
+
sql = report.sql('0000-00-00 00:00:00', '0000-00-00 00:00:00', period)
|
138
126
|
|
139
|
-
|
127
|
+
exec("create table #{table_name} ENGINE=InnoDB default CHARSET=utf8 as #{sql} limit 0;")
|
128
|
+
end
|
140
129
|
end
|
141
130
|
end
|
142
131
|
|
@@ -186,46 +175,152 @@ module Reportme
|
|
186
175
|
exec("insert into #{report_information_table_name} values ('#{table_name}', '#{von}', '#{bis}', now());")
|
187
176
|
exec("insert into #{table_name} select #{column_names.join(',')} from #{report.table_name(:day)} as d where d.von between '#{von}' and '#{(_von + num_days.days).strftime("%Y-%m-%d 00:00:00")}';")
|
188
177
|
|
189
|
-
notify_subscriber(report.name, period_name, _von)
|
178
|
+
self.class.notify_subscriber(report.name, period_name, _von)
|
190
179
|
end
|
191
180
|
end
|
192
181
|
end
|
193
182
|
|
194
|
-
def
|
195
|
-
|
196
|
-
|
197
|
-
|
183
|
+
def validate_dependencies
|
184
|
+
@@reports.each do |r|
|
185
|
+
r.dependencies.each do |d|
|
186
|
+
raise "report #{r.name} depends on non existing report #{d}" unless self.class.has_report?(d)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
198
190
|
|
199
|
-
|
200
|
-
|
191
|
+
def __fill_periods_queue(since)
|
201
192
|
periods_queue = []
|
202
193
|
|
203
|
-
|
204
|
-
ReportFactory.periods(
|
194
|
+
loop do
|
195
|
+
ReportFactory.periods(since).each do |period|
|
205
196
|
periods_queue << period
|
206
197
|
end
|
207
|
-
|
198
|
+
since += 1.day
|
199
|
+
break if since.future?
|
200
|
+
end
|
201
|
+
|
202
|
+
periods_queue
|
203
|
+
end
|
204
|
+
|
205
|
+
def run(since=Date.today)
|
206
|
+
|
207
|
+
raise "since cannot be in the future" if since.future?
|
208
|
+
|
209
|
+
begin
|
210
|
+
@@init.call if @@init
|
211
|
+
|
212
|
+
ensure_report_informations_table_exist
|
213
|
+
|
214
|
+
validate_dependencies
|
215
|
+
|
216
|
+
run_dependency_aware(@@reports) do |report|
|
217
|
+
ensure_report_tables_exist(report)
|
218
|
+
end
|
219
|
+
|
220
|
+
periods_queue = __fill_periods_queue(since)
|
221
|
+
|
222
|
+
# we will generate all daily reports first.
|
223
|
+
# this will speed up generation of weekly and monthly reports.
|
224
|
+
|
225
|
+
self.class.__sort_periods(periods_queue).each do |period|
|
226
|
+
|
227
|
+
run_dependency_aware(@@reports) do |report|
|
228
|
+
__report_period(report, period)
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
ensure
|
233
|
+
@@reports.each do |report|
|
234
|
+
|
235
|
+
if report.temporary?
|
236
|
+
[:today, :day, :week, :calendar_week, :month, :calendar_month].each do |period|
|
237
|
+
|
238
|
+
table_name = report.table_name(period)
|
239
|
+
|
240
|
+
exec("delete from #{report_information_table_name} where report = '#{table_name}';")
|
241
|
+
exec("drop table if exists #{table_name};")
|
242
|
+
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
208
247
|
end
|
209
248
|
|
210
|
-
|
211
|
-
|
249
|
+
end
|
250
|
+
|
251
|
+
def run_dependency_aware(reports, &block)
|
252
|
+
|
253
|
+
dependencies = __dependency_hash
|
254
|
+
reports = reports.dup
|
212
255
|
|
213
|
-
|
214
|
-
|
256
|
+
while true
|
257
|
+
|
258
|
+
break if reports.blank?
|
259
|
+
|
260
|
+
num_run = 0
|
261
|
+
|
262
|
+
reports.each do |r|
|
263
|
+
|
264
|
+
unless dependencies[r.name].blank?
|
265
|
+
puts "report ['#{r.name}'] waits on dependencies: #{dependencies[r.name].collect{|d|d.name}.join(',')}"
|
266
|
+
next
|
267
|
+
end
|
268
|
+
|
269
|
+
block.call(r)
|
270
|
+
|
271
|
+
dependencies.each_pair do |key, values|
|
272
|
+
|
273
|
+
if values.include?(r)
|
274
|
+
# puts "remove '#{r[:name]}' from '#{key}' list of dependencies"
|
275
|
+
values.delete(r)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
num_run += 1
|
280
|
+
reports.delete(r)
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
raise "deadlock" if num_run == 0
|
285
|
+
|
215
286
|
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.__sort_periods(periods)
|
291
|
+
|
292
|
+
sorting = {
|
293
|
+
:today => 99,
|
294
|
+
:day => 1,
|
295
|
+
:week => 2,
|
296
|
+
:calendar_week => 3,
|
297
|
+
:month => 4,
|
298
|
+
:calendar_month => 5
|
299
|
+
}
|
300
|
+
|
301
|
+
periods.sort{|a, b| sorting[a[:name]] <=> sorting[b[:name]]}
|
302
|
+
|
303
|
+
end
|
216
304
|
|
217
|
-
|
218
|
-
|
305
|
+
def __dependency_hash
|
306
|
+
dependencies = {}
|
307
|
+
@@reports.each do |r|
|
308
|
+
|
309
|
+
dependencies[r.name] = []
|
310
|
+
|
311
|
+
r.dependencies.each do |d|
|
312
|
+
dependencies[r.name] << self.class.report_by_name(d)
|
313
|
+
end
|
219
314
|
end
|
220
315
|
|
316
|
+
dependencies
|
221
317
|
end
|
222
318
|
|
223
|
-
def
|
224
|
-
@reports.each do |r|
|
319
|
+
def __report_period(r, period)
|
225
320
|
|
226
|
-
|
321
|
+
period_name = period[:name]
|
227
322
|
|
228
|
-
|
323
|
+
if r.wants_period?(period_name)
|
229
324
|
|
230
325
|
_von = period[:von]
|
231
326
|
_bis = period[:bis]
|
@@ -239,8 +334,6 @@ module Reportme
|
|
239
334
|
sql = r.sql(von, bis, period_name)
|
240
335
|
|
241
336
|
puts "report: #{r.table_name(period_name)} von: #{von}, bis: #{bis}"
|
242
|
-
|
243
|
-
ensure_report_table_exist(r, period_name)
|
244
337
|
|
245
338
|
report_exists = report_exists?(table_name, von, bis)
|
246
339
|
|
@@ -257,30 +350,35 @@ module Reportme
|
|
257
350
|
if !report_exists || period_name == :today
|
258
351
|
ActiveRecord::Base.transaction do
|
259
352
|
exec("insert into #{report_information_table_name} values ('#{table_name}', '#{von}', '#{bis}', now());") unless report_exists
|
260
|
-
|
261
|
-
if period_name == :today
|
262
|
-
exec("truncate #{table_name};")
|
263
|
-
end
|
353
|
+
|
354
|
+
exec("truncate #{table_name};") if period_name == :today
|
264
355
|
|
265
356
|
exec("insert into #{table_name} #{sql};")
|
266
357
|
|
267
|
-
notify_subscriber(r.name, period_name, _von)
|
358
|
+
self.class.notify_subscriber(r.name, period_name, _von)
|
268
359
|
end
|
269
360
|
end
|
270
361
|
|
271
|
-
|
272
362
|
end
|
273
363
|
|
274
364
|
end
|
275
|
-
|
365
|
+
|
276
366
|
def exec(sql)
|
367
|
+
self.class.exec(sql)
|
368
|
+
end
|
369
|
+
|
370
|
+
def self.exec(sql)
|
277
371
|
puts "// ------------------------"
|
278
372
|
puts "exec: #{sql}"
|
279
373
|
puts "------------------------ //"
|
280
374
|
ActiveRecord::Base.connection.execute(sql)
|
281
375
|
end
|
282
|
-
|
376
|
+
|
283
377
|
def select_value(sql)
|
378
|
+
self.class.select_value(sql)
|
379
|
+
end
|
380
|
+
|
381
|
+
def self.select_value(sql)
|
284
382
|
puts "// ------------------------"
|
285
383
|
puts "select_value: #{sql}"
|
286
384
|
puts "------------------------ //"
|
@@ -288,6 +386,10 @@ module Reportme
|
|
288
386
|
end
|
289
387
|
|
290
388
|
def select_one(sql)
|
389
|
+
self.class.select_one(sql)
|
390
|
+
end
|
391
|
+
|
392
|
+
def self.select_one(sql)
|
291
393
|
puts "// ------------------------"
|
292
394
|
puts "select_one: #{sql}"
|
293
395
|
puts "------------------------ //"
|
@@ -295,6 +397,10 @@ module Reportme
|
|
295
397
|
end
|
296
398
|
|
297
399
|
def select_all(sql)
|
400
|
+
self.class.select_all(sql)
|
401
|
+
end
|
402
|
+
|
403
|
+
def self.select_all(sql)
|
298
404
|
puts "// ------------------------"
|
299
405
|
puts "select_all: #{sql}"
|
300
406
|
puts "------------------------ //"
|
@@ -302,6 +408,10 @@ module Reportme
|
|
302
408
|
end
|
303
409
|
|
304
410
|
def select_rows(sql)
|
411
|
+
self.class.select_rows(sql)
|
412
|
+
end
|
413
|
+
|
414
|
+
def self.select_rows(sql)
|
305
415
|
puts "// ------------------------"
|
306
416
|
puts "select_rows: #{sql}"
|
307
417
|
puts "------------------------ //"
|
@@ -309,32 +419,40 @@ module Reportme
|
|
309
419
|
end
|
310
420
|
|
311
421
|
def select_values(sql)
|
422
|
+
self.class.select_values(sql)
|
423
|
+
end
|
424
|
+
|
425
|
+
def self.select_values(sql)
|
312
426
|
puts "// ------------------------"
|
313
427
|
puts "select_values: #{sql}"
|
314
428
|
puts "------------------------ //"
|
315
429
|
ActiveRecord::Base.connection.select_values(sql)
|
316
430
|
end
|
317
431
|
|
318
|
-
def has_subscribtion?(report_name)
|
319
|
-
|
432
|
+
def self.has_subscribtion?(report_name)
|
433
|
+
!@@subscribtions[report_name].blank?
|
434
|
+
end
|
435
|
+
|
436
|
+
def self.report_by_name(report_name)
|
437
|
+
@@reports.find{|r|r.name == report_name}
|
320
438
|
end
|
321
439
|
|
322
|
-
def has_report?(report_name)
|
323
|
-
|
440
|
+
def self.has_report?(report_name)
|
441
|
+
!@@reports.find{|r|r.name == report_name}.blank?
|
324
442
|
end
|
325
443
|
|
326
|
-
def subscribe(report_name, &block)
|
444
|
+
def self.subscribe(report_name, &block)
|
327
445
|
report_name = report_name.to_sym
|
328
446
|
|
329
447
|
raise "report: #{report_name} does not exist" unless has_report?(report_name)
|
330
448
|
|
331
|
-
existing =
|
449
|
+
existing = @@subscribtions[report_name] || (@@subscribtions[report_name] = [])
|
332
450
|
existing << block
|
333
451
|
end
|
334
452
|
|
335
|
-
def notify_subscriber(report_name, period, von)
|
453
|
+
def self.notify_subscriber(report_name, period, von)
|
336
454
|
|
337
|
-
(
|
455
|
+
(@@subscribtions[report_name] || []).each do |subscription|
|
338
456
|
begin
|
339
457
|
subscription.call(period, von)
|
340
458
|
rescue Exception => e
|
@@ -344,14 +462,14 @@ module Reportme
|
|
344
462
|
|
345
463
|
end
|
346
464
|
|
347
|
-
def report(name, &block)
|
465
|
+
def self.report(name, temporary=false, &block)
|
348
466
|
|
349
467
|
name = name.to_sym
|
350
468
|
|
351
|
-
r = Report.new(self, name)
|
469
|
+
r = Report.new(self, name, temporary)
|
352
470
|
r.instance_eval(&block)
|
353
471
|
|
354
|
-
|
472
|
+
@@reports << r
|
355
473
|
end
|
356
474
|
|
357
475
|
end
|
data/test/reportme_test.rb
CHANGED
@@ -16,55 +16,73 @@ class ReportmeTest < Test::Unit::TestCase
|
|
16
16
|
)
|
17
17
|
SQL
|
18
18
|
end
|
19
|
+
|
20
|
+
class TestReport < Reportme::ReportFactory
|
21
|
+
end
|
19
22
|
|
20
23
|
def create_visit_report_factory(opts={})
|
21
24
|
|
22
25
|
defaults = {
|
23
26
|
:periods => [],
|
24
|
-
:
|
27
|
+
:init => lambda {}
|
25
28
|
}
|
26
29
|
|
27
30
|
opts = defaults.merge(opts)
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
SQL
|
51
|
-
end
|
32
|
+
TestReport.connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
33
|
+
TestReport.init do
|
34
|
+
opts[:init].call
|
35
|
+
end
|
36
|
+
TestReport.report :visits do
|
37
|
+
periods opts[:periods]
|
38
|
+
source do |von, bis|
|
39
|
+
<<-SQL
|
40
|
+
select
|
41
|
+
'#{von}' as von,
|
42
|
+
date(created_at) as datum,
|
43
|
+
channel,
|
44
|
+
count(1) as cnt
|
45
|
+
from
|
46
|
+
visits
|
47
|
+
where
|
48
|
+
created_at between '#{von}' and '#{bis}'
|
49
|
+
group by
|
50
|
+
date(created_at),
|
51
|
+
channel
|
52
|
+
SQL
|
52
53
|
end
|
53
54
|
end
|
54
|
-
|
55
|
+
|
56
|
+
@rme = TestReport.new
|
57
|
+
|
55
58
|
end
|
56
59
|
|
57
60
|
def exec(sql)
|
61
|
+
puts "exec: #{sql}"
|
58
62
|
ActiveRecord::Base.connection.execute(sql)
|
59
63
|
end
|
60
64
|
|
61
65
|
def one(sql)
|
66
|
+
puts "one: #{sql}"
|
62
67
|
ActiveRecord::Base.connection.select_one(sql)
|
63
68
|
end
|
64
69
|
|
65
70
|
def teardown
|
66
71
|
unless @debug
|
67
|
-
|
72
|
+
exec("drop table if exists report_informations;")
|
73
|
+
|
74
|
+
[:today, :day, :week, :calendar_week, :month, :calendar_month].each do |period|
|
75
|
+
|
76
|
+
TestReport.reports_value.each do |report|
|
77
|
+
exec("drop table if exists #{report.table_name(period)};")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
TestReport.reports_reset
|
82
|
+
TestReport.init_reset
|
83
|
+
TestReport.subscribtions_reset
|
84
|
+
TestReport.properties_reset
|
85
|
+
|
68
86
|
exec("truncate visits;");
|
69
87
|
end
|
70
88
|
end
|
@@ -82,6 +100,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
82
100
|
assert_equal 2, one("select cnt from visits_today where channel = 'sem' and datum = curdate()")["cnt"].to_i
|
83
101
|
end
|
84
102
|
|
103
|
+
|
85
104
|
should "create visitors in the today report for channel sem and seo" do
|
86
105
|
exec("insert into visits values (null, 'sem', now())");
|
87
106
|
exec("insert into visits values (null, 'sem', now())");
|
@@ -126,6 +145,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
126
145
|
|
127
146
|
should "create a daily report for the previous 3 days" do
|
128
147
|
|
148
|
+
|
129
149
|
#should be ignored
|
130
150
|
exec("insert into visits values (null, 'sem', curdate());");
|
131
151
|
|
@@ -137,7 +157,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
137
157
|
# should be ignored
|
138
158
|
exec("insert into visits values (null, 'sem', date_sub(curdate(), interval 5 day));");
|
139
159
|
|
140
|
-
create_visit_report_factory(:
|
160
|
+
create_visit_report_factory(:periods => [:day]).run(3.days.ago)
|
141
161
|
assert_equal 4, one("select count(1) as cnt from visits_day where von between date_sub(curdate(), interval 4 day) and date_sub(curdate(), interval 1 day)")["cnt"].to_i
|
142
162
|
end
|
143
163
|
|
@@ -159,10 +179,12 @@ class ReportmeTest < Test::Unit::TestCase
|
|
159
179
|
# should be ignored in weekly
|
160
180
|
exec("insert into visits values (null, 'sem', date_sub(curdate(), interval 9 day));");
|
161
181
|
|
162
|
-
create_visit_report_factory(:
|
182
|
+
create_visit_report_factory(:periods => [:day]).run(10.days.ago)
|
163
183
|
|
164
184
|
exec("truncate visits;")
|
165
185
|
|
186
|
+
Reportme::ReportFactory.init_reset
|
187
|
+
|
166
188
|
create_visit_report_factory(:periods => [:week]).run
|
167
189
|
|
168
190
|
assert_equal 7, one("select count(1) as cnt from visits_week where date(von) between date_sub(curdate(), interval 7 day) and date_sub(curdate(), interval 1 day)")["cnt"].to_i
|
@@ -320,7 +342,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
320
342
|
|
321
343
|
assert_equal '2009-04-01 00:00:00'.to_datetime, periods[:calendar_month][:von]
|
322
344
|
assert_equal '2009-04-30 23:59:59'.to_datetime, periods[:calendar_month][:bis]
|
323
|
-
|
345
|
+
|
324
346
|
##
|
325
347
|
# today
|
326
348
|
##
|
@@ -333,7 +355,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
333
355
|
assert_equal "#{today.strftime('%Y-%m-%d')} 23:59:59".to_datetime, periods[:today][:bis]
|
334
356
|
|
335
357
|
end
|
336
|
-
|
358
|
+
|
337
359
|
should "create the calendar_weekly report by using 7 daily reports" do
|
338
360
|
|
339
361
|
today = '2009-06-24'
|
@@ -353,58 +375,84 @@ class ReportmeTest < Test::Unit::TestCase
|
|
353
375
|
exec("insert into visits values (null, 'sem', date_sub('#{today}', interval 9 day));");
|
354
376
|
# should be ignored in weekly
|
355
377
|
exec("insert into visits values (null, 'sem', date_sub('#{today}', interval 10 day));");
|
378
|
+
|
379
|
+
create_visit_report_factory(:periods => [:day]).run(15.days.ago)
|
380
|
+
|
381
|
+
exec("truncate visits;")
|
382
|
+
|
383
|
+
Reportme::ReportFactory.init_reset
|
356
384
|
|
357
|
-
|
385
|
+
d1 = Date.today
|
386
|
+
d2 = today.to_date
|
387
|
+
|
388
|
+
num_days = 0
|
358
389
|
|
359
|
-
|
390
|
+
while d2.past?
|
391
|
+
d2 += 1.day
|
392
|
+
num_days += 1
|
393
|
+
end
|
394
|
+
|
395
|
+
create_visit_report_factory(:periods => [:calendar_week]).run(num_days.days.ago)
|
360
396
|
|
361
|
-
|
397
|
+
day_lastweek = today.to_date - 7.days
|
398
|
+
|
399
|
+
monday = day_lastweek - (day_lastweek.cwday - 1).days
|
400
|
+
|
401
|
+
von, bis = [monday, monday + 6.days]
|
402
|
+
|
403
|
+
von = von.to_datetime
|
404
|
+
bis = bis.to_datetime + 23.hours + 59.minutes + 59.seconds
|
362
405
|
|
363
|
-
|
406
|
+
sql = "select count(1) as cnt from visits_calendar_week where von between '#{von.strftime('%Y-%m-%d 00:00:00')}' and '#{bis.strftime('%Y-%m-%d 23:59:59')}'"
|
407
|
+
|
408
|
+
# assert_equal 7, one("select count(1) as cnt from visits_calendar_week where von between '2009-06-15 00:00:00' and '2009-06-21 00:00:00'")["cnt"].to_i
|
409
|
+
assert_equal 7, one(sql)["cnt"].to_i
|
364
410
|
|
365
411
|
end
|
366
|
-
|
412
|
+
|
367
413
|
should "probe existing reports" do
|
368
414
|
rme = create_visit_report_factory
|
369
|
-
assert rme.has_report?(:visits)
|
370
|
-
assert !rme.has_report?(:some_not_existing_report)
|
415
|
+
assert rme.class.has_report?(:visits)
|
416
|
+
assert !rme.class.has_report?(:some_not_existing_report)
|
371
417
|
end
|
372
|
-
|
418
|
+
|
373
419
|
should "subscribe to visits report" do
|
374
420
|
rme = create_visit_report_factory
|
375
|
-
rme.subscribe :visits do
|
421
|
+
rme.class.subscribe :visits do
|
376
422
|
end
|
377
|
-
assert rme.has_subscribtion?(:visits)
|
423
|
+
assert rme.class.has_subscribtion?(:visits)
|
378
424
|
end
|
379
425
|
|
380
426
|
should "fail on subscribtion to not existing report" do
|
381
427
|
rme = create_visit_report_factory
|
382
428
|
assert_raise RuntimeError do
|
383
|
-
rme.subscribe :some_not_existing_report do
|
429
|
+
rme.class.subscribe :some_not_existing_report do
|
384
430
|
end
|
385
431
|
end
|
386
432
|
end
|
387
433
|
|
388
434
|
should "notify subscriptions" do
|
389
435
|
notifed = false
|
390
|
-
|
436
|
+
|
391
437
|
rme = create_visit_report_factory
|
392
|
-
rme.subscribe :visits do
|
438
|
+
rme.class.subscribe :visits do
|
393
439
|
notifed = true
|
394
440
|
end
|
395
441
|
|
396
|
-
rme.notify_subscriber(:visits, :day, '2009-01-01'.to_datetime)
|
442
|
+
rme.class.notify_subscriber(:visits, :day, '2009-01-01'.to_datetime)
|
397
443
|
|
398
444
|
assert notifed
|
399
445
|
end
|
400
446
|
|
401
447
|
should "call initializer before running reports" do
|
402
448
|
initialized = false
|
403
|
-
|
404
|
-
rme = create_visit_report_factory
|
405
|
-
|
406
|
-
|
407
|
-
|
449
|
+
|
450
|
+
rme = create_visit_report_factory({
|
451
|
+
:init => lambda {
|
452
|
+
initialized = true
|
453
|
+
}
|
454
|
+
})
|
455
|
+
|
408
456
|
rme.run
|
409
457
|
|
410
458
|
assert initialized
|
@@ -412,26 +460,115 @@ class ReportmeTest < Test::Unit::TestCase
|
|
412
460
|
end
|
413
461
|
|
414
462
|
should "fail when multiple init blocks are defined" do
|
415
|
-
|
463
|
+
|
416
464
|
rme = create_visit_report_factory
|
417
|
-
rme.init do
|
418
|
-
end
|
419
465
|
|
420
466
|
assert_raise RuntimeError do
|
421
|
-
rme.init do
|
467
|
+
rme.class.init do
|
422
468
|
end
|
423
469
|
end
|
424
470
|
end
|
425
471
|
|
426
|
-
should "fail on
|
472
|
+
should "fail on non existing report dependencies" do
|
473
|
+
|
474
|
+
class ReportDependencyTestReport < Reportme::ReportFactory
|
475
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
476
|
+
report :report1 do
|
477
|
+
depends_on [:report2]
|
478
|
+
end
|
479
|
+
end
|
427
480
|
|
428
|
-
rme = create_visit_report_factory
|
429
|
-
# 'since' will be implicitly called by ower testing factory method above
|
430
|
-
# any further call should fails
|
431
|
-
|
432
481
|
assert_raise RuntimeError do
|
433
|
-
|
482
|
+
ReportDependencyTestReport.new.validate_dependencies
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
should "return a report by name" do
|
487
|
+
class ReportByNameTestReport < Reportme::ReportFactory
|
488
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
489
|
+
report :report1 do
|
490
|
+
end
|
491
|
+
report :report2 do
|
492
|
+
end
|
434
493
|
end
|
494
|
+
|
495
|
+
assert :report1, ReportByNameTestReport.report_by_name(:report1).name
|
496
|
+
assert :report2, ReportByNameTestReport.report_by_name(:report2).name
|
497
|
+
|
498
|
+
end
|
499
|
+
|
500
|
+
should "compute a dependency hash" do
|
501
|
+
class ReportDependencyHashTestReport < Reportme::ReportFactory
|
502
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
503
|
+
report :report1 do
|
504
|
+
depends_on [:report2, :report3]
|
505
|
+
end
|
506
|
+
report :report2 do
|
507
|
+
depends_on [:report3]
|
508
|
+
end
|
509
|
+
report :report3 do
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
hash = ReportDependencyHashTestReport.new.__dependency_hash
|
514
|
+
|
515
|
+
assert [
|
516
|
+
ReportDependencyHashTestReport.report_by_name(:report2),
|
517
|
+
ReportDependencyHashTestReport.report_by_name(:report3)
|
518
|
+
], hash[:report1]
|
519
|
+
|
520
|
+
assert [
|
521
|
+
ReportDependencyHashTestReport.report_by_name(:report3)
|
522
|
+
], hash[:report2]
|
523
|
+
|
524
|
+
assert [], hash[:report3]
|
525
|
+
end
|
526
|
+
|
527
|
+
should "sort some periods" do
|
528
|
+
assert [:day, :today], Reportme::ReportFactory.__sort_periods([{:name => :today}, {:name => :day}])
|
529
|
+
assert [:day, :week, :today], Reportme::ReportFactory.__sort_periods([{:name => :today}, {:name => :day}, {:name => :week}])
|
530
|
+
assert [:day, :week], Reportme::ReportFactory.__sort_periods([{:name => :week}, {:name => :day}])
|
531
|
+
assert [:day, :week, :month, :calendar_month, :today], Reportme::ReportFactory.__sort_periods([{:name => :week}, {:name => :day}, {:name => :today}, {:name => :calendar_month}, {:name => :month}])
|
532
|
+
|
533
|
+
assert [:day, :week, :week, :today, :today], Reportme::ReportFactory.__sort_periods([{:name => :week}, {:name => :today}, {:name => :today}, {:name => :week}, {:name => :day}])
|
534
|
+
end
|
535
|
+
|
536
|
+
should "run reports in a dependency aware manner" do
|
537
|
+
class ReportDependencyAwareTestReport < Reportme::ReportFactory
|
538
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
539
|
+
report :report1 do
|
540
|
+
depends_on [:report2, :report3]
|
541
|
+
end
|
542
|
+
report :report2 do
|
543
|
+
depends_on [:report3]
|
544
|
+
end
|
545
|
+
report :report3 do
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
runned = []
|
550
|
+
|
551
|
+
reports = []
|
552
|
+
reports << ReportDependencyAwareTestReport.report_by_name(:report1)
|
553
|
+
reports << ReportDependencyAwareTestReport.report_by_name(:report2)
|
554
|
+
reports << ReportDependencyAwareTestReport.report_by_name(:report3)
|
555
|
+
|
556
|
+
ReportDependencyAwareTestReport.new.run_dependency_aware(reports) do |report|
|
557
|
+
runned << report.name
|
558
|
+
end
|
559
|
+
|
560
|
+
assert [:report3, :report2, :report1], runned
|
561
|
+
|
562
|
+
end
|
563
|
+
|
564
|
+
should "prefix tablename with tmp_ for temporary reports" do
|
565
|
+
class ReportTemporaryTestReport < Reportme::ReportFactory
|
566
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
567
|
+
report :report1, :temporary => true do
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
assert "tmp_report1_day", ReportTemporaryTestReport.report_by_name(:report1).table_name(:day)
|
435
572
|
end
|
436
573
|
|
437
574
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jzimmek-reportme
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Zimmek
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-29 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|