monocle 0.2.2 → 0.2.3

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.
@@ -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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Monocle
2
- VERSION = '0.2.2'
2
+ VERSION = '0.2.3'
3
3
  end
@@ -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.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