boffin 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1390bed0369dd43eb7dbe07d1ecf8742ffdaf134
4
+ data.tar.gz: 2cdd53fe1d9598b296302340dc4bebe0f016f450
5
+ SHA512:
6
+ metadata.gz: c9f6ca3b08a95c6ff48915a9d68c94b405769fe0767f7ed4eef42e0cb6cdc2e4d5ccfe61f8cf58c68c1e20380d2c24400bbdb4c7249720bb32498ee7049cc401
7
+ data.tar.gz: becf97f999b9050ede5bf07f85329440ffa4ce5d244fa595f0f60543142c427da6689fd0af79d83c9124bbfa42d74db9a73f09fcdf5f50d65d5761e4d6f0f90b
@@ -1,15 +1,29 @@
1
- **0.3.0**
1
+ 1.0.0
2
+
3
+ * Support for redis-rb 3.0, no backwards compatibility is maintained
4
+ * Ruby 2.0 is now officially supported, 1.9.3, and 1.8.7 are still supported
5
+ * Removed `Tracker#uhit_count` in favour of `Tracker#count(..., unique: true)`
6
+ * Renamed `Utils#object_as_session_identifier` to `Utils#object_as_uid`
7
+ * Renamed `Tracker#hit_count` to `Tracker#count`
8
+ * Renamed `Utils#uniquenesses_as_session_identifier` to `Utils#uniquenesses_as_uid`
9
+ * Changed `Utils#uniquenesses_as_uid` to splat arguments, this allows for uses
10
+ like `Tracker.hit(:thing, unique: current_user)` instead of
11
+ `Tracker.hit(:thing, unique: [current_user])`
12
+ * Removed `Tracker#hit_count_for_session_id` in favour of
13
+ `Tracker#count(..., unique: unique_object)`
14
+
15
+ 0.3.0
2
16
 
3
17
  * `Hit` can now accept a custom increment, this allows values such as cents to
4
- be tracked. (Justin Giancola)
18
+ be tracked (Justin Giancola)
5
19
  * Unique qualities are now passed in as a member in an options hash for
6
20
  `Tracker#hit`, this deprecates the unique qualities argument and allows for
7
- other options such as `:increment` to be passed as well. (Justin Giancola)
21
+ other options such as `:increment` to be passed as well (Justin Giancola)
8
22
 
9
- **0.2.0**
23
+ 0.2.0
10
24
 
11
- * Support for Ruby 1.8.7 thanks to Justin Giancola
25
+ * Support for Ruby 1.8.7 (Justin Giancola)
12
26
 
13
- **0.1.0**
27
+ 0.1.0
14
28
 
15
29
  * Initial public release
data/Gemfile CHANGED
@@ -1,8 +1,6 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
4
  group :development do
5
- gem 'rake'
6
5
  gem 'redcarpet'
7
- gem 'yard', :git => 'https://github.com/lsegal/yard.git'
8
6
  end
data/README.md CHANGED
@@ -36,14 +36,6 @@ probably that of a Rails or Sinatra application. Just add `boffin` to your
36
36
  gem 'boffin'
37
37
  ```
38
38
 
39
- For utmost performance on *nix-based systems, require
40
- [hiredis](https://github.com/pietern/hiredis-rb) before you require Boffin:
41
-
42
- ```ruby
43
- gem 'hiredis'
44
- gem 'boffin'
45
- ```
46
-
47
39
  Configuration
48
40
  -------------
49
41
 
@@ -118,7 +110,7 @@ Now to track hits on instances of the Listing model, simply:
118
110
  get '/listings/:id' do
119
111
  @listing = Listing[params[:id]]
120
112
  @listing.hit(:views)
121
- haml :'listings/show'
113
+ erb :'listings/show'
122
114
  end
123
115
  ```
124
116
 
@@ -129,13 +121,13 @@ identify hits from particular users or sessions:
129
121
  get '/listings/:id' do
130
122
  @listing = Listing[params[:id]]
131
123
  @listing.hit(:views, unique: [current_user, session[:id]])
132
- haml :'listings/show'
124
+ erb :'listings/show'
133
125
  end
