norton 0.0.24 → 0.0.26
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 +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
|
+
[](https://travis-ci.org/jianshucom/norton)
|
4
|
+
[](https://codeclimate.com/github/jianshucom/norton)
|
5
|
+
[](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"
|