norton 0.0.24 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +16 -0
- data/.travis.yml +2 -1
- data/Gemfile +6 -1
- data/README.md +9 -5
- data/lib/norton/counter.rb +15 -8
- data/lib/norton/hash_map.rb +3 -1
- data/lib/norton/helper.rb +70 -9
- data/lib/norton/timed_value.rb +3 -3
- data/lib/norton/timestamp.rb +22 -5
- data/lib/norton/version.rb +1 -1
- data/lib/norton.rb +84 -1
- data/spec/norton/hash_map_spec.rb +2 -2
- data/spec/norton/helper_spec.rb +94 -14
- data/spec/norton_spec.rb +99 -0
- data/spec/spec_helper.rb +3 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcc25c436cc01399c68e17739b2181d7298e5a05
|
4
|
+
data.tar.gz: 9add33b7a73eb52e1cceaceecee1728db377ae15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8dd9328148d9ec90be45726443cdadabbf99de363c11a9680897f53886f6cf5aabe8b6de429c9c92e28986b8ee4d03f95c1a63e0543116f3c7146e3725ac8ee
|
7
|
+
data.tar.gz: 3e7b992f5406d3c3876f1e065f108a5d3c0bc690bb90429d85f6709980c9d14a02abd1f88252cce62ab9d39f01ef482b94a950a8dc01fb2d8513ddbfb9df9c05
|
data/.codeclimate.yml
ADDED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
|
3
|
+
group :test do
|
4
|
+
gem "simplecov", "~> 0.14", require: false
|
5
|
+
gem "codeclimate-test-reporter", "~> 1.0", require: false
|
6
|
+
end
|
7
|
+
|
8
|
+
# Specify your gem"s dependencies in norton.gemspec
|
4
9
|
gemspec
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Norton
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.org/jianshucom/norton.svg?branch=master)](https://travis-ci.org/jianshucom/norton)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/jianshucom/norton/badges/gpa.svg)](https://codeclimate.com/github/jianshucom/norton)
|
5
|
+
[![Test Coverage](https://codeclimate.com/github/jianshucom/norton/badges/coverage.svg)](https://codeclimate.com/github/jianshucom/norton/coverage)
|
6
|
+
|
3
7
|
## Installation
|
4
8
|
|
5
9
|
Add this line to your application's Gemfile:
|
@@ -16,7 +20,7 @@ Or install it yourself as:
|
|
16
20
|
|
17
21
|
## Setup
|
18
22
|
|
19
|
-
You need to setup Norton with a redis connection,
|
23
|
+
You need to setup Norton with a redis connection,
|
20
24
|
|
21
25
|
`Norton.setup url: <some redis connection url> `
|
22
26
|
|
@@ -33,7 +37,7 @@ Simply include `Norton::Counter` in your model, and define a counter.
|
|
33
37
|
```
|
34
38
|
class User < ActiveRecord::Base
|
35
39
|
include Norton::Counter
|
36
|
-
|
40
|
+
|
37
41
|
counter :total_likes_count
|
38
42
|
end
|
39
43
|
```
|
@@ -48,7 +52,7 @@ You could also give a reset block:
|
|
48
52
|
```
|
49
53
|
class User < ActiveRecord::Base
|
50
54
|
include Norton::Counter
|
51
|
-
|
55
|
+
|
52
56
|
counter :total_likes_count do
|
53
57
|
self.likes.count
|
54
58
|
end
|
@@ -65,7 +69,7 @@ Simply include `Norton::Timestamp` in your model, and define a timestamp.
|
|
65
69
|
```
|
66
70
|
class Note < ActiveRecord::Base
|
67
71
|
include Norton::Timestamp
|
68
|
-
|
72
|
+
|
69
73
|
timestamp :content_updated_at
|
70
74
|
end
|
71
75
|
```
|
@@ -79,7 +83,7 @@ You could specify callbacks along with condition Procs of when to touch the time
|
|
79
83
|
```
|
80
84
|
class Note < ActiveRecord::Base
|
81
85
|
include Norton::Timestamp
|
82
|
-
|
86
|
+
|
83
87
|
timestamp :content_updated_at, before_save: Proc.new { title_changed? || content_changed? }
|
84
88
|
end
|
85
89
|
```
|
data/lib/norton/counter.rb
CHANGED
@@ -15,39 +15,46 @@ module Norton
|
|
15
15
|
#
|
16
16
|
# @return [type] [description]
|
17
17
|
def counter(name, options={}, &blk)
|
18
|
+
self.register_norton_value(name, :counter)
|
19
|
+
|
18
20
|
define_method(name) do
|
19
21
|
Norton.redis.with do |conn|
|
20
|
-
conn.get(self.
|
22
|
+
conn.get(self.norton_value_key(name)).try(:to_i) || send("#{name}_default_value".to_sym)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
26
|
+
define_method("#{name}_default_value") do
|
27
|
+
0
|
28
|
+
end
|
29
|
+
send(:private, "#{name}_default_value".to_sym)
|
30
|
+
|
24
31
|
define_method("incr_#{name}") do
|
25
32
|
Norton.redis.with do |conn|
|
26
|
-
conn.incr(self.
|
33
|
+
conn.incr(self.norton_value_key(name))
|
27
34
|
end
|
28
35
|
end
|
29
36
|
|
30
37
|
define_method("decr_#{name}") do
|
31
38
|
Norton.redis.with do |conn|
|
32
|
-
conn.decr(self.
|
39
|
+
conn.decr(self.norton_value_key(name))
|
33
40
|
end
|
34
41
|
end
|
35
42
|
|
36
43
|
define_method("incr_#{name}_by") do |increment|
|
37
44
|
Norton.redis.with do |conn|
|
38
|
-
conn.incrby(self.
|
45
|
+
conn.incrby(self.norton_value_key(name), increment)
|
39
46
|
end
|
40
47
|
end
|
41
48
|
|
42
49
|
define_method("decr_#{name}_by") do |decrement|
|
43
50
|
Norton.redis.with do |conn|
|
44
|
-
conn.decrby(self.
|
51
|
+
conn.decrby(self.norton_value_key(name), decrement)
|
45
52
|
end
|
46
53
|
end
|
47
54
|
|
48
55
|
define_method("#{name}=") do |v|
|
49
56
|
Norton.redis.with do |conn|
|
50
|
-
conn.set(self.
|
57
|
+
conn.set(self.norton_value_key(name), v)
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
@@ -55,13 +62,13 @@ module Norton
|
|
55
62
|
count = instance_eval(&blk)
|
56
63
|
|
57
64
|
Norton.redis.with do |conn|
|
58
|
-
conn.set(self.
|
65
|
+
conn.set(self.norton_value_key(name), count)
|
59
66
|
end
|
60
67
|
end
|
61
68
|
|
62
69
|
define_method("remove_#{name}") do
|
63
70
|
Norton.redis.with do |conn|
|
64
|
-
conn.del(self.
|
71
|
+
conn.del(self.norton_value_key(name))
|
65
72
|
end
|
66
73
|
end
|
67
74
|
send(:after_destroy, "remove_#{name}".to_sym) if respond_to? :after_destroy
|
data/lib/norton/hash_map.rb
CHANGED
@@ -8,10 +8,12 @@ module Norton
|
|
8
8
|
|
9
9
|
module ClassMethods
|
10
10
|
def hash_map(name)
|
11
|
+
self.register_norton_value(name, :hash_map)
|
12
|
+
|
11
13
|
define_method(name) do
|
12
14
|
instance_variable_get("@#{name}") ||
|
13
15
|
instance_variable_set("@#{name}",
|
14
|
-
Norton::Objects::Hash.new(self.
|
16
|
+
Norton::Objects::Hash.new(self.norton_value_key(name))
|
15
17
|
)
|
16
18
|
end
|
17
19
|
|
data/lib/norton/helper.rb
CHANGED
@@ -2,6 +2,51 @@ module Norton
|
|
2
2
|
module Helper
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
+
included do
|
6
|
+
instance_variable_set(:@norton_values, {})
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
attr_reader :norton_values
|
11
|
+
|
12
|
+
|
13
|
+
#
|
14
|
+
# 当前类是否定义了某个 Norton Value
|
15
|
+
#
|
16
|
+
# @param [String/Symbol] name
|
17
|
+
#
|
18
|
+
# @return [Boolean]
|
19
|
+
#
|
20
|
+
def norton_value_defined?(name)
|
21
|
+
self.norton_values.has_key?(name.to_sym)
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# 返回当前类定义的某个 Norton Value 的类型
|
26
|
+
#
|
27
|
+
# @param [String] name
|
28
|
+
#
|
29
|
+
# @return [Symbol]
|
30
|
+
#
|
31
|
+
def norton_value_type(name)
|
32
|
+
self.norton_values[name.to_sym].try(:to_sym)
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# 当定义一个 Norton Value 的时候,将这个 Norton Value 记录在 Class Variable `@norton_values` 中
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
#
|
41
|
+
def register_norton_value(name, norton_type)
|
42
|
+
if !Norton::SUPPORTED_TYPES.include?(norton_type.to_sym)
|
43
|
+
raise Norton::InvalidType.new("Norton Type: #{norton_type} invalid!")
|
44
|
+
end
|
45
|
+
|
46
|
+
@norton_values[name.to_sym] = norton_type.to_sym
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
5
50
|
#
|
6
51
|
# Prefix of Redis Key of Norton value, consists with Class name string in plural form
|
7
52
|
# and Instance id.
|
@@ -34,28 +79,44 @@ module Norton
|
|
34
79
|
#
|
35
80
|
# @return [String]
|
36
81
|
#
|
37
|
-
def
|
82
|
+
def norton_value_key(name)
|
38
83
|
"#{self.norton_prefix}:#{name}"
|
39
84
|
end
|
40
85
|
|
41
86
|
#
|
42
|
-
# 批量取出当前对象的多个 Norton value
|
87
|
+
# 批量取出当前对象的多个 Norton value, 仅仅支持 counter / timestamp
|
43
88
|
#
|
44
89
|
# @param [Array] *value_keys 直接传入需要的值的 key,例如: :key1, :key2, :key3
|
45
90
|
#
|
46
91
|
# @return [Hash]
|
47
92
|
#
|
48
|
-
def
|
93
|
+
def norton_mget(*names)
|
49
94
|
ret = {}
|
50
95
|
|
51
|
-
redis_keys = names.map { |n| self.
|
96
|
+
redis_keys = names.map { |n| self.norton_value_key(n) }
|
52
97
|
|
53
|
-
|
54
|
-
|
55
|
-
|
98
|
+
Norton.redis.with do |conn|
|
99
|
+
# mget 一次取出所有的值
|
100
|
+
redis_values = conn.mget(redis_keys)
|
101
|
+
|
102
|
+
# 组装结果 Hash
|
103
|
+
names.each_with_index do |n, index|
|
104
|
+
val = redis_values[index].try(:to_i)
|
105
|
+
|
106
|
+
# 如果返回值为 nil 并且定义了这个 norton value
|
107
|
+
# 那么获取返回值
|
108
|
+
if val.nil? && self.class.norton_value_defined?(n)
|
109
|
+
val = send("#{n}_default_value".to_sym)
|
110
|
+
|
111
|
+
# 如果返回值不为空,将默认值存入 SSDB
|
112
|
+
# 并且当前 Value 是 `:timestamp`
|
113
|
+
if !val.nil? && self.class.norton_value_type(n) == :timestamp
|
114
|
+
conn.set(self.norton_value_key(n), val)
|
115
|
+
end
|
116
|
+
end
|
56
117
|
|
57
|
-
|
58
|
-
|
118
|
+
ret[n] = val
|
119
|
+
end
|
59
120
|
end
|
60
121
|
|
61
122
|
ret
|
data/lib/norton/timed_value.rb
CHANGED
@@ -16,11 +16,11 @@ module Norton
|
|
16
16
|
# Define getter
|
17
17
|
define_method(name) do
|
18
18
|
Norton.redis.with do |conn|
|
19
|
-
v = conn.get(self.
|
19
|
+
v = conn.get(self.norton_value_key(name))
|
20
20
|
|
21
21
|
if v.nil?
|
22
22
|
v = instance_eval(&blk)
|
23
|
-
conn.setex(self.
|
23
|
+
conn.setex(self.norton_value_key(name), options[:ttl], v)
|
24
24
|
end
|
25
25
|
|
26
26
|
v
|
@@ -30,7 +30,7 @@ module Norton
|
|
30
30
|
define_method("reset_#{name}") do
|
31
31
|
Norton.redis.with do |conn|
|
32
32
|
v = instance_eval(&blk)
|
33
|
-
conn.setex(self.
|
33
|
+
conn.setex(self.norton_value_key(name), options[:ttl], v)
|
34
34
|
v
|
35
35
|
end
|
36
36
|
end
|
data/lib/norton/timestamp.rb
CHANGED
@@ -14,27 +14,44 @@ module Norton
|
|
14
14
|
#
|
15
15
|
# @return [type] [description]
|
16
16
|
def timestamp(name, options={})
|
17
|
+
self.register_norton_value(name, :timestamp)
|
18
|
+
|
17
19
|
define_method(name) do
|
18
20
|
ts = nil
|
19
21
|
|
20
22
|
Norton.redis.with do |conn|
|
21
|
-
ts = conn.get(self.
|
23
|
+
ts = conn.get(self.norton_value_key(name)).try(:to_i)
|
24
|
+
|
25
|
+
if ts.nil?
|
26
|
+
ts = send("#{name}_default_value".to_sym)
|
27
|
+
conn.set(self.norton_value_key(name), ts) if !ts.nil?
|
28
|
+
end
|
22
29
|
|
23
|
-
|
30
|
+
ts
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
define_method("#{name}_default_value") do
|
35
|
+
if !options[:allow_nil]
|
36
|
+
if options[:digits].present? && options[:digits] == 13
|
37
|
+
ts = (Time.now.to_f * 1000).to_i
|
38
|
+
else
|
24
39
|
ts = Time.now.to_i
|
25
|
-
conn.set(self.norton_redis_key(name), ts)
|
26
40
|
end
|
27
41
|
|
28
42
|
ts
|
43
|
+
else
|
44
|
+
nil
|
29
45
|
end
|
30
46
|
end
|
47
|
+
send(:private, "#{name}_default_value".to_sym)
|
31
48
|
|
32
49
|
define_method("touch_#{name}") do
|
33
50
|
Norton.redis.with do |conn|
|
34
51
|
if options[:digits].present? && options[:digits] == 13
|
35
|
-
conn.set(self.
|
52
|
+
conn.set(self.norton_value_key(name), (Time.now.to_f * 1000).to_i)
|
36
53
|
else
|
37
|
-
conn.set(self.
|
54
|
+
conn.set(self.norton_value_key(name), Time.now.to_i)
|
38
55
|
end
|
39
56
|
end
|
40
57
|
end
|
data/lib/norton/version.rb
CHANGED
data/lib/norton.rb
CHANGED
@@ -11,7 +11,10 @@ require "norton/objects/hash"
|
|
11
11
|
require "norton/hash_map"
|
12
12
|
|
13
13
|
module Norton
|
14
|
+
SUPPORTED_TYPES = %i(counter timestamp hash_map)
|
15
|
+
|
14
16
|
class NilObjectId < StandardError; end
|
17
|
+
class InvalidType < StandardError; end
|
15
18
|
|
16
19
|
class << self
|
17
20
|
attr_accessor :redis
|
@@ -28,8 +31,88 @@ module Norton
|
|
28
31
|
timeout = (options[:timeout] || 2).to_i
|
29
32
|
|
30
33
|
Norton.redis = ConnectionPool.new(:size => pool_size, :timeout => timeout) do
|
31
|
-
Redis.new(
|
34
|
+
Redis.new(
|
35
|
+
options.slice(:url, :host, :port, :db, :path, :password, :namespace, :ssl_params, :driver)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# 为多个 Norton 对象一次性取出多个值
|
42
|
+
#
|
43
|
+
# 从一组相同的对象中,一次性取出多个 Norton 值。
|
44
|
+
#
|
45
|
+
# 例如:
|
46
|
+
#
|
47
|
+
# vals = Norton.mget([user1, user2, user3], [followers_count, profile_updated_at])
|
48
|
+
#
|
49
|
+
# 将会返回:
|
50
|
+
#
|
51
|
+
# ```
|
52
|
+
# {
|
53
|
+
# "users:1:followers_count": 2,
|
54
|
+
# "users:2:followers_count": 3,
|
55
|
+
# "users:3:followers_count": 4,
|
56
|
+
# "users:1:profile_updated_at": 1498315792,
|
57
|
+
# "users:2:profile_updated_at": 1499315792,
|
58
|
+
# "users:3:profile_updated_at": 1409315792,
|
59
|
+
# }
|
60
|
+
# ```
|
61
|
+
#
|
62
|
+
# * 返回的 Field 之间的顺序无法保证
|
63
|
+
#
|
64
|
+
# @param [Array] objects
|
65
|
+
# @param [Array] names
|
66
|
+
#
|
67
|
+
# @return [Hash]
|
68
|
+
#
|
69
|
+
def mget(objects, names)
|
70
|
+
ret = {}
|
71
|
+
|
72
|
+
mapping = {}
|
73
|
+
redis_keys = []
|
74
|
+
|
75
|
+
objects.each_with_index do |obj, index|
|
76
|
+
next if obj.nil?
|
77
|
+
|
78
|
+
names.each do |n|
|
79
|
+
redis_key = obj.norton_value_key(n)
|
80
|
+
|
81
|
+
redis_keys << redis_key
|
82
|
+
mapping[redis_key] = [n, index]
|
83
|
+
end
|
32
84
|
end
|
85
|
+
|
86
|
+
Norton.redis.with do |conn|
|
87
|
+
values = conn.mget(redis_keys)
|
88
|
+
|
89
|
+
redis_keys.each_with_index do |k, i|
|
90
|
+
val = values[i].try(:to_i)
|
91
|
+
|
92
|
+
# 如果返回值为 nil 并且定义了这个 norton value
|
93
|
+
# 那么获取返回值
|
94
|
+
if val.nil?
|
95
|
+
# 从 mapping 中取出 value name 和对应的 object
|
96
|
+
value_name, obj_index = mapping[k]
|
97
|
+
obj = objects[obj_index]
|
98
|
+
|
99
|
+
# 如果 object 定义了这个 value
|
100
|
+
if obj.class.norton_value_defined?(value_name)
|
101
|
+
# 获取默认值
|
102
|
+
val = obj.send("#{value_name}_default_value".to_sym)
|
103
|
+
|
104
|
+
# 如果返回值不为空,并且当前 value 的类型是 `timestamp` 将默认值存入 Redis
|
105
|
+
if !val.nil? && obj.class.norton_value_type(value_name) == :timestamp
|
106
|
+
conn.set(k, val)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
ret[k] = val
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
ret
|
33
116
|
end
|
34
117
|
end
|
35
118
|
end
|
@@ -11,10 +11,10 @@ class HashMapObject
|
|
11
11
|
end
|
12
12
|
|
13
13
|
describe Norton::HashMap do
|
14
|
-
describe "#
|
14
|
+
describe "#norton_value_key" do
|
15
15
|
it "generates the correct field key" do
|
16
16
|
object = HashMapObject.new
|
17
|
-
expect(object.
|
17
|
+
expect(object.norton_value_key(:profile)).to eq("hash_map_objects:99:profile")
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
data/spec/norton/helper_spec.rb
CHANGED
@@ -3,12 +3,16 @@ require 'spec_helper'
|
|
3
3
|
class Dummy
|
4
4
|
include Norton::Counter
|
5
5
|
include Norton::Timestamp
|
6
|
+
include Norton::HashMap
|
6
7
|
|
7
8
|
counter :counter1
|
8
9
|
counter :counter2
|
9
10
|
counter :counter3
|
10
11
|
|
11
12
|
timestamp :time1
|
13
|
+
timestamp :time2
|
14
|
+
|
15
|
+
hash_map :map1
|
12
16
|
|
13
17
|
def id
|
14
18
|
@id ||= Random.rand(10000)
|
@@ -26,12 +30,47 @@ module HolyLight
|
|
26
30
|
end
|
27
31
|
|
28
32
|
describe Norton::Helper do
|
29
|
-
describe "
|
33
|
+
describe "@norton_values" do
|
34
|
+
it "should contain defined values and type" do
|
35
|
+
expect(Dummy.norton_values[:counter1]).to eq(:counter)
|
36
|
+
expect(Dummy.norton_values[:counter2]).to eq(:counter)
|
37
|
+
expect(Dummy.norton_values[:counter3]).to eq(:counter)
|
38
|
+
|
39
|
+
expect(Dummy.norton_values[:time1]).to eq(:timestamp)
|
40
|
+
expect(Dummy.norton_values[:time2]).to eq(:timestamp)
|
41
|
+
|
42
|
+
expect(Dummy.norton_values[:map1]).to eq(:hash_map)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not contain undefined values" do
|
46
|
+
expect(Dummy.norton_values[:foobar]).to be_nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe ".register_norton_value" do
|
51
|
+
it "should raise error if type is not supported" do
|
52
|
+
expect {
|
53
|
+
Dummy.register_norton_value("foo", "bar")
|
54
|
+
}.to raise_error(Norton::InvalidType)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe ".norton_value_defined?" do
|
59
|
+
it "should return true for a defined value" do
|
60
|
+
expect(Dummy.norton_value_defined?(:counter1)).to eq(true)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return false for a defined value" do
|
64
|
+
expect(Dummy.norton_value_defined?(:time3)).to eq(false)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#norton_value_key" do
|
30
69
|
it do
|
31
70
|
n = SecureRandom.hex(3)
|
32
71
|
|
33
72
|
dummy = Dummy.new
|
34
|
-
expect(dummy.
|
73
|
+
expect(dummy.norton_value_key(n)).to eq("dummies:#{dummy.id}:#{n}")
|
35
74
|
end
|
36
75
|
|
37
76
|
it "should raise `Norton::NilObjectId` if id returns nil" do
|
@@ -54,11 +93,11 @@ describe Norton::Helper do
|
|
54
93
|
end
|
55
94
|
end
|
56
95
|
|
57
|
-
describe "#
|
58
|
-
it "should respond to `:
|
96
|
+
describe "#norton_mget" do
|
97
|
+
it "should respond to `:norton_mget`" do
|
59
98
|
dummy = Dummy.new
|
60
99
|
|
61
|
-
expect(dummy).to respond_to(:
|
100
|
+
expect(dummy).to respond_to(:norton_mget)
|
62
101
|
end
|
63
102
|
|
64
103
|
it "should return the specific values" do
|
@@ -70,7 +109,7 @@ describe Norton::Helper do
|
|
70
109
|
|
71
110
|
dummy.touch_time1
|
72
111
|
|
73
|
-
values = dummy.
|
112
|
+
values = dummy.norton_mget(:counter1, :time1)
|
74
113
|
|
75
114
|
expect(values).to include(:counter1, :time1)
|
76
115
|
expect(values.size).to eq(2)
|
@@ -78,22 +117,63 @@ describe Norton::Helper do
|
|
78
117
|
expect(values[:time1]).to eq(dummy.time1)
|
79
118
|
end
|
80
119
|
|
81
|
-
it "should
|
120
|
+
it "should default value if the value of does not exist" do
|
82
121
|
dummy = Dummy.new
|
83
122
|
|
84
123
|
dummy.counter1 = 10
|
85
124
|
dummy.counter2 = 15
|
86
|
-
dummy.counter3 = 100
|
87
125
|
|
88
126
|
dummy.touch_time1
|
89
127
|
|
90
|
-
|
128
|
+
t = Time.now
|
91
129
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
130
|
+
Timecop.freeze(t) do
|
131
|
+
values = dummy.norton_mget(:counter1, :counter2, :time2)
|
132
|
+
|
133
|
+
expect(values).to include(:counter1, :counter2, :time2)
|
134
|
+
expect(values.size).to eq(3)
|
135
|
+
expect(values[:counter1]).to eq(dummy.counter1)
|
136
|
+
expect(values[:counter2]).to eq(dummy.counter2)
|
137
|
+
expect(values[:time2]).to eq(t.to_i)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should save the default value for timestamp" do
|
142
|
+
dummy = Dummy.new
|
143
|
+
|
144
|
+
t = Time.now
|
145
|
+
|
146
|
+
Timecop.freeze(t) do
|
147
|
+
values = dummy.norton_mget(:time2)
|
148
|
+
expect(values[:time2]).to eq(t.to_i)
|
149
|
+
|
150
|
+
# Test value directly from Redis
|
151
|
+
val = Norton.redis.with { |conn| conn.get(dummy.norton_value_key(:time2)) }.to_i
|
152
|
+
expect(val).to eq(t.to_i)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should not save the default value for counter" do
|
157
|
+
dummy = Dummy.new
|
158
|
+
|
159
|
+
t = Time.now
|
160
|
+
|
161
|
+
Timecop.freeze(t) do
|
162
|
+
values = dummy.norton_mget(:counter1)
|
163
|
+
expect(values[:counter1]).to eq(0)
|
164
|
+
|
165
|
+
# Test value directly from Redis
|
166
|
+
expect(Norton.redis.with { |conn| conn.get(dummy.norton_value_key(:counter1)) }).to be_nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should return nil if the norton value is not defined" do
|
171
|
+
dummy = Dummy.new
|
172
|
+
|
173
|
+
values = dummy.norton_mget(:time3)
|
174
|
+
|
175
|
+
expect(values).to include(:time3)
|
176
|
+
expect(values[:time3]).to be_nil
|
97
177
|
end
|
98
178
|
end
|
99
179
|
end
|
data/spec/norton_spec.rb
CHANGED
@@ -7,4 +7,103 @@ describe Norton do
|
|
7
7
|
expect(Norton.redis).not_to be_nil
|
8
8
|
end
|
9
9
|
end
|
10
|
+
|
11
|
+
describe "mget" do
|
12
|
+
class Foobar
|
13
|
+
include Norton::Counter
|
14
|
+
include Norton::Timestamp
|
15
|
+
|
16
|
+
counter :test_counter
|
17
|
+
timestamp :test_timestamp
|
18
|
+
|
19
|
+
def initialize(id)
|
20
|
+
@id = id
|
21
|
+
end
|
22
|
+
|
23
|
+
def id
|
24
|
+
@id
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should get the values correctly" do
|
29
|
+
foobar1 = Foobar.new(SecureRandom.hex(2))
|
30
|
+
foobar2 = Foobar.new(SecureRandom.hex(2))
|
31
|
+
|
32
|
+
Random.rand(100).times { foobar1.incr_test_counter }
|
33
|
+
foobar1.touch_test_timestamp
|
34
|
+
|
35
|
+
sleep(2)
|
36
|
+
|
37
|
+
Random.rand(100).times { foobar2.incr_test_counter }
|
38
|
+
foobar2.touch_test_timestamp
|
39
|
+
|
40
|
+
vals = Norton.mget([foobar1, foobar2], [:test_counter, :test_timestamp])
|
41
|
+
|
42
|
+
expect(vals).to include("foobars:#{foobar1.id}:test_counter" => foobar1.test_counter)
|
43
|
+
expect(vals).to include("foobars:#{foobar1.id}:test_timestamp" => foobar1.test_timestamp)
|
44
|
+
expect(vals).to include("foobars:#{foobar2.id}:test_counter" => foobar2.test_counter)
|
45
|
+
expect(vals).to include("foobars:#{foobar2.id}:test_timestamp" => foobar2.test_timestamp)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should get default value correctly if no value in norton redis database" do
|
49
|
+
foobar1 = Foobar.new(SecureRandom.hex(2))
|
50
|
+
foobar2 = Foobar.new(SecureRandom.hex(2))
|
51
|
+
|
52
|
+
t = Time.now
|
53
|
+
|
54
|
+
Timecop.freeze(t) do
|
55
|
+
foobar1.incr_test_counter
|
56
|
+
foobar2.touch_test_timestamp
|
57
|
+
end
|
58
|
+
|
59
|
+
sleep(1)
|
60
|
+
|
61
|
+
t2 = Time.now
|
62
|
+
|
63
|
+
vals = Timecop.freeze(t2) do
|
64
|
+
Norton.mget([foobar1, foobar2], [:test_counter, :test_timestamp])
|
65
|
+
end
|
66
|
+
|
67
|
+
expect(vals).to include("foobars:#{foobar1.id}:test_counter" => 1)
|
68
|
+
expect(vals).to include("foobars:#{foobar1.id}:test_timestamp" => t2.to_i)
|
69
|
+
expect(vals).to include("foobars:#{foobar2.id}:test_counter" => 0)
|
70
|
+
expect(vals).to include("foobars:#{foobar2.id}:test_timestamp" => t.to_i)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return nil for undefined norton values" do
|
74
|
+
foobar1 = Foobar.new(SecureRandom.hex(2))
|
75
|
+
foobar2 = Foobar.new(SecureRandom.hex(2))
|
76
|
+
|
77
|
+
t = Time.now
|
78
|
+
|
79
|
+
Timecop.freeze(t) do
|
80
|
+
foobar1.incr_test_counter
|
81
|
+
foobar2.touch_test_timestamp
|
82
|
+
end
|
83
|
+
|
84
|
+
vals = Norton.mget([foobar1, foobar2], [:test_counter, :test_timestamp, :test_foobar])
|
85
|
+
|
86
|
+
expect(vals).to include("foobars:#{foobar1.id}:test_counter" => 1)
|
87
|
+
expect(vals).to include("foobars:#{foobar2.id}:test_timestamp" => t.to_i)
|
88
|
+
expect(vals).to include("foobars:#{foobar1.id}:test_foobar" => nil)
|
89
|
+
expect(vals).to include("foobars:#{foobar2.id}:test_foobar" => nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns the default value when the field value is nil" do
|
93
|
+
object = Foobar.new(99)
|
94
|
+
allow(object).to receive(:test_timestamp_default_value) { 22 }
|
95
|
+
|
96
|
+
ret = Norton.mget([object], %i[test_timestamp])
|
97
|
+
expect(ret["foobars:99:test_timestamp"]).to eq(22)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "sets the default value in redis if the `Timestamp` field value is nil" do
|
101
|
+
object = Foobar.new(99)
|
102
|
+
allow(object).to receive(:test_timestamp_default_value) { 22 }
|
103
|
+
|
104
|
+
Norton.mget([object], %i[test_timestamp])
|
105
|
+
|
106
|
+
expect(Norton.redis.with { |conn| conn.get("foobars:99:test_timestamp") }.to_i).to eq(22)
|
107
|
+
end
|
108
|
+
end
|
10
109
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: norton
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Larry Zhao
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -185,6 +185,7 @@ executables: []
|
|
185
185
|
extensions: []
|
186
186
|
extra_rdoc_files: []
|
187
187
|
files:
|
188
|
+
- ".codeclimate.yml"
|
188
189
|
- ".gitignore"
|
189
190
|
- ".rspec"
|
190
191
|
- ".travis.yml"
|