has_metrics 0.0.1 → 0.0.2
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/has_metrics.gemspec +6 -6
- data/lib/has_metrics/metrics.rb +11 -5
- data/lib/has_metrics/segmentation.rb +36 -0
- data/lib/has_metrics/version.rb +1 -1
- data/lib/has_metrics.rb +5 -1
- data/test/functional/metrics_test.rb +19 -26
- data/test/functional/segmentation_test.rb +34 -0
- data/test/test_helper.rb +20 -2
- data/test.db +0 -0
- metadata +101 -86
data/has_metrics.gemspec
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path('../lib/has_metrics/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Allan Grant"]
|
6
6
|
gem.email = ["allan@allangrant.net"]
|
7
|
-
gem.description = %q{
|
7
|
+
gem.description = %q{Calculate metrics and store them in the DB.}
|
8
8
|
gem.summary = %q{Calculate "metrics" (any expensive methods) on ActiveRecord entries and memoize them to an automagical table.}
|
9
9
|
gem.homepage = "http://github.com/allangrant/has_metrics"
|
10
10
|
|
@@ -15,9 +15,9 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = HasMetrics::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency
|
19
|
-
gem.add_development_dependency
|
20
|
-
gem.add_development_dependency
|
21
|
-
|
22
|
-
gem.add_development_dependency
|
18
|
+
gem.add_dependency "activerecord"
|
19
|
+
gem.add_development_dependency "rake"
|
20
|
+
gem.add_development_dependency "shoulda"
|
21
|
+
gem.add_development_dependency "sqlite3"
|
22
|
+
gem.add_development_dependency "pry"
|
23
23
|
end
|
data/lib/has_metrics/metrics.rb
CHANGED
@@ -53,9 +53,14 @@ module Metrics
|
|
53
53
|
result = instance_exec(&block)
|
54
54
|
result = nil if result.is_a?(Float) && !result.finite?
|
55
55
|
begin
|
56
|
-
metrics.
|
57
|
-
|
58
|
-
|
56
|
+
metrics.send "#{name}=", result
|
57
|
+
metrics.send "#{datestamp_column}=", Time.now
|
58
|
+
rescue NoMethodError => e
|
59
|
+
raise e unless e.name == "#{name}=".to_sym
|
60
|
+
# This happens if the migrations haven't run yet for this metric. We should still calculate & return the metric.
|
61
|
+
end
|
62
|
+
unless changed?
|
63
|
+
metrics.save
|
59
64
|
end
|
60
65
|
result
|
61
66
|
end
|
@@ -88,7 +93,8 @@ module Metrics
|
|
88
93
|
:datetime
|
89
94
|
when @float_metrics && @float_metrics.include?(column)
|
90
95
|
:float
|
91
|
-
else
|
96
|
+
else
|
97
|
+
:integer
|
92
98
|
end
|
93
99
|
end
|
94
100
|
|
@@ -145,7 +151,7 @@ module Metrics
|
|
145
151
|
raise "Cannot determine if there were extra columns for has_metric when using the table itself for storing the metric! Remove any columns manually"
|
146
152
|
[] # We wont know what columns are excessive if the source changed
|
147
153
|
else
|
148
|
-
(columns.map(&:name) - %w(id created_at updated_at))
|
154
|
+
(columns.map(&:name) - %w(id created_at updated_at)) - required_columns
|
149
155
|
end
|
150
156
|
|
151
157
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# include Segmentation
|
2
|
+
module Segmentation
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
# CLASS METHODS ADDED
|
8
|
+
module ClassMethods
|
9
|
+
def segment_by category, &definition
|
10
|
+
(@segment_categories ||= []) << category.to_sym
|
11
|
+
define_method("segment_by_#{category}", definition)
|
12
|
+
if respond_to?(:has_metric)
|
13
|
+
has_metric "by_#{category}" do
|
14
|
+
send("segment_by_#{category}")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
def segment_categories
|
19
|
+
@segment_categories
|
20
|
+
end
|
21
|
+
def update_segments!
|
22
|
+
puts "Updating all segments on #{name}: #{segment_categories.join(', ')}"
|
23
|
+
all.each do |object|
|
24
|
+
segment_categories.each do |category|
|
25
|
+
object.update_segment!(category)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end # END OF CLASS METHODS
|
30
|
+
|
31
|
+
# INSTANCE METHODS ADDED
|
32
|
+
def update_segment!(category)
|
33
|
+
update_attribute("by_#{category}", send("segment_by_#{category}"))
|
34
|
+
end
|
35
|
+
# END OF INSTANCE METHODS
|
36
|
+
end
|
data/lib/has_metrics/version.rb
CHANGED
data/lib/has_metrics.rb
CHANGED
@@ -1,23 +1,5 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
|
2
2
|
|
3
|
-
ActiveRecord::Base.establish_connection(:adapter => "sqlite3",
|
4
|
-
:database => File.expand_path(File.dirname(__FILE__) + "/../test.db"))
|
5
|
-
|
6
|
-
class CreateTestTables < ActiveRecord::Migration
|
7
|
-
def self.up
|
8
|
-
create_table "users", :force => true do |t|
|
9
|
-
t.string "name"
|
10
|
-
end
|
11
|
-
create_table "user_metrics", :force => true
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.down
|
15
|
-
drop_table "users"
|
16
|
-
drop_table "user_metrics"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
3
|
class User < ActiveRecord::Base
|
22
4
|
include Metrics
|
23
5
|
has_metric :name_length do
|
@@ -25,16 +7,12 @@ class User < ActiveRecord::Base
|
|
25
7
|
end
|
26
8
|
end
|
27
9
|
|
28
|
-
|
29
10
|
class MetricsTest < Test::Unit::TestCase
|
30
11
|
context "when defining metrics" do
|
31
12
|
setup do
|
32
|
-
|
33
|
-
|
34
|
-
CreateTestTables.up
|
35
|
-
User.update_all_metrics!
|
36
|
-
@user_name =
|
13
|
+
CreateTestTables.up(:user)
|
37
14
|
@user = User.create(:name => "Fuzz")
|
15
|
+
User.update_all_metrics!
|
38
16
|
end
|
39
17
|
|
40
18
|
should "create rows for the metrics" do
|
@@ -47,12 +25,27 @@ class MetricsTest < Test::Unit::TestCase
|
|
47
25
|
assert_equal 16, @user.name_length_squared
|
48
26
|
end
|
49
27
|
|
50
|
-
should "
|
28
|
+
should "calculate their block when called" do
|
51
29
|
assert_equal "Fuzz", @user.name
|
52
30
|
assert_equal 4, @user.name_length
|
31
|
+
|
53
32
|
@user.name = "Bib"
|
54
|
-
|
33
|
+
|
34
|
+
# since 20 hours hasn't passed, the value is pulled from cache, not recalculated
|
35
|
+
assert_equal 4, @user.name_length
|
36
|
+
# (true) forces it to recalculate right away
|
37
|
+
assert_equal 3, @user.name_length(true)
|
38
|
+
|
39
|
+
# since it wasn't saved, it's the same in the DB
|
55
40
|
assert_equal 4, User.find_by_name("Fuzz").name_length
|
41
|
+
|
42
|
+
@user.save
|
43
|
+
assert_equal 3, @user.name_length(true)
|
44
|
+
assert_equal 3, User.find_by_name("Bib").name_length
|
45
|
+
end
|
46
|
+
|
47
|
+
should "have their values precomputed" do
|
48
|
+
assert_equal({4=>1}, UserMetrics.count(:group => :name_length))
|
56
49
|
end
|
57
50
|
end
|
58
51
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
|
2
|
+
|
3
|
+
class Post < ActiveRecord::Base
|
4
|
+
include Metrics
|
5
|
+
include Segmentation
|
6
|
+
|
7
|
+
segment_by :name_length do
|
8
|
+
case name.length
|
9
|
+
when 0..6
|
10
|
+
"short"
|
11
|
+
when 7
|
12
|
+
"seven"
|
13
|
+
else
|
14
|
+
"long"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class SegmentationTest < Test::Unit::TestCase
|
20
|
+
context "when defining segments" do
|
21
|
+
setup do
|
22
|
+
CreateTestTables.up(:post)
|
23
|
+
|
24
|
+
Post.create(:name => "Shorty")
|
25
|
+
Post.create(:name => "Seven!!")
|
26
|
+
Post.create(:name => "Really long")
|
27
|
+
Post.update_all_metrics!
|
28
|
+
end
|
29
|
+
|
30
|
+
should "segment properly" do
|
31
|
+
assert_equal({'short'=>1, 'seven'=>1, 'long'=>1}, PostMetrics.count(:group => :by_name_length))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -5,6 +5,24 @@ $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
|
5
5
|
|
6
6
|
require 'shoulda'
|
7
7
|
# require 'mocha'
|
8
|
-
require '
|
8
|
+
require 'active_record'
|
9
9
|
require 'sqlite3'
|
10
|
-
require 'has_metrics
|
10
|
+
require 'has_metrics'
|
11
|
+
require 'pry'
|
12
|
+
|
13
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => File.expand_path(File.dirname(__FILE__) + "/../test.db"))
|
14
|
+
|
15
|
+
|
16
|
+
class CreateTestTables < ActiveRecord::Migration
|
17
|
+
def self.up(model = :user)
|
18
|
+
create_table "#{model}s", :force => true do |t|
|
19
|
+
t.string "name"
|
20
|
+
end
|
21
|
+
create_table "#{model}_metrics", :force => true
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down(model = :user)
|
25
|
+
drop_table "#{model}s"
|
26
|
+
drop_table "#{model}_metrics"
|
27
|
+
end
|
28
|
+
end
|
data/test.db
ADDED
Binary file
|
metadata
CHANGED
@@ -1,89 +1,103 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_metrics
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 0.0.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Allan Grant
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
22
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
23
|
-
none: false
|
24
|
-
requirements:
|
25
|
-
- - ">="
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
hash: 3
|
28
|
-
segments:
|
29
|
-
- 0
|
30
|
-
version: "0"
|
31
|
-
requirement: *id001
|
32
|
-
prerelease: false
|
12
|
+
date: 2012-11-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
33
15
|
name: activerecord
|
34
|
-
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
37
17
|
none: false
|
38
|
-
requirements:
|
39
|
-
- -
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
|
42
|
-
|
43
|
-
- 0
|
44
|
-
version: "0"
|
45
|
-
requirement: *id002
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
46
23
|
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
47
31
|
name: rake
|
48
|
-
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
51
33
|
none: false
|
52
|
-
requirements:
|
53
|
-
- -
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
|
56
|
-
|
57
|
-
- 0
|
58
|
-
version: "0"
|
59
|
-
requirement: *id003
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
60
39
|
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
61
47
|
name: shoulda
|
62
|
-
|
63
|
-
- !ruby/object:Gem::Dependency
|
64
|
-
version_requirements: &id004 !ruby/object:Gem::Requirement
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
65
49
|
none: false
|
66
|
-
requirements:
|
67
|
-
- -
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
|
70
|
-
|
71
|
-
- 0
|
72
|
-
version: "0"
|
73
|
-
requirement: *id004
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
74
55
|
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
75
63
|
name: sqlite3
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
76
70
|
type: :development
|
77
|
-
|
78
|
-
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: pry
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Calculate metrics and store them in the DB.
|
95
|
+
email:
|
79
96
|
- allan@allangrant.net
|
80
97
|
executables: []
|
81
|
-
|
82
98
|
extensions: []
|
83
|
-
|
84
99
|
extra_rdoc_files: []
|
85
|
-
|
86
|
-
files:
|
100
|
+
files:
|
87
101
|
- .gitignore
|
88
102
|
- Gemfile
|
89
103
|
- LICENSE
|
@@ -92,43 +106,44 @@ files:
|
|
92
106
|
- has_metrics.gemspec
|
93
107
|
- lib/has_metrics.rb
|
94
108
|
- lib/has_metrics/metrics.rb
|
109
|
+
- lib/has_metrics/segmentation.rb
|
95
110
|
- lib/has_metrics/version.rb
|
111
|
+
- test.db
|
96
112
|
- test/functional/metrics_test.rb
|
113
|
+
- test/functional/segmentation_test.rb
|
97
114
|
- test/test_helper.rb
|
98
|
-
has_rdoc: true
|
99
115
|
homepage: http://github.com/allangrant/has_metrics
|
100
116
|
licenses: []
|
101
|
-
|
102
117
|
post_install_message:
|
103
118
|
rdoc_options: []
|
104
|
-
|
105
|
-
require_paths:
|
119
|
+
require_paths:
|
106
120
|
- lib
|
107
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
122
|
none: false
|
109
|
-
requirements:
|
110
|
-
- -
|
111
|
-
- !ruby/object:Gem::Version
|
112
|
-
|
113
|
-
segments:
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
segments:
|
114
128
|
- 0
|
115
|
-
|
116
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
hash: -764161358984080823
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
131
|
none: false
|
118
|
-
requirements:
|
119
|
-
- -
|
120
|
-
- !ruby/object:Gem::Version
|
121
|
-
|
122
|
-
segments:
|
132
|
+
requirements:
|
133
|
+
- - ! '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
segments:
|
123
137
|
- 0
|
124
|
-
|
138
|
+
hash: -764161358984080823
|
125
139
|
requirements: []
|
126
|
-
|
127
140
|
rubyforge_project:
|
128
|
-
rubygems_version: 1.
|
141
|
+
rubygems_version: 1.8.24
|
129
142
|
signing_key:
|
130
143
|
specification_version: 3
|
131
|
-
summary: Calculate "metrics" (any expensive methods) on ActiveRecord entries and memoize
|
132
|
-
|
144
|
+
summary: Calculate "metrics" (any expensive methods) on ActiveRecord entries and memoize
|
145
|
+
them to an automagical table.
|
146
|
+
test_files:
|
133
147
|
- test/functional/metrics_test.rb
|
148
|
+
- test/functional/segmentation_test.rb
|
134
149
|
- test/test_helper.rb
|