kpi 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -22,62 +22,108 @@ Add to your Gemfile:
22
22
  and run in console in project directory:
23
23
 
24
24
  $ bundle
25
+
26
+ === Rails 2.x
25
27
 
26
- == Configuration
27
-
28
- Create config/initializers/kpi.rb:
29
-
30
- KPI.configure do |c|
31
- c.app_name = "Your App Name"
32
- c.mail_from = "Your App KPI Service <kpi@example.com>"
33
- c.mail_to = "your@email.com"
34
- end
28
+ This gem is tested with Rails 2.3.8.
35
29
 
36
30
  == Defining report
37
31
 
38
32
  Example report in app/models/daily_kpi_report.rb:
39
33
 
40
- class DailyKpiReport < KPI::Report::Base
34
+ class DailyKpiReport < KPI::Report
41
35
  def users_count
42
- return ["Users count", User.count, "Total users count"]
36
+ result "Users count", User.count, :description => "Total users count"
43
37
  end
44
38
 
45
39
  def today_registrations_count
46
- return ["Today registrations count", User.where("created_at > ?", @time - 24.hours)]
40
+ result "Today registrations count", User.where("created_at > ?", @time - 24.hours)
41
+ end
42
+
43
+ def total_income
44
+ result "Total income", Order.sum(:total), :unit => 'EUR'
45
+ end
46
+
47
+ def today_income
48
+ result "Total income", Order.where(:created_at => today).sum(:total), :unit => 'EUR'
49
+ end
50
+
51
+ private
52
+
53
+ def today
54
+ ((time - 24.hours)..time)
47
55
  end
48
56
  end
49
57
 
50
- Each defined method should return an array containing 2 or 3 elements:
51
- * KPI title
58
+ Each defined method should return a KPI::Entry object with following accessors:
59
+ * name
52
60
  * value
53
- * optional description
61
+ * description
62
+ * unit
63
+
64
+ A collection of KPI::Entry is available through Enuberable: Report#entries
54
65
 
55
66
  It is important, if your indicator depends on current time (last 24 hours, last week),
56
67
  to rely on @time instance variable instead of Time.now. This lets you to generate report
57
68
  for every moment in history:
58
69
 
59
- report = DailyKpiReport.new(2.days.ago)
60
-
61
- == Sending report
62
-
63
- To collect all statistics and send an email to you just call:
64
-
65
- DailyKpiReport.collect_and_send!
70
+ report = DailyKpiReport.new(:time => 2.days.ago)
71
+
72
+ === Merged reports
73
+
74
+ You can create merged report from two or more reports of the same type. Look at examples:
75
+
76
+ > today = DailyKpiReport.new
77
+ > today.users_count.value
78
+ # => 20
79
+ > today.today_income.value
80
+ # => 350
81
+ > yesterday = DailyKpiReport.new(:time => 1.day.ago)
82
+ > yesterday.users_count.value
83
+ # => 16
84
+ > yesterday.today_income.value
85
+ # => 250
86
+ > diff = KPI::MergedReport.new(today, yesterday) do |today, yesterday|
87
+ > KPI::Entry.new "$$ (change)", today - yesterday
88
+ > end
89
+ > avg = KPI::MergedReport.new(today, yesterday) do |*entries|
90
+ > KPI::Entry.new "$$ (avg)", entries
91
+ > end
92
+ > diff.users_count.value
93
+ # => 4
94
+ > avg.today_income.value
95
+ # => 300
96
+ > avg.today_income.unit
97
+ # => "EUR"
98
+
99
+ More reports can be passed to constructor of Merged report:
100
+ avg = KPI::MergedReport.new(week_now, week_last, week_next_to_last) do |*entries|
101
+ # ...
102
+ end
66
103
 
67
104
  == Other
68
105
  * You can override report title by overriding title method in report:
69
- class DailyKpiReport < KPI::Report::Base
106
+ class DailyKpiReport < KPI::Report
70
107
  def title; "Your daily report"; end
71
108
  # ...
72
109
  end
73
110
  * You can use Whenever gem to generate periodic reports
