hit_list 1.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7b66c6daf960a7b4f088908bda841f84826764ae
4
+ data.tar.gz: bb2ab292705bc84bb727475922897d43bb8ffbe0
5
+ SHA512:
6
+ metadata.gz: 03d341c62daa4992d6d64a9152d27ca358392a0edcafee8315cb07d434d3a8b80e690124df2d53cdddacad1d7d1f7396abe9a663545fde6eb2bca1bfb46d5392
7
+ data.tar.gz: 52fecd21ee1eaff7cb2d4f6f16f2485e48fa10b7df9f3ef28922fa4678ab25e6e1e4f92c7a2efa1aec2c40f01291b9ab313dcaf8273a18bc98bb4b10ee9fc3c2
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode
6
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hot_or_not.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Krists Ozols
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.
@@ -0,0 +1,95 @@
1
+ # HitList
2
+
3
+ Very simple and fast hit and popularity counter using Redis sorted sets.
4
+ It solves problem where you need to know most popular article or project in last X days.
5
+
6
+ [![Build Status](https://travis-ci.org/krists/hit_list.png?branch=master)](https://travis-ci.org/krists/hit_list)
7
+ [![Gem Version](https://badge.fury.io/rb/hit_list.png)](http://badge.fury.io/rb/hit_list)
8
+ [![Code Climate](https://codeclimate.com/github/krists/hit_list.png)](https://codeclimate.com/github/krists/hit_list)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'hit_list'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install hit_list
23
+
24
+ ## Usage with Rails
25
+
26
+ # Set Redis connection in initializer
27
+ HitList::RailsModelExtension.redis_connection= Redis.new(host: '127.0.0.1', port: 6380)
28
+
29
+ # If you don't do this HitList will attempt to create one on its own with default arguments
30
+ # Equivalent to:
31
+ HitList::RailsModelExtension.redis_connection= Redis.new
32
+
33
+ # include in models..
34
+ class Article < ActiveRecord::Base
35
+ include HitList::RailsModelExtension
36
+ # ..
37
+ end
38
+
39
+ # Use..
40
+ Article.top_records(3) # => ["1", "43", "13"]
41
+
42
+ article = Article.first
43
+ article.total_hits # => 4
44
+ article.increment_hit_counter! # Increments total hits counter and ranking for days
45
+ article.increment_only_total_hits!
46
+ article.increment_only_rank!
47
+
48
+ # When you want to preserve rank stats for more than default 7 days you have to overwrite method hit_list_day_count
49
+ class Article < ActiveRecord::Base
50
+ include HitList::RailsModelExtension
51
+
52
+ def hit_list_day_count
53
+ 14
54
+ end
55
+
56
+ # ..
57
+
58
+ end
59
+
60
+
61
+ ## Usage without Rails
62
+
63
+ # connect to redis db
64
+ redis_connection = Redis.new(:host => "10.0.1.1", :port => 6380)
65
+
66
+ # pass connection when initializing counter
67
+ counter = HitList::Counter.new(connection, 'articles')
68
+
69
+ # make hits..
70
+ counter.hit!(2)
71
+ counter.hit!(2)
72
+ counter.hit!('bob')
73
+
74
+ # see results..
75
+ counter.total_hits(2) # => 2
76
+ counter.total_hits('bob') # => 1
77
+
78
+ # You can track hits on objects. Just provide different name
79
+ counter_1 = HitList::Counter.new(connection, 'articles')
80
+ counter_1.hit!('top-story')
81
+ counter_2 = HitList::Counter.new(connection, 'users')
82
+ counter_2.hit!('alice')
83
+
84
+ # Finaly you can see top records for any given time.
85
+ counter_1 = HitList::Counter.new(connection, 'articles')
86
+ counter_1.top_records(3) # => ["91","5","34"]
87
+
88
+ # or rankings 3 days ago..
89
+ counter_1.top_records(2, Time.now - 3.days) # => ["5","34"]
90
+
91
+ If you want to preserve ranking for more than 7 days you have to provide day count when initializing `HitList::Counter` object
92
+
93
+ # Preserve rankings for 2 weeks
94
+ counter = HitList::Counter.new(connection, 'articles', 14)
95
+ counter.hit!('something')
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ rescue LoadError
7
+ end
8
+
9
+ task :default => :spec
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hit_list/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hit_list"
8
+ spec.version = HitList::VERSION
9
+ spec.authors = ["Krists Ozols"]
10
+ spec.email = ["krists.ozols@gmail.com"]
11
+ spec.description = %q{Very simple and fast hit and popularity counter using Redis sorted sets.}
12
+ spec.summary = %q{It solves problem where you need to know most popular article or project in last X days.}
13
+ spec.homepage = "https://github.com/krists/hit_list"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency 'timecop'
25
+ spec.add_development_dependency "fakeredis"
26
+
27
+ end
@@ -0,0 +1,6 @@
1
+ require "hit_list/version"
2
+ require "hit_list/counter"
3
+ require "hit_list/rails_model_extension"
4
+
5
+ module HitList
6
+ end
@@ -0,0 +1,78 @@
1
+ module HitList
2
+ class Counter
3
+ DEFAULT_NAMESPACE = 'hit_list'
4
+ DEFAULT_DAYS_OF_INTEREST = 7
5
+ SECONDS_IN_DAY = 86400
6
+ DATE_PARTIAL_FORMAT = "%Y-%m-%d"
7
+ DEFAULT_INCR_VALUE = 1
8
+
9
+ # Creates new instance of counter. It requires a working Redis connection as first argument.
10
+ #
11
+ # ==== Examples
12
+ #
13
+ # counter = HitList::Counter.new(connection, 'articles', 7)
14
+ # counter = HitList::Counter.new(connection, 'articles')
15
+ def initialize(connection, name, days_of_interest = DEFAULT_DAYS_OF_INTEREST)
16
+ @connection, @name, @days_of_interest = connection, name, days_of_interest
17
+ end
18
+
19
+ attr_reader :namespace, :connection, :name, :days_of_interest
20
+
21
+ # Returns namespace used in keys
22
+ def namespace
23
+ DEFAULT_NAMESPACE
24
+ end
25
+
26
+ # Returns integer representing total hit count for specific id
27
+ #
28
+ # ==== Examples
29
+ #
30
+ # counter.total_hits(5) # => 12
31
+ # counter.total_hits('some-slug') # => 3
32
+ def total_hits(id)
33
+ connection.get("#{namespace}:#{name}:total:#{id}").to_i
34
+ end
35
+
36
+ # Returns array of ids sorted by most hits first
37
+ #
38
+ # ==== Examples
39
+ #
40
+ # counter.top_records(3) # => ["31", "1", "44"]
41
+ # counter.top(1, Time.now - 4.days) # => ["5"]
42
+ def top_records(limit, time_of_interest = nil)
43
+ time = time_of_interest || Time.now
44
+ date = time.strftime(DATE_PARTIAL_FORMAT)
45
+ connection.zrevrange("#{namespace}:#{name}:date:#{date}", 0, limit - 1)
46
+ end
47
+
48
+ # Increments total hits and rank for given id
49
+ def hit!(id)
50
+ increment_total_hits!(id)
51
+ increment_rank!(id)
52
+ end
53
+
54
+ # Increments total hits only for given id
55
+ def increment_total_hits!(id)
56
+ connection.incr("#{namespace}:#{name}:total:#{id}")
57
+ end
58
+
59
+ # Increments rank only for given id
60
+ def increment_rank!(id)
61
+ @connection.pipelined do
62
+ date_partials.each do |date_partial|
63
+ connection.zincrby("#{namespace}:#{name}:date:#{date_partial}", DEFAULT_INCR_VALUE, id)
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def date_partials
71
+ partials = []
72
+ 0.upto(days_of_interest - 1) do |index|
73
+ partials << (Time.now + (index * SECONDS_IN_DAY)).strftime(DATE_PARTIAL_FORMAT)
74
+ end
75
+ partials.to_enum
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,52 @@
1
+ module HitList::RailsModelExtension
2
+
3
+ def self.redis_connection
4
+ @redis_connection ||= begin
5
+ puts "HitList::RailsModelExtension: No Redis connection provided. Creating new with default settings"
6
+ Redis.new
7
+ end
8
+ end
9
+
10
+ def self.redis_connection=(connection)
11
+ @redis_connection = connection
12
+ end
13
+
14
+ module ClassMethods
15
+ def top_records(count = 5)
16
+ counter = HitList::Counter.new(HitList::RailsModelExtension.redis_connection, self.name)
17
+ counter.top_records(count)
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+
23
+ def hit_list_day_count
24
+ 7
25
+ end
26
+
27
+ def total_hits
28
+ hit_counter.total_hits(self.id)
29
+ end
30
+
31
+ def increment_hit_counter!
32
+ hit_counter.hit!(self.id)
33
+ end
34
+
35
+ def increment_only_total_hits!
36
+ hit_counter.increment_total_hits!(self.id)
37
+ end
38
+
39
+ def increment_only_rank!
40
+ hit_counter.increment_rank!(self.id)
41
+ end
42
+
43
+ def hit_counter
44
+ @hit_counter ||= HitList::Counter.new(HitList::RailsModelExtension.redis_connection, self.class.name, hit_list_day_count)
45
+ end
46
+ end
47
+
48
+ def self.included(receiver)
49
+ receiver.extend ClassMethods
50
+ receiver.send :include, InstanceMethods
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module HitList
2
+ VERSION = "1.1.1"
3
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe HitList::Counter do
4
+ let(:real_connection) { Redis.new }
5
+ let(:name) { 'article' }
6
+ let(:days_of_interest) { 7 }
7
+
8
+ subject { described_class.new(real_connection, name, days_of_interest) }
9
+
10
+ before(:each) do
11
+ real_connection.flushall
12
+ end
13
+
14
+ describe "#total_hits" do
15
+ it "works as expected" do
16
+ Timecop.travel(Date.parse('2013-01-21'))
17
+ subject.hit!(22)
18
+ subject.hit!(22)
19
+ subject.hit!(7)
20
+ subject.hit!(44)
21
+ subject.hit!(44)
22
+ subject.hit!(44)
23
+ subject.total_hits(22).should eq(2)
24
+ subject.total_hits(7).should eq(1)
25
+ subject.total_hits(44).should eq(3)
26
+ Timecop.return
27
+ end
28
+ end
29
+
30
+ describe "#top_records" do
31
+ it 'top records should work' do
32
+ Timecop.travel(Date.parse('2013-01-21'))
33
+ subject.hit!(22)
34
+ subject.hit!(22)
35
+ subject.hit!(22)
36
+ subject.hit!(7)
37
+ Timecop.travel(Date.parse('2013-01-22'))
38
+ subject.hit!(22)
39
+ subject.hit!(22)
40
+ Timecop.travel(Date.parse('2013-01-23'))
41
+ subject.hit!(22)
42
+ subject.hit!(7)
43
+ subject.hit!(7)
44
+ subject.hit!(7)
45
+ subject.hit!(7)
46
+ subject.top_records(2).should eq(["22", "7"])
47
+ Timecop.travel(Date.parse('2013-01-25'))
48
+ subject.top_records(2).should eq(["22", "7"])
49
+ Timecop.travel(Date.parse('2013-01-28'))
50
+ subject.top_records(2).should eq(["7", "22"])
51
+ Timecop.return
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,88 @@
1
+ require "spec_helper"
2
+
3
+ describe HitList::Counter do
4
+ let(:connection) { double "connection" }
5
+ let(:name) { 'article' }
6
+ let(:days_of_interest) { 7 }
7
+
8
+ subject { described_class.new(connection, name, days_of_interest) }
9
+
10
+ before(:each) do
11
+ connection.stub(:get) { '' }
12
+ connection.stub(:incr) { '' }
13
+ connection.stub(:zincrby) { '' }
14
+ connection.stub(:pipelined).and_yield
15
+ end
16
+
17
+ describe "#initialize" do
18
+ it "requires connection, name and days of interest as arguments" do
19
+ expect { subject }.not_to raise_error
20
+ end
21
+ end
22
+
23
+ describe "#namespace" do
24
+ it "returns default namespace for counter keys" do
25
+ subject.namespace.should eq("hit_list")
26
+ end
27
+ end
28
+
29
+ describe "#total_hits" do
30
+ it "calls #get to connection with key like '<namespace>:<name>:total:<id>'" do
31
+ connection.should_receive(:get).with('hit_list:article:total:12')
32
+ subject.total_hits(12)
33
+ end
34
+ end
35
+
36
+ describe "#hit!" do
37
+ it "calls #increment_total_hits!" do
38
+ subject.should_receive(:increment_total_hits!).with(13)
39
+ subject.hit!(13)
40
+ end
41
+ it "calls #increment_rank!" do
42
+ subject.should_receive(:increment_rank!).with(13)
43
+ subject.hit!(13)
44
+ end
45
+ end
46
+
47
+ describe "#increment_total_hits!" do
48
+ it "calls #incr to connection with key like '<namespace>:<name>:total:<id>'" do
49
+ connection.should_receive(:incr).with('hit_list:article:total:14')
50
+ subject.increment_total_hits!(14)
51
+ end
52
+ end
53
+
54
+ describe "#increment_rank!" do
55
+ it "calls #zincrby on connection with key like '<namespace>:<name>:date:<date>:<id>' multiple times with right dates" do
56
+ Timecop.freeze(Date.parse('2013-07-29')) do
57
+ connection.should_receive(:zincrby).with("hit_list:article:date:2013-07-29", 1, 66)
58
+ connection.should_receive(:zincrby).with("hit_list:article:date:2013-07-30", 1, 66)
59
+ connection.should_receive(:zincrby).with("hit_list:article:date:2013-07-31", 1, 66)
60
+ connection.should_receive(:zincrby).with("hit_list:article:date:2013-08-01", 1, 66)
61
+ connection.should_receive(:zincrby).with("hit_list:article:date:2013-08-02", 1, 66)
62
+ connection.should_receive(:zincrby).with("hit_list:article:date:2013-08-03", 1, 66)
63
+ connection.should_receive(:zincrby).with("hit_list:article:date:2013-08-04", 1, 66)
64
+ subject.increment_rank!(66)
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#top_records" do
70
+ context "when time not specified" do
71
+ it "should get top records in period" do
72
+ Timecop.freeze(Date.parse('2013-07-29')) do
73
+ connection.should_receive(:zrevrange).with("hit_list:article:date:2013-07-29", 0, 4)
74
+ subject.top_records(5)
75
+ end
76
+ end
77
+ end
78
+
79
+ context "when time is specified" do
80
+ it "should get top records in period" do
81
+ Timecop.freeze(Date.parse('2013-07-29')) do
82
+ connection.should_receive(:zrevrange).with("hit_list:article:date:2013-02-22", 0, 2)
83
+ subject.top_records(3, Date.parse('2013-02-22'))
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,72 @@
1
+ require "spec_helper"
2
+
3
+ describe HitList::RailsModelExtension do
4
+
5
+ describe "#module methods" do
6
+ subject { HitList::RailsModelExtension }
7
+ describe "#redis_connection" do
8
+ context "when not specifying any specific connection" do
9
+ it "returns Redis connection with default configuration" do
10
+ expect(subject.redis_connection).to be_a_kind_of(Redis)
11
+ end
12
+ end
13
+ end
14
+
15
+ describe "#redis_connection=" do
16
+ it "allows to set Redis connection" do
17
+ subject.redis_connection= 'fake connection'
18
+ subject.redis_connection.should eq('fake connection')
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "Class with RailsModelExtension included" do
24
+
25
+ SomethingModelish = Struct.new(:id) do
26
+ include HitList::RailsModelExtension
27
+ end
28
+
29
+ describe "class methods" do
30
+ subject { SomethingModelish }
31
+
32
+ describe "#top_records" do
33
+ it "calls counter top_records method" do
34
+ HitList::Counter.any_instance.should_receive(:top_records).with(3)
35
+ subject.top_records(3)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "instance methods" do
41
+ subject { SomethingModelish.new(:the_id) }
42
+
43
+ describe "#total_hits" do
44
+ it "calls counter total_hits method with model id" do
45
+ HitList::Counter.any_instance.should_receive(:total_hits).with(:the_id)
46
+ subject.total_hits
47
+ end
48
+ end
49
+
50
+ describe "#increment_hit_counter!" do
51
+ it "calls counter hit! method with record id" do
52
+ HitList::Counter.any_instance.should_receive(:hit!).with(:the_id)
53
+ subject.increment_hit_counter!
54
+ end
55
+ end
56
+
57
+ describe "#increment_only_total_hits!" do
58
+ it "calls counter hit! method with record id" do
59
+ HitList::Counter.any_instance.should_receive(:increment_total_hits!).with(:the_id)
60
+ subject.increment_only_total_hits!
61
+ end
62
+ end
63
+
64
+ describe "#increment_only_rank!" do
65
+ it "calls counter hit! method with record id" do
66
+ HitList::Counter.any_instance.should_receive(:increment_rank!).with(:the_id)
67
+ subject.increment_only_rank!
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,7 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rspec'
5
+ require "fakeredis"
6
+ require 'timecop'
7
+ require 'hit_list'
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hit_list
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Krists Ozols
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-10 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: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
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: fakeredis
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
+ description: Very simple and fast hit and popularity counter using Redis sorted sets.
84
+ email:
85
+ - krists.ozols@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - hit_list.gemspec
97
+ - lib/hit_list.rb
98
+ - lib/hit_list/counter.rb
99
+ - lib/hit_list/rails_model_extension.rb
100
+ - lib/hit_list/version.rb
101
+ - spec/counter_end_to_end_spec.rb
102
+ - spec/counter_spec.rb
103
+ - spec/rails_model_extension_spec.rb
104
+ - spec/spec_helper.rb
105
+ homepage: https://github.com/krists/hit_list
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.6.10
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: It solves problem where you need to know most popular article or project
129
+ in last X days.
130
+ test_files:
131
+ - spec/counter_end_to_end_spec.rb
132
+ - spec/counter_spec.rb
133
+ - spec/rails_model_extension_spec.rb
134
+ - spec/spec_helper.rb