134
126
  ```
135
127
 
136
128
  Boffin now adds uniqueness to the hit in the form of `current_user.id` if
137
129
  available. If `current_user` is nil, Boffin then uses `session[:id]`. You can
138
- provide as many uniquenesses as you'd like, the first one that is not blank
130
+ provide as many unique factors as you'd like, the first one that is not blank
139
131
  (`nil`, `false`, `[]`, `{}`, or `''`) will be used.
140
132
 
141
133
  It could get a bit tedious having to add `[current_user, session[:id]]` whenever
@@ -167,7 +159,7 @@ You get the idea, now storing a hit is as easy as:
167
159
  get '/listings/:id' do
168
160
  @listing = Listing[params[:id]]
169
161
  hit @listing, :views
170
- haml :'listings/show'
162
+ erb :'listings/show'
171
163
  end
172
164
  ```
173
165
 
@@ -182,10 +174,16 @@ After some hits have been tracked, you can start to do some queries:
182
174
  @listing.hit_count(:views)
183
175
  ```
184
176
 
185
- **Get count of unique views for an instance**
177
+ **Get count of all unique views for an instance**
186
178
 
187
179
  ```ruby
188
- @listing.uhit_count(:views)
180
+ @listing.hit_count(:views, unique: true)
181
+ ```
182
+
183
+ **Get count of unique views for a specific user**
184
+
185
+ ```ruby
186
+ @listing.hit_count(:views, unique: current_user)
189
187
  ```
190
188
 
191
189
  **Get IDs of the most viewed listings in the past 5 days**
@@ -197,7 +195,7 @@ Listing.top_ids(:views, days: 5)
197
195
  **Get IDs of the least viewed listings (that were viewed) in the past 8 hours**
198
196
 
199
197
  ```ruby
200
- Listing.top_ids(:views, hours: 8, order: 'asc')
198
+ Listing.top_ids(:views, hours: 8, order: :asc)
201
199
  ```
202
200
 
203
201
  **Get IDs and hit counts of the most liked listings in the past 5 days**
@@ -238,12 +236,12 @@ track your friends' favourite and least favourite colours:
238
236
  ```ruby
239
237
  @tracker = Boffin::Tracker.new(:colours, [:faves, :unfaves])
240
238
 
241
- @tracker.hit(:faves, 'red', unique: ['lena'])
242
- @tracker.hit(:unfaves, 'blue', unique: ['lena'])
243
- @tracker.hit(:faves, 'green', unique: ['soren'])
244
- @tracker.hit(:unfaves, 'red', unique: ['soren'])
245
- @tracker.hit(:faves, 'green', unique: ['jens'])
246
- @tracker.hit(:unfaves, 'yellow', unique: ['jens'])
239
+ @tracker.hit(:faves, 'red', unique: 'lena')
240
+ @tracker.hit(:unfaves, 'blue', unique: 'lena')
241
+ @tracker.hit(:faves, 'green', unique: 'soren')
242
+ @tracker.hit(:unfaves, 'red', unique: 'soren')
243
+ @tracker.hit(:faves, 'green', unique: 'jens')
244
+ @tracker.hit(:unfaves, 'yellow', unique: 'jens')
247
245
 
248
246
  @tracker.top(:faves, days: 1)
249
247
  ```
@@ -257,7 +255,7 @@ WordsTracker = Boffin::Tracker.new(:words, [:searches, :tweets])
257
255
  get '/search' do
258
256
  @tweets = Tweet.search(params[:q])
259
257
  params[:q].split.each { |word| WordsTracker.hit(:searches, word) }
260
- haml :'search/show'
258
+ erb :'search/show'
261
259
  end
262
260
 
263
261
  post '/tweets' do
@@ -266,13 +264,13 @@ post '/tweets' do
266
264
  @tweet.words.each { |word| WordsTracker.hit(:tweets, word) }
267
265
  redirect to("/tweets/#{@tweet.id}")
268
266
  else
269
- haml :'tweets/form'
267
+ erb :'tweets/form'
270
268
  end
271
269
  end
272
270
 
273
271
  get '/trends' do
274
272
  @words = WordsTracker.top({ tweets: 3, searches: 1 }, hours: 5)
275
- haml :'trends/index'
273
+ erb :'trends/index'
276
274
  end
277
275
  ```
278
276
  _*This is a joke._
@@ -327,6 +325,12 @@ The Future™
327
325
  FAQ
328
326
  ---
329
327
 
328
+ ### OMG haven't you heard of page caching?! How am I supposed to use this if my Ruby app doesn't get hit?
329
+
330
+ Make an XHR request to an endpoint which is soley responsible for tracking hits
331
+ to stuff whenever a specific thing loads. My above examples are just to
332
+ demonstrate how to use the APIs, you can use them wherever you want.
333
+
330
334
  ### What's with the name?
