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 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"