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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47f5a6a213e297cec27645a41ff453ae1b7d4bfd
4
- data.tar.gz: 37b3492ec453174d6bb8993ddf835ae2af2a43b4
3
+ metadata.gz: dcc25c436cc01399c68e17739b2181d7298e5a05
4
+ data.tar.gz: 9add33b7a73eb52e1cceaceecee1728db377ae15
5
5
  SHA512:
6
- metadata.gz: cd5c343f935788a653d31e65b8f94107353df0121ced3610cc65613782fdc462450b05437a06c613f1dfd6c84dc6941dcf90119ccb66f0e1dbd81ce12ce6ca47
7
- data.tar.gz: 12969d600acc46904a4680e49cf62f3acaff0243970449358d98619a9cf4e9e08f441f6c4cb86ddb057c81b56312f9cea06780e7b51bfa8ebde631cd5ce29a7f
6
+ metadata.gz: e8dd9328148d9ec90be45726443cdadabbf99de363c11a9680897f53886f6cf5aabe8b6de429c9c92e28986b8ee4d03f95c1a63e0543116f3c7146e3725ac8ee
7
+ data.tar.gz: 3e7b992f5406d3c3876f1e065f108a5d3c0bc690bb90429d85f6709980c9d14a02abd1f88252cce62ab9d39f01ef482b94a950a8dc01fb2d8513ddbfb9df9c05
data/.codeclimate.yml ADDED
@@ -0,0 +1,16 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ fixme:
9
+ enabled: true
10
+ rubocop:
11
+ enabled: true
12
+ ratings:
13
+ paths:
14
+ - "**.rb"
15
+ exclude_paths:
16
+ - spec/
data/.travis.yml CHANGED
@@ -7,7 +7,8 @@ rvm:
7
7
  - 2.3.0
8
8
 
9
9
  script:
10
- - RAILS_ENV=test bundle exec rake
10
+ - bundle exec rake
11
+ - bundle exec codeclimate-test-reporter
11
12
 
12
13
  notifications:
13
14
  email: false
data/Gemfile CHANGED
@@ -1,4 +1,9 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in norton.gemspec
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
  ```
@@ -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.norton_redis_key(name)).try(:to_i) || 0
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.norton_redis_key(name))
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.norton_redis_key(name))
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.norton_redis_key(name), increment)
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.norton_redis_key(name), decrement)
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.norton_redis_key(name), v)
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.norton_redis_key(name), count)
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.norton_redis_key(name))
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
@@ -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.norton_redis_key(name))
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 norton_redis_key(name)
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 norton_vals(*names)
93
+ def norton_mget(*names)
49
94
  ret = {}
50
95
 
51
- redis_keys = names.map { |n| self.norton_redis_key(n) }
96
+ redis_keys = names.map { |n| self.norton_value_key(n) }
52
97
 
53
- redis_values = Norton.redis.with do |conn|
54
- conn.mget(redis_keys)
55
- end
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
- names.each_with_index do |n, index|
58
- ret[n] = redis_values[index].try(:to_i)
118
+ ret[n] = val
119
+ end
59
120
  end
60
121
 
61
122
  ret
@@ -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.norton_redis_key(name))
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.norton_redis_key(name), options[:ttl], v)
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.norton_redis_key(name), options[:ttl], v)
33
+ conn.setex(self.norton_value_key(name), options[:ttl], v)
34
34
  v
35
35
  end
36
36
  end
@@ -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.norton_redis_key(name)).try(:to_i)
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
- if !options[:allow_nil] && ts.nil?
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.norton_redis_key(name), (Time.now.to_f * 1000).to_i)
52
+ conn.set(self.norton_value_key(name), (Time.now.to_f * 1000).to_i)
36
53
  else
37
- conn.set(self.norton_redis_key(name), Time.now.to_i)
54
+ conn.set(self.norton_value_key(name), Time.now.to_i)
38
55
  end
39
56
  end
40
57
  end
@@ -1,3 +1,3 @@
1
1
  module Norton
2
- VERSION = "0.0.24"
2
+ VERSION = "0.0.26"
3
3
  end
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(options.slice(:url, :host, :port, :db, :path, :password, :namespace, :ssl_params, :driver))
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 "#norton_redis_key" do
14
+ describe "#norton_value_key" do
15
15
  it "generates the correct field key" do
16
16
  object = HashMapObject.new
17
- expect(object.norton_redis_key(:profile)).to eq("hash_map_objects:99:profile")
17
+ expect(object.norton_value_key(:profile)).to eq("hash_map_objects:99:profile")
18
18
  end
19
19
  end
20
20
 
@@ -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 "#norton_redis_key" do
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.norton_redis_key(n)).to eq("dummies:#{dummy.id}:#{n}")
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 "#norton_vals" do
58
- it "should respond to `:norton_vals`" do
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(:norton_vals)
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.norton_vals(:counter1, :time1)
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 return nil if the specific key does not exist" do
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
- values = dummy.norton_vals(:counter1, :counter2, :time2)
128
+ t = Time.now
91
129
 
92
- expect(values).to include(:counter1, :counter2, :time2)
93
- expect(values.size).to eq(3)
94
- expect(values[:counter1]).to eq(dummy.counter1)
95
- expect(values[:counter2]).to eq(dummy.counter2)
96
- expect(values[:time2]).to be_nil
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
@@ -1,9 +1,12 @@
1
+ require "simplecov"
1
2
  require "active_record"
2
3
  require "nulldb"
3
4
  require "norton"
4
5
  require "rspec"
5
6
  require "timecop"
6
7
 
8
+ SimpleCov.start
9
+
7
10
  RSpec.configure do |config|
8
11
  config.expect_with :rspec do |expectations|
9
12
  expectations.syntax = :expect
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.24
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-24 00:00:00.000000000 Z
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"