331
335
 
332
336
  Well, it means [this](http://en.wikipedia.org/wiki/Boffin). For the purposes of
@@ -1,25 +1,16 @@
1
- require File.expand_path('../lib/boffin/version', __FILE__)
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'boffin/version'
2
4
 
3
5
  Gem::Specification.new do |s|
4
- s.name = 'boffin'
5
- s.version = Boffin::VERSION
6
- s.platform = Gem::Platform::RUBY
7
- s.date = Date.today.strftime('%F')
8
- s.homepage = 'http://github.com/heycarsten/boffin'
9
- s.author = 'Carsten Nielsen'
10
- s.email = 'heycarsten@gmail.com'
11
- s.summary = 'Hit tracking library for Ruby using Redis'
12
- s.has_rdoc = 'yard'
13
- s.rubyforge_project = 'boffin'
14
- s.files = `git ls-files`.split(/\n/)
15
- s.test_files = `git ls-files -- spec/*`.split(/\n/)
16
- s.require_paths = ['lib']
17
-
18
- s.add_dependency 'redis', '>= 2.2'
19
- s.add_development_dependency 'rspec', '~> 2.6'
20
- s.add_development_dependency 'timecop'
21
- s.add_development_dependency 'bundler', '>= 1.0.14'
22
-
6
+ s.name = 'boffin'
7
+ s.version = Boffin::VERSION
8
+ s.homepage = 'http://github.com/heycarsten/boffin'
9
+ s.authors = ['Carsten Nielsen']
10
+ s.email = ['heycarsten@gmail.com']
11
+ s.summary = 'Hit tracking library for Ruby using Redis'
12
+ s.has_rdoc = 'yard'
13
+ s.license = 'MIT'
23
14
  s.description = <<-END
24
15
  Boffin is a library for tracking hits to things in your Ruby application. Things
25
16
  can be IDs of records in a database, strings representing tags or topics, URLs
@@ -27,4 +18,16 @@ of webpages, names of places, whatever you desire. Boffin is able to provide
27
18
  lists of those things based on most hits, least hits, it can even report on
28
19
  weighted combinations of different types of hits.
29
20
  END
21
+
22
+ s.files = `git ls-files`.split($/)
23
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
24
+ s.require_paths = ['lib']
25
+
26
+ s.add_development_dependency 'bundler', '~> 1.3'
27
+ s.add_development_dependency 'rake'
28
+ s.add_development_dependency 'yard'
29
+ s.add_development_dependency 'rspec', '~> 2.13'
30
+ s.add_development_dependency 'timecop'
31
+
32
+ s.add_dependency 'redis', '~> 3.0'
30
33
  end
@@ -12,27 +12,19 @@ module Boffin
12
12
  # @param [Object] instance
13
13
  # The instance that is being hit, any object that responds to
14
14
  # `#to_member`, `#id`, or `#to_s`
15
- # @param [Hash] options
16
- # @option options [Array] :unique ([]) An array of which the first
15
+ # @param [Hash] opts
16
+ # @option opts [Array] :unique ([]) An array of which the first
17
17
  # object is used to generate a session identifier for hit uniqueness
18
- # @option options [Fixnum] :increment (1) The hit increment
18
+ # @option opts [Fixnum] :increment (1) The hit increment
19
19
  def initialize(tracker, type, instance, opts = {})
20
- if opts.is_a?(Array)
21
- warn "This constructor is deprecated and will soon be unavailable\n" \
22
- "please create Hits with: \n" \
23
- "Hit.new(@tracker, :type, @instance, :unique => [1,2,3,4])\n"
24
- uniquenesses = opts
25
- @increment = 1
26
- else
27
- uniquenesses = opts.delete(:unique) || []
28
- @increment = opts.delete(:increment) || 1
29
- end
30
- @now = Time.now
31
- @sessid = Utils.uniquenesses_as_session_identifier(uniquenesses)
32
- @type = type
33
- @tracker = tracker
34
- @instance = instance
35
- @member = Utils.object_as_member(@instance)
20
+ uniquenesses = opts.delete(:unique) || []
21
+ @increment = opts.delete(:increment) || 1
22
+ @now = Time.now
23
+ @sessid = Utils.uniquenesses_as_uid(uniquenesses)
24
+ @type = type
25
+ @tracker = tracker
26
+ @instance = instance
27
+ @member = Utils.object_as_member(@instance)
36
28
  store
37
29
  freeze
38
30
  end
@@ -65,11 +57,11 @@ module Boffin
65
57
  # `true` if this hit is unique, `false` if it has been made before by the
66
58
  # same session identifer.
67
59
  def track_hit
68
- redis.incrby(keyspace.hit_count(@type, @instance), @increment)
69
- redis.zincrby(keyspace.hits(@type, @instance), 1, @sessid) == '1'
60
+ redis.incrbyfloat(keyspace.hit_count(@type, @instance), @increment)
61
+ redis.zincrby(keyspace.hits(@type, @instance), 1, @sessid) == 1.0
70
62
  end
71
63
 
72
- # Store the hit member across all time interval for the current window
64
+ # Store the hit member across all time intervals for the current window
73
65
  # @param [true, false] uniq
74
66
  # If `true` the hit is also added to the keys scoped for unique hits
75
67
  def set_windows(uniq)
@@ -45,21 +45,9 @@ module Boffin
45
45
  end
46
46
 
47
47
  # @see Tracker#hit_count
48
- # @return [Fixnum]
49
- def hit_count(type)
50
- self.class.boffin.hit_count(type, self)
51
- end
52
-
53
- # @see Tracker#uhit_count
54
- # @return [Fixnum]
55
- def uhit_count(type)
56
- self.class.boffin.uhit_count(type, self)
57
- end
58
-
59
- # @see Tracker#hit_count_for_session_id
60
- # @return [Fixnum]
61
- def hit_count_for_session_id(type, sess_obj)
62
- self.class.boffin.hit_count_for_session_id(type, self, sess_obj)
48
+ # @return [Float]
49
+ def hit_count(type, opts = {})
50
+ self.class.boffin.count(type, self, opts)
63
51
  end
64
52
 
65
53
  end
@@ -25,9 +25,9 @@ module Boffin
25
25
 
26
26
  # @param [Symbol] hit_type
27
27
  # @param [#as_member, #id, #to_s] instance
28
- # @param [Hash] options
29
- # @option options [Array] :unique ([]) uniquenesses
30
- # @option options [Fixnum] :increment (1) hit increment
28
+ # @param [Hash] opts
29
+ # @option opts [Array] :unique ([]) uniquenesses
30
+ # @option opts [Fixnum] :increment (1) hit increment
31
31
  # @return [Hit]
32
32
  # @raise Boffin::UndefinedHitTypeError
33
33
  # Raised if a list of hit types is available and the provided hit type is
@@ -38,45 +38,37 @@ module Boffin
38
38
  end
39
39
 
40
40
  # @param [Symbol] hit_type
41
+ # Type of hit.
41
42
  # @param [#as_member, #id, #to_s] instance
42
- # @return [Fixnum]
43
- # @raise Boffin::UndefinedHitTypeError
44
- # Raised if a list of hit types is available and the provided hit type is
45
- # not in the list.
46
- def hit_count(hit_type, instance)
47
- validate_hit_type(hit_type)
48
- redis.get(keyspace.hit_count(hit_type, instance)).to_i
49
- end
50
-
51
- # @param [Symbol] hit_type
52
- # @param [#as_member, #id, #to_s] instance
53
- # @return [Fixnum]
54
- # @raise Boffin::UndefinedHitTypeError
55
- # Raised if a list of hit types is available and the provided hit type is
56
- # not in the list.
57
- def uhit_count(hit_type, instance)
58
- validate_hit_type(hit_type)
59
- redis.zcard(keyspace.hits(hit_type, instance)).to_i
60
- end
61
-
62
- # @param [Symbol] hit_type
63
- # @param [#as_member, #id, #to_s] instance
64
- # @param [#as_member, #id, #to_s] sess_obj
65
- # @return [Fixnum]
43
+ # Object to track.
44
+ # @param [Hash] opts
45
+ # @option opts [true, #as_member, #id, #to_s] :unique (false)
46
+ # If `true` will return a count of unique hits. If passed an object, will
47
+ # use that object as a unique identifier and return the score associated
48
+ # with it.
49
+ # @return [Float]
66
50
  # @raise Boffin::UndefinedHitTypeError
67
51
  # Raised if a list of hit types is available and the provided hit type is
68
52
  # not in the list.
69
- def hit_count_for_session_id(hit_type, instance, sess_obj)
53
+ def count(hit_type, instance, opts = {})
70
54
  validate_hit_type(hit_type)
71
- sessid = Utils.object_as_session_identifier(sess_obj)
72
- redis.zscore(keyspace.hits(hit_type, instance), sessid).to_i
55
+ count = case
56
+ when opts[:unique] == true
57
+ redis.zcard(keyspace.hits(hit_type, instance))
58
+ when opts[:unique]
59
+ uid = Utils.object_as_uid(opts[:unique])
60
+ redis.zscore(keyspace.hits(hit_type, instance), uid)
61
+ else
62
+ redis.get(keyspace.hit_count(hit_type, instance))
63
+ end
64
+ (count && count.to_f) || 0.0
73
65
  end
74
66
 
75
67
  # Performs set union across the specified number of hours, days, or months
76
68
  # to calculate the members with the highest hit counts. The operation can
77
69
  # be performed on one hit type, or multiple hit types with weights.
78
70
  # @param [Symbol, Hash] type_or_weights
79
- # When Hash the set union is calculated
71
+ # When Hash the set union is calculated
80
72
  # @param [Hash] opts
81
73
  # @option opts [true, false] :unique (false)
82
74
  # If `true` then only unique hits are considered in the calculation
@@ -169,7 +161,6 @@ module Boffin
169
161
  # @param [Keyspace] ks
170
162
  # Keyspace to perform the union on
171
163
  # @param [Hash] weights
172
- # @param [Symbol] hit_type
173
164
  # @param [:hours, :days, :months] unit
174
165
  # @param [Fixnum] size
175
166
  # Number of intervals to include in the union
@@ -200,7 +191,7 @@ module Boffin
200
191
  zrangeopts = {
201
192
  :counts => opts.delete(:counts),
202
193
  :order => (opts.delete(:order) || :desc).to_sym }
203
- if redis.zcard(storkey) == 0
194
+ if redis.zcard(storkey) < 1
204
195
  redis.zunionstore(storkey, keys, opts)
205
196
  redis.expire(storkey, @config.cache_expire_secs)
206
197
  end
@@ -217,17 +208,16 @@ module Boffin
217
208
  # option is `true` it returns an array of pairs where the first value is
218
209
  # the member, and the second value is the member's score.
219
210
  def zrange(key, opts)
220
- args = [key, 0, -1, opts[:counts] ? { :withscores => true } : {}]
221
- result = case opts[:order]
222
- when :asc then redis.zrange(*args)
223
- when :desc then redis.zrevrange(*args)
224
- end
225
- if opts[:counts]
226
- result.each_slice(2).map { |mbr, score| [mbr, score.to_i] }
211
+ args = [key, 0, -1]
212
+ args << { :with_scores => true } if opts[:counts]
213
+ case opts[:order]
214
+ when :asc
215
+ redis.zrange(*args)
216
+ when :desc
217
+ redis.zrevrange(*args)
227
218
  else
228
- result
219
+ raise ArgumentError, "unknown order type: #{opts[:order].inspect}"
229
220
  end
230
221
  end
231
-
232
222
  end
233
223
  end
@@ -114,16 +114,16 @@ module Boffin
114
114
  times
115
115
  end
116
116
 
117
- # Generates a set member based off the first object in the provided array
118
- # that is not `nil`. If the array is empty or only contains `nil` elements
119
- # then {Boffin::NIL_SESSION_MEMBER} is returned.
117
+ # Generates a unique set member based off the first object in the provided
118
+ # array that is not `nil`. If the array is empty or only contains `nil`
119
+ # element then {Boffin::NIL_SESSION_MEMBER} is returned.
120
120
  # @param [Array] aspects
121
121
  # An array of which the first non-nil element is passed to
122
- # {#object_as_session_identifier}
122
+ # {#object_as_uid}
123
123
  # @return [String]
124
- def uniquenesses_as_session_identifier(aspects)
124
+ def uniquenesses_as_uid(*aspects)
125
125
  if (obj = aspects.flatten.reject { |u| blank?(u) }.first)
126
- object_as_session_identifier(obj)
126
+ object_as_uid(obj)
127
127
  else
128
128
  NIL_SESSION_MEMBER
129
129
  end
@@ -172,7 +172,7 @@ module Boffin
172
172
  # @param [#as_member, #id, #to_s] obj
173
173
  # @return [String] A string that can be used as a member in {Keyspace#hits}.
174
174
  # @see #object_as_identifier
175
- def object_as_session_identifier(obj)
175
+ def object_as_uid(obj)
176
176
  object_as_identifier(obj, :namespace => true)
177
177
  end
178
178
 
@@ -1,4 +1,4 @@
1
1
  module Boffin
2
2
  # Version of this Boffin release
3
- VERSION = '0.3.0'
3
+ VERSION = '1.0.0'
4
4
  end
@@ -21,8 +21,8 @@ describe Boffin::Hit, '::new' do
21
21
  @tracker.top(:tests, interval => 1, :counts => true, :unique => true).
22
22
  should == [['1', 1]]
23
23
  end
24
- @tracker.hit_count(:tests, @ditty).should == 1
25
- @tracker.uhit_count(:tests, @ditty).should == 1
24
+ @tracker.count(:tests, @ditty).should == 1
25
+ @tracker.count(:tests, @ditty, :unique => true).should == 1
26
26
  end
27
27
 
28
28
  it 'does not store data under unique keys if the hit is not unique' do
@@ -34,9 +34,9 @@ describe Boffin::Hit, '::new' do
34
34
  @tracker.top(:tests, interval => 1, :counts => true, :unique => true).
35
35
  should == [['1', 1]]
36
36
  end
37
- @tracker.hit_count_for_session_id(:tests, @ditty, @user).should == 2
38
- @tracker.hit_count(:tests, @ditty).should == 2
39
- @tracker.uhit_count(:tests, @ditty).should == 1
37
+ @tracker.count(:tests, @ditty, :unique => @user).should == 2
38
+ @tracker.count(:tests, @ditty).should == 2
39
+ @tracker.count(:tests, @ditty, :unique => true).should == 1
40
40
  end
41
41
 
42
42
  it 'allows arbitrary hit increments' do
@@ -4,8 +4,8 @@ describe Boffin::Trackable do
4
4
  before :all do
5
5
  SpecHelper.flush_keyspace!
6
6
  @mock = MockTrackableInjected.new(1)
7
- @mock.hit(:views, :unique => ['sess.1'])
8
- @mock.hit(:views, :unique => ['sess.1'])
7
+ @mock.hit(:views, :unique => 'sess.1')
8
+ @mock.hit(:views, :unique => 'sess.1')
9
9
  end
10
10
 
11
11
  it 'can be included' do
@@ -28,11 +28,11 @@ describe Boffin::Trackable do
28
28
  @mock.hit_count(:views).should == 2
29
29
  end
30
30
 
31
- it 'delegates #uhit_count to the Tracker instance' do
32
- @mock.uhit_count(:views).should == 1
31
+ it 'delegates #hit_count { unique: true } to the Tracker instance' do
32
+ @mock.hit_count(:views, :unique => true).should == 1
33
33
  end
34
34
 
35
- it 'delegates #hit_count_for_session_id to the Tracker instance' do
36
- @mock.hit_count_for_session_id(:views, 'sess.1').should == 2
35
+ it 'delegates #hit_count { unique: obj } to the Tracker instance' do
36
+ @mock.hit_count(:views, :unique => 'sess.1').should == 2
37
37
  end
38
38
  end
@@ -55,64 +55,57 @@ describe Boffin::Tracker do
55
55
 
56
56
  describe '#hit' do
57
57
  it 'throws an error if the hit type is not in the list' do
58
- lambda { @tracker.hit(:view, @instance1) }.
58
+ lambda { @tracker.hit(:view, @instance1) }.
59
59
  should raise_error Boffin::UndefinedHitTypeError
60
60
  end
61
61
  end
62
62
 
63
63
  describe '#hit_count' do
64
64
  it 'throws an error if the hit type is not in the list' do
65
- lambda { @tracker.hit_count(:view, @instance1) }.
65
+ lambda { @tracker.count(:view, @instance1) }.
66
66
  should raise_error Boffin::UndefinedHitTypeError
67
67
  end
68
68
 
69
69
  it 'returns the raw hit count for the instance' do
70
- @tracker.hit_count(:views, @instance1).should == 8
70
+ @tracker.count(:views, @instance1).should == 8
71
71
  end
72
72
 
73
73
  it 'returns 0 for an instance that was never hit' do
74
- @tracker.hit_count(:views, 'neverhit').should == 0
75
- end
76
- end
77
-
78
- describe '#uhit_count' do
79
- it 'throws an error if the hit type is not in the list' do
80
- lambda { @tracker.uhit_count(:view, @instance1) }.
81
- should raise_error Boffin::UndefinedHitTypeError
74
+ @tracker.count(:views, 'neverhit').should == 0
82
75
  end
83
76
 
84
77
  it 'returns the unique hit count for the instance' do
85
- @tracker.uhit_count(:views, @instance1).should == 5
78
+ @tracker.count(:views, @instance1, :unique => true).should == 5
86
79
  end
87
80
 
88
81
  it 'returns 0 for an instance that was never hit' do
89
- @tracker.hit_count(:likes, @instance4).should == 0
82
+ @tracker.count(:likes, @instance4, :unique => true).should == 0
90
83
  end
91
84
  end
92
85
 
93
86
  describe '#hit_count_for_session_id' do
94
87
  it 'throws an error if the hit type is not in the list' do
95
- lambda { @tracker.hit_count_for_session_id(:view, @instance1, 'sess.1') }.
88
+ lambda { @tracker.count(:view, @instance1, :unique => 'sess.1') }.
96
89
  should raise_error Boffin::UndefinedHitTypeError
97
90
  end
98
91
 
99
92
  it 'returns the number of times the instance was hit by the session id' do
100
- @tracker.hit_count_for_session_id(:views, @instance3, 'sess.1').should == 3
93
+ @tracker.count(:views, @instance3, :unique => 'sess.1').should == 3
101
94
  end
102
95
 
103
96
  it 'returns a count of 0 if the session id never hit the instance' do
104
- @tracker.hit_count_for_session_id(:views, @instance1, 'nohit').should == 0
97
+ @tracker.count(:views, @instance1, :unique => 'nohit').should == 0
105
98
  end
106
99
  end
107
100
 
108
101
  describe '#top' do
109
102
  it 'throws an error if passed hit type is invalid' do
110
- lambda { @tracker.top(:view, :days => 3) }.
103
+ lambda { @tracker.top(:view, :days => 3) }.
111
104
  should raise_error Boffin::UndefinedHitTypeError
112
105
  end
113
106
 
114
107
  it 'throws an error if passed weights with hit type that is invalid' do
115
- lambda { @tracker.top({ :view => 1 }, :days => 3) }.
108
+ lambda { @tracker.top({ :view => 1 }, :days => 3) }.
116
109
  should raise_error Boffin::UndefinedHitTypeError
117
110
  end
118
111
 
@@ -131,6 +124,11 @@ describe Boffin::Tracker do
131
124
  ids.should == ['200', '100', '300']
132
125
  end
133
126
 
127
+ it 'throws an error if the specified order is not valid' do
128
+ lambda { @tracker.top(:views, :days => 3, :order => 'desk') }.
129
+ should raise_error ArgumentError
130
+ end
131
+
134
132
  it 'returns ids and counts when passed { counts: true } as an option' do
135
133
  ids = @tracker.top(:views, :days => 3, :counts => true)
136
134
  ids.should == [
@@ -99,29 +99,29 @@ describe Boffin::Utils do
99
99
  end
100
100
  end
101
101
 
102
- describe '::uniquenesses_as_session_identifier' do
102
+ describe '::uniquenesses_as_uid' do
103
103
  specify do
104
- subject.uniquenesses_as_session_identifier([]).
104
+ subject.uniquenesses_as_uid([]).
105
105
  should == Boffin::NIL_SESSION_MEMBER
106
106
  end
107
107
 
108
108
  specify do
109
- subject.uniquenesses_as_session_identifier([nil, 'hi']).
109
+ subject.uniquenesses_as_uid([nil, 'hi']).
110
110
  should == 'hi'
111
111
  end
112
112
 
113
113
  specify do
114
- subject.uniquenesses_as_session_identifier([MockDitty.new]).
114
+ subject.uniquenesses_as_uid([MockDitty.new]).
115
115
  should == 'mock_ditty:1'
116
116
  end
117
117
  end
118
118
 
119
- describe '::object_as_session_identifier' do
120
- specify { subject.object_as_session_identifier(nil).should == '' }
121
- specify { subject.object_as_session_identifier(3.14).should == '3.14' }
119
+ describe '::object_as_uid' do
120
+ specify { subject.object_as_uid(nil).should == '' }
121
+ specify { subject.object_as_uid(3.14).should == '3.14' }
122
122
 
123
123
  specify do
124
- subject.object_as_session_identifier(MockDitty.new).
124
+ subject.object_as_uid(MockDitty.new).
125
125
  should == 'mock_ditty:1'
126
126
  end
127
127
  end
metadata CHANGED
@@ -1,73 +1,107 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boffin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Carsten Nielsen
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2011-09-12 00:00:00.000000000Z
11
+ date: 2013-05-08 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: redis
16
- requirement: &70276273568860 !ruby/object:Gem::Requirement
17
- none: false
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - ~>
20
18
  - !ruby/object:Gem::Version
21
- version: '2.2'
22
- type: :runtime
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
23
49
  prerelease: false
24
- version_requirements: *70276273568860
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
25
55
  - !ruby/object:Gem::Dependency
26
56
  name: rspec
27
- requirement: &70276273568280 !ruby/object:Gem::Requirement
28
- none: false
57
+ requirement: !ruby/object:Gem::Requirement
29
58
  requirements:
30
59
  - - ~>
31
60
  - !ruby/object:Gem::Version
32
- version: '2.6'
61
+ version: '2.13'
33
62
  type: :development
34
63
  prerelease: false
35
- version_requirements: *70276273568280
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.13'
36
69
  - !ruby/object:Gem::Dependency
37
70
  name: timecop
38
- requirement: &70276273567900 !ruby/object:Gem::Requirement
39
- none: false
71
+ requirement: !ruby/object:Gem::Requirement
40
72
  requirements:
41
- - - ! '>='
73
+ - - '>='
42
74
  - !ruby/object:Gem::Version
43
75
  version: '0'
44
76
  type: :development
45
77
  prerelease: false
46
- version_requirements: *70276273567900
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
47
83
  - !ruby/object:Gem::Dependency
48
- name: bundler
49
- requirement: &70276273567340 !ruby/object:Gem::Requirement
50
- none: false
84
+ name: redis
85
+ requirement: !ruby/object:Gem::Requirement
51
86
  requirements:
52
- - - ! '>='
87
+ - - ~>
53
88
  - !ruby/object:Gem::Version
54
- version: 1.0.14
55
- type: :development
89
+ version: '3.0'
90
+ type: :runtime
56
91
  prerelease: false
57
- version_requirements: *70276273567340
58
- description: ! 'Boffin is a library for tracking hits to things in your Ruby application.
59
- Things
60
-
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description: |
98
+ Boffin is a library for tracking hits to things in your Ruby application. Things
61
99
  can be IDs of records in a database, strings representing tags or topics, URLs
62
-
63
100
  of webpages, names of places, whatever you desire. Boffin is able to provide
64
-
65
101
  lists of those things based on most hits, least hits, it can even report on
66
-
67
102
  weighted combinations of different types of hits.
68
-
69
- '
70
- email: heycarsten@gmail.com
103
+ email:
104
+ - heycarsten@gmail.com
71
105
  executables: []
72
106
  extensions: []
73
107
  extra_rdoc_files: []
@@ -98,34 +132,28 @@ files:
98
132
  - spec/boffin_spec.rb
99
133
  - spec/spec_helper.rb
100
134
  homepage: http://github.com/heycarsten/boffin
101
- licenses: []
135
+ licenses:
136
+ - MIT
137
+ metadata: {}
102
138
  post_install_message:
103
139
  rdoc_options: []
104
140
  require_paths:
105
141
  - lib
106
142
  required_ruby_version: !ruby/object:Gem::Requirement
107
- none: false
108
143
  requirements:
109
- - - ! '>='
144
+ - - '>='
110
145
  - !ruby/object:Gem::Version
111
146
  version: '0'
112
- segments:
113
- - 0
114
- hash: -2879744131493119363
115
147
  required_rubygems_version: !ruby/object:Gem::Requirement
116
- none: false
117
148
  requirements:
118
- - - ! '>='
149
+ - - '>='
119
150
  - !ruby/object:Gem::Version
120
151
  version: '0'
121
- segments:
122
- - 0
123
- hash: -2879744131493119363
124
152
  requirements: []
125
- rubyforge_project: boffin
126
- rubygems_version: 1.8.6
153
+ rubyforge_project:
154
+ rubygems_version: 2.0.3
127
155
  signing_key:
128
- specification_version: 3
156
+ specification_version: 4
129
157
  summary: Hit tracking library for Ruby using Redis
130
158
  test_files:
131
159
  - spec/boffin/config_spec.rb