trackoid 0.1.1 → 0.1.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/VERSION +1 -1
- data/lib/trackoid/aggregates.rb +95 -21
- data/lib/trackoid/errors.rb +9 -0
- data/lib/trackoid/tracker.rb +30 -8
- data/lib/trackoid/tracker_aggregates.rb +29 -0
- data/lib/trackoid/tracking.rb +21 -9
- data/lib/trackoid.rb +1 -0
- data/spec/aggregates_spec.rb +98 -12
- data/spec/spec_helper.rb +2 -1
- data/spec/trackoid_spec.rb +12 -4
- data/trackoid.gemspec +3 -2
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/lib/trackoid/aggregates.rb
CHANGED
@@ -1,26 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
module Mongoid #:nodoc:
|
2
|
-
module Tracking
|
3
|
-
|
3
|
+
module Tracking #:nodoc:
|
4
4
|
module Aggregates
|
5
5
|
# This module includes aggregate data extensions to Trackoid instances
|
6
6
|
def self.included(base)
|
7
7
|
base.class_eval do
|
8
8
|
extend ClassMethods
|
9
|
-
include InstanceMethods
|
10
9
|
|
11
10
|
class_inheritable_accessor :aggregate_fields, :aggregate_klass
|
12
|
-
self.aggregate_fields =
|
11
|
+
self.aggregate_fields = {}
|
13
12
|
self.aggregate_klass = nil
|
14
|
-
|
13
|
+
delegate :aggregate_fields,
|
14
|
+
:aggregate_klass,
|
15
|
+
:aggregated?,
|
16
|
+
:to => "self.class"
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
module ClassMethods
|
19
|
-
|
21
|
+
# Defines an aggregate token to an already tracked model. It defines
|
22
|
+
# a new mongoid model named after the original model.
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
#
|
26
|
+
# <tt>class Page</tt>
|
27
|
+
# <tt> include Mongoid::Document</tt>
|
28
|
+
# <tt> include Mongoid::Document</tt>
|
29
|
+
# <tt> track :visits</tt>
|
30
|
+
# <tt> aggregate :browsers do |b|</tt>
|
31
|
+
# <tt> b.split(" ").first</tt>
|
32
|
+
# <tt> end</tt>
|
33
|
+
# <tt>end</tt>
|
34
|
+
#
|
35
|
+
# A new model is defined as <tt>class PageAggregates</tt>
|
36
|
+
#
|
37
|
+
# This model has the following structure:
|
38
|
+
#
|
39
|
+
# <tt>belongs_to :page</tt>
|
40
|
+
# <tt>field :ns, :type => String</tt>
|
41
|
+
# <tt>field :key, :type => String</tt>
|
42
|
+
# <tt>index [:ns, :key], :unique => true</tt>
|
43
|
+
# <tt>track :[original_parent_tracking_data]</tt>
|
44
|
+
# <tt>track :...</tt>
|
45
|
+
#
|
46
|
+
# :ns is the "namespace". It's the name you put along the
|
47
|
+
# "aggregate :browsers" in the original model definition.
|
48
|
+
#
|
49
|
+
# :key is your aggregation key. This is the value you are required to
|
50
|
+
# return in the "aggregate" block.
|
51
|
+
#
|
52
|
+
# With the above structure, you can always query aggregates directly
|
53
|
+
# using Mongoid this way:
|
54
|
+
#
|
55
|
+
# <tt>TestModelAggregates.where(:ns => "browsers", :key => "explorer").first</tt>
|
56
|
+
#
|
57
|
+
# But you are encouraged to use Trackoid methods whenever possible.
|
58
|
+
#
|
20
59
|
def aggregate(name, &block)
|
60
|
+
raise Errors::AggregationAlreadyDefined.new(self.name, name) if
|
61
|
+
aggregate_fields.has_key? name
|
62
|
+
|
21
63
|
define_aggregate_model if aggregate_klass.nil?
|
22
|
-
|
64
|
+
has_many_related internal_accessor_name(name), :class_name => aggregate_klass.to_s
|
23
65
|
add_aggregate_field(name, block)
|
66
|
+
create_aggregation_accessors(name)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return true if this model has aggregated data.
|
70
|
+
def aggregated?
|
71
|
+
!aggregate_klass.nil?
|
24
72
|
end
|
25
73
|
|
26
74
|
protected
|
@@ -30,37 +78,62 @@ module Mongoid #:nodoc:
|
|
30
78
|
str.camelize
|
31
79
|
end
|
32
80
|
|
81
|
+
def internal_accessor_name(name)
|
82
|
+
(name.to_s + "_accessor").to_sym
|
83
|
+
end
|
84
|
+
|
85
|
+
# Defines the aggregation model. It checks for class name conflicts
|
33
86
|
def define_aggregate_model
|
34
87
|
raise Errors::ClassAlreadyDefined.new(internal_aggregates_name) if foreign_class_defined
|
88
|
+
parent_name = self.name.underscore
|
35
89
|
define_klass do
|
36
90
|
include Mongoid::Document
|
37
91
|
include Mongoid::Tracking
|
38
|
-
|
39
|
-
#
|
92
|
+
|
93
|
+
# Make the relation to the original class
|
94
|
+
belongs_to_related parent_name.to_sym, :class_name => parent_name.camelize
|
95
|
+
|
96
|
+
# Internal fields to track aggregation token and keys
|
97
|
+
field :ns, :type => String
|
98
|
+
field :key, :type => String
|
99
|
+
index [[:ns, Mongo::ASCENDING], [:key, Mongo::ASCENDING]], :unique => true, :background => true
|
100
|
+
|
101
|
+
# Include parent tracking data.
|
102
|
+
parent_name.camelize.constantize.tracked_fields.each {|track_field| track track_field }
|
40
103
|
end
|
41
104
|
self.aggregate_klass = internal_aggregates_name.constantize
|
42
105
|
end
|
43
|
-
|
106
|
+
|
107
|
+
# Returns true if there is a class defined with the same name as our
|
108
|
+
# aggregate class.
|
44
109
|
def foreign_class_defined
|
45
110
|
Object.const_defined?(internal_aggregates_name.to_sym)
|
46
111
|
end
|
47
112
|
|
113
|
+
# Adds the aggregate field to the array of aggregated fields.
|
48
114
|
def add_aggregate_field(name, block)
|
49
|
-
aggregate_fields
|
115
|
+
aggregate_fields[name] = block
|
50
116
|
end
|
51
117
|
|
118
|
+
# Defines the aggregation external class. This class is named after
|
119
|
+
# the original class model but with "Aggregates" appended.
|
120
|
+
# Example: TestModel ==> TestModelAggregates
|
52
121
|
def define_klass(&block)
|
53
|
-
|
54
|
-
klass = Object.const_set internal_aggregates_name, Class.new
|
122
|
+
klass = Object.const_set(internal_aggregates_name, Class.new)
|
55
123
|
klass.class_eval(&block)
|
56
124
|
end
|
57
125
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
126
|
+
def create_aggregation_accessors(name)
|
127
|
+
# Aggregation accessors in the model acts like a named scope
|
128
|
+
define_method(name) do |*args|
|
129
|
+
TrackerAggregates.new(self, name, args)
|
130
|
+
end
|
131
|
+
|
132
|
+
define_method("#{name}=") do
|
133
|
+
raise NoMethodError
|
134
|
+
end
|
63
135
|
end
|
136
|
+
|
64
137
|
end
|
65
138
|
|
66
139
|
end
|
@@ -79,9 +152,10 @@ module Mongoid #:nodoc:
|
|
79
152
|
# end
|
80
153
|
#
|
81
154
|
#
|
82
|
-
# self.visits.inc
|
83
|
-
#
|
84
|
-
#
|
155
|
+
# self.visits(agg).inc
|
156
|
+
# self.visits.today
|
157
|
+
# self.visits.browsers.today
|
158
|
+
#
|
85
159
|
# users
|
86
160
|
# { _id: 32334333, name:"pepe", visits_data:{} }
|
87
161
|
#
|
data/lib/trackoid/errors.rb
CHANGED
@@ -11,6 +11,15 @@ module Mongoid #:nodoc
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
class AggregationAlreadyDefined < RuntimeError
|
15
|
+
def initialize(klass, token)
|
16
|
+
@token = token
|
17
|
+
end
|
18
|
+
def message
|
19
|
+
"Aggregation '#{@token}' already defined for model #{klass}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
class ModelNotSaved < RuntimeError; end
|
15
24
|
|
16
25
|
class NotMongoid < RuntimeError; end
|
data/lib/trackoid/tracker.rb
CHANGED
@@ -3,19 +3,41 @@ module Mongoid #:nodoc:
|
|
3
3
|
module Tracking
|
4
4
|
# This internal class handles all interaction for a track field.
|
5
5
|
class Tracker
|
6
|
-
|
6
|
+
|
7
|
+
def initialize(owner, field, aggregate_data)
|
7
8
|
@owner, @for = owner, field
|
8
|
-
@data = @owner.read_attribute(@for)
|
9
|
+
@data = @owner.read_attribute(@for)
|
10
|
+
|
11
|
+
# The following is needed if the "field" Mongoid definition for our
|
12
|
+
# internal tracking field does not include option ":default => {}"
|
13
|
+
if @data.nil?
|
14
|
+
@owner.write_attribute(@for, {})
|
15
|
+
@data = @owner.read_attribute(@for)
|
16
|
+
end
|
17
|
+
|
18
|
+
@aggregate_data = aggregate_data
|
9
19
|
end
|
10
20
|
|
11
21
|
# Update methods
|
12
22
|
def add(how_much = 1, date = DateTime.now)
|
13
23
|
raise Errors::ModelNotSaved, "Can't update a new record" if @owner.new_record?
|
14
|
-
|
15
24
|
update_data(data_for(date) + how_much, date)
|
25
|
+
|
16
26
|
@owner.collection.update( @owner._selector,
|
17
27
|
{ (how_much > 0 ? "$inc" : "$dec") => update_hash(how_much.abs, date) },
|
18
28
|
:upsert => true)
|
29
|
+
|
30
|
+
return unless @owner.aggregated?
|
31
|
+
|
32
|
+
@owner.aggregate_fields.each do |(k,v)|
|
33
|
+
token = v.call(@aggregate_data)
|
34
|
+
fk = @owner.class.name.to_s.foreign_key.to_sym
|
35
|
+
selector = { fk => @owner.id, :ns => k, :key => token }
|
36
|
+
|
37
|
+
@owner.aggregate_klass.collection.update( selector,
|
38
|
+
{ (how_much > 0 ? "$inc" : "$dec") => update_hash(how_much.abs, date) },
|
39
|
+
:upsert => true)
|
40
|
+
end
|
19
41
|
end
|
20
42
|
|
21
43
|
def inc(date = DateTime.now)
|
@@ -28,13 +50,13 @@ module Mongoid #:nodoc:
|
|
28
50
|
|
29
51
|
def set(how_much, date = DateTime.now)
|
30
52
|
raise Errors::ModelNotSaved, "Can't update a new record" if @owner.new_record?
|
31
|
-
|
32
53
|
update_data(how_much, date)
|
33
54
|
@owner.collection.update( @owner._selector,
|
34
55
|
{ "$set" => update_hash(how_much, date) },
|
35
56
|
:upsert => true)
|
36
57
|
end
|
37
58
|
|
59
|
+
|
38
60
|
# Access methods
|
39
61
|
def today
|
40
62
|
data_for(Date.today)
|
@@ -46,7 +68,6 @@ module Mongoid #:nodoc:
|
|
46
68
|
|
47
69
|
def last_days(how_much = 7)
|
48
70
|
return [today] unless how_much > 0
|
49
|
-
|
50
71
|
date, values = DateTime.now, []
|
51
72
|
(date - how_much.abs + 1).step(date) {|d| values << data_for(d) }
|
52
73
|
values
|
@@ -61,11 +82,13 @@ module Mongoid #:nodoc:
|
|
61
82
|
# Private methods
|
62
83
|
private
|
63
84
|
def data_for(date)
|
64
|
-
return 0 if @data
|
65
|
-
|
85
|
+
return 0 if @data.nil? ||
|
86
|
+
@data[date.year.to_s].nil? ||
|
87
|
+
@data[date.year.to_s][date.month.to_s].nil?
|
66
88
|
@data[date.year.to_s][date.month.to_s][date.day.to_s] || 0
|
67
89
|
end
|
68
90
|
|
91
|
+
# TODO: It should be a better way of updating a hash. :-)
|
69
92
|
def update_data(value, date)
|
70
93
|
if @data[date.year.to_s]
|
71
94
|
if @data[date.year.to_s][date.month.to_s]
|
@@ -94,7 +117,6 @@ module Mongoid #:nodoc:
|
|
94
117
|
}
|
95
118
|
end
|
96
119
|
|
97
|
-
|
98
120
|
# WARNING: This is +only+ for debugging pourposes (rspec y tal)
|
99
121
|
def _original_hash
|
100
122
|
@data
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Tracking
|
4
|
+
# This internal class handles all interaction of an aggregation token.
|
5
|
+
class TrackerAggregates
|
6
|
+
|
7
|
+
def initialize(owner, token, key_selector)
|
8
|
+
@owner, @token = owner, token
|
9
|
+
@key = key_selector
|
10
|
+
|
11
|
+
@accessor = @owner.class.send(:internal_accessor_name, @token)
|
12
|
+
@selector = {:ns => @token}
|
13
|
+
@selector.merge!(:key => @key.first) if @key.first
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(name, *args, &block)
|
17
|
+
@criteria ||= @owner.send(@accessor).where(@selector)
|
18
|
+
|
19
|
+
# Delegate all missing methods to the underlying Mongoid Criteria
|
20
|
+
return @criteria.send(name) unless @owner.tracked_fields.member?(name)
|
21
|
+
|
22
|
+
# Otherwise, it's a track method, so process it
|
23
|
+
@criteria.collect {|x| x.send(name, *args, &block) }
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/trackoid/tracking.rb
CHANGED
@@ -20,13 +20,14 @@ module Mongoid #:nodoc:
|
|
20
20
|
|
21
21
|
module ClassMethods
|
22
22
|
# Adds analytics tracking for +name+. Adds a +'name'_data+ mongoid
|
23
|
-
# field as a Hash for tracking this information. Additionaly,
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
23
|
+
# field as a Hash for tracking this information. Additionaly, hiddes
|
24
|
+
# the field, so that the user can not mangle with the original one.
|
25
|
+
# This is necessary so that Mongoid does not "dirty" the field
|
26
|
+
# potentially overwriting the original data.
|
27
27
|
def track(name)
|
28
28
|
set_tracking_field(name)
|
29
29
|
create_tracking_accessors(name)
|
30
|
+
update_aggregates(name) if aggregated?
|
30
31
|
end
|
31
32
|
|
32
33
|
protected
|
@@ -38,10 +39,10 @@ module Mongoid #:nodoc:
|
|
38
39
|
# Configures the internal fields for tracking. Additionally also creates
|
39
40
|
# an index for the internal tracking field.
|
40
41
|
def set_tracking_field(name)
|
41
|
-
field internal_track_name(name), :type => Hash, :default => {}
|
42
|
-
#
|
42
|
+
field internal_track_name(name), :type => Hash # , :default => {}
|
43
|
+
# Should we make an index for this field?
|
43
44
|
index internal_track_name(name)
|
44
|
-
tracked_fields <<
|
45
|
+
tracked_fields << name.to_sym
|
45
46
|
end
|
46
47
|
|
47
48
|
# Creates the tracking field accessor and also disables the original
|
@@ -49,8 +50,8 @@ module Mongoid #:nodoc:
|
|
49
50
|
# Mongoid fields ensures they doesn't get dirty, so Mongoid does not
|
50
51
|
# overwrite old data.
|
51
52
|
def create_tracking_accessors(name)
|
52
|
-
define_method("#{name}") do
|
53
|
-
Tracker.new(self, "#{name}_data".to_sym)
|
53
|
+
define_method("#{name}") do |*aggr|
|
54
|
+
Tracker.new(self, "#{name}_data".to_sym, aggr)
|
54
55
|
end
|
55
56
|
|
56
57
|
# Should we just "undef" this methods?
|
@@ -62,6 +63,17 @@ module Mongoid #:nodoc:
|
|
62
63
|
define_method("#{name}_data=") do
|
63
64
|
raise NoMethodError
|
64
65
|
end
|
66
|
+
|
67
|
+
# I think it's important to override also the #{name}_changed? so
|
68
|
+
# as to be sure Mongoid never mark this field as dirty.
|
69
|
+
define_method("#{name}_changed?") do
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Updates the aggregated class for it to include a new tracking field
|
75
|
+
def update_aggregates(name)
|
76
|
+
aggregate_klass.track name
|
65
77
|
end
|
66
78
|
|
67
79
|
end
|
data/lib/trackoid.rb
CHANGED
data/spec/aggregates_spec.rb
CHANGED
@@ -5,11 +5,15 @@ class TestModel
|
|
5
5
|
include Mongoid::Tracking
|
6
6
|
|
7
7
|
field :name # Dummy field
|
8
|
+
|
9
|
+
# Note that references to "track" and "aggregate" in this test are mixed
|
10
|
+
# for testing pourposes. Trackoid does not make any difference in the
|
11
|
+
# declaration order of tracking fields and aggregate tokens.
|
8
12
|
track :visits
|
13
|
+
aggregate :browsers do; "Mozilla".downcase; end
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
15
|
+
track :uniques
|
16
|
+
aggregate :referers do; "GoogleBot".downcase; end
|
13
17
|
end
|
14
18
|
|
15
19
|
class SecondTestModel
|
@@ -20,7 +24,7 @@ class SecondTestModel
|
|
20
24
|
track :visits
|
21
25
|
|
22
26
|
aggregate :browsers do
|
23
|
-
"Chrome"
|
27
|
+
"Chrome".downcase
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
@@ -39,30 +43,61 @@ describe Mongoid::Tracking::Aggregates do
|
|
39
43
|
end
|
40
44
|
|
41
45
|
it "should create a has_many relationship in the original model" do
|
42
|
-
|
46
|
+
# Note that due to ActiveSupport "class_inheritable_accessor" this method
|
47
|
+
# is available both as class method and instance method.
|
48
|
+
@mock.class.method_defined?(:browsers_accessor).should be_true
|
43
49
|
end
|
44
50
|
|
45
|
-
it "should have the aggregates klass in a instance var" do
|
46
|
-
|
51
|
+
it "should have the aggregates klass in a class/instance var" do
|
52
|
+
# Note that due to ActiveSupport "class_inheritable_accessor" this method
|
53
|
+
# is available both as class method and instance method.
|
54
|
+
@mock.class.aggregate_klass == TestModelAggregates
|
47
55
|
end
|
48
56
|
|
49
|
-
it "should create
|
50
|
-
|
57
|
+
it "should create a hash in the class with all aggregate fields" do
|
58
|
+
# Note that due to ActiveSupport "class_inheritable_accessor" this method
|
59
|
+
# is available both as class method and instance method.
|
60
|
+
@mock.class.aggregate_fields.keys.to_set.should == [ :browsers, :referers ].to_set
|
51
61
|
end
|
52
62
|
|
53
63
|
it "should create an array in the class with all aggregate fields even when monkey patching" do
|
54
64
|
class TestModel
|
55
|
-
aggregate :
|
56
|
-
"
|
65
|
+
aggregate :quarters do
|
66
|
+
"Q1"
|
57
67
|
end
|
58
68
|
end
|
59
|
-
@mock.class.aggregate_fields.
|
69
|
+
@mock.class.aggregate_fields.keys.to_set.should == [ :browsers, :referers, :quarters ].to_set
|
70
|
+
end
|
71
|
+
|
72
|
+
it "the aggregated class should have the same tracking fields as the parent class" do
|
73
|
+
TestModelAggregates.tracked_fields.should == TestModel.tracked_fields
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should raise error if we try to add an aggregation token twice" do
|
77
|
+
lambda {
|
78
|
+
class TestModel
|
79
|
+
aggregate :referers do
|
80
|
+
"(none)"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
}.should raise_error Mongoid::Errors::AggregationAlreadyDefined
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should have Mongoid accessors defined" do
|
87
|
+
tm = TestModel.create(:name => "Dummy")
|
88
|
+
tm.send(tm.class.send(:internal_accessor_name, "browsers")).class.should == Mongoid::Criteria
|
89
|
+
tm.send(tm.class.send(:internal_accessor_name, "referers")).class.should == Mongoid::Criteria
|
90
|
+
tm.send(tm.class.send(:internal_accessor_name, "quarters")).class.should == Mongoid::Criteria
|
60
91
|
end
|
61
92
|
|
62
93
|
it "should indicate this is an aggregated traking object with aggregated?" do
|
63
94
|
@mock.aggregated?.should be_true
|
64
95
|
end
|
65
96
|
|
97
|
+
it "should indicate this is an aggregated class with aggregated?" do
|
98
|
+
@mock.class.aggregated?.should be_true
|
99
|
+
end
|
100
|
+
|
66
101
|
it "should raise error if already defined class with the same aggregated klass name" do
|
67
102
|
lambda {
|
68
103
|
class MockTestAggregates
|
@@ -115,4 +150,55 @@ describe Mongoid::Tracking::Aggregates do
|
|
115
150
|
}.should raise_error Mongoid::Errors::ClassAlreadyDefined
|
116
151
|
end
|
117
152
|
|
153
|
+
describe "when tracking a model with aggregation data" do
|
154
|
+
|
155
|
+
before(:all) do
|
156
|
+
TestModel.delete_all
|
157
|
+
TestModel.create(:name => "test")
|
158
|
+
@object_id = TestModel.first.id
|
159
|
+
end
|
160
|
+
|
161
|
+
before do
|
162
|
+
@mock = TestModel.find(@object_id)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "calling an aggregation scope should return the appropiate class" do
|
166
|
+
@mock.browsers.class.should == Mongoid::Tracking::TrackerAggregates
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should increment visits for all aggregated instances" do
|
170
|
+
@mock.visits("Aggregate data").inc
|
171
|
+
@mock.browsers.count.should == 1
|
172
|
+
@mock.referers.count.should == 1
|
173
|
+
@mock.quarters.count.should == 1
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should increment visits for specific aggregation keys" do
|
177
|
+
@mock.browsers("mozilla").size.should == 1
|
178
|
+
@mock.referers("googlebot").size.should == 1
|
179
|
+
@mock.quarters("Q1").size.should == 1
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should NOT increment visits for different aggregation keys" do
|
183
|
+
@mock.browsers("internet explorer").size.should == 0
|
184
|
+
@mock.referers("yahoo slurp").size.should == 0
|
185
|
+
@mock.quarters("Q2").size.should == 0
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should have 1 in visits" do
|
189
|
+
tt = @mock.browsers.visits.collect {|v| v.last_days(7)}
|
190
|
+
tt.should == [[0, 0, 0, 0, 0, 0, 1]]
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
# it "should print methods && their classes to stdout" do
|
198
|
+
# TestModel.methods.sort.each {|x|
|
199
|
+
# puts "#{x}"
|
200
|
+
# }
|
201
|
+
# should be_true
|
202
|
+
# end
|
203
|
+
|
118
204
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,8 +14,9 @@ Mongoid.configure do |config|
|
|
14
14
|
name = "trackoid_test"
|
15
15
|
host = "localhost"
|
16
16
|
port = "27017"
|
17
|
-
|
17
|
+
# config.master = Mongo::Connection.new(host, port, :logger => Logger.new(STDOUT)).db(name)
|
18
18
|
config.master = Mongo::Connection.new.db(name)
|
19
|
+
config.use_object_ids = true
|
19
20
|
end
|
20
21
|
|
21
22
|
Spec::Runner.configure do |config|
|
data/spec/trackoid_spec.rb
CHANGED
@@ -49,7 +49,13 @@ describe Mongoid::Tracking do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should create a method for accesing the stats" do
|
52
|
-
@mock.respond_to?(:visits).should
|
52
|
+
@mock.respond_to?(:visits).should be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should respond 'false' to field_changed? method" do
|
56
|
+
# Ok, this test is not very relevant since it will return false even
|
57
|
+
# if Trackid does not override it.
|
58
|
+
@mock.visits_changed?.should be_false
|
53
59
|
end
|
54
60
|
|
55
61
|
it "should create a method for accesing the stats of the proper class" do
|
@@ -57,14 +63,14 @@ describe Mongoid::Tracking do
|
|
57
63
|
end
|
58
64
|
|
59
65
|
it "should create an array in the class with all tracking fields" do
|
60
|
-
@mock.class.tracked_fields.should == [ :
|
66
|
+
@mock.class.tracked_fields.should == [ :visits ]
|
61
67
|
end
|
62
68
|
|
63
69
|
it "should create an array in the class with all tracking fields even when monkey patching" do
|
64
70
|
class Test
|
65
71
|
track :something_else
|
66
72
|
end
|
67
|
-
@mock.class.tracked_fields.should == [ :
|
73
|
+
@mock.class.tracked_fields.should == [ :visits, :something_else ]
|
68
74
|
end
|
69
75
|
|
70
76
|
it "should not update stats when new record" do
|
@@ -211,8 +217,10 @@ describe Mongoid::Tracking do
|
|
211
217
|
end
|
212
218
|
tm = TestModel.first
|
213
219
|
tm.something.today.should == 0
|
220
|
+
tm.something.inc
|
221
|
+
tm.something.today.should == 1
|
214
222
|
end
|
215
|
-
|
223
|
+
|
216
224
|
end
|
217
225
|
|
218
226
|
end
|
data/trackoid.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{trackoid}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jose Miguel Perez"]
|
12
|
-
s.date = %q{2010-06-
|
12
|
+
s.date = %q{2010-06-06}
|
13
13
|
s.description = %q{Trackoid uses an embeddable approach to track analytics data using the poweful features of MongoDB for scalability}
|
14
14
|
s.email = %q{josemiguel@perezruiz.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
"lib/trackoid/aggregates.rb",
|
28
28
|
"lib/trackoid/errors.rb",
|
29
29
|
"lib/trackoid/tracker.rb",
|
30
|
+
"lib/trackoid/tracker_aggregates.rb",
|
30
31
|
"lib/trackoid/tracking.rb",
|
31
32
|
"spec/aggregates_spec.rb",
|
32
33
|
"spec/spec.opts",
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trackoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jose Miguel Perez
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-06 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/trackoid/aggregates.rb
|
55
55
|
- lib/trackoid/errors.rb
|
56
56
|
- lib/trackoid/tracker.rb
|
57
|
+
- lib/trackoid/tracker_aggregates.rb
|
57
58
|
- lib/trackoid/tracking.rb
|
58
59
|
- spec/aggregates_spec.rb
|
59
60
|
- spec/spec.opts
|