rails_rank 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +118 -0
- data/Rakefile +1 -0
- data/lib/generators/ranking_generator.rb +10 -0
- data/lib/generators/templates/base.rb.template +46 -0
- data/lib/rails_rank/base.rb +55 -0
- data/lib/rails_rank/defined_base_methods.rb +149 -0
- data/lib/rails_rank/types/date.rb +11 -0
- data/lib/rails_rank/version.rb +3 -0
- data/lib/rails_rank.rb +5 -0
- data/lib/railtie.rb +9 -0
- data/lib/tasks/table.rake +28 -0
- data/rails_rank.gemspec +29 -0
- data/spec/rails_rank/defined_base_methods_spec.rb +289 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/tasks/tasks_spec.rb +19 -0
- metadata +164 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a226174d165b3f53c80a2220a072dffc7f46e49d
|
4
|
+
data.tar.gz: 071e16d3ec71e8b59f9a54d786d43914f8ef9040
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: daa60282c8d910a6b448aaabf2d38b1406038fce36b5948ba6f6886e0248e4dacd087ab6e8087c79fb0a545f33250fca722440a6d72fc5150bbd4a906b4a8411
|
7
|
+
data.tar.gz: b586bd44ae43fc4571e84258837c46c6fd665b3fb4056f7b52d5c17350614ee6286e1312dc6e78a54c867a41722c76284560ed0abe57031d6ecab840f4254741
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Atsushi Nakamura
|
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,118 @@
|
|
1
|
+
# RailsRank
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rails_rank'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rails_rank
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
## Usage: (using redis_driver)
|
22
|
+
|
23
|
+
### Install rails\_kvs\_driver
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem "rails_kvs_driver-redis_driver", ">= 0.2.0"
|
27
|
+
```
|
28
|
+
|
29
|
+
### Generate a class of ranking
|
30
|
+
This code generate access_rank.rb in lib/rankings/ .
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
bundle exec rails g ranking access_rank
|
34
|
+
```
|
35
|
+
|
36
|
+
## Edit generated lib/rankings/access_rank.rb
|
37
|
+
add driver setting.
|
38
|
+
```ruby
|
39
|
+
def self.rails_kvs_driver
|
40
|
+
RailsKvsDriver::RedisDriver::Driver
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
And override after_table methods.
|
45
|
+
This method will call after done tabulation.
|
46
|
+
Specifically,
|
47
|
+
|
48
|
+
- after count hourly.(onece an hour)
|
49
|
+
- after count daily. (onece a day)
|
50
|
+
- after count monthly.(once a month)
|
51
|
+
- after count yearly.(once a year)
|
52
|
+
|
53
|
+
when table, after_table will be called repeatedly as the number of the data.
|
54
|
+
|
55
|
+
You should write a code in here, to insert data to database.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# callbacked after table.
|
59
|
+
# if use data, override this method.
|
60
|
+
#
|
61
|
+
# @param date_type [RailsRank::Types::Date] type of tabulation.(HOURLY or DAILY or MONTHLY or YEARLY)
|
62
|
+
# @param time [Time] time slot of tabulation.
|
63
|
+
# @param value [String] value of tabulation.
|
64
|
+
# @param score [Integer] score of value.
|
65
|
+
# @param position [Integer] position of value.
|
66
|
+
def self.after_table(date_type, time, value, score, position)
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
For example
|
71
|
+
|
72
|
+
when there are the next hourly data.
|
73
|
+
|
74
|
+
|value|score|
|
75
|
+
|:----:|---:|
|
76
|
+
|'id-1'| 5|
|
77
|
+
|'id-2'|10|
|
78
|
+
|'id-3'| 8|
|
79
|
+
|
80
|
+
|
81
|
+
after_table will be called 3 times with the next parameter when table the time slot.
|
82
|
+
|
83
|
+
|data_type|time|value|score|position|
|
84
|
+
|:-------:|:--:|:---:|:---:|:------:|
|
85
|
+
|RailsRank::Types::Date::HOURLY| data_time|'id-2'|10|0|
|
86
|
+
|RailsRank::Types::Date::HOURLY| data_time|'id-3'|8|1|
|
87
|
+
|RailsRank::Types::Date::HOURLY| data_time|'id-1'|5|2|
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
### Add autoload setting in application.rb
|
92
|
+
If your application.rb include this setting, don't need this step.
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
config.autoload_paths += %W("#{config.root}/lib")
|
96
|
+
config.autoload_paths += Dir["#{config.root}/lib/**/"]
|
97
|
+
```
|
98
|
+
|
99
|
+
### Periodical practice
|
100
|
+
This task must be called every an hour. use cron.
|
101
|
+
```ruby
|
102
|
+
bundle exec rake rails_rank:table
|
103
|
+
```
|
104
|
+
|
105
|
+
### How to add and get data.
|
106
|
+
When add a data of the ranking, or get data before table. use next methods.
|
107
|
+
```
|
108
|
+
Rankings::AccessRank.increment(@hoge.id)
|
109
|
+
Rankings::AccessRank.score(@hoge.id)
|
110
|
+
```
|
111
|
+
|
112
|
+
## Contributing
|
113
|
+
|
114
|
+
1. Fork it
|
115
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
116
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
117
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
118
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class RankingGenerator < Rails::Generators::NamedBase
|
2
|
+
|
3
|
+
source_root File.expand_path("../templates", __FILE__)
|
4
|
+
|
5
|
+
desc "This generator creates ranking class file in lib/rankings."
|
6
|
+
|
7
|
+
def create_ranking_file
|
8
|
+
template "base.rb.template", "lib/rankings/#{file_name}.rb"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rails_rank/base'
|
2
|
+
|
3
|
+
module Rankings
|
4
|
+
class <%= class_name %> < RailsRank::Base
|
5
|
+
|
6
|
+
# return driver class of rails_kvs_driver.
|
7
|
+
#
|
8
|
+
# @example use rails_kvs_driver-redis_driver
|
9
|
+
# def self.rails_kvs_driver
|
10
|
+
# RailsKvsDriver::RedisDriver::Driver
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# @return [RailsKvsDriver::Base] return driver class of rails_kvs_driver.
|
14
|
+
def self.rails_kvs_driver
|
15
|
+
raise NoMethodError 'Should override lib/rankings/<%= file_name %>.rb rails_kvs_driver method.'
|
16
|
+
end
|
17
|
+
|
18
|
+
# return driver config of rails_kvs_driver.
|
19
|
+
#
|
20
|
+
# @return [Hash] return driver config of rails_kvs_driver.
|
21
|
+
def self.rails_kvs_driver_config
|
22
|
+
{
|
23
|
+
:host => 'localhost', # host of KVS.
|
24
|
+
:port => 6379, # port of KVS.
|
25
|
+
:namespace => 'Ranking::<%= class_name %>', # namespace of avoid a conflict with key
|
26
|
+
:timeout_sec => 5, # timeout seconds.
|
27
|
+
:pool_size => 5, # connection pool size.
|
28
|
+
:config_key => :none # this key is option.(defaults=:none)
|
29
|
+
# when set this key.
|
30
|
+
# will refer to a connection-pool based on config_key,
|
31
|
+
# even if driver setting is the same without this key.
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
# callbacked after table.
|
36
|
+
# if use data, override this method.
|
37
|
+
#
|
38
|
+
# @param date_type [RailsRank::Types::Date] type of tabulation.
|
39
|
+
# @param time [Time] time slot of tabulation.
|
40
|
+
# @param value [String] value of tabulation.
|
41
|
+
# @param score [Integer] score of value.
|
42
|
+
# @param position [Integer] position of value.
|
43
|
+
def self.after_table(date_type, time, value, score, position)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rails_rank/defined_base_methods'
|
2
|
+
|
3
|
+
module RailsRank
|
4
|
+
# @abstract a class of Ranking is override this class.
|
5
|
+
class Base
|
6
|
+
extend DefinedBaseMethods
|
7
|
+
|
8
|
+
# return driver class of rails_kvs_driver.
|
9
|
+
#
|
10
|
+
# @example use rails_kvs_driver-redis_driver
|
11
|
+
# def self.rails_kvs_driver
|
12
|
+
# RailsKvsDriver::RedisDriver::Driver
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# @return [RailsKvsDriver::Base] return driver class of rails_kvs_driver.
|
16
|
+
# @abstract override and return driver class of rails_kvs_driver.
|
17
|
+
def self.rails_kvs_driver
|
18
|
+
raise NoMethodError 'Should override rails_kvs_driver method.'
|
19
|
+
end
|
20
|
+
|
21
|
+
# return driver config of rails_kvs_driver.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# def self.rails_kvs_driver_config
|
25
|
+
# {
|
26
|
+
# :host => 'localhost', # host of KVS.
|
27
|
+
# :port => 6379, # port of KVS.
|
28
|
+
# :namespace => 'Example', # namespace of avoid a conflict with key
|
29
|
+
# :timeout_sec => 5, # timeout seconds.
|
30
|
+
# :pool_size => 5, # connection pool size.
|
31
|
+
# :config_key => :none # this key is option.(defaults=:none)
|
32
|
+
# # when set this key.
|
33
|
+
# # will refer to a connection-pool based on config_key,
|
34
|
+
# # even if driver setting is the same without this key.
|
35
|
+
# }
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @return [Hash] return driver config of rails_kvs_driver.
|
39
|
+
# @abstract override and return driver config of rails_kvs_driver.
|
40
|
+
def self.rails_kvs_driver_config
|
41
|
+
raise NoMethodError 'Should override rails_kvs_driver_config method.'
|
42
|
+
end
|
43
|
+
|
44
|
+
# callbacked after table.
|
45
|
+
# if use data, override this method.
|
46
|
+
#
|
47
|
+
# @param date_type [RailsRank::Types::Date] type of tabulation.
|
48
|
+
# @param time [Time] time slot of tabulation.
|
49
|
+
# @param value [String] value of tabulation.
|
50
|
+
# @param score [Integer] score of value.
|
51
|
+
# @param position [Integer] position of value.
|
52
|
+
def self.after_table(date_type, time, value, score, position)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'rails_rank/types/date'
|
2
|
+
|
3
|
+
module RailsRank
|
4
|
+
module DefinedBaseMethods
|
5
|
+
|
6
|
+
# get all time slot(s).
|
7
|
+
#
|
8
|
+
# @param date_type [RailsRank::Types::Date] delete type.(default=HOURLY)
|
9
|
+
# @param session [RailsKvsDriver::Base] default is nil. if there's session instance, set it.
|
10
|
+
# @return [Array<Time>] all time slot(s).
|
11
|
+
def all(date_type=RailsRank::Types::Date::HOURLY, session=nil)
|
12
|
+
start_kvs_session(session) do |kvs|
|
13
|
+
times = Array.new
|
14
|
+
all_key = (date_type == RailsRank::Types::Date::ALL)
|
15
|
+
|
16
|
+
kvs.sorted_sets.each do |key|
|
17
|
+
key_a = key.split('-')
|
18
|
+
times.push(Time.local(*key_a)) if all_key or key_a.length == date_type
|
19
|
+
end
|
20
|
+
|
21
|
+
times
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# delete the data of ranking.
|
26
|
+
#
|
27
|
+
# @param time [Time] delete time slot.
|
28
|
+
# @param date_type [RailsRank::Types::Date] delete type.(default=HOURLY)
|
29
|
+
# @param session [RailsKvsDriver::Base] default is nil. if there's session instance, set it.
|
30
|
+
def delete(time, date_type=RailsRank::Types::Date::HOURLY, session=nil)
|
31
|
+
start_kvs_session(session) do |kvs|
|
32
|
+
kvs.delete(key_name(time, date_type))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# delete all ranking data.
|
37
|
+
# @param session [RailsKvsDriver::Base] default is nil. if there's session instance, set it.
|
38
|
+
def delete_all(session=nil)
|
39
|
+
start_kvs_session(session) do |kvs|
|
40
|
+
kvs.delete_all
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# execute the block of code for each ranking.
|
45
|
+
#
|
46
|
+
# @param key [String] key of time slot.
|
47
|
+
# @param reverse [Boolean] order desc. [default=asc]
|
48
|
+
# @param limit [Integer] The maximum size of the request at once.
|
49
|
+
# @param session [RailsKvsDriver::Base] default is nil. if there's session instance, set it.
|
50
|
+
# @param &block [{|value, score, absolute_position| ...}] block of exec code.
|
51
|
+
def each(key, reverse=false, limit=1000, session=nil, &block)
|
52
|
+
start_kvs_session(session) {|kvs| kvs.sorted_sets[key].each(reverse, limit, &block) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# increment this time slot score of a value. (Time slot is hourly.)
|
56
|
+
# @note when doesn't exist the value, set 'score' to value of score.
|
57
|
+
#
|
58
|
+
# @param value [String] value to record the score.
|
59
|
+
# @param score [Integer] score to increment.
|
60
|
+
# @param session [RailsKvsDriver::Base] default is nil. if there's session instance, set it.
|
61
|
+
# @return [Integer] score after increment
|
62
|
+
def increment(value, score=1, session=nil)
|
63
|
+
start_kvs_session(session) do |kvs|
|
64
|
+
kvs.sorted_sets[key_name(Time.now)].increment(value, score).to_i
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# get ranking key of a time slot.
|
69
|
+
#
|
70
|
+
# @param time [Time] time of key.
|
71
|
+
# @param date_type [RailsRank::Types::Date] type of key.(default=HOURLY)
|
72
|
+
# @return [String] key name.
|
73
|
+
def key_name(time, date_type=RailsRank::Types::Date::HOURLY)
|
74
|
+
case date_type
|
75
|
+
when RailsRank::Types::Date::YEARLY
|
76
|
+
time.strftime('%Y')
|
77
|
+
when RailsRank::Types::Date::MONTHLY
|
78
|
+
time.strftime('%Y-%m')
|
79
|
+
when RailsRank::Types::Date::DAILY
|
80
|
+
time.strftime('%Y-%m-%d')
|
81
|
+
else
|
82
|
+
time.strftime('%Y-%m-%d-%H')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# get this time slot score of a value.(Time slot is hourly.)
|
87
|
+
# @note when doesn't exist the value, return 0.
|
88
|
+
#
|
89
|
+
# @param value [String] value to record the score.
|
90
|
+
# @param session [RailsKvsDriver::Base] default is nil. if there's session instance, set it.
|
91
|
+
# @return [Integer] score
|
92
|
+
def score(value, session=nil)
|
93
|
+
start_kvs_session(session) do |kvs|
|
94
|
+
score = kvs.sorted_sets[key_name(Time.now)][value]
|
95
|
+
(score.nil?) ? 0 : score.to_i
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# table score.
|
100
|
+
# this methods total the calculations done data.
|
101
|
+
#
|
102
|
+
# @param date_type [RailsRank::Types::Date] type of tabulation.
|
103
|
+
# @return [Integer] count tabled data.
|
104
|
+
def table(date_type)
|
105
|
+
raise ArgumentError if date_type < RailsRank::Types::Date::YEARLY
|
106
|
+
|
107
|
+
tabled_data_count = 0
|
108
|
+
base_time = Time.local(*(Time.now.to_a.reverse[4..(3+date_type)]))
|
109
|
+
|
110
|
+
start_kvs_session do |kvs|
|
111
|
+
all(date_type).each do |data_time|
|
112
|
+
next unless data_time < base_time
|
113
|
+
|
114
|
+
key = key_name(data_time, date_type)
|
115
|
+
total_key = key_name(data_time, date_type - 1)
|
116
|
+
|
117
|
+
each(key, false, 1000, kvs) do |member, score, position|
|
118
|
+
if RailsRank::Types::Date::YEARLY < date_type
|
119
|
+
kvs.sorted_sets[total_key].increment(member, score)
|
120
|
+
end
|
121
|
+
after_table(date_type, data_time, member, score.to_i, position)
|
122
|
+
end
|
123
|
+
|
124
|
+
delete(data_time, date_type, kvs)
|
125
|
+
tabled_data_count += 1
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
return tabled_data_count
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
private
|
134
|
+
# start key-value store session.
|
135
|
+
# if session of params isn't nil, call &block with this session.
|
136
|
+
#
|
137
|
+
# @params session [RailsKvsDriver::Base] session.
|
138
|
+
# @params yield [block] exec block with session.
|
139
|
+
# @return [Object] Evaluation of the block.
|
140
|
+
def start_kvs_session(session=nil)
|
141
|
+
if session.nil?
|
142
|
+
rails_kvs_driver::session(rails_kvs_driver_config) {|new_session| yield new_session }
|
143
|
+
else
|
144
|
+
yield session
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
data/lib/rails_rank.rb
ADDED
data/lib/railtie.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
namespace :rails_rank do
|
2
|
+
|
3
|
+
desc 'table all the rankings.'
|
4
|
+
|
5
|
+
task :table => :environment do
|
6
|
+
# Load all ranking classes.
|
7
|
+
Dir.glob('lib/rankings/*.rb').each {|f| require "rankings/#{File.basename(f, '.rb')}" }
|
8
|
+
|
9
|
+
if Object.const_defined?('Rankings')
|
10
|
+
Rankings::constants.each do |name|
|
11
|
+
object = Rankings::const_get(name)
|
12
|
+
next unless object.ancestors.include?(RailsRank::Base)
|
13
|
+
|
14
|
+
puts("#{name} table the ranking...")
|
15
|
+
|
16
|
+
cnt = object.table(RailsRank::Types::Date::HOURLY)
|
17
|
+
puts "- tabled #{cnt} hourly data."
|
18
|
+
object.table(RailsRank::Types::Date::DAILY)
|
19
|
+
puts "- tabled #{cnt} daily data."
|
20
|
+
object.table(RailsRank::Types::Date::MONTHLY)
|
21
|
+
puts "- tabled #{cnt} monthly data."
|
22
|
+
object.table(RailsRank::Types::Date::YEARLY)
|
23
|
+
puts "- tabled #{cnt} yearly data."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/rails_rank.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rails_rank/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rails_rank"
|
8
|
+
spec.version = RailsRank::VERSION
|
9
|
+
spec.authors = ["alfa-jpn"]
|
10
|
+
spec.email = ["a.nkmr.ja@gmail.com"]
|
11
|
+
spec.description = "develop now"
|
12
|
+
spec.summary = "develop now"
|
13
|
+
spec.homepage = ""
|
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", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "yard"
|
25
|
+
spec.add_development_dependency "rails_kvs_driver-redis_driver", "0.2.0"
|
26
|
+
|
27
|
+
spec.add_dependency "rails", ">= 3"
|
28
|
+
spec.add_dependency "rails_kvs_driver", "0.2.1"
|
29
|
+
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rails_rank/defined_base_methods'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
describe RailsRank::DefinedBaseMethods do
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@driver = RailsKvsDriver::RedisDriver::Driver
|
11
|
+
@driver_config = {
|
12
|
+
:host => 'localhost', # host of KVS.
|
13
|
+
:port => 6379, # port of KVS.
|
14
|
+
:namespace => 'Spec::RailsRank', # namespace of avoid a conflict with key
|
15
|
+
:timeout_sec => 5, # timeout seconds.
|
16
|
+
:pool_size => 5, # connection pool size.
|
17
|
+
:config_key => :none # this key is option.(defaults=:none)
|
18
|
+
# when set this key.
|
19
|
+
# will refer to a connection-pool based on config_key,
|
20
|
+
# even if driver setting is the same without this key.
|
21
|
+
}
|
22
|
+
|
23
|
+
class IncludeDefinedBaseMethods
|
24
|
+
include RailsRank::DefinedBaseMethods
|
25
|
+
end
|
26
|
+
|
27
|
+
@defined_base_methods = IncludeDefinedBaseMethods.new
|
28
|
+
@defined_base_methods.stub({ rails_kvs_driver: @driver, rails_kvs_driver_config: @driver_config, after_table: nil })
|
29
|
+
|
30
|
+
Time.stub({ now: Time.local(2013,11,5) })
|
31
|
+
|
32
|
+
@driver::session(@driver_config) {|kvs| kvs.delete_all }
|
33
|
+
end
|
34
|
+
|
35
|
+
after(:each) do
|
36
|
+
@driver::session(@driver_config) {|kvs| kvs.delete_all }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when call all,' do
|
40
|
+
before(:each) do
|
41
|
+
(0 .. 11).each do |i|
|
42
|
+
Time.stub({ now: Time.local(2013,11,5, i) })
|
43
|
+
@defined_base_methods.increment("NyarukoSan", 2865)
|
44
|
+
end
|
45
|
+
@times = @defined_base_methods.all
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'return times' do
|
49
|
+
expect(@times[0].instance_of?(Time)).to be_true
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'return correct length' do
|
54
|
+
expect(@times.length).to eq(12)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when call delete' do
|
59
|
+
before(:each) do
|
60
|
+
@defined_base_methods.increment('NyarukoSan',2865)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'delete ranking data.' do
|
64
|
+
@driver::session(@driver_config) do |kvs|
|
65
|
+
expect{
|
66
|
+
@defined_base_methods.delete(Time.now)
|
67
|
+
}.to change{
|
68
|
+
kvs.sorted_sets.length
|
69
|
+
}.by(-1)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when call delete_all' do
|
75
|
+
before(:each) do
|
76
|
+
(0 .. 23).each do |i|
|
77
|
+
Time.stub({ now: Time.local(2013,11,5, i) })
|
78
|
+
@defined_base_methods.increment("NyarukoSan", 2865)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'delete ranking data.' do
|
83
|
+
@driver::session(@driver_config) do |kvs|
|
84
|
+
expect{
|
85
|
+
@defined_base_methods.delete_all
|
86
|
+
}.to change{
|
87
|
+
kvs.sorted_sets.length
|
88
|
+
}.by(-24)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when call each' do
|
94
|
+
before(:each) do
|
95
|
+
@defined_base_methods.increment('be_0',100)
|
96
|
+
@defined_base_methods.increment('be_1', 10)
|
97
|
+
@defined_base_methods.increment('be_2', 1)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'return correct data.' do
|
101
|
+
key = @defined_base_methods.key_name(Time.now, RailsRank::Types::Date::HOURLY)
|
102
|
+
@defined_base_methods.each(key, true) do |value, score, position|
|
103
|
+
expect(value).to eq("be_#{position}")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when call increment,' do
|
109
|
+
before(:each) do
|
110
|
+
@key = @defined_base_methods.key_name(Time.now)
|
111
|
+
@defined_base_methods.increment('NyarukoSan',2865)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'create sorted_set, and set score' do
|
115
|
+
@driver::session(@driver_config) do |kvs|
|
116
|
+
expect(kvs.sorted_sets.length).to eq(1)
|
117
|
+
expect(kvs.sorted_sets[@key]['NyarukoSan']).to eq(2865)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'increment score of value' do
|
122
|
+
@driver::session(@driver_config) do |kvs|
|
123
|
+
expect{
|
124
|
+
@defined_base_methods.increment('NyarukoSan')
|
125
|
+
}.to change{
|
126
|
+
kvs.sorted_sets[@key]['NyarukoSan']
|
127
|
+
}.by(1)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when call key_name' do
|
133
|
+
it 'return correct key.' do
|
134
|
+
expect(@defined_base_methods.key_name(Time.now)).to eq('2013-11-05-00')
|
135
|
+
expect(@defined_base_methods.key_name(Time.now, RailsRank::Types::Date::DAILY)).to eq('2013-11-05')
|
136
|
+
expect(@defined_base_methods.key_name(Time.now, RailsRank::Types::Date::MONTHLY)).to eq('2013-11')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when call score' do
|
141
|
+
before(:each) do
|
142
|
+
@defined_base_methods.increment('NyarukoSan',2865)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'return score of value' do
|
146
|
+
expect(@defined_base_methods.score('NyarukoSan')).to eq(2865)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'nothing value, return 0' do
|
150
|
+
expect(@defined_base_methods.score('Nothing value')).to eq(0)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when call table' do
|
155
|
+
before(:each) do
|
156
|
+
@defined_base_methods.increment('NyarukoSan',2865)
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'with RailsRank::Types::Date::HOURLY' do
|
160
|
+
before(:each) do
|
161
|
+
Time.stub({ now: Time.local(2013,11,5,1) })
|
162
|
+
@defined_base_methods.increment('NyarukoSan',2865)
|
163
|
+
@defined_base_methods.increment('KotouraSan',3000)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'add previous time slot to DAILY' do
|
167
|
+
expect{
|
168
|
+
@defined_base_methods.table(RailsRank::Types::Date::HOURLY)
|
169
|
+
}.to change{
|
170
|
+
@defined_base_methods.all(RailsRank::Types::Date::DAILY).length
|
171
|
+
}.by(1)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'delete previous time slot' do
|
175
|
+
expect{
|
176
|
+
@defined_base_methods.table(RailsRank::Types::Date::HOURLY)
|
177
|
+
}.to change{
|
178
|
+
@defined_base_methods.all(RailsRank::Types::Date::HOURLY).length
|
179
|
+
}.by(-1)
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'callback with date' do
|
183
|
+
args = [RailsRank::Types::Date::HOURLY, Time.local(2013,11,5), 'NyarukoSan', 2865, 0]
|
184
|
+
@defined_base_methods.should_receive(:after_table).with(*args)
|
185
|
+
@defined_base_methods.table(RailsRank::Types::Date::HOURLY)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'return tabled data number.' do
|
189
|
+
expect(@defined_base_methods.table(RailsRank::Types::Date::HOURLY)). to eq(1)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'correct data after add up' do
|
193
|
+
Time.stub({ now: Time.local(2013,11,5,2) })
|
194
|
+
expect(@defined_base_methods.table(RailsRank::Types::Date::HOURLY)). to eq(2)
|
195
|
+
|
196
|
+
key = @defined_base_methods.key_name(Time.now, RailsRank::Types::Date::DAILY)
|
197
|
+
data = Hash.new
|
198
|
+
@defined_base_methods.each(key, true) {|value, score, position| data[value] = score }
|
199
|
+
|
200
|
+
expect(data['NyarukoSan']).to eq(2865*2)
|
201
|
+
expect(data['KotouraSan']).to eq(3000)
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'with RailsRank::Types::Date::DAILY' do
|
207
|
+
before(:each) do
|
208
|
+
Time.stub({ now: Time.local(2013,11,6) })
|
209
|
+
@defined_base_methods.table(RailsRank::Types::Date::HOURLY)
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'add previous time slot to MONTHLY' do
|
213
|
+
expect{
|
214
|
+
@defined_base_methods.table(RailsRank::Types::Date::DAILY)
|
215
|
+
}.to change{
|
216
|
+
@defined_base_methods.all(RailsRank::Types::Date::MONTHLY).length
|
217
|
+
}.by(1)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'delete previous time slot' do
|
221
|
+
expect{
|
222
|
+
@defined_base_methods.table(RailsRank::Types::Date::DAILY)
|
223
|
+
}.to change{
|
224
|
+
@defined_base_methods.all(RailsRank::Types::Date::DAILY).length
|
225
|
+
}.by(-1)
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'callback with date' do
|
229
|
+
args = [RailsRank::Types::Date::DAILY, Time.local(2013,11,5), 'NyarukoSan', 2865, 0]
|
230
|
+
@defined_base_methods.should_receive(:after_table).with(*args)
|
231
|
+
@defined_base_methods.table(RailsRank::Types::Date::DAILY)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'with RailsRank::Types::Date::MONTHLY' do
|
236
|
+
before(:each) do
|
237
|
+
Time.stub({ now: Time.local(2013,12) })
|
238
|
+
@defined_base_methods.table(RailsRank::Types::Date::HOURLY)
|
239
|
+
@defined_base_methods.table(RailsRank::Types::Date::DAILY)
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'add previous time slot to YAERLY' do
|
243
|
+
expect{
|
244
|
+
@defined_base_methods.table(RailsRank::Types::Date::MONTHLY)
|
245
|
+
}.to change{
|
246
|
+
@defined_base_methods.all(RailsRank::Types::Date::YEARLY).length
|
247
|
+
}.by(1)
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'delete previous time slot' do
|
251
|
+
expect{
|
252
|
+
@defined_base_methods.table(RailsRank::Types::Date::MONTHLY)
|
253
|
+
}.to change{
|
254
|
+
@defined_base_methods.all(RailsRank::Types::Date::MONTHLY).length
|
255
|
+
}.by(-1)
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'callback with date' do
|
259
|
+
args = [RailsRank::Types::Date::MONTHLY, Time.local(2013,11), 'NyarukoSan', 2865, 0]
|
260
|
+
@defined_base_methods.should_receive(:after_table).with(*args)
|
261
|
+
@defined_base_methods.table(RailsRank::Types::Date::MONTHLY)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'with RailsRank::Types::Date::YEARLY' do
|
266
|
+
before(:each) do
|
267
|
+
Time.stub({ now: Time.local(2014,1) })
|
268
|
+
@defined_base_methods.table(RailsRank::Types::Date::HOURLY)
|
269
|
+
@defined_base_methods.table(RailsRank::Types::Date::DAILY)
|
270
|
+
@defined_base_methods.table(RailsRank::Types::Date::MONTHLY)
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'delete previous time slot' do
|
274
|
+
expect{
|
275
|
+
@defined_base_methods.table(RailsRank::Types::Date::YEARLY)
|
276
|
+
}.to change{
|
277
|
+
@defined_base_methods.all(RailsRank::Types::Date::YEARLY).length
|
278
|
+
}.by(-1)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'callback with date' do
|
282
|
+
args = [RailsRank::Types::Date::YEARLY, Time.local(2013), 'NyarukoSan', 2865, 0]
|
283
|
+
@defined_base_methods.should_receive(:after_table).with(*args)
|
284
|
+
@defined_base_methods.table(RailsRank::Types::Date::YEARLY)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'tasks' do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
# load all rake tasks.
|
8
|
+
@rake = Rake::Application.new
|
9
|
+
Rake.application = @rake
|
10
|
+
Dir.glob('lib/tasks/*.rake') do |file|
|
11
|
+
Rake.application.rake_require(File::basename(file, '.rake'), ['lib/tasks'])
|
12
|
+
end
|
13
|
+
Rake::Task.define_task(:environment)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'exec total' do
|
17
|
+
@rake["rails_rank:table"].execute
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rails_rank
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- alfa-jpn
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-17 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.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: 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: yard
|
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: rails_kvs_driver-redis_driver
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.2.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.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rails_kvs_driver
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.2.1
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.2.1
|
111
|
+
description: develop now
|
112
|
+
email:
|
113
|
+
- a.nkmr.ja@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- lib/generators/ranking_generator.rb
|
124
|
+
- lib/generators/templates/base.rb.template
|
125
|
+
- lib/rails_rank.rb
|
126
|
+
- lib/rails_rank/base.rb
|
127
|
+
- lib/rails_rank/defined_base_methods.rb
|
128
|
+
- lib/rails_rank/types/date.rb
|
129
|
+
- lib/rails_rank/version.rb
|
130
|
+
- lib/railtie.rb
|
131
|
+
- lib/tasks/table.rake
|
132
|
+
- rails_rank.gemspec
|
133
|
+
- spec/rails_rank/defined_base_methods_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/tasks/tasks_spec.rb
|
136
|
+
homepage: ''
|
137
|
+
licenses:
|
138
|
+
- MIT
|
139
|
+
metadata: {}
|
140
|
+
post_install_message:
|
141
|
+
rdoc_options: []
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - '>='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 2.0.3
|
157
|
+
signing_key:
|
158
|
+
specification_version: 4
|
159
|
+
summary: develop now
|
160
|
+
test_files:
|
161
|
+
- spec/rails_rank/defined_base_methods_spec.rb
|
162
|
+
- spec/spec_helper.rb
|
163
|
+
- spec/tasks/tasks_spec.rb
|
164
|
+
has_rdoc:
|