74
-
111
+ * Private methods are not considered as indicator methods and can be used as helper methods:
112
+ class WeeklyReport < KPI::Report
113
+ # ...
114
+ private
115
+
116
+ def week_range
117
+ t_prev_mon_begin = time - (time.wday-1)*24*60*60 - time.hour*60*60 - time.min*60 - time.sec
118
+ t_next_sun_end = t_prev_mon_begin + 7*24*60*60 - 1
119
+ (t_prev_mon_begin..t_next_sun_end)
120
+ end
121
+ end
75
122
  == Todo
76
123
 
77
124
  * Generators for configuration and reports
78
125
  * Database persistence - storing reports in different databases: PostgreSQL & Mongo prioritized
79
- * Controllers & views allowing to review stored reports
80
- * More tests ;)
126
+ * Support for "result" helper in block passed to constructor of MergedReport
81
127
 
82
128
 
83
129
  == Contributing to KPI
@@ -1,15 +1,16 @@
1
1
  module KPI
2
2
  class Entry
3
- attr_reader :name, :value, :description
3
+ attr_reader :name, :value, :description, :unit
4
4
  def initialize(*args)
5
5
  options = args.extract_options!
6
6
  raise ArgumentError, "Wrong number of arguments (#{args.count} of 2)" unless args.count == 2
7
7
  @name, @value = args
8
8
  @description = options[:description]
9
+ @unit = options[:unit]
9
10
  end
10
11
 
11
12
  def to_a
12
- [@title, @value, @description].compact
13
+ [@title, @value, @description, @unit].compact
13
14
  end
14
15
  end
15
16
  end
@@ -28,9 +28,12 @@ module KPI
28
28
  def method_missing(name, *args)
29
29
  result = @compare.call(*@reports.map(&name.to_sym))
30
30
  orginal = @reports.first.send(name.to_sym)
31
- description = (orginal.description ? result.description.gsub("$$", orginal.description) : nil)
31
+ description = (orginal.description && result.description ? result.description.gsub("$$", orginal.description) : nil)
32
32
 
33
- KPI::Entry.new(result.name.gsub("$$", orginal.name), result.value, :description => description)
33
+ KPI::Entry.new(result.name.gsub("$$", orginal.name),
34
+ result.value,
35
+ :description => description,
36
+ :unit => (result.unit || orginal.unit))
34
37
  end
35
38
  end
36
39
  end
@@ -8,8 +8,8 @@ module KPI
8
8
  blacklist :initialize, :collect!, :entries, :time, :title, :defined_kpis, :result
9
9
 
10
10
  def initialize(*args)
11
- options = args.extract_options!
12
- @time = options[:time] || Time.now
11
+ @options = args.extract_options!
12
+ @time = @options[:time] || Time.now
13
13
  end
14
14
  attr_reader :time
15
15
 
@@ -28,5 +28,13 @@ describe "KPI::Entry" do
28
28
  assert_equal("desc", @entry.description)
29
29
  end
30
30
  end
31
+
32
+ describe "when unit given" do
33
+ before { @entry = KPI::Entry.new "Income", 1294.23, :description => "EUR" }
34
+
35
+ it "returns description" do
36
+ assert_equal("EUR", @entry.unit)
37
+ end
38
+ end
31
39
  end
32
40
  end
@@ -14,7 +14,7 @@ describe "KPI::MergedReport" do
14
14
  end
15
15
 
16
16
  def test_kpi_2
17
- result "title 2 ", @return*2
17
+ result "title 2 ", @return*2, :unit => 'EUR'
18
18
  end
19
19
  end
20
20
  class AnotherReport < KPI::Report
@@ -54,10 +54,10 @@ describe "KPI::MergedReport" do
54
54
 
55
55
  describe "when two reports given for average" do
56
56
  before do
57
- report1 = TestKpi.new(2)
58
- report2 = TestKpi.new(8)
57
+ @report1 = TestKpi.new(2)
58
+ @report2 = TestKpi.new(8)
59
59
 
60
- @average = KPI::MergedReport.new(report1, report2) do |*entries|
60
+ @average = KPI::MergedReport.new(@report1, @report2) do |*entries|
61
61
  average = entries.map(&:value).sum / entries.size
62
62
  KPI::Entry.new "Average $$", average, :description => "$$ (average)"
63
63
  end
@@ -74,6 +74,18 @@ describe "KPI::MergedReport" do
74
74
  it "should change $$ in description to indicator descripiton" do
75
75
  assert_equal "description (average)", @average.test_kpi.description
76
76
  end
