mini_cache 1.0.1 → 1.1.0

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: d667eb0ee357eea898da78996e2641164ee66c6c
4
- data.tar.gz: 5d8daab29c61434ccc298f59e2c313507be4d181
3
+ metadata.gz: a985472b71d6f27c56bbc2f4eb78e9a6587d3a46
4
+ data.tar.gz: dbf5cc0c90cf4d555cb315c526dbf12d67d8e177
5
5
  SHA512:
6
- metadata.gz: 2de1d028b8ea353425e84e971e2fb572f69dc95748d8a7fafde1513d5d5b37d67afbb454fa0fe1074c4551fbf820c1dec06382d8df70c5a360ebf6eeee457f1e
7
- data.tar.gz: 0d932bf0b9ff36e6252ea4e452da53ea56d6fc844066e024880b548e06cae39e16f1061742d2c0a3ddbfa9fb821460fdba11a1e139d194b64489c983ebd1c616
6
+ metadata.gz: a6940e77b4988ca034d6c031c564613ed79e0ffe2d140d06b70a2b59ef6ae7dcdb10e19b75f91a08c9bd872a942a391e583529ee948c1911089a8ad9373b7af2
7
+ data.tar.gz: e7e1687c3b0c58b7d189ac43f0d5bd8fa06a3224650393faf415e660239694fa9cf1ea6e4e836a3dfe5e8108ebb10bf34b96956d11b8973d87ffff9978c2854c
@@ -0,0 +1,4 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.3
@@ -0,0 +1,24 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2017-04-22 10:39:26 -0500 using RuboCop version 0.46.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 3
10
+ # Configuration parameters: CountComments.
11
+ Metrics/BlockLength:
12
+ Max: 68
13
+
14
+ # Offense count: 1
15
+ # Configuration parameters: CountComments.
16
+ Metrics/ClassLength:
17
+ Max: 227
18
+
19
+ # Offense count: 1
20
+ Style/Documentation:
21
+ Exclude:
22
+ - 'spec/**/*'
23
+ - 'test/**/*'
24
+ - 'lib/mini_cache/data.rb'
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - 2.3.0
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in mini_cache.gemspec
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Derrick Reimer
1
+ Copyright (c) 2017 Derrick Reimer
2
2
 
3
3
  MIT License
4
4
 
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,16 +1,15 @@
1
1
  # MiniCache
2
2
 
