gatoroid 0.1.0

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/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'mongoid', '>= 2.1.0'
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ gem 'jeweler'
8
+ gem 'rspec', '>= 2.2.0'
9
+ gem 'mocha'
10
+ gem 'bson_ext'
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Kevin Haight (kevinjhaight@gmail.com)
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,59 @@
1
+ = Gatoroid
2
+
3
+ Gatoroid is a way to store analytics using the powerful features of MongoDB for scalability
4
+
5
+ Leveraging mongoid, Gatoroid is a way to increment, decrement, add to, and reset counters in MongoDB. The data is stored using an hourly grain in a utc allowing for easy analytics for on just about anything.
6
+
7
+ == Using Gatoroid to store analytics information
8
+ Simply create a class that includes Mongoid::Gator
9
+
10
+ class SiteStats
11
+ include Mongoid::Gator
12
+ field :siteid
13
+ gator_field :visits
14
+ end
15
+
16
+ Use the class to increment the counter for visits to the site.
17
+
18
+ @site_stats = SiteStats.new()
19
+ @site_stats.visits.inc(:siteid=>100)
20
+
21
+ You can also add to the count using the add method. The following adds 10 visits to tomorrow.
22
+
23
+ @site_stats.visits.add(10, :date=>Today.now + 1.day)
24
+
25
+ The data will be stored in MongoDB using seconds since the epoch in hours
26
+
27
+ {
28
+ "_id" : ObjectId("4f85b40f2a2c4e4d9709eaf9"),
29
+ "date" : 1334160000,
30
+ "siteid" : 100,
31
+ "visits" : 1
32
+ }
33
+
34
+ You can view the total visits to a site by using some built in functions. For example:
35
+
36
+ @site_stats = SiteStats.new()
37
+ @site_stats.visits.today(:siteid=>100) # returns total for today as integer
38
+ @site_stats.visits.yesterday(:siteid=100) # returns total for yesterday as integer
39
+
40
+
41
+ To get a list of visits to for a range, use the range method.
42
+
43
+ @site_stats = SiteStats.new()
44
+ @site_stats.visits.range(Time.now..Time.now + 1.day,Mongoid::Gator::Readers::DAY, :siteid=>100)
45
+
46
+ You can change the grain on which you would like to return the data using
47
+
48
+ Mongoid::Gator::Readers::HOUR
49
+ Mongoid::Gator::Readers::DAY
50
+ Mongoid::Gator::Readers::MONTH
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "gatoroid"
8
+ gem.summary = %Q{Gatoroid is an easy scalable analytics plugin using MongoDB and Mongoid}
9
+ gem.description = %Q{Gatoroid is a way to store analytics using the poweful features of MongoDB for scalability}
10
+ gem.email = "kevinjhaight@gmail.com"
11
+ gem.homepage = "http://github.com/alayho/gatoroid"
12
+ gem.authors = ["Kevin Haight"]
13
+ end
14
+ Jeweler::GemcutterTasks.new
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
17
+ end
18
+
19
+ require 'rspec/core/rake_task'
20
+ RSpec::Core::RakeTask.new(:spec) do |spec|
21
+ spec.pattern = 'spec/**/*_spec.rb'
22
+ end
23
+
24
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
25
+ spec.pattern = 'spec/**/*_spec.rb'
26
+ spec.rcov = true
27
+ end
28
+
29
+ task :default => :spec
30
+
31
+ require 'rake/rdoctask'
32
+ Rake::RDocTask.new do |rdoc|
33
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
34
+ rdoc.rdoc_dir = 'rdoc'
35
+ rdoc.title = "gatoroid #{version}"
36
+ rdoc.rdoc_files.include('README*')
37
+ rdoc.rdoc_files.include('lib/**/*.rb')
38
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/gatoroid.gemspec ADDED
@@ -0,0 +1,70 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "gatoroid"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kevin Haight"]
12
+ s.date = "2012-04-11"
13
+ s.description = "Gatoroid is a way to store analytics using the poweful features of MongoDB for scalability"
14
+ s.email = "kevinjhaight@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".rspec",
21
+ "Gemfile",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "gatoroid.gemspec",
27
+ "lib/gator/errors.rb",
28
+ "lib/gator/gator.rb",
29
+ "lib/gator/gatorer.rb",
30
+ "lib/gator/javascript.rb",
31
+ "lib/gator/javascript/functions.yml",
32
+ "lib/gator/readers.rb",
33
+ "lib/gatoroid.rb",
34
+ "spec/gatoroid_spec.rb",
35
+ "spec/spec.opts",
36
+ "spec/spec_helper.rb"
37
+ ]
38
+ s.homepage = "http://github.com/alayho/gatoroid"
39
+ s.require_paths = ["lib"]
40
+ s.rubygems_version = "1.8.17"
41
+ s.summary = "Gatoroid is an easy scalable analytics plugin using MongoDB and Mongoid"
42
+
43
+ if s.respond_to? :specification_version then
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_runtime_dependency(%q<mongoid>, [">= 2.1.0"])
48
+ s.add_development_dependency(%q<rake>, [">= 0"])
49
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
50
+ s.add_development_dependency(%q<rspec>, [">= 2.2.0"])
51
+ s.add_development_dependency(%q<mocha>, [">= 0"])
52
+ s.add_development_dependency(%q<bson_ext>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<mongoid>, [">= 2.1.0"])
55
+ s.add_dependency(%q<rake>, [">= 0"])
56
+ s.add_dependency(%q<jeweler>, [">= 0"])
57
+ s.add_dependency(%q<rspec>, [">= 2.2.0"])
58
+ s.add_dependency(%q<mocha>, [">= 0"])
59
+ s.add_dependency(%q<bson_ext>, [">= 0"])
60
+ end
61
+ else
62
+ s.add_dependency(%q<mongoid>, [">= 2.1.0"])
63
+ s.add_dependency(%q<rake>, [">= 0"])
64
+ s.add_dependency(%q<jeweler>, [">= 0"])
65
+ s.add_dependency(%q<rspec>, [">= 2.2.0"])
66
+ s.add_dependency(%q<mocha>, [">= 0"])
67
+ s.add_dependency(%q<bson_ext>, [">= 0"])
68
+ end
69
+ end
70
+
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc
3
+ module Errors #:nodoc
4
+
5
+ class ClassAlreadyDefined < RuntimeError
6
+ def initialize(klass)
7
+ @klass = klass
8
+ end
9
+ def message
10
+ "#{@klass} already defined, can't aggregate!"
11
+ end
12
+ end
13
+
14
+ class AggregationAlreadyDefined < RuntimeError
15
+ def initialize(klass, token)
16
+ @klass = klass
17
+ @token = token
18
+ end
19
+ def message
20
+ "Aggregation '#{@token}' already defined for model #{@klass}"
21
+ end
22
+ end
23
+
24
+ class AggregationNameDeprecated < RuntimeError
25
+ def initialize(token)
26
+ @token = token
27
+ end
28
+ def message
29
+ "Ussing aggregation name '#{@klass}' is deprecated. Please select another name."
30
+ end
31
+ end
32
+
33
+ class ModelNotSaved < RuntimeError; end
34
+
35
+ class NotMongoid < RuntimeError; end
36
+
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ require 'mongoid'
3
+ module Mongoid #:nodoc:
4
+ module Gator #:nodoc:
5
+ def self.included(base)
6
+ base.class_eval do
7
+ include Mongoid::Document
8
+ extend ClassMethods
9
+ class_attribute :gator_keys, :gator_fields
10
+ self.gator_keys = []
11
+ self.gator_fields = []
12
+ delegate :gator_keys, :to => "self.class"
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def field(name=nil)
18
+ gator_keys << name
19
+ end
20
+
21
+ def gator_field(name=nil)
22
+ gator_fields << name
23
+ create_accessors(name)
24
+ end
25
+
26
+ protected
27
+ def create_accessors(name)
28
+ define_method(name) do
29
+ Gatorer.new(self, name)
30
+ end
31
+
32
+ define_singleton_method(name) do
33
+ Gatorer.new(self, name)
34
+ end
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,204 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Gator
4
+ class Gatorer
5
+
6
+ include Readers
7
+
8
+ # Initialize object
9
+ def initialize(object, field)
10
+ @object, @for = object, field
11
+ create_accessors()
12
+ end
13
+
14
+ private
15
+
16
+ # Get total for
17
+ def total_for(date,grain,opts={})
18
+ unless date.nil?
19
+ begin
20
+ return @object.class.where(create_query_hash(date,grain,opts)).sum(@for)
21
+ rescue
22
+ return @object.where(create_query_hash(date,grain,opts)).sum(@for)
23
+ end
24
+ end
25
+ end
26
+
27
+ # Get collections for
28
+ def collection_for(date,grain, opts={})
29
+ unless date.nil?
30
+ return @object.collection.group(:keyf => create_fkey(grain),
31
+ :reduce => "function(obj,prev){for (var key in obj.#{@for}) {prev.#{@for} += obj.#{@for}}}",
32
+ :cond=>create_query_hash(date,grain,opts),
33
+ :initial => {@for => 0})
34
+ end
35
+ end
36
+
37
+ # Convert date levels
38
+ def convert_date_by_level(date,level)
39
+ if date.is_a?(Range)
40
+ sdate = date.first
41
+ edate = date.last
42
+ else
43
+ sdate = date
44
+ edate = date
45
+ end
46
+ case level
47
+ when HOUR
48
+ return sdate.change(:sec=>0), edate.change(:sec=>0) + 1.hour
49
+ when DAY
50
+ return sdate.change(:hour=>0).change(:sec=>0), edate.change(:hour=>0).change(:sec=>0) + 1.day
51
+ when MONTH
52
+ return sdate.change(:day=>1).change(:hour=>0).change(:sec=>0), edate.change(:day=>1).change(:hour=>0).change(:sec=>0) + 1.month
53
+ end
54
+ end
55
+
56
+ # Create fkey
57
+ def create_fkey(grain)
58
+ case grain
59
+ when HOUR
60
+ fkey = Javascript.aggregate_hour
61
+ when MONTH
62
+ fkey = Javascript.aggregate_month
63
+ else # DEFAULT TO DAY
64
+ fkey = Javascript.aggregate_day
65
+ end
66
+ return fkey
67
+ end
68
+
69
+ protected
70
+ def create_accessors
71
+ self.class.class_eval do
72
+ define_method :inc do | *args |
73
+ keys, date = gen_params(Hash[*args])
74
+ inc_counter(keys,date)
75
+ end
76
+
77
+ define_method :dec do | *args |
78
+ keys, date = gen_params(Hash[*args])
79
+ dec_counter(keys,date)
80
+ end
81
+
82
+ define_method :add do | how_many, *args |
83
+ keys, date = gen_params(Hash[*args])
84
+ add_to_counter(how_many,keys,date)
85
+ end
86
+
87
+ define_method :reset do | *args |
88
+ keys, date = gen_params(Hash[*args])
89
+ reset_counter(keys,date)
90
+ end
91
+ end
92
+ end
93
+
94
+ # Add
95
+ def add_to_counter(how_much = 1, keys=[], date = Time.now)
96
+ return if how_much == 0
97
+ # Upsert value
98
+ @object.collection.update(create_key_hash(keys,date.utc),
99
+ {"$inc" => {
100
+ "#{@for}" => how_much,
101
+ }},
102
+ :upsert => true
103
+ )
104
+ end
105
+
106
+ # Reset Counter
107
+ def reset_counter(keys=[], date = Time.now)
108
+ # Upsert value
109
+ @object.collection.update(create_key_hash(keys,date.utc),
110
+ {"$set" => {
111
+ "#{@for}" => 0,
112
+ }},
113
+ :upsert => true
114
+ )
115
+ end
116
+
117
+ # Increment Counter
118
+ def inc_counter(keys,date = Time.now)
119
+ add_to_counter(1,keys,date)
120
+ end
121
+
122
+ # Decrement Counter
123
+ def dec_counter(keys, date = Time.now)
124
+ add_to_counter(-1,keys,date)
125
+ end
126
+
127
+ # Generate parameters
128
+ def gen_params(params)
129
+ date = Time.now # Set default date to now
130
+ key_hash = Hash.new { |hash, key| hash[key] = [] }
131
+ @object.gator_keys.each do| gk |
132
+ raise Errors::ModelNotSaved, "Missing key value #{gk}" if params[gk].nil?
133
+ key_hash[gk] = params[gk]
134
+ end
135
+ # Set Date
136
+ if !params[:date].nil?
137
+ date = params[:date]
138
+ end
139
+ return key_hash, date
140
+ end
141
+
142
+ # Create Hash Key
143
+ def create_key_hash(keys,date = Time.now)
144
+ keys = Hash[keys]
145
+ key_hash = Hash.new { |hash, key| hash[key] = [] }
146
+ @object.gator_keys.each do | gk |
147
+ if keys[gk].kind_of?(Array)
148
+ keys[gk].each do |k|
149
+ key_hash[gk] = k
150
+ end
151
+ else
152
+ key_hash[gk] = keys[gk]
153
+ end
154
+ end
155
+ key_hash[:date] = normalize_date(date)
156
+ return key_hash
157
+ end
158
+
159
+ # Create Group Key Hash
160
+ def create_group_key_hash
161
+ keys = []
162
+ @object.gator_keys.each do | gk |
163
+ keys << gk
164
+ end
165
+ keys << :date
166
+ return keys
167
+ end
168
+
169
+ # Create Query Hash
170
+ def create_query_hash(date = Time.now, grain, opts)
171
+ key_hash = Hash.new { |hash, key| hash[key] = [] }
172
+ # Set Keys
173
+ @object.gator_keys.each do | gk |
174
+ raise Errors::ModelNotSaved, "Missing key value #{gk}" if opts[gk].nil?
175
+ if opts[gk].kind_of?(Array)
176
+ key_hash[gk] = {"$in" => opts[gk]}
177
+ else
178
+ key_hash[gk] = opts[gk]
179
+ end
180
+ end
181
+ sdate,edate = convert_date_by_level(date,grain) # Set Dates
182
+ key_hash[:date] = {"$gte" => normalize_date(sdate), "$lt" => normalize_date(edate)}
183
+ return key_hash
184
+ end
185
+
186
+ # Normalize Dates
187
+ def normalize_date(date)
188
+ case date
189
+ when String
190
+ date = Time.parse(date).change(:sec => 0).change(:min => 0)
191
+ when Date
192
+ date = date.to_time.change(:sec => 0).change(:min => 0)
193
+ when Range
194
+ date = normalize_date(date.change(:sec => 0).change(:min => 0).first)..normalize_date(date.change(:sec => 0).change(:min => 0).last)
195
+ else
196
+ date = date.change(:sec => 0).change(:min => 0)
197
+ end
198
+ return date.to_i
199
+
200
+ end
201
+
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,17 @@
1
+ aggregate_hour:
2
+ "function(doc) {
3
+ d = new Date(doc.date* 1000);
4
+ return {date: Date.parse((d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear() + ' ' + d.getHours() + ':00:00') / 1000};
5
+ }"
6
+
7
+ aggregate_day:
8
+ "function(doc) {
9
+ d = new Date(doc.date* 1000);
10
+ return {date: Date.parse((d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear()) / 1000};
11
+ }"
12
+
13
+ aggregate_month:
14
+ "function(doc) {
15
+ d = new Date(doc.date* 1000);
16
+ return {date: Date.parse((d.getMonth() + 1) + '/1/' + d.getFullYear()) / 1000};
17
+ }"
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Gator
4
+ class Javascript
5
+ # Constant for the file that defines all the js functions.
6
+ FUNCTIONS = File.join(File.dirname(__FILE__), "javascript", "functions.yml")
7
+
8
+ # Load the javascript functions and define a class method for each one,
9
+ # that memoizes the value.
10
+ #
11
+ # @example Get the function.
12
+ # Mongoid::Javascript.aggregate
13
+ YAML.load(File.read(FUNCTIONS)).each_pair do |key, function|
14
+ (class << self; self; end).class_eval <<-EOT
15
+ def #{key}
16
+ @#{key} ||= "#{function}"
17
+ end
18
+ EOT
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Gator
4
+ module Readers
5
+
6
+ HOUR = "HOUR"
7
+ DAY = "DAY"
8
+ MONTH = "MONTH"
9
+ DEFAULT_GRAIN = DAY
10
+
11
+ # Today - Gets total for today on DAY level
12
+ def today(opts={})
13
+ total_for(Time.now, DEFAULT_GRAIN, opts).to_i
14
+ end
15
+
16
+ # Yesterday - Gets total for tomorrow on DAY level
17
+ def yesterday(opts={})
18
+ total_for(Time.now - 1.day, DEFAULT_GRAIN,opts).to_i
19
+ end
20
+
21
+ # On - Gets total for a specified day on DAY level
22
+ def on(date,opts={})
23
+ total_for(date, DEFAULT_GRAIN,opts).to_i
24
+ end
25
+
26
+ # Range - retuns a collection for a specified range on specified level
27
+ def range(date, grain=DEFAULT_GRAIN, opts={})
28
+ collection_for(date,grain,opts)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
data/lib/gatoroid.rb ADDED
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+
4
+ gem "mongoid", ">= 1.9.0"
5
+
6
+ #require 'gator/errors'
7
+ #require 'gator/core_ext'
8
+ #require 'gator/reader_extender'
9
+ #require 'gator/readers'
10
+ #require 'gator/gator'
11
+ #require 'gator/aggregates'
12
+ #require 'gator/gator_aggregates'
13
+ #require '../lib/gator/gatoring.rb'
14
+ #require File.expand_path('../gator/errors.rb', __FILE__)
15
+ #require File.expand_path('../gator/reader_extender.rb', __FILE__)
16
+ require File.expand_path('../gator/errors.rb', __FILE__)
17
+ require File.expand_path('../gator/javascript.rb', __FILE__)
18
+ require File.expand_path('../gator/readers.rb', __FILE__)
19
+ require File.expand_path('../gator/gatorer.rb', __FILE__)
20
+ require File.expand_path('../gator/gator.rb', __FILE__)
21
+ #require File.expand_path('../../lib/gator.rb', __FILE__)
22
+
23
+ module Mongoid
24
+ module Gator
25
+ VERSION = File.read(File.expand_path("../VERSION", File.dirname(__FILE__)))
26
+ end
27
+ end
@@ -0,0 +1,198 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class Test
4
+ include Mongoid::Gator
5
+ field :siteid
6
+ gator_field :visits
7
+ end
8
+
9
+
10
+ describe Mongoid::Gator do
11
+ before(:all) do
12
+ @gatoroid_version = File.read(File.expand_path("../VERSION", File.dirname(__FILE__)))
13
+ end
14
+
15
+ it "should expose the same version as the VERSION file" do
16
+ Mongoid::Gator::VERSION.should == @gatoroid_version
17
+ end
18
+
19
+ it "should not raise errors when using to/as_json" do
20
+ mock = Test.new(:siteid => 1000)
21
+ json_as = {}
22
+ json_to = ""
23
+
24
+ lambda {
25
+ json_as = mock.as_json(:except => :_id)
26
+ json_to = mock.to_json(:except => :_id)
27
+ }.should_not raise_error
28
+ json_as.should == { "siteid" => 1000 }
29
+ json_to.should == "{\"siteid\":1000}"
30
+ end
31
+
32
+ describe "when using an instance of the object" do
33
+ before(:all) do
34
+ @obj = Test.new
35
+ end
36
+
37
+ it "should deny access to undefined methods" do
38
+ lambda { @obj.test_method }.should raise_error NoMethodError
39
+ lambda { @obj.test_method = {} }.should raise_error NoMethodError
40
+ end
41
+
42
+ it "should create a method for gator_fields" do
43
+ @obj.respond_to?(:visits).should be_true
44
+ end
45
+
46
+ it "should NOT create an index for the gator_fields" do
47
+ @obj.class.index_options.should_not include(:visits)
48
+ end
49
+
50
+ it "should create a method for accesing the stats of the proper class" do
51
+ @obj.visits.class.should == Mongoid::Gator::Gatorer
52
+ end
53
+
54
+ it "should create an array in the class with all gator fields" do
55
+ @obj.class.gator_fields.should == [ :visits ]
56
+ end
57
+
58
+ it "should create an array in the class with all gator fields even when monkey patching" do
59
+ class Test
60
+ gator_field :something_else
61
+ end
62
+ @obj.class.gator_fields.should == [ :visits, :something_else ]
63
+ end
64
+
65
+ it "should not increment stats when missing key" do
66
+ lambda { @obj.visits.inc }.should raise_error Mongoid::Errors::ModelNotSaved
67
+ end
68
+
69
+ it "should increment stats when key is present" do
70
+ lambda { @obj.visits.inc(:siteid=>100) }.should_not raise_error Mongoid::Errors::ModelNotSaved
71
+ end
72
+
73
+ it "should not decrement stats when key is present" do
74
+ lambda { @obj.visits.dec() }.should raise_error Mongoid::Errors::ModelNotSaved
75
+ end
76
+
77
+ it "should decrement stats when key is present" do
78
+ lambda { @obj.visits.dec(:siteid=>100) }.should_not raise_error Mongoid::Errors::ModelNotSaved
79
+ end
80
+
81
+ it "should not add stats when key is present" do
82
+ lambda { @obj.visits.add(1) }.should raise_error Mongoid::Errors::ModelNotSaved
83
+ end
84
+
85
+ it "should add stats when key is present" do
86
+ lambda { @obj.visits.add(1,:siteid=>100) }.should_not raise_error Mongoid::Errors::ModelNotSaved
87
+ end
88
+
89
+
90
+ it "should give 1 for today stats" do
91
+ @obj.visits.today(:siteid=>100).should == 1
92
+ end
93
+
94
+ it "should give 0 for yesterday stats" do
95
+ @obj.visits.yesterday(:siteid=>100).should == 0
96
+ end
97
+
98
+ it "should give 1 for using on for today stats" do
99
+ @obj.visits.on(Time.now,:siteid=>100).should == 1
100
+ end
101
+
102
+ it "should have 1 record using range method for today and yesterday at day grain" do
103
+ @obj.visits.range(Time.now..Time.now + 1.day,Mongoid::Gator::Readers::DAY, :siteid=>100).should have(1).record
104
+ end
105
+
106
+ it "should have 1 record using range method for today and yesterday at hour grain" do
107
+ @obj.visits.range(Time.now..Time.now + 1.day,Mongoid::Gator::Readers::HOUR, :siteid=>100).should have(1).record
108
+ end
109
+
110
+ it "should have 1 record using range method for today and yesterday at month grain" do
111
+ @obj.visits.range(Time.now..Time.now + 1.day,Mongoid::Gator::Readers::HOUR, :siteid=>100).should have(1).record
112
+ end
113
+
114
+ it "should reset value to zero" do
115
+ @obj.visits.reset(:date => Time.now, :siteid=>100).should_not raise_error Mongoid::Errors::ModelNotSaved
116
+ @obj.visits.today(:siteid=>100).should == 0
117
+ end
118
+
119
+ end
120
+
121
+
122
+ describe "when using as a model" do
123
+ it "should deny access to undefined methods" do
124
+ lambda { Test.test_method }.should raise_error NoMethodError
125
+ lambda { Test.test_method = {} }.should raise_error NoMethodError
126
+ end
127
+
128
+ it "should create a method for gator_fields" do
129
+ Test.respond_to?(:visits).should be_true
130
+ end
131
+
132
+ it "should NOT create an index for the gator_fields" do
133
+ Test.index_options.should_not include(:visits)
134
+ end
135
+
136
+ it "should create a method for accesing the stats of the proper class" do
137
+ Test.visits.class.should == Mongoid::Gator::Gatorer
138
+ end
139
+
140
+ it "should create an array in the class with all gator fields even when monkey patching" do
141
+ Test.gator_fields.should == [ :visits, :something_else ]
142
+ end
143
+
144
+ it "should not increment stats when missing key" do
145
+ lambda { Test.visits.inc }.should raise_error Mongoid::Errors::ModelNotSaved
146
+ end
147
+
148
+ it "should increment stats when key is present" do
149
+ lambda { Test.visits.inc(:siteid=>200) }.should_not raise_error Mongoid::Errors::ModelNotSaved
150
+ end
151
+
152
+ it "should not decrement stats when key is present" do
153
+ lambda { Test.visits.dec() }.should raise_error Mongoid::Errors::ModelNotSaved
154
+ end
155
+
156
+ it "should decrement stats when key is present" do
157
+ lambda { Test.visits.dec(:siteid=>200) }.should_not raise_error Mongoid::Errors::ModelNotSaved
158
+ end
159
+
160
+ it "should not add stats when key is present" do
161
+ lambda { Test.visits.add(1) }.should raise_error Mongoid::Errors::ModelNotSaved
162
+ end
163
+
164
+ it "should add stats when key is present" do
165
+ lambda { Test.visits.add(1,:siteid=>200) }.should_not raise_error Mongoid::Errors::ModelNotSaved
166
+ end
167
+
168
+ it "should give 1 for today stats" do
169
+ Test.visits.today(:siteid=>200).should == 1
170
+ end
171
+
172
+ it "should give 0 for yesterday stats" do
173
+ Test.visits.yesterday(:siteid=>200).should == 0
174
+ end
175
+
176
+ it "should give 1 for using on for today stats" do
177
+ Test.visits.on(Time.now,:siteid=>200).should == 1
178
+ end
179
+
180
+ it "should have 1 record using range method for today and yesterday at day grain" do
181
+ Test.visits.range(Time.now..Time.now + 1.day,Mongoid::Gator::Readers::DAY, :siteid=>200).should have(1).record
182
+ end
183
+
184
+ it "should have 1 record using range method for today and yesterday at hour grain" do
185
+ Test.visits.range(Time.now..Time.now + 1.day,Mongoid::Gator::Readers::HOUR, :siteid=>200).should have(1).record
186
+ end
187
+
188
+ it "should have 1 record using range method for today and yesterday at month grain" do
189
+ Test.visits.range(Time.now..Time.now + 1.day,Mongoid::Gator::Readers::HOUR, :siteid=>200).should have(1).record
190
+ end
191
+
192
+ it "should reset value to zero" do
193
+ Test.visits.reset(:date => Time.now, :siteid=>200).should_not raise_error Mongoid::Errors::ModelNotSaved
194
+ Test.visits.today(:siteid=>200).should == 0
195
+ end
196
+ end
197
+
198
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
@@ -0,0 +1,26 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+
5
+ gem 'mocha', '>= 0.9.8'
6
+
7
+ require 'mocha'
8
+ require 'mongoid'
9
+ require 'gatoroid'
10
+ require 'bson'
11
+ require 'rspec'
12
+ require 'rspec/autorun'
13
+
14
+ Mongoid.configure do |config|
15
+ name = "gatoroid_test"
16
+ host = "localhost"
17
+ port = "27017"
18
+ config.master = Mongo::Connection.new.db(name)
19
+ end
20
+
21
+ RSpec.configure do |config|
22
+ config.mock_with :mocha
23
+ config.before :suite do
24
+ Mongoid.master.collections.reject { |c| c.name =~ /^system\./ }.each(&:drop)
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gatoroid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kevin Haight
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mongoid
16
+ requirement: &2164561420 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2164561420
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &2164560940 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2164560940
36
+ - !ruby/object:Gem::Dependency
37
+ name: jeweler
38
+ requirement: &2164560400 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2164560400
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &2164559640 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.2.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2164559640
58
+ - !ruby/object:Gem::Dependency
59
+ name: mocha
60
+ requirement: &2164558740 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2164558740
69
+ - !ruby/object:Gem::Dependency
70
+ name: bson_ext
71
+ requirement: &2164557900 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2164557900
80
+ description: Gatoroid is a way to store analytics using the poweful features of MongoDB
81
+ for scalability
82
+ email: kevinjhaight@gmail.com
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files:
86
+ - LICENSE
87
+ - README.rdoc
88
+ files:
89
+ - .rspec
90
+ - Gemfile
91
+ - LICENSE
92
+ - README.rdoc
93
+ - Rakefile
94
+ - VERSION
95
+ - gatoroid.gemspec
96
+ - lib/gator/errors.rb
97
+ - lib/gator/gator.rb
98
+ - lib/gator/gatorer.rb
99
+ - lib/gator/javascript.rb
100
+ - lib/gator/javascript/functions.yml
101
+ - lib/gator/readers.rb
102
+ - lib/gatoroid.rb
103
+ - spec/gatoroid_spec.rb
104
+ - spec/spec.opts
105
+ - spec/spec_helper.rb
106
+ homepage: http://github.com/alayho/gatoroid
107
+ licenses: []
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.17
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: Gatoroid is an easy scalable analytics plugin using MongoDB and Mongoid
130
+ test_files: []