77
+
78
+ it "should have unit" do
79
+ assert_equal "EUR", @average.test_kpi_2.unit
80
+ end
81
+
82
+ it "should allow to override unit" do
83
+ @merged = KPI::MergedReport.new(@report1, @report2) do |*entries|
84
+ KPI::Entry.new "merged $$", 1, :unit => "$"
85
+ end
86
+ assert_equal '$', @merged.test_kpi.unit
87
+ assert_equal '$', @merged.test_kpi_2.unit
88
+ end
77
89
 
78
90
  it "should return nil description when no description" do
79
91
  assert_nil @average.test_kpi_2.description
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kpi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 1
10
- version: 0.5.1
9
+ - 2
10
+ version: 0.5.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Artur Roszczyk
@@ -15,12 +15,12 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-13 00:00:00 +02:00
18
+ date: 2011-05-14 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- type: :runtime
23
- requirement: &id001 !ruby/object:Gem::Requirement
22
+ name: actionmailer
23
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
24
  none: false
25
25
  requirements:
26
26
  - - ">="
@@ -30,12 +30,12 @@ dependencies:
30
30
  - 2
31
31
  - 3
32
32
  version: "2.3"
33
- name: actionmailer
34
- version_requirements: *id001
35
33
  prerelease: false
36
- - !ruby/object:Gem::Dependency
37
34
  type: :runtime
38
- requirement: &id002 !ruby/object:Gem::Requirement
35
+ requirement: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: activesupport
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ">="
@@ -45,12 +45,12 @@ dependencies:
45
45
  - 2
46
46
  - 3
47
47
  version: "2.3"
48
- name: activesupport
49
- version_requirements: *id002
50
48
  prerelease: false
49
+ type: :runtime
50
+ requirement: *id002
51
51
  - !ruby/object:Gem::Dependency
52
- type: :development
53
- requirement: &id003 !ruby/object:Gem::Requirement
52
+ name: minitest
53
+ version_requirements: &id003 !ruby/object:Gem::Requirement
54
54
  none: false
55
55
  requirements:
56
56
  - - ">="
@@ -59,12 +59,12 @@ dependencies:
59
59
  segments:
60
60
  - 0
61
61
  version: "0"
62
- name: minitest
63
- version_requirements: *id003
64
62
  prerelease: false
65
- - !ruby/object:Gem::Dependency
66
63
  type: :development
67
- requirement: &id004 !ruby/object:Gem::Requirement
64
+ requirement: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: bundler
67
+ version_requirements: &id004 !ruby/object:Gem::Requirement
68
68
  none: false
69
69
  requirements:
70
70
  - - ~>
@@ -74,12 +74,12 @@ dependencies:
74
74
  - 1
75
75
  - 0
76
76
  version: "1.0"
77
- name: bundler
78
- version_requirements: *id004
79
77
  prerelease: false
80
- - !ruby/object:Gem::Dependency
81
78
  type: :development
82
- requirement: &id005 !ruby/object:Gem::Requirement
79
+ requirement: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: jeweler
82
+ version_requirements: &id005 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -90,12 +90,12 @@ dependencies:
90
90
  - 5
91
91
  - 2
92
92
  version: 1.5.2
93
- name: jeweler
94
- version_requirements: *id005
95
93
  prerelease: false
96
- - !ruby/object:Gem::Dependency
97
94
  type: :development
98
- requirement: &id006 !ruby/object:Gem::Requirement
95
+ requirement: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ name: rcov
98
+ version_requirements: &id006 !ruby/object:Gem::Requirement
99
99
  none: false
100
100
  requirements:
101
101
  - - ">="
@@ -104,9 +104,9 @@ dependencies:
104
104
  segments:
105
105
  - 0
106
106
  version: "0"
107
- name: rcov
108
- version_requirements: *id006
109
107
  prerelease: false
108
+ type: :development
109
+ requirement: *id006
110
110
  description: This gem helps you to track key indicators in your Rails app.
111
111
  email: artur.roszczyk@gmail.com
112
112
  executables: []
@@ -165,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  requirements: []
166
166
 
167
167
  rubyforge_project:
168
- rubygems_version: 1.6.2
168
+ rubygems_version: 1.5.2
169
169
  signing_key:
170
170
  specification_version: 3
171
171
  summary: Key Performance Indicators for Rails 3.x