monocle 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/monocle.rb +36 -0
- data/lib/monocle/server.rb +17 -0
- data/lib/monocle/version.rb +1 -1
- data/spec/monocle_spec.rb +41 -2
- metadata +1 -2
- data/VERSION +0 -1
data/lib/monocle.rb
CHANGED
@@ -51,6 +51,15 @@ module Monocle
|
|
51
51
|
field = v.call
|
52
52
|
field.is_a?(String) ? field : field.to_i
|
53
53
|
end
|
54
|
+
|
55
|
+
define_method("#{k}_clicks_count") do
|
56
|
+
self._monocle_redis_connection.hget(self.class.monocle_key(id), self.send("#{k}_clicks_field")).to_i || 0
|
57
|
+
end
|
58
|
+
|
59
|
+
define_method("#{k}_clicks_field") do
|
60
|
+
field = v.call
|
61
|
+
field.is_a?(String) ? field : field.to_i
|
62
|
+
end
|
54
63
|
end
|
55
64
|
end
|
56
65
|
|
@@ -90,10 +99,32 @@ module Monocle
|
|
90
99
|
end
|
91
100
|
end
|
92
101
|
|
102
|
+
def click!
|
103
|
+
results = self._monocle_redis_connection.pipelined do
|
104
|
+
self._monocle_view_types.keys.each do |view_type|
|
105
|
+
self._monocle_redis_connection.hincrby(self.class.monocle_key(id), self.send("#{view_type}_clicks_field"), 1)
|
106
|
+
end
|
107
|
+
self._monocle_redis_connection.zadd(self.class.monocle_key('recently_clicked'), Time.now.to_i, id)
|
108
|
+
self._monocle_redis_connection.zincrby(self.class.monocle_key('click_counts'), 1, id)
|
109
|
+
end
|
110
|
+
|
111
|
+
if should_cache_view_count?
|
112
|
+
self._monocle_view_types.keys.each_with_index do |view_type, i|
|
113
|
+
cache_click_count(view_type, results[i])
|
114
|
+
end
|
115
|
+
self.update_column(self._monocle_options[:cache_threshold_check_field].to_sym, Time.now) if respond_to?(:update_column)
|
116
|
+
self.set(self._monocle_options[:cache_threshold_check_field].to_sym, Time.now) if respond_to?(:set)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
93
120
|
def cache_field_for_view(view_type)
|
94
121
|
:"#{view_type}_views"
|
95
122
|
end
|
96
123
|
|
124
|
+
def cache_field_for_click(view_type)
|
125
|
+
:"#{view_type}_clicks"
|
126
|
+
end
|
127
|
+
|
97
128
|
def should_cache_view_count?
|
98
129
|
if self._monocle_options[:cache_view_counts]
|
99
130
|
self.send(self._monocle_options[:cache_threshold_check_field]) < (Time.now - self._monocle_options[:cache_threshold])
|
@@ -107,6 +138,11 @@ module Monocle
|
|
107
138
|
set(cache_field_for_view(view_type), count) if respond_to?(:set)
|
108
139
|
end
|
109
140
|
|
141
|
+
def cache_click_count(view_type, count)
|
142
|
+
update_column(cache_field_for_click(view_type), count) if respond_to?(:update_column)
|
143
|
+
set(cache_field_for_click(view_type), count) if respond_to?(:set)
|
144
|
+
end
|
145
|
+
|
110
146
|
def destroy_views
|
111
147
|
self._monocle_redis_connection.del(self.class.monocle_key(id))
|
112
148
|
end
|
data/lib/monocle/server.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'sinatra/base'
|
2
|
+
require 'base64'
|
3
|
+
require 'uri'
|
2
4
|
|
3
5
|
module Monocle
|
4
6
|
class Server < Sinatra::Base
|
@@ -10,6 +12,14 @@ module Monocle
|
|
10
12
|
view_object(params[:type], params[:id])
|
11
13
|
end
|
12
14
|
|
15
|
+
get '/:type/click/:id.:format' do
|
16
|
+
click_object(params[:type], params[:id], params[:redirect_to])
|
17
|
+
end
|
18
|
+
|
19
|
+
get '/:type/click/:redirect_to/:id.:format' do
|
20
|
+
click_object(params[:type], params[:id], params[:redirect_to])
|
21
|
+
end
|
22
|
+
|
13
23
|
def view_object(type, id)
|
14
24
|
if object = type.classify.constantize.find(id)
|
15
25
|
object.view!
|
@@ -18,5 +28,12 @@ module Monocle
|
|
18
28
|
'o_0'
|
19
29
|
end
|
20
30
|
end
|
31
|
+
|
32
|
+
def click_object(type, id, redirect_to)
|
33
|
+
if object = type.classify.constantize.find(id)
|
34
|
+
object.click!
|
35
|
+
redirect(Base64.decode64(URI.unescape(redirect_to)), 301)
|
36
|
+
end
|
37
|
+
end
|
21
38
|
end
|
22
39
|
end
|
data/lib/monocle/version.rb
CHANGED
data/spec/monocle_spec.rb
CHANGED
@@ -21,6 +21,10 @@ class TestObject
|
|
21
21
|
attr_accessor :weekly_views, :daily_views, :hourly_views
|
22
22
|
attr_accessor :quarterly_views
|
23
23
|
|
24
|
+
attr_accessor :overall_clicks, :yearly_clicks, :monthly_clicks
|
25
|
+
attr_accessor :weekly_clicks, :daily_clicks, :hourly_clicks
|
26
|
+
attr_accessor :quarterly_clicks
|
27
|
+
|
24
28
|
def self.find(id)
|
25
29
|
o = new
|
26
30
|
o.id = id.to_i
|
@@ -29,7 +33,7 @@ class TestObject
|
|
29
33
|
|
30
34
|
def initialize
|
31
35
|
@id = '12345'
|
32
|
-
@overall_views = 0
|
36
|
+
@overall_views, @overall_clicks = 0
|
33
37
|
@updated_at = Time.now - 1.hour
|
34
38
|
end
|
35
39
|
|
@@ -43,6 +47,7 @@ def make_viewed_objects(number_of_objects_to_make)
|
|
43
47
|
o = TestObject.new
|
44
48
|
o.id = i
|
45
49
|
o.view!
|
50
|
+
o.click!
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
@@ -81,12 +86,14 @@ describe Monocle do
|
|
81
86
|
object.view!
|
82
87
|
object.destroy_views
|
83
88
|
REDIS.hget('monocle:test_object:12345', 'overall_views').should == nil
|
89
|
+
REDIS.hget('monocle:test_object:12345', 'overall_clicks').should == nil
|
84
90
|
end
|
85
91
|
end
|
86
92
|
|
87
93
|
describe '#cache_field_for_view' do
|
88
94
|
it 'returns the cache field for the given view type' do
|
89
95
|
object.cache_field_for_view('overall').should == :overall_views
|
96
|
+
object.cache_field_for_click('overall').should == :overall_clicks
|
90
97
|
end
|
91
98
|
end
|
92
99
|
|
@@ -117,7 +124,7 @@ describe Monocle do
|
|
117
124
|
context 'when cache time is over threshold' do
|
118
125
|
describe '#view!' do
|
119
126
|
before { object.stub(:updated_at).and_return(Time.now - 1.hour) }
|
120
|
-
before { 50.times { object.view! }}
|
127
|
+
before { 50.times { object.view! } }
|
121
128
|
after { object.destroy_views }
|
122
129
|
|
123
130
|
%w(overall yearly monthly weekly daily hourly quarterly).each do |view_type|
|
@@ -130,6 +137,22 @@ describe Monocle do
|
|
130
137
|
end
|
131
138
|
end
|
132
139
|
end
|
140
|
+
|
141
|
+
describe '#click!' do
|
142
|
+
before { object.stub(:updated_at).and_return(Time.now - 1.hour) }
|
143
|
+
before { 50.times { object.click! } }
|
144
|
+
after { object.destroy_views }
|
145
|
+
|
146
|
+
%w(overall yearly monthly weekly daily hourly quarterly).each do |view_type|
|
147
|
+
it "sets #{view_type} views count" do
|
148
|
+
object.send("#{view_type}_clicks_count").should == 50
|
149
|
+
end
|
150
|
+
|
151
|
+
it "updates cached #{view_type} views count" do
|
152
|
+
object.send("#{view_type}_clicks").should == 50
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
133
156
|
end
|
134
157
|
|
135
158
|
context 'when cache time is under threshold' do
|
@@ -148,5 +171,21 @@ describe Monocle do
|
|
148
171
|
end
|
149
172
|
end
|
150
173
|
end
|
174
|
+
|
175
|
+
describe '#click!' do
|
176
|
+
before { object.stub(:updated_at).and_return(Time.now) }
|
177
|
+
before { 50.times { object.click! }}
|
178
|
+
after { object.destroy_views }
|
179
|
+
|
180
|
+
%w(overall yearly monthly weekly daily hourly quarterly).each do |view_type|
|
181
|
+
it "sets #{view_type} views count" do
|
182
|
+
object.send("#{view_type}_clicks_count").should == 50
|
183
|
+
end
|
184
|
+
|
185
|
+
it "updates cached #{view_type} views count" do
|
186
|
+
object.send("#{view_type}_clicks").to_i.should == 0
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
151
190
|
end
|
152
191
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monocle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -74,7 +74,6 @@ files:
|
|
74
74
|
- LICENSE.txt
|
75
75
|
- README.rdoc
|
76
76
|
- Rakefile
|
77
|
-
- VERSION
|
78
77
|
- lib/monocle.rb
|
79
78
|
- lib/monocle/core_ext.rb
|
80
79
|
- lib/monocle/server.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.1.1
|