fatboy 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +97 -0
- data/Rakefile +2 -0
- data/fatboy.gemspec +34 -0
- data/lib/fatboy/helpers.rb +44 -0
- data/lib/fatboy/popularity.rb +70 -0
- data/lib/fatboy/time_based_popularity.rb +63 -0
- data/lib/fatboy/version.rb +5 -0
- data/lib/fatboy/viewed_item.rb +28 -0
- data/lib/fatboy.rb +56 -0
- data/spec/fatboy_spec.rb +50 -0
- data/spec/mocks/model.rb +8 -0
- data/spec/spec_helper.rb +13 -0
- metadata +163 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 14480b9fa576ac0e81318733af2789f82f5caaa8
|
4
|
+
data.tar.gz: 987e8724d2cd01bfad21a66853cf3f53803cd0a6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 78061dc924ed74f6205bfb8715eb3c7edcbf91eb14b2c2c8066e01137396b0bcca307a46d5058e4118c5eb7f5e2cffa51760b869da8195b856371101fbcab939
|
7
|
+
data.tar.gz: 48a20e5e25c67f52e6a0e0631beab08abe409cd512e32e0fc9d995b1948e05ed9fe9de9d5decdfbb800347dfda444b6e4fc171f5a65ef5fcd3a89f4cc2f274b0
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
*.swp
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Anthony Super
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Fatboy
|
2
|
+
##### See views, right here, right now
|
3
|
+
Fatboy is a gem which manages view counts on ActiveRecord objects (or things that quack like them).
|
4
|
+
It's great for seeing the most (and least) viewed models on your website.
|
5
|
+
To make things even better, Fatboy will store view counts by day, month, year,
|
6
|
+
and all-time.
|
7
|
+
|
8
|
+
It doesn't touch your SQL database.
|
9
|
+
Fatboy stays slim in Redis.
|
10
|
+
|
11
|
+
NOTE: This is currenlty not production-ready.
|
12
|
+
It will be soon, though.
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
gem 'fatboy'
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install fatboy
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Fatboy is easy to set up. First, initialize it:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# if you don't provide your own redis, fatoby will create one
|
33
|
+
# with Redis.new
|
34
|
+
fatboy = Fatboy.new(redis: redis)
|
35
|
+
```
|
36
|
+
|
37
|
+
Then, just tell it what your users look at.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
# As long as the variable you're passing in responds to
|
41
|
+
# .id, this will work
|
42
|
+
fatboy.view(image)
|
43
|
+
# You can also use the shorthand method:
|
44
|
+
# fatboy[image]
|
45
|
+
```
|
46
|
+
|
47
|
+
Now, managing views is pretty useless if you can't retrieve them later.
|
48
|
+
Thankfully, fatboy makes this easy as well:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
fatboy.views_for(image) # => 1
|
52
|
+
```
|
53
|
+
|
54
|
+
Don't worry if that's a brand-new Fatboy instance---as long as the Redis is the same, Fatboy's view count will be the same.
|
55
|
+
|
56
|
+
#### Getting Top Viewed
|
57
|
+
|
58
|
+
Fatboy makes it easy to retrieve a list of the most-popular records in your database.
|
59
|
+
Check it now now:
|
60
|
+
```ruby
|
61
|
+
fatboy.popular(Image).today.most # => most viewed image today
|
62
|
+
fatboy.popular("Image").all_time.most # => Top viewed image of all time
|
63
|
+
```
|
64
|
+
|
65
|
+
Want it from other days?
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# most popular image a month ago
|
69
|
+
fatboy.popular(Image).day(Time.now << 1).most
|
70
|
+
# Or with active support
|
71
|
+
fatboy.popular(Image).day(1.months.ago).most
|
72
|
+
```
|
73
|
+
Don't want just the most popular?
|
74
|
+
Maybe you'd like the least popular?
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
fatboy.popular(Image).day(Time.now).least
|
78
|
+
fatboy.popular(Image).month(Time.now).least
|
79
|
+
```
|
80
|
+
|
81
|
+
Or perhaps a range?
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
fatboy.popular(Image).this_month.range(10..20)
|
85
|
+
# or, a range for a while ago
|
86
|
+
fatboy.popular(Image).month(3.months.ago).range(10..20)
|
87
|
+
```
|
88
|
+
|
89
|
+
Fatboy makes it easier. See the rdoc for details.
|
90
|
+
## Contributing
|
91
|
+
|
92
|
+
1. Fork it ( https://github.com/[my-github-username]/fatboy/fork )
|
93
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
94
|
+
3. Write functionality and tests
|
95
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
96
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
97
|
+
6. Create a new Pull Request
|
data/Rakefile
ADDED
data/fatboy.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'fatboy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "fatboy"
|
8
|
+
spec.version = Fatboy::VERSION
|
9
|
+
spec.authors = ["Anthony Super"]
|
10
|
+
spec.email = ["anthony@noided.media"]
|
11
|
+
spec.summary = %q{Fatboy keeps track of your models's views, right here, right now.}
|
12
|
+
spec.description = %q{
|
13
|
+
Fatboy is a gem designed to easily keep track of views.
|
14
|
+
It doesn't touch your SQL, and stays slim in redis.
|
15
|
+
It also makes it easy to query based on how viewed something is.
|
16
|
+
}
|
17
|
+
spec.homepage = "http://github.com/AnthonySuper/fatboy"
|
18
|
+
spec.license = "MIT"
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0")
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "timecop"
|
29
|
+
spec.add_development_dependency "mock_redis"
|
30
|
+
spec.add_development_dependency "simplecov"
|
31
|
+
spec.add_runtime_dependency "redis"
|
32
|
+
spec.required_ruby_version = ">= 2.0"
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Fatboy
|
2
|
+
##
|
3
|
+
# Common helper functions, which are used across many
|
4
|
+
# classes.
|
5
|
+
module Helpers
|
6
|
+
##
|
7
|
+
# Given a model_name and the properly formated hour, day, etc. string,
|
8
|
+
# give the name of the key views are stored in
|
9
|
+
def self.format_store(model_name, store_name)
|
10
|
+
"#{model_name}-#{store_name}"
|
11
|
+
end
|
12
|
+
##
|
13
|
+
# Properly format the time to retrieve or set an hour
|
14
|
+
def self.hour_format(hr)
|
15
|
+
hr.utc.strftime(Fatboy::HOUR_FORMAT_STR)
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Properly format the time to retrieve or set a day
|
20
|
+
def self.day_format(day)
|
21
|
+
day.utc.strftime(Fatboy::DAY_FORMAT_STR)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Properly format the time to retrieve or set a month
|
26
|
+
def self.month_format(mth)
|
27
|
+
mth.utc.strftime(Fatboy::MONTH_FORMAT_STR)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Properly format the time to retrieve or set a year
|
32
|
+
def self.year_format(yr)
|
33
|
+
yr.utc.strftime(Fatboy::YEAR_FORMAT_STR)
|
34
|
+
end
|
35
|
+
##
|
36
|
+
# Get an array of the hour format, the day format, the month format, and
|
37
|
+
# the year format
|
38
|
+
def self.all_format(time)
|
39
|
+
[:hour_format, :day_format, :month_format, :year_format].map do |func|
|
40
|
+
self.send(func, time)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative './time_based_popularity'
|
2
|
+
class Fatboy
|
3
|
+
##
|
4
|
+
# This class is used to query how popular something is.
|
5
|
+
class Popularity
|
6
|
+
##
|
7
|
+
# We always pass in a redis
|
8
|
+
def initialize(model, redis)
|
9
|
+
@redis = redis
|
10
|
+
@model_name = model.to_s
|
11
|
+
end
|
12
|
+
##
|
13
|
+
# Get a Fatboy::TimeBasedPopularity for a specific hour in time.
|
14
|
+
# Arguments:
|
15
|
+
# * +time+: a DateTime or Time containing the hour in time you wish to query
|
16
|
+
def hour(time)
|
17
|
+
fmt_tim = Fatboy::Helpers.hour_format(time.utc)
|
18
|
+
store_name = Fatboy::Helpers.format_store(@model_name, fmt_tim)
|
19
|
+
Fatboy::TimeBasedPopularity.new(@redis, store_name)
|
20
|
+
end
|
21
|
+
##
|
22
|
+
# Get a Fatboy::TimeBasedPopularity for a specific day in time.
|
23
|
+
# Arguments:
|
24
|
+
# * +time+: A Datetime or Time in the day you wish to query.
|
25
|
+
def day(time)
|
26
|
+
fmt_time = Fatboy::Helpers.day_format(time.utc)
|
27
|
+
store_name = Fatboy::Helpers.format_store(@model_name, fmt_time)
|
28
|
+
|
29
|
+
Fatboy::TimeBasedPopularity.new(@redis, store_name)
|
30
|
+
end
|
31
|
+
##
|
32
|
+
# Get a Fatboy::TimeBasedPopularity for a specific month in time.
|
33
|
+
# Arguments:
|
34
|
+
# * +time+: A time within the month you wish to query.
|
35
|
+
def month(time)
|
36
|
+
fmt_time = Fatboy::Helpers.month_format(time.utc)
|
37
|
+
store_name = Fatboy::Helpers.format_store(@model_name, fmt_time)
|
38
|
+
Fatboy::TimeBasedPopularity.new(@redis, store_name)
|
39
|
+
end
|
40
|
+
##
|
41
|
+
# Get a Fatboy::TimeBasedPopularity for a specific year in time.
|
42
|
+
# Arguments:
|
43
|
+
# * +time+: A DateTime or Time in the year you wish to query.
|
44
|
+
def year(time)
|
45
|
+
fmt_time = Fatboy::Helpers.year_format(time.utc)
|
46
|
+
store_name = Fatboy::Helpers.format_store(@model_name, fmt_time)
|
47
|
+
Fatboy::TimeBasedPopularity.new(@redis, store_name)
|
48
|
+
end
|
49
|
+
##
|
50
|
+
# Get a Fatboy::TimeBasedPopularity for this hour.
|
51
|
+
def this_hour
|
52
|
+
hour(Time.now)
|
53
|
+
end
|
54
|
+
##
|
55
|
+
# Get a Fatboy::TimeBasedPopularity for this day.
|
56
|
+
def today
|
57
|
+
day(Time.now)
|
58
|
+
end
|
59
|
+
##
|
60
|
+
# Get a Fatboy::TimeBasedPopularity for this month.
|
61
|
+
def this_month
|
62
|
+
month(Time.now)
|
63
|
+
end
|
64
|
+
##
|
65
|
+
# Get a Fatboy::TimeBasedPopularity for this year.
|
66
|
+
def this_year
|
67
|
+
year(Time.now)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative './viewed_item'
|
2
|
+
class Fatboy
|
3
|
+
##
|
4
|
+
# TimeBasedPopularity measures the popularity based on a set period of time.
|
5
|
+
# You should probably never initialize this yourself.
|
6
|
+
class TimeBasedPopularity
|
7
|
+
##
|
8
|
+
# What redis to look in, and what sorted set we're using.
|
9
|
+
# Probably don't ever initialize this yourself.
|
10
|
+
def initialize(redis, store)
|
11
|
+
@redis = redis
|
12
|
+
@store = store
|
13
|
+
end
|
14
|
+
##
|
15
|
+
# Get an enumerator of all viewed items, as a Fatboy::ViewedItem, in
|
16
|
+
# rank order.
|
17
|
+
# Pretty useful for lazy operations and such.
|
18
|
+
def enumerator
|
19
|
+
Enumerator.new(size) do |yielder|
|
20
|
+
range(0..(size-1)).each{|x| yielder.yield x}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
##
|
24
|
+
# Get the most viewed item.
|
25
|
+
# Returns a Fatboy::ViewedItem
|
26
|
+
def most
|
27
|
+
range(0..1).first
|
28
|
+
end
|
29
|
+
##
|
30
|
+
# Get the least viewed item.
|
31
|
+
# Returns a Fatboy::ViewedItem
|
32
|
+
def least
|
33
|
+
range(-1..-2).first
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Get the total number of items viewed.
|
38
|
+
def size
|
39
|
+
@redis.zcard(@store)
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Specify a range of ranks, and gets them.
|
44
|
+
# Returns an array of Fatboy::ViewedItem
|
45
|
+
def range(rng)
|
46
|
+
start = rng.first
|
47
|
+
stop = rng.last
|
48
|
+
##
|
49
|
+
# Build up a list of pairs: [id, score]
|
50
|
+
pairs = @redis.zrevrange(@store, start, stop, withscores: true)
|
51
|
+
##
|
52
|
+
# Get rid of nils, zip up list with range of rank
|
53
|
+
triplets = pairs.reject{|p| !p}.zip(start..stop)
|
54
|
+
# After the zip, we have [[[id, score], rank], [[id, score], rank]]
|
55
|
+
# So we flatten out the inner arrays, giving us
|
56
|
+
# [[id, score, rank], [id, score, rank]]
|
57
|
+
triplets.map!(&:flatten)
|
58
|
+
##
|
59
|
+
# Use the array splat to more easily pass in the 3 arguments
|
60
|
+
triplets.map{|trip| Fatboy::ViewedItem.new(*trip)}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Fatboy
|
2
|
+
##
|
3
|
+
# The viewed item class provides a (very) simple interface for interacting
|
4
|
+
# with views on Models.
|
5
|
+
# Almost always obtained from a TimeBasedPopularity, this struct simply
|
6
|
+
# shows the id of the model, the number of views, and the rank.
|
7
|
+
# NOTE: The highest-ranked item has rank 0. Ranks are 0-indexed.
|
8
|
+
class ViewedItem
|
9
|
+
def initialize(id, views, rank)
|
10
|
+
@id = id.to_i
|
11
|
+
@views = views.to_i
|
12
|
+
@rank = rank.to_i
|
13
|
+
end
|
14
|
+
##
|
15
|
+
# Id of the model contained this this ViewedItem
|
16
|
+
attr_reader :id
|
17
|
+
##
|
18
|
+
# Amount this ViewedItem has been viewed in a time period.
|
19
|
+
# This time period was pre-set on construction.
|
20
|
+
attr_reader :views
|
21
|
+
##
|
22
|
+
# The rank, 0 being the most viewed, of this item.
|
23
|
+
# The time period was pre-set on construction, typically from a
|
24
|
+
# Fatboy::TimeBasedView
|
25
|
+
attr_reader :rank
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
data/lib/fatboy.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require "fatboy/version"
|
2
|
+
require 'redis'
|
3
|
+
require_relative './fatboy/popularity'
|
4
|
+
require_relative './fatboy/helpers'
|
5
|
+
##
|
6
|
+
# Fatboy is the main class for interacting with the system.
|
7
|
+
# It provides a variety of functionality.
|
8
|
+
class Fatboy
|
9
|
+
##
|
10
|
+
# Create a new Fatboy.
|
11
|
+
# Options:
|
12
|
+
# * +redis:+ : The redis to store views in. By default, Redis.new
|
13
|
+
def initialize(redis: Redis.new)
|
14
|
+
@redis = redis
|
15
|
+
end
|
16
|
+
##
|
17
|
+
# Say that you have viewed an object, making the proper records for
|
18
|
+
# hour, day, month, and year.
|
19
|
+
# * +model+ - a model of some sort. Should quack like an ActiveRecord model (that is, responding to .id)
|
20
|
+
def view(obj)
|
21
|
+
throw ArgumentError.new("That doesn't quack like a model!") unless obj.respond_to?(:id)
|
22
|
+
stores = Fatboy::Helpers.all_format(Time.now).map do |time|
|
23
|
+
Fatboy::Helpers.format_store(obj.class.to_s, time)
|
24
|
+
end
|
25
|
+
stores.map{|store| inc_member(store, obj.id)}
|
26
|
+
end
|
27
|
+
##
|
28
|
+
# let users view with a shorthand
|
29
|
+
alias :[] view
|
30
|
+
##
|
31
|
+
# This method returns a Fatboy::Popularity, the main interface for
|
32
|
+
# determining the popularity of your models.
|
33
|
+
# Example:
|
34
|
+
# fatboy.popular(Image)
|
35
|
+
# fatboy.popular("Image")
|
36
|
+
# fatboy.popular(model.class)
|
37
|
+
def popular(model)
|
38
|
+
Popularity.new(model, @redis)
|
39
|
+
end
|
40
|
+
##
|
41
|
+
# Format string we use to store the views per hour
|
42
|
+
HOUR_FORMAT_STR = "%Y%m%d%H"
|
43
|
+
##
|
44
|
+
# Format string we use to store the views per day
|
45
|
+
DAY_FORMAT_STR = "%Y%m%d"
|
46
|
+
##
|
47
|
+
# Format string we use to store the views per month
|
48
|
+
MONTH_FORMAT_STR = "%Y%m"
|
49
|
+
##
|
50
|
+
# Format string we use to store the views per year
|
51
|
+
YEAR_FORMAT_STR = "%Y"
|
52
|
+
private
|
53
|
+
def inc_member(store, id)
|
54
|
+
@redis.zincrby(store, 1, id)
|
55
|
+
end
|
56
|
+
end
|
data/spec/fatboy_spec.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
RSpec.describe Fatboy do
|
3
|
+
it "can be initialized" do
|
4
|
+
expect{Fatboy.new}.to_not raise_error
|
5
|
+
end
|
6
|
+
let(:redis){MockRedis.new}
|
7
|
+
let(:f){Fatboy.new(redis: redis)}
|
8
|
+
describe "storage" do
|
9
|
+
before(:each){Timecop.freeze(Date.today)}
|
10
|
+
after(:each){Timecop.return}
|
11
|
+
it "ads to the redis" do
|
12
|
+
l = Fatboy::Helpers.day_format(Time.now)
|
13
|
+
l = Fatboy::Helpers.format_store("Model", l)
|
14
|
+
expect{
|
15
|
+
f.view(Model.new(10))
|
16
|
+
}.to change{redis.zcount(l, -100, 100)}.from(0).to(1)
|
17
|
+
f.view(Model.new(11))
|
18
|
+
expect(redis.zscore(l, 11)).to eq(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
describe "ordering" do
|
23
|
+
|
24
|
+
before(:each){Timecop.freeze(Date.today)}
|
25
|
+
after(:each){Timecop.return}
|
26
|
+
it "orders views by day" do
|
27
|
+
2.times{f.view(Model.new(10))}
|
28
|
+
1.times{f.view(Model.new(11))}
|
29
|
+
expect(f.popular(Model).today.most.id).to eq(10)
|
30
|
+
end
|
31
|
+
it "orders views by month" do
|
32
|
+
2.times{f.view(Model.new(10))}
|
33
|
+
1.times{f.view(Model.new(11))}
|
34
|
+
expect(f.popular(Model).this_month.most.id).to eq(10)
|
35
|
+
end
|
36
|
+
it "orders views by year" do
|
37
|
+
2.times{f.view(Model.new(10))}
|
38
|
+
1.times{f.view(Model.new(11))}
|
39
|
+
expect(f.popular(Model).this_year.most.id).to eq(10)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
describe "popularity finding" do
|
43
|
+
it "doesn't throw an error" do
|
44
|
+
expect{f.popular(Model)}.to_not raise_error
|
45
|
+
end
|
46
|
+
it "returns a popularity" do
|
47
|
+
expect(f.popular(Model)).to be_instance_of(Fatboy::Popularity)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/mocks/model.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.setup
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start
|
5
|
+
require 'fatboy'
|
6
|
+
require_relative './mocks/model.rb'
|
7
|
+
require 'timecop'
|
8
|
+
require 'mock_redis'
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
# Don't need to actually do anything
|
12
|
+
end
|
13
|
+
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fatboy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anthony Super
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
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: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: timecop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mock_redis
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: redis
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: "\n Fatboy is a gem designed to easily keep track of views.\n It doesn't
|
112
|
+
touch your SQL, and stays slim in redis.\n It also makes it easy to query based
|
113
|
+
on how viewed something is.\n "
|
114
|
+
email:
|
115
|
+
- anthony@noided.media
|
116
|
+
executables: []
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- ".gitignore"
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- fatboy.gemspec
|
126
|
+
- lib/fatboy.rb
|
127
|
+
- lib/fatboy/helpers.rb
|
128
|
+
- lib/fatboy/popularity.rb
|
129
|
+
- lib/fatboy/time_based_popularity.rb
|
130
|
+
- lib/fatboy/version.rb
|
131
|
+
- lib/fatboy/viewed_item.rb
|
132
|
+
- spec/fatboy_spec.rb
|
133
|
+
- spec/mocks/model.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
homepage: http://github.com/AnthonySuper/fatboy
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
metadata: {}
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '2.0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.2.2
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: Fatboy keeps track of your models's views, right here, right now.
|
159
|
+
test_files:
|
160
|
+
- spec/fatboy_spec.rb
|
161
|
+
- spec/mocks/model.rb
|
162
|
+
- spec/spec_helper.rb
|
163
|
+
has_rdoc:
|