jzimmek-reportme 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jan Zimmek
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,29 @@
1
+ = report_me
2
+
3
+ ReportMe is a thin ruby wrapper around your reporting sql queries which empowers you to automate, historicize, graph and mail them in an easy manner.
4
+
5
+ == Usage
6
+
7
+ ReportFactory.create do
8
+ report :visits do
9
+ source do |von, bis|
10
+ <<-SQL
11
+ select
12
+ date(v.created_at) as datum,
13
+ channel,
14
+ count(1) as cnt
15
+ from
16
+ visits v
17
+ where
18
+ v.created_at between '#{von}' and '#{bis}'
19
+ group by
20
+ date(v.created_at),
21
+ channel
22
+ SQL
23
+ end
24
+ end
25
+ end
26
+
27
+ == Copyright
28
+
29
+ Copyright (c) 2009 Jan Zimmek. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "reportme"
8
+ gem.summary = "Ruby wrapper to automate sql reports"
9
+ gem.description = "ReportMe is a thin ruby wrapper around your reporting sql queries which empowers you to automate, historicize, graph and mail them in an easy manner."
10
+ gem.email = "jan.zimmek@web.de"
11
+ gem.homepage = "http://github.com/jzimmek/report_me"
12
+ gem.authors = ["Jan Zimmek"]
13
+ gem.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ if File.exist?('VERSION.yml')
47
+ config = YAML.load(File.read('VERSION.yml'))
48
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
49
+ else
50
+ version = ""
51
+ end
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "report_me #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
58
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.5
data/lib/reportme.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'activerecord'
3
+
4
+ require 'reportme/report'
5
+ require 'reportme/report_factory'
@@ -0,0 +1,45 @@
1
+ module Reportme
2
+ class Report
3
+
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ @periods = [:today, :day, :week, :calendar_week, :month, :calendar_month]
9
+ end
10
+
11
+ def source(&block)
12
+ @source = block
13
+ end
14
+
15
+ def periods(*args)
16
+ unless args.blank?
17
+ @periods.clear
18
+ args.each do |period|
19
+ @periods << period
20
+ end
21
+ end
22
+ end
23
+
24
+ def wants_period?(period)
25
+ @periods.include?(period)
26
+ end
27
+
28
+ def periods
29
+
30
+ end
31
+
32
+ def sql(von, bis)
33
+ @source.call(von, bis)
34
+ end
35
+
36
+ def table_name(period)
37
+ "#{name}_#{period}"
38
+ end
39
+
40
+ def table_exist?(period)
41
+ ActiveRecord::Base.connection.select_value("show tables like '#{table_name(period)}'") != nil
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,152 @@
1
+ require 'reportme/report'
2
+
3
+ module Reportme
4
+ class ReportFactory
5
+
6
+ def self.create(&block)
7
+ rme = ReportFactory.new
8
+ rme.instance_eval(&block)
9
+ rme.run
10
+ rme
11
+ end
12
+
13
+ def initialize
14
+ @reports = []
15
+ end
16
+
17
+ def periods(today = DateTime.now)
18
+
19
+ periods = []
20
+
21
+ [:today, :day, :week, :calendar_week, :month, :calendar_month].each do |period|
22
+
23
+ von, bis = case period
24
+ when :today
25
+ [today, today]
26
+ when :day
27
+ [today - 1.day, today - 1.day]
28
+ when :week
29
+ [today - 1.day - 1.week, today - 1.day]
30
+ when :calendar_week
31
+ n = today - 1.day
32
+ [n - n.cwday + 1, n - n.cwday + 7]
33
+ when :month
34
+ [today - 1.day - 1.month, today - 1.day]
35
+ when :calendar_month
36
+ n = today - 1.month
37
+ [n.beginning_of_month, n.end_of_month]
38
+ end
39
+
40
+ periods << {:name => period, :von => von, :bis => bis}
41
+
42
+ end
43
+
44
+ periods
45
+ end
46
+
47
+ def report_information_table_name
48
+ "report_informations"
49
+ end
50
+
51
+ def report_information_table_name_exist?
52
+ ActiveRecord::Base.connection.select_value("show tables like '#{report_information_table_name}'") != nil
53
+ end
54
+
55
+ def report_exists?(name, von, bis)
56
+ ActiveRecord::Base.connection.select_value("select 1 from #{report_information_table_name} where report = '#{name}' and von = '#{von}' and bis = '#{bis}'") != nil
57
+ end
58
+
59
+ def reset
60
+ exec("drop table if exists #{report_information_table_name};")
61
+
62
+ periods.each do |period|
63
+ @reports.each do |r|
64
+ exec("drop table if exists #{r.table_name(period[:name])};")
65
+ end
66
+ end
67
+ end
68
+
69
+ def run
70
+
71
+ debug = false
72
+
73
+ unless report_information_table_name_exist?
74
+ ddl = <<-SQL
75
+ create
76
+ table report_informations
77
+ (
78
+ report varchar(255) not null,
79
+ von datetime not null,
80
+ bis datetime not null,
81
+ created_at datetime not null,
82
+ primary key (report)
83
+ )
84
+ ENGINE=InnoDB default CHARSET=utf8;
85
+ SQL
86
+ exec(ddl)
87
+ end
88
+
89
+ if debug
90
+ # just for testing
91
+ exec("truncate #{report_information_table_name};")
92
+ end
93
+
94
+ periods.each do |period|
95
+
96
+ @reports.each do |r|
97
+
98
+ next unless r.wants_period?(period[:name])
99
+
100
+ von = period[:von].strftime("%Y-%m-%d 00:00:00")
101
+ bis = period[:bis].strftime("%Y-%m-%d 23:59:59")
102
+
103
+ table_name = r.table_name(period[:name])
104
+
105
+ if debug
106
+ # drop and create table while in testing mode
107
+ exec("drop table if exists #{table_name};")
108
+ end
109
+
110
+ table_exist = r.table_exist?(period[:name])
111
+ sql = r.sql(von, bis)
112
+ report_exist = report_exists?(table_name, von, bis)
113
+
114
+ puts "report: #{r.name}_#{period[:name]} :: #{report_exist}"
115
+
116
+
117
+ unless table_exist
118
+ exec("create table #{table_name} ENGINE=InnoDB default CHARSET=utf8 as #{sql} limit 0;")
119
+ end
120
+
121
+ puts sql
122
+
123
+ # if !report_exist || period[:name] == :today
124
+ # ActiveRecord::Base.transaction do
125
+ # exec("insert into #{report_information_table_name} values ('#{table_name}', '#{von}', '#{bis}', now());") unless report_exist
126
+ #
127
+ # if period[:name] == :today
128
+ # exec("truncate #{table_name};")
129
+ # end
130
+ #
131
+ # exec("insert into #{table_name} #{sql};")
132
+ # end
133
+ # end
134
+
135
+
136
+ end
137
+ end
138
+ end
139
+
140
+ def exec(sql)
141
+ ActiveRecord::Base.connection.execute(sql)
142
+ end
143
+
144
+ def report(name, &block)
145
+ r = Report.new(name)
146
+ r.instance_eval(&block)
147
+
148
+ @reports << r
149
+ end
150
+
151
+ end
152
+ end
@@ -0,0 +1,96 @@
1
+ require 'test_helper'
2
+
3
+ class ReportMeTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ exec("use report_me_test")
7
+ exec "drop table if exists visits"
8
+ exec <<-SQL
9
+ create
10
+ table visits
11
+ (
12
+ id bigint auto_increment,
13
+ channel varchar(255),
14
+ created_at datetime,
15
+ primary key (id)
16
+ )
17
+ SQL
18
+ end
19
+
20
+ def create_visit_report_factory
21
+
22
+ rme = ReportMe::ReportFactory.create do
23
+ report :visits do
24
+ source do |von, bis|
25
+ <<-SQL
26
+ select
27
+ date('#{von}') as datum,
28
+ channel,
29
+ count(1) as cnt
30
+ from
31
+ visits
32
+ where
33
+ created_at between '#{von}' and '#{bis}'
34
+ group by
35
+ date(created_at),
36
+ channel
37
+ SQL
38
+ end
39
+ end
40
+ end
41
+
42
+ rme.reset
43
+ rme
44
+ end
45
+
46
+ def exec(sql)
47
+ ActiveRecord::Base.connection.execute(sql)
48
+ end
49
+
50
+ def one(sql)
51
+ ActiveRecord::Base.connection.select_one(sql)
52
+ end
53
+
54
+ def teardown
55
+ exec("truncate visits;");
56
+ end
57
+
58
+ should "create one visitor in the today report for channel sem" do
59
+ exec("insert into visits values (null, 'sem', now())");
60
+ create_visit_report_factory.run
61
+ assert_equal 1, one("select count(1) as cnt from visits_today where channel = 'sem' and datum = curdate()")["cnt"].to_i
62
+ end
63
+
64
+ should "create two visitors in the today report for channel sem" do
65
+ exec("insert into visits values (null, 'sem', now())");
66
+ exec("insert into visits values (null, 'sem', now())");
67
+ create_visit_report_factory.run
68
+ assert_equal 2, one("select cnt from visits_today where channel = 'sem' and datum = curdate()")["cnt"].to_i
69
+ end
70
+
71
+ should "create visitors in the today report for channel sem and seo" do
72
+ exec("insert into visits values (null, 'sem', now())");
73
+ exec("insert into visits values (null, 'sem', now())");
74
+ exec("insert into visits values (null, 'seo', now())");
75
+ exec("insert into visits values (null, 'sem', now())");
76
+ exec("insert into visits values (null, 'seo', now())");
77
+ create_visit_report_factory.run
78
+ assert_equal 2, one("select cnt from visits_today where channel = 'seo' and datum = curdate()")["cnt"].to_i
79
+ assert_equal 3, one("select cnt from visits_today where channel = 'sem' and datum = curdate()")["cnt"].to_i
80
+ end
81
+
82
+ should "create visitors in the day report for channel sem and seo" do
83
+ exec("insert into visits values (null, 'sem', date_sub(curdate(), interval 1 day));");
84
+ exec("insert into visits values (null, 'sem', date_sub(curdate(), interval 1 day));");
85
+ exec("insert into visits values (null, 'seo', date_sub(curdate(), interval 1 day));");
86
+ exec("insert into visits values (null, 'sem', date_sub(curdate(), interval 1 day));");
87
+ exec("insert into visits values (null, 'seo', date_sub(curdate(), interval 1 day));");
88
+ create_visit_report_factory.run
89
+ assert_equal 2, one("select cnt from visits_day where channel = 'seo' and datum = date_sub(curdate(), interval 1 day)")["cnt"].to_i
90
+ assert_equal 3, one("select cnt from visits_day where channel = 'sem' and datum = date_sub(curdate(), interval 1 day)")["cnt"].to_i
91
+ end
92
+
93
+ should "handle today and day periods but nothing else" do
94
+ end
95
+
96
+ end
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'report_me'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+
9
+
10
+ class Test::Unit::TestCase
11
+ end
12
+
13
+ ActiveRecord::Base.establish_connection(:adapter => "mysql", :database => "mysql", :username => "root", :password => "root", :host => "localhost", :port => 3306)
14
+
15
+ ActiveRecord::Base.connection.execute "drop database if exists report_me_test;"
16
+ ActiveRecord::Base.connection.execute "create database report_me_test;"
17
+ ActiveRecord::Base.connection.execute "use report_me_test;"
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jzimmek-reportme
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Jan Zimmek
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-23 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: ReportMe is a thin ruby wrapper around your reporting sql queries which empowers you to automate, historicize, graph and mail them in an easy manner.
17
+ email: jan.zimmek@web.de
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.rdoc
25
+ files:
26
+ - LICENSE
27
+ - README.rdoc
28
+ - Rakefile
29
+ - VERSION
30
+ - lib/reportme.rb
31
+ - lib/reportme/report.rb
32
+ - lib/reportme/report_factory.rb
33
+ - test/report_me_test.rb
34
+ - test/test_helper.rb
35
+ has_rdoc: false
36
+ homepage: http://github.com/jzimmek/report_me
37
+ post_install_message:
38
+ rdoc_options:
39
+ - --charset=UTF-8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.2.0
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: Ruby wrapper to automate sql reports
61
+ test_files:
62
+ - test/report_me_test.rb
63
+ - test/test_helper.rb