jzimmek-reportme 0.2.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.4.0
@@ -2,5 +2,31 @@ require 'rubygems'
2
2
  require 'activerecord'
3
3
  require "actionmailer"
4
4
 
5
- require 'reportme/report'
6
- require 'reportme/report_factory'
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
+
@@ -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
- "#{name}_#{period}"
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
- def self.create(&block)
8
- rme = ReportFactory.new
9
- rme.instance_eval(&block)
10
- rme
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
- @properties = properties
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 since(since)
33
- raise "since has already been set to '#{@since}' and cannot be changed to: '#{since}'" if @since
34
- raise "since cannot be in the future" if since.future?
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.to_date == Date.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 = @properties[:database]
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 reset
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
- ReportFactory.periods(@since).each do |period|
128
- @reports.each do |r|
129
- exec("drop table if exists #{r.table_name(period[:name])};")
130
- end
131
- end
132
- end
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
- exec("create table #{table_name} ENGINE=InnoDB default CHARSET=utf8 as #{sql} limit 0;")
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 run
195
-
196
- @init.call if @init
197
- @since = Date.today unless @since
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
- ensure_report_informations_table_exist
200
-
191
+ def __fill_periods_queue(since)
201
192
  periods_queue = []
202
193
 
203
- while !@since.future?
204
- ReportFactory.periods(@since).each do |period|
194
+ loop do
195
+ ReportFactory.periods(since).each do |period|
205
196
  periods_queue << period
206
197
  end
207
- @since += 1.day
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
- # we will generate all daily reports first.
211
- # this will speed up generation of weekly and monthly reports.
249
+ end
250
+
251
+ def run_dependency_aware(reports, &block)
252
+
253
+ dependencies = __dependency_hash
254
+ reports = reports.dup
212
255
 
213
- periods_queue.reject{|p| p[:name] != :day}.each do |period|
214
- report_period(period)
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
- periods_queue.reject{|p| p[:name] == :day}.each do |period|
218
- report_period(period)
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 report_period(period)
224
- @reports.each do |r|
319
+ def __report_period(r, period)
225
320
 
226
- period_name = period[:name]
321
+ period_name = period[:name]
227
322
 
228
- next unless r.wants_period?(period_name)
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
- !@subscribtions[report_name].blank?
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
- !@reports.find{|r|r.name == report_name}.blank?
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 = @subscribtions[report_name] || (@subscribtions[report_name] = [])
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
- (@subscribtions[report_name] || []).each do |subscription|
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
- @reports << r
472
+ @@reports << r
355
473
  end
356
474
 
357
475
  end
@@ -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
- :since => DateTime.now
27
+ :init => lambda {}
25
28
  }
26
29
 
27
30
  opts = defaults.merge(opts)
28
31
 
29
- @rme = Reportme::ReportFactory.create do
30
-
31
- since opts[:since]
32
- connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
33
-
34
- report :visits do
35
- periods opts[:periods]
36
- source do |von, bis|
37
- <<-SQL
38
- select
39
- '#{von}' as von,
40
- date(created_at) as datum,
41
- channel,
42
- count(1) as cnt
43
- from
44
- visits
45
- where
46
- created_at between '#{von}' and '#{bis}'
47
- group by
48
- date(created_at),
49
- channel
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
- @rme
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
- @rme.reset if @rme
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(:since => 3.days.ago,:periods => [:day]).run
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(:since => 10.days.ago, :periods => [:day]).run
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
- create_visit_report_factory(:since => 15.days.ago, :periods => [:day]).run
385
+ d1 = Date.today
386
+ d2 = today.to_date
387
+
388
+ num_days = 0
358
389
 
359
- exec("truncate visits;")
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
- create_visit_report_factory(:periods => [:calendar_week]).run
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
- 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
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
- rme.init do
406
- initialized = true
407
- end
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 multiple since calls" do
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
- rme.since 20.days.ago
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.2.2
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-27 00:00:00 -07:00
12
+ date: 2009-06-29 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15