3
- MiniCache is a lightweight in-memory key-value store for Ruby objects.
4
- This gem has no external dependencies and has been tested in MRI 1.9.x and
5
- JRuby 1.9 mode.
3
+ [![Build Status](https://travis-ci.org/djreimer/mini_cache.svg?branch=master)](https://travis-ci.org/djreimer/mini_cache)
6
4
 
7
- Extracted from [Leadscreener](http://www.leadscreener.com/).
5
+ MiniCache is a lightweight in-memory key-value store for Ruby objects.
6
+ This gem requires Ruby version 2.3.0 or higher.
8
7
 
9
8
  ## Motivation
10
9
 
11
- It is common practice to cache certain values on an object that are
12
- computationally expensive to obtain, such as a property that requires a
13
- database query.
10
+ It is common practice to cache certain values on an object that are
11
+ computationally expensive to obtain, such as a property that requires a
12
+ database query.
14
13
 
15
14
  The simplest way to do this is by storing the value in an instance variable:
16
15
 
@@ -19,14 +18,14 @@ class Account
19
18
  def calculate_balance
20
19
  # Do something expensive.
21
20
  end
22
-
21
+
23
22
  def balance
24
23
  @balance ||= self.calculate_balance
25
24
  end
26
25
  end
27
26
  ```
28
27
 
29
- While this method works in many scenarios, it fails when the value you
28
+ While this method works in many scenarios, it fails when the value you
30
29
  need to cache is:
31
30
 
32
31
  - Either `nil` or `false`
@@ -39,7 +38,7 @@ class Account
39
38
  def lookup_role(user)
40
39
  # Execute a database query to find the user's role.
41
40
  end
42
-
41
+
43
42
  def role(user)
44
43
  # Perform the lookup once and cache the value. We can't use
45
44
  #
@@ -53,14 +52,14 @@ class Account
53
52
  self.lookup_role(user)
54
53
  end
55
54
  end
56
-
55
+
57
56
  def cache
58
57
  @cache ||= MiniCache::Store.new
59
58
  end
60
59
  end
61
60
  ```
62
61
 
63
- The `#get_or_set` method works similarly to the `||=` operator, except it
62
+ The `#get_or_set` method works similarly to the `||=` operator, except it
64
63
  knows how to handle `false` and `nil` values and it's keyed off of a unique string ID.
65
64
  Problem solved!
66
65
 
@@ -86,29 +85,77 @@ To create a new MiniCache store object, just initialize it:
86
85
  store = MiniCache::Store.new
87
86
 
88
87
  # Optionally pass in a Hash of data
89
- store = MiniCache::Store.new(:name => "Derrick", :occupation => "Developer")
88
+ store = MiniCache::Store.new(name: 'Derrick', occupation: 'Developer')
90
89
  ```
91
90
 
92
91
  Set and retrieve data using `#get` and `#set`:
93
92
 
94
93
  ```ruby
95
94
  # Pass in the value as an argument or block
96
- store.set("age", 24)
97
- store.set("birth_year") { 1988 }
95
+ store.set('age', 24)
96
+ store.set('birth_year') { 1988 }
97
+
98
+ store.get('age')
99
+ # => 24
100
+
101
+ store.get('birth_year')
102
+ # => 1988
103
+
104
+ # Sets an expiration time to cache (in seconds)
105
+ store.set('age', 24, expires_in: 60)
106
+ store.set('day', expires_in: 60) { 12 }
107
+ store.set('birth_year') { MiniCache::Data.new(1988, 60) }
108
+
109
+ store.get('age')
110
+ # => 24
111
+
112
+ store.get('day')
113
+ # => 12
114
+
115
+ store.get('birth_year')
116
+ # => 1988
117
+
118
+ sleep(60)
119
+
120
+ store.get('age')
121
+ # => nil
122
+
123
+ store.get('day')
124
+ # => nil
98
125
 
99
- store.get("birth_year")
100
- => 1988
126
+ store.get('birth_year')
127
+ #=> nil
101
128
  ```
102
129
 
103
130
  Use the `#get_or_set` method to either set the value if it hasn't already been
104
131
  set, or get the value that was already set.
105
132
 
106
133
  ```ruby
107
- store.set("birth_year") { 1988 }
108
- => 1988
134
+ store.set('birth_year') { 1988 }
135
+ #=> 1988
109
136
 
110
- store.get_or_set("birth_year") { 1964 }
111
- => 1988 # Did not overwrite previously set value
137
+ store.get_or_set('birth_year') { 1964 }
138
+ #=> 1988 # Did not overwrite previously set value
139
+
140
+ # You may also set an expiration time (in seconds):
141
+
142
+ store.get_or_set('age', expires_in: 60) { 24 }
143
+ #=> 24
144
+
145
+ store.get_or_set('birth_year') do
146
+ MiniCache::Data.new(1988, expires_in: 60)
147
+ end
148
+ #=> 1988
149
+
150
+ sleep(60)
151
+
152
+ store.get_or_set('age', expires_in: 60) { 28 }
153
+ #=> 28
154
+
155
+ store.get_or_set('birth_year') do
156
+ MiniCache::Data.new(1964, expires_in: 60)
157
+ end
158
+ #=> 1964
112
159
  ```
113
160
 
114
161
  Other convenience methods:
@@ -125,28 +172,3 @@ Other convenience methods:
125
172
  3. Commit your changes (`git commit -am 'Added some feature'`)
126
173
  4. Push to the branch (`git push origin my-new-feature`)
127
174
  5. Create new Pull Request
128
-
129
- ## License
130
-
131
- Copyright © 2012 Derrick Reimer
132
-
133
- MIT License
134
-
135
- Permission is hereby granted, free of charge, to any person obtaining
136
- a copy of this software and associated documentation files (the
137
- "Software"), to deal in the Software without restriction, including
138
- without limitation the rights to use, copy, modify, merge, publish,
139
- distribute, sublicense, and/or sell copies of the Software, and to
140
- permit persons to whom the Software is furnished to do so, subject to
141
- the following conditions:
142
-
143
- The above copyright notice and this permission notice shall be
144
- included in all copies or substantial portions of the Software.
145
-
146
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
147
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
148
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
149
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
150
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
151
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
152
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,12 +1,20 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/gem_tasks'
3
5
  require 'rake/testtask'
6
+ require 'rubocop/rake_task'
4
7
 
5
8
  Rake::TestTask.new do |t|
6
- t.libs << "lib"
7
- t.pattern = "test/**/*_test.rb"
9
+ t.libs << 'lib'
10
+ t.pattern = 'test/**/*_test.rb'
8
11
  t.verbose = true
9
12
  end
10
13
 
11
- desc "Run tests"
12
- task :default => :test
14
+ RuboCop::RakeTask.new
15
+
16
+ desc 'Run tests'
17
+ task :default do
18
+ Rake::Task['rubocop'].invoke
19
+ Rake::Task['test'].invoke
20
+ end
@@ -1,2 +1,5 @@
1
- require "mini_cache/version"
2
- require "mini_cache/store"
1
+ # frozen_string_literal: true
2
+
3
+ require 'mini_cache/version'
4
+ require 'mini_cache/data'
5
+ require 'mini_cache/store'
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniCache
4
+ class Data
5
+ attr_reader :value
6
+ attr_reader :expires_in
7
+
8
+ def initialize(value, expires_in: nil)
9
+ @value = value
10
+ @expires_in = expires_in.nil? ? nil : Time.now + expires_in
11
+ end
12
+
13
+ def expired?
14
+ !@expires_in.nil? && Time.now > @expires_in
15
+ end
16
+
17
+ def ==(other)
18
+ other.is_a?(MiniCache::Data) && @value == other.value
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MiniCache
2
- class Store
4
+ class Store # :nodoc:
3
5
  include Enumerable
4
6
 
5
7
  # Public: Returns the hash of key-value pairs.
@@ -8,11 +10,12 @@ module MiniCache
8
10
  # Public: Initializes a new MiniCache object.
9
11
  #
10
12
  # data - A Hash of key-value pairs (optional).
13
+ # The values can be String or MiniCache::Data.
11
14
  #
12
15
  # Returns nothing.
13
16
  def initialize(data = {})
14
17
  @data = {}
15
- self.load(data)
18
+ load(data)
16
19
  end
17
20
 
18
21
  # Public: Retrieves the value for a given key.
@@ -23,7 +26,8 @@ module MiniCache
23
26
  # set, returns nil.
24
27
  def get(key)
25
28
  check_key!(key)
26
- @data[key.to_s]
29
+ expires!(key)
30
+ @data[key.to_s]&.value
27
31
  end
28
32
 
29
33
  # Public: Sets a value for a given key either as
@@ -31,22 +35,37 @@ module MiniCache
31
35
  #
32
36
  # key - A String or Symbol representing the key.
33
37
  # value - Any object that represents the value (optional).
38
+ # The value can be a MiniCache::Data.
34
39
  # Not used if a block is given.
35
- # block - A block of code that returns the value to set
36
- # (optional).
40
+ # block - A block of code that returns the value to set (optional).
41
+ # Can be set a MiniCache::Data in the block.
42
+ # expires_in - Time, in seconds, to expire the cache (optional).
43
+ # If not set, the cache never expires.
37
44
  #
38
45
  # Examples
39
46
  #
40
47
  # cache.set("name", "Derrick")
41
48
  # => "Derrick"
42
49
  #
50
+ # cache.set("name", "Derrick", expires_in: 60)
51
+ # => "Derrick"
52
+ #
43
53
  # cache.set("name") { "Joe" }
44
54
  # => "Joe"
45
55
  #
56
+ # cache.set("name") { MiniCache::Data.new("Joe", 60) }
57
+ # => "Joe"
58
+ #
46
59
  # Returns the value given.
47
- def set(key, value = nil)
60
+ def set(key, value = nil, expires_in: nil)
48
61
  check_key!(key)
49
- @data[key.to_s] = block_given? ? yield : value
62
+ data = block_given? ? yield : value
63
+ @data[key.to_s] = if data.is_a?(MiniCache::Data)
64
+ data
65
+ else
66
+ MiniCache::Data.new(data, expires_in: expires_in)
67
+ end
68
+ get(key)
50
69
  end
51
70
 
52
71
  # Public: Determines whether a value has been set for
@@ -57,6 +76,7 @@ module MiniCache
57
76
  # Returns a Boolean.
58
77
  def set?(key)
59
78
  check_key!(key)
79
+ expires!(key)
60
80
  @data.keys.include?(key.to_s)
61
81
  end
62
82
 
@@ -66,9 +86,12 @@ module MiniCache
66
86
  #
67
87
  # key - A String or Symbol representing the key.
68
88
  # value - Any object that represents the value (optional).
89
+ # The value can be a MiniCache::Data.
69
90
  # Not used if a block is given.
70
- # block - A block of code that returns the value to set
71
- # (optional).
91
+ # block - A block of code that returns the value to set (optional).
92
+ # Can be set a MiniCache::Data in the block.
93
+ # expires_in - Time, in seconds, to expire the cache (optional).
94
+ # If not set, the cache never expires.
72
95
  #
73
96
  # Examples
74
97
  #
@@ -85,9 +108,9 @@ module MiniCache
85
108
  # => "Engineer"
86
109
  #
87
110
  # Returns the value.
88
- def get_or_set(key, value = nil)
111
+ def get_or_set(key, value = nil, expires_in: nil)
89
112
  return get(key) if set?(key)
90
- set(key, block_given? ? yield : value)
113
+ set(key, block_given? ? yield : value, expires_in: expires_in)
91
114
  end
92
115
 
93
116
  # Public: Removes the key-value pair from the cache
@@ -114,7 +137,7 @@ module MiniCache
114
137
  # and value of each pair.
115
138
  #
116
139
  # Yields the String key and value.
117
- def each(&block)
140
+ def each
118
141
  @data.each { |k, v| yield(k, v) }
119
142
  end
120
143
 
@@ -126,20 +149,24 @@ module MiniCache
126
149
  def load(data)
127
150
  data.each do |key, value|
128
151
  check_key!(key)
129
- @data[key.to_s] = value
152
+ set(key, value)
130
153
  end
131
154
  end
132
155
 
133
156
  private
134
157
 
135
- # Internal: Raises an error if the key is not a String
136
- # or a Symbol.
137
- #
138
- # key - A key provided by the user.
139
- def check_key!(key)
140
- unless key.is_a?(String) || key.is_a?(Symbol)
141
- raise TypeError, "key must be a String or Symbol"
142
- end
143
- end
158
+ # Internal: Raises an error if the key is not a String
159
+ # or a Symbol.
160
+ #
161
+ # key - A key provided by the user.
162
+ def check_key!(key)
163
+ return if key.is_a?(String) || key.is_a?(Symbol)
164
+ raise TypeError, 'key must be a String or Symbol'
165
+ end
166
+
167
+ # Internal: Verifies if data is expired and unset it
168
+ def expires!(key)
169
+ unset(key) if @data[key.to_s]&.expired?
170
+ end
144
171
  end
145
172
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MiniCache
2
- VERSION = "1.0.1"
4
+ VERSION = '1.1.0'
3
5
  end
@@ -1,19 +1,26 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
2
4
  require File.expand_path('../lib/mini_cache/version', __FILE__)
3
5
 
4
6
  Gem::Specification.new do |gem|
5
- gem.authors = ["Derrick Reimer"]
6
- gem.email = ["derrickreimer@gmail.com"]
7
- gem.description = %q{A lightweight, in-memory cache for Ruby objects}
8
- gem.summary = %q{MiniCache is a lightweight, in-memory key-value store for Ruby objects}
9
- gem.homepage = "https://github.com/djreimer/mini_cache"
7
+ gem.authors = ['Derrick Reimer']
8
+ gem.email = ['derrickreimer@gmail.com']
9
+ gem.description = 'A lightweight, in-memory cache for Ruby objects'
10
+ gem.summary = 'MiniCache is a lightweight, in-memory key-value store' \
11
+ 'for Ruby objects'
12
+ gem.homepage = 'https://github.com/djreimer/mini_cache'
10
13
 
11
- gem.files = `git ls-files`.split($\)
12
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
15
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
13
16
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
- gem.name = "mini_cache"
15
- gem.require_paths = ["lib"]
17
+ gem.name = 'mini_cache'
18
+ gem.require_paths = ['lib']
16
19
  gem.version = MiniCache::VERSION
17
-
18
- gem.add_development_dependency "shoulda-context"
20
+
21
+ gem.add_development_dependency 'shoulda-context'
22
+ gem.add_development_dependency 'timecop', '~> 0.8'
23
+ gem.add_development_dependency 'rake'
24
+ gem.add_development_dependency 'minitest'
25
+ gem.add_development_dependency 'rubocop', '~> 0.48'
19
26
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper.rb', __FILE__)
4
+
5
+ module MiniCache
6
+ class DataTest < MiniTest::Test
7
+ context 'initialize' do
8
+ should 'return initialized value' do
9
+ data = MiniCache::Data.new('Gunter')
10
+ assert_equal('Gunter', data.value)
11
+ end
12
+
13
+ should 'return a nil expires_in as default' do
14
+ data = MiniCache::Data.new('Gunter')
15
+ assert_nil(data.expires_in)
16
+ end
17
+
18
+ should 'return initialized expires_in' do
19
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
20
+ data = MiniCache::Data.new('Gunter', expires_in: 60)
21
+ assert_equal(Time.now + 60, data.expires_in)
22
+ end
23
+ end
24
+ end
25
+
26
+ context '#equals' do
27
+ should 'be compared only by value and be the same' do
28
+ data1 = MiniCache::Data.new('Finn', expires_in: 10)
29
+ data2 = MiniCache::Data.new('Finn', expires_in: 30)
30
+ assert_equal(data1, data2)
31
+ end
32
+
33
+ should 'be compared only by value and not be the same' do
34
+ data1 = MiniCache::Data.new('Finn', expires_in: 10)
35
+ data2 = MiniCache::Data.new('Grass Finn', expires_in: 10)
36
+ refute_equal(data1, data2)
37
+ end
38
+ end
39
+
40
+ context '#expired?' do
41
+ should 'be expired' do
42
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
43
+ data = MiniCache::Data.new('Gunter', expires_in: 60)
44
+ Timecop.travel(data.expires_in) do
45
+ assert_equal(true, data.expired?)
46
+ end
47
+ end
48
+ end
49
+
50
+ should 'not be expired' do
51
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
52
+ data = MiniCache::Data.new('Gunter', expires_in: 60)
53
+ Timecop.travel(data.expires_in - 1) do
54
+ assert_equal(false, data.expired?)
55
+ end
56
+ end
57
+ end
58
+
59
+ should 'not be expired because expires_in is nil' do
60
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
61
+ data = MiniCache::Data.new('Gunter')
62
+ assert_equal(false, data.expired?)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,138 +1,272 @@
1
- require File.dirname(__FILE__) + '/../test_helper.rb'
1
+ # frozen_string_literal: true
2
2
 
3
- class MiniCache::StoreTest < Test::Unit::TestCase
4
- def setup
5
- @store = MiniCache::Store.new
6
- end
7
-
8
- context "initialize" do
9
- should "default to empty data" do
10
- store = MiniCache::Store.new
11
- assert_equal Hash.new, store.data
12
- end
13
-
14
- should "load seed data" do
15
- data = { "name" => "Derrick" }
16
- store = MiniCache::Store.new(data)
17
- assert_equal data, store.data
18
- end
19
- end
20
-
21
- context "#get" do
22
- should "return a value if set" do
23
- @store.set("name", "Derrick")
24
- assert_equal "Derrick", @store.get("name")
25
- end
26
-
27
- should "return nil if not set" do
28
- assert_nil @store.get("name")
29
- end
30
-
31
- should "raise a TypeError if key is not valid" do
32
- assert_raises(TypeError) { @store.get([1, 2]) }
33
- end
34
- end
35
-
36
- context "#set" do
37
- should "accept the value as an argument" do
38
- @store.set("name", "Derrick")
39
- assert_equal "Derrick", @store.get("name")
40
- end
41
-
42
- should "accept the value as a block" do
43
- @store.set("name") { "Derrick" }
44
- assert_equal "Derrick", @store.get("name")
45
- end
46
-
47
- should "raise a TypeError if key is not valid" do
48
- assert_raises(TypeError) { @store.set([1, 2], "foo") }
49
- end
50
- end
51
-
52
- context "#set?" do
53
- should "be true if key has been set" do
54
- @store.set("name", "Derrick")
55
- assert_equal true, @store.set?("name")
56
- end
57
-
58
- should "be false if key has not been set" do
59
- assert_equal false, @store.set?("foobar")
60
- end
61
-
62
- should "raise a TypeError if key is not valid" do
63
- assert_raises(TypeError) { @store.set?([1, 2]) }
64
- end
65
- end
66
-
67
- context "#get_or_set" do
68
- should "set the value if it hasn't already been set" do
69
- @store.get_or_set("name", "Derrick")
70
- assert_equal "Derrick", @store.get("name")
71
- end
72
-
73
- should "not set the value if it has already been set" do
74
- @store.set("name", "Derrick")
75
- @store.get_or_set("name", "Joe")
76
- assert_equal "Derrick", @store.get("name")
77
- end
78
-
79
- should "return the value if not already set" do
80
- assert_equal "Derrick", @store.get_or_set("name", "Derrick")
3
+ require File.expand_path('../../test_helper.rb', __FILE__)
4
+
5
+ module MiniCache
6
+ class StoreTest < MiniTest::Test
7
+ def setup
8
+ @store = MiniCache::Store.new
81
9
  end
82
-
83
- should "return the value if already set" do
84
- @store.set("name", "Derrick")
85
- assert_equal "Derrick", @store.get_or_set("name", "Joe")
10
+
11
+ context 'initialize' do
12
+ should 'default to empty data' do
13
+ store = MiniCache::Store.new
14
+ assert_equal({}, store.data)
15
+ end
16
+
17
+ should 'load seed data' do
18
+ data = { 'name' => 'Derrick' }
19
+ store = MiniCache::Store.new(data)
20
+ assert_equal(
21
+ { data.keys.first => MiniCache::Data.new(data.values.first) },
22
+ store.data
23
+ )
24
+ end
25
+
26
+ should 'load seed data using MiniCache::Data' do
27
+ data = { 'name' => MiniCache::Data.new('Derrick', expires_in: 60) }
28
+ store = MiniCache::Store.new(data)
29
+ assert_equal(
30
+ data,
31
+ store.data
32
+ )
33
+ end
86
34
  end
87
-
88
- should "accept the value as a block" do
89
- @store.get_or_set("name") { "Joe" }
90
- assert_equal "Joe", @store.get("name")
35
+
36
+ context '#get' do
37
+ should 'return a value if set' do
38
+ @store.set('name', 'Derrick')
39
+ assert_equal 'Derrick', @store.get('name')
40
+ end
41
+
42
+ should 'return nil if not set' do
43
+ assert_nil @store.get('name')
44
+ end
45
+
46
+ should 'raise a TypeError if key is not valid' do
47
+ assert_raises(TypeError) { @store.get([1, 2]) }
48
+ end
49
+
50
+ should 'return an not expired value' do
51
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
52
+ @store.set('name', 'Derrick', expires_in: 60)
53
+ Timecop.travel(Time.now + 59) do
54
+ assert_equal('Derrick', @store.get('name'))
55
+ end
56
+ end
57
+ end
58
+
59
+ should 'not return an expired value' do
60
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
61
+ @store.set('name', 'Derrick', expires_in: 60)
62
+ Timecop.travel(Time.now + 60) do
63
+ assert_nil @store.get('name')
64
+ end
65
+ end
66
+ end
91
67
  end
92
-
93
- should "raise a TypeError if key is not valid" do
94
- assert_raises(TypeError) { @store.get_or_set([1, 2], "foo") }
68
+
69
+ context '#set' do
70
+ should 'accept the value as an argument' do
71
+ @store.set('name', 'Derrick')
72
+ assert_equal 'Derrick', @store.get('name')
73
+ end
74
+
75
+ should 'accept the value as a block' do
76
+ @store.set('name') { 'Derrick' }
77
+ assert_equal 'Derrick', @store.get('name')
78
+ end
79
+
80
+ should 'accept the value as a MiniCache::Data argument' do
81
+ @store.set('name', MiniCache::Data.new('Derrick'))
82
+ assert_equal 'Derrick', @store.get('name')
83
+ end
84
+
85
+ should 'accept the value as a block with MiniCache::Data' do
86
+ @store.set('name') { MiniCache::Data.new('Derrick') }
87
+ assert_equal 'Derrick', @store.get('name')
88
+ end
89
+
90
+ should 'raise a TypeError if key is not valid' do
91
+ assert_raises(TypeError) { @store.set([1, 2], 'foo') }
92
+ end
93
+
94
+ should 'returns cached value' do
95
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
96
+ @store.set('name', 'Derrick', expires_in: 60)
97
+ Timecop.travel(Time.now + 59) do
98
+ assert_equal('Derrick', @store.get('name'))
99
+ end
100
+ end
101
+ end
102
+
103
+ should 'returns nil, because cache was expired' do
104
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
105
+ @store.set('name', 'Derrick', expires_in: 60)
106
+ Timecop.travel(Time.now + 60) do
107
+ assert_nil(@store.get('name'))
108
+ end
109
+ end
110
+ end
111
+
112
+ should 'returns cached value. Using block' do
113
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
114
+ @store.get_or_set('name', expires_in: 60) do
115
+ 'Derrick'
116
+ end
117
+ Timecop.travel(Time.now + 59) do
118
+ assert_equal('Derrick', @store.get('name'))
119
+ end
120
+ end
121
+ end
122
+
123
+ should 'returns nil, because cache was expired. Using block' do
124
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
125
+ @store.get_or_set('name', expires_in: 60) do
126
+ 'Derrick'
127
+ end
128
+ Timecop.travel(Time.now + 60) do
129
+ assert_nil(@store.get('name'))
130
+ end
131
+ end
132
+ end
95
133
  end
96
- end
97
-
98
- context "#unset" do
99
- should "remove the key-value pair" do
100
- @store.set("name", "Derrick")
101
- @store.unset("name")
102
- assert !@store.data.keys.include?("name")
134
+
135
+ context '#set?' do
136
+ should 'be true if key has been set' do
137
+ @store.set('name', 'Derrick')
138
+ assert_equal true, @store.set?('name')
139
+ end
140
+
141
+ should 'be false if key has not been set' do
142
+ assert_equal false, @store.set?('foobar')
143
+ end
144
+
145
+ should 'raise a TypeError if key is not valid' do
146
+ assert_raises(TypeError) { @store.set?([1, 2]) }
147
+ end
103
148
  end
104
- end
105
-
106
- context "#reset" do
107
- should "remove all data" do
108
- @store.set("name", "Derrick")
109
- @store.reset
110
- assert_equal Hash.new, @store.data
149
+
150
+ context '#get_or_set' do
151
+ should "set the value if it hasn't already been set" do
152
+ @store.get_or_set('name', 'Derrick')
153
+ assert_equal 'Derrick', @store.get('name')
154
+ end
155
+
156
+ should 'not set the value if it has already been set' do
157
+ @store.set('name', 'Derrick')
158
+ @store.get_or_set('name', 'Joe')
159
+ assert_equal 'Derrick', @store.get('name')
160
+ end
161
+
162
+ should 'return the value if not already set' do
163
+ assert_equal('Derrick',
164
+ @store.get_or_set('name', 'Derrick'))
165
+ end
166
+
167
+ should 'return the value if already set' do
168
+ @store.set('name', 'Derrick')
169
+ assert_equal 'Derrick', @store.get_or_set('name', 'Joe')
170
+ end
171
+
172
+ should 'accept the value as a block' do
173
+ @store.get_or_set('name') { 'Joe' }
174
+ assert_equal 'Joe', @store.get('name')
175
+ end
176
+
177
+ should 'raise a TypeError if key is not valid' do
178
+ assert_raises(TypeError) { @store.get_or_set([1, 2], 'foo') }
179
+ end
180
+
181
+ should 'returns first set value' do
182
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
183
+ @store.set('name', 'Derrick', expires_in: 60)
184
+ Timecop.travel(Time.now + 59) do
185
+ @store.get_or_set('name', 'Gunter', expires_in: 60)
186
+ assert_equal('Derrick', @store.get('name'))
187
+ end
188
+ end
189
+ end
190
+
191
+ should 'returns next set value' do
192
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
193
+ @store.set('name', 'Derrick', expires_in: 60)
194
+ Timecop.travel(Time.now + 60) do
195
+ @store.get_or_set('name', 'Gunter', expires_in: 60)
196
+ assert_equal('Gunter', @store.get('name'))
197
+ end
198
+ end
199
+ end
200
+
201
+ should 'returns first set value. Using block' do
202
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
203
+ @store.get_or_set('name', expires_in: 60) do
204
+ 'Derrick'
205
+ end
206
+ Timecop.travel(Time.now + 59) do
207
+ @store.get_or_set('name', expires_in: 60) do
208
+ 'Gunter'
209
+ end
210
+ assert_equal('Derrick', @store.get('name'))
211
+ end
212
+ end
213
+ end
214
+
215
+ should 'returns next set value. Using block' do
216
+ Timecop.freeze(Time.local(2010, 4, 5, 12, 0, 0)) do
217
+ @store.get_or_set('name', expires_in: 60) do
218
+ 'Derrick'
219
+ end
220
+ Timecop.travel(Time.now + 60) do
221
+ @store.get_or_set('name', expires_in: 60) do
222
+ 'Derrick'
223
+ end
224
+ assert_equal('Derrick', @store.get('name'))
225
+ end
226
+ end
227
+ end
111
228
  end
112
- end
113
-
114
- context "#load" do
115
- should "append the data to the cache" do
116
- @store.set("title", "Mr.")
117
-
118
- data = { "name" => "Derrick", "occupation" => "Developer" }
119
- @store.load(data)
120
-
121
- all_data = { "title" => "Mr.",
122
- "name" => "Derrick", "occupation" => "Developer" }
123
- assert_equal all_data, @store.data
229
+
230
+ context '#unset' do
231
+ should 'remove the key-value pair' do
232
+ @store.set('name', 'Derrick')
233
+ @store.unset('name')
234
+ assert !@store.data.keys.include?('name')
235
+ end
124
236
  end
125
-
126
- should "stringify the keys" do
127
- data = { :name => "Derrick" }
128
- @store.load(data)
129
- stringified_data = { "name" => "Derrick" }
130
- assert_equal stringified_data, @store.data
237
+
238
+ context '#reset' do
239
+ should 'remove all data' do
240
+ @store.set('name', 'Derrick')
241
+ @store.reset
242
+ assert_equal({}, @store.data)
243
+ end
131
244
  end
132
-
133
- should "raise a TypeError if an invalid key is encountered" do
134
- data = { [1, 2] => "Derrick" }
135
- assert_raises(TypeError) { @store.load(data) }
245
+
246
+ context '#load' do
247
+ should 'append the data to the cache' do
248
+ @store.set('title', 'Mr.')
249
+
250
+ data = { 'name' => 'Derrick', 'occupation' => 'Developer' }
251
+ @store.load(data)
252
+
253
+ all_data = { 'title' => MiniCache::Data.new('Mr.'),
254
+ 'name' => MiniCache::Data.new('Derrick'),
255
+ 'occupation' => MiniCache::Data.new('Developer') }
256
+ assert_equal all_data, @store.data
257
+ end
258
+
259
+ should 'stringify the keys' do
260
+ data = { name: 'Derrick' }
261
+ @store.load(data)
262
+ stringified_data = { 'name' => MiniCache::Data.new('Derrick') }
263
+ assert_equal stringified_data, @store.data
264
+ end
265
+
266
+ should 'raise a TypeError if an invalid key is encountered' do
267
+ data = { [1, 2] => 'Derrick' }
268
+ assert_raises(TypeError) { @store.load(data) }
269
+ end
136
270
  end
137
271
  end
138
- end
272
+ end
@@ -1,4 +1,8 @@
1
- $:.unshift File.expand_path('../../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+
2
5
  require 'mini_cache'
3
6
  require 'minitest/autorun'
4
- require 'shoulda-context'
7
+ require 'shoulda-context'
8
+ require 'timecop'
metadata CHANGED
@@ -1,29 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derrick Reimer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-10 00:00:00.000000000 Z
11
+ date: 2017-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: shoulda-context
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: timecop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.48'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.48'
27
83
  description: A lightweight, in-memory cache for Ruby objects
28
84
  email:
29
85
  - derrickreimer@gmail.com
@@ -31,15 +87,20 @@ executables: []
31
87
  extensions: []
32
88
  extra_rdoc_files: []
33
89
  files:
34
- - .gitignore
90
+ - ".gitignore"
91
+ - ".rubocop.yml"
92
+ - ".rubocop_todo.yml"
93
+ - ".travis.yml"
35
94
  - Gemfile
36
95
  - LICENSE
37
96
  - README.md
38
97
  - Rakefile
39
98
  - lib/mini_cache.rb
99
+ - lib/mini_cache/data.rb
40
100
  - lib/mini_cache/store.rb
41
101
  - lib/mini_cache/version.rb
42
102
  - mini_cache.gemspec
103
+ - test/mini_cache/data_test.rb
43
104
  - test/mini_cache/store_test.rb
44
105
  - test/test_helper.rb
45
106
  homepage: https://github.com/djreimer/mini_cache
@@ -51,21 +112,21 @@ require_paths:
51
112
  - lib
52
113
  required_ruby_version: !ruby/object:Gem::Requirement
53
114
  requirements:
54
- - - '>='
115
+ - - ">="
55
116
  - !ruby/object:Gem::Version
56
117
  version: '0'
57
118
  required_rubygems_version: !ruby/object:Gem::Requirement
58
119
  requirements:
59
- - - '>='
120
+ - - ">="
60
121
  - !ruby/object:Gem::Version
61
122
  version: '0'
62
123
  requirements: []
63
124
  rubyforge_project:
64
- rubygems_version: 2.3.0
125
+ rubygems_version: 2.5.1
65
126
  signing_key:
66
127
  specification_version: 4
67
- summary: MiniCache is a lightweight, in-memory key-value store for Ruby objects
128
+ summary: MiniCache is a lightweight, in-memory key-value storefor Ruby objects
68
129
  test_files:
130
+ - test/mini_cache/data_test.rb
69
131
  - test/mini_cache/store_test.rb
70
132
  - test/test_helper.rb
71
- has_rdoc: