zache 0.2.0 → 0.3.0
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/.rultor.yml +3 -0
- data/README.md +1 -0
- data/Rakefile +7 -0
- data/lib/zache.rb +63 -2
- data/test/test_zache.rb +74 -0
- data/zache.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ad9aee02e0592400be73acb02cdf8878c314950df90fce1632ea00e7d07d396
|
4
|
+
data.tar.gz: 802eba8bf8ad6e027b17d85eb296957b0255fde72e9340713bad5b0b96e4dd67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c756d6ba076c41371f3c47d1d2f825f06876ea9dea1d39a86f1d7f5f6b93a87d077427af2726e4dc211248e416b02dba26a130a54b1a40e74eeb8f3e64b982bc
|
7
|
+
data.tar.gz: af8e41d5048f8afa5275362d3e23da9b9276c6277f7f0db33d0353e40bac2e4223806da97f612621b5b587e9f8c964aa737310696a76b9829f242ec543b6fae1
|
data/.rultor.yml
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
[](http://www.elegantobjects.org)
|
1
2
|
[](http://www.rultor.com/p/yegor256/zache)
|
2
3
|
[](https://www.jetbrains.com/ruby/)
|
3
4
|
|
data/Rakefile
CHANGED
@@ -44,6 +44,13 @@ Rake::TestTask.new(:test) do |test|
|
|
44
44
|
test.verbose = false
|
45
45
|
end
|
46
46
|
|
47
|
+
require 'rdoc/task'
|
48
|
+
RDoc::Task.new do |rdoc|
|
49
|
+
rdoc.main = 'README.md'
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
|
52
|
+
end
|
53
|
+
|
47
54
|
require 'rubocop/rake_task'
|
48
55
|
desc 'Run RuboCop on all directories'
|
49
56
|
RuboCop::RakeTask.new(:rubocop) do |task|
|
data/lib/zache.rb
CHANGED
@@ -22,18 +22,36 @@
|
|
22
22
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
23
|
# SOFTWARE.
|
24
24
|
|
25
|
-
#
|
25
|
+
# It is a very simple thread-safe in-memory cache with an ability to expire
|
26
|
+
# keys automatically, when their lifetime is over. Use it like this:
|
27
|
+
#
|
28
|
+
# require 'zache'
|
29
|
+
# zache = Zache.new
|
30
|
+
# # Expires in 5 minutes
|
31
|
+
# v = zache.get(:count, lifetime: 5 * 60) { expensive() }
|
32
|
+
#
|
33
|
+
# For more information read
|
34
|
+
# {README}[https://github.com/yegor256/zache/blob/master/README.md] file.
|
35
|
+
#
|
26
36
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
27
37
|
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
28
38
|
# License:: MIT
|
29
39
|
class Zache
|
40
|
+
# Makes a new object of the cache.
|
41
|
+
# "sync" is whether the hash is thread-safe (`true`)
|
42
|
+
# or not (`false`); it is recommended to leave this parameter untouched,
|
43
|
+
# unless you really know what you are doing.
|
30
44
|
def initialize(sync: true)
|
31
45
|
@hash = {}
|
32
46
|
@sync = sync
|
33
47
|
@mutex = Mutex.new
|
34
48
|
end
|
35
49
|
|
50
|
+
# Gets the value from the cache by the provided key. If the value is not
|
51
|
+
# found in the cache, it will be calculated via the provided block. If
|
52
|
+
# the block is not given, an exception will be raised.
|
36
53
|
def get(key, lifetime: 60 * 60)
|
54
|
+
raise 'A block is required' unless block_given?
|
37
55
|
if @sync
|
38
56
|
@mutex.synchronize do
|
39
57
|
calc(key, lifetime) { yield }
|
@@ -43,11 +61,49 @@ class Zache
|
|
43
61
|
end
|
44
62
|
end
|
45
63
|
|
64
|
+
# Checks whether the value exists in the cache by the provided key. Returns
|
65
|
+
# TRUE if the value is here. If the key is already expired in the hash,
|
66
|
+
# it will be removed by this method and the result will be FALSE.
|
67
|
+
def exists?(key)
|
68
|
+
rec = @hash[key]
|
69
|
+
if key_expired?(key)
|
70
|
+
@hash.delete(key)
|
71
|
+
rec = nil
|
72
|
+
end
|
73
|
+
!rec.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
# Removes the value from the hash, by the provied key. If the key is absent
|
77
|
+
# and the block is provide, the block will be called.
|
78
|
+
def remove(key)
|
79
|
+
if @sync
|
80
|
+
@mutex.synchronize do
|
81
|
+
@hash.delete(key) { yield if block_given? }
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@hash.delete(key) { yield if block_given? }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def clean
|
89
|
+
if @sync
|
90
|
+
@mutex.synchronize do
|
91
|
+
@hash.delete_if do |_key, value|
|
92
|
+
value[:start] < Time.now - value[:lifetime]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
else
|
96
|
+
@hash.delete_if do |_key, value|
|
97
|
+
value[:start] < Time.now - value[:lifetime]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
46
102
|
private
|
47
103
|
|
48
104
|
def calc(key, lifetime)
|
49
105
|
rec = @hash[key]
|
50
|
-
rec = nil if
|
106
|
+
rec = nil if key_expired?(key)
|
51
107
|
if rec.nil?
|
52
108
|
@hash[key] = {
|
53
109
|
value: yield,
|
@@ -57,4 +113,9 @@ class Zache
|
|
57
113
|
end
|
58
114
|
@hash[key][:value]
|
59
115
|
end
|
116
|
+
|
117
|
+
def key_expired?(key)
|
118
|
+
rec = @hash[key]
|
119
|
+
!rec.nil? && rec[:start] < Time.now - rec[:lifetime]
|
120
|
+
end
|
60
121
|
end
|
data/test/test_zache.rb
CHANGED
@@ -52,4 +52,78 @@ class ZacheTest < Minitest::Test
|
|
52
52
|
cache.get(:hey, lifetime: 0.0001) { Random.rand }
|
53
53
|
end
|
54
54
|
end
|
55
|
+
|
56
|
+
def test_key_exists
|
57
|
+
cache = Zache.new
|
58
|
+
cache.get(:hey) { Random.rand }
|
59
|
+
exists_result = cache.exists?(:hey)
|
60
|
+
not_exists_result = cache.exists?(:bye)
|
61
|
+
assert(exists_result == true)
|
62
|
+
assert(not_exists_result == false)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_remove_key
|
66
|
+
cache = Zache.new
|
67
|
+
cache.get(:hey) { Random.rand }
|
68
|
+
cache.get(:wey) { Random.rand }
|
69
|
+
assert(cache.exists?(:hey) == true)
|
70
|
+
assert(cache.exists?(:wey) == true)
|
71
|
+
cache.remove(:hey)
|
72
|
+
assert(cache.exists?(:hey) == false)
|
73
|
+
assert(cache.exists?(:wey) == true)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_remove_key_with_sync_false
|
77
|
+
cache = Zache.new(sync: false)
|
78
|
+
cache.get(:hey) { Random.rand }
|
79
|
+
cache.get(:wey) { Random.rand }
|
80
|
+
assert(cache.exists?(:hey) == true)
|
81
|
+
assert(cache.exists?(:wey) == true)
|
82
|
+
cache.remove(:hey)
|
83
|
+
assert(cache.exists?(:hey) == false)
|
84
|
+
assert(cache.exists?(:wey) == true)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_clean_with_threads
|
88
|
+
cache = Zache.new
|
89
|
+
Threads.new(300).assert(3000) do
|
90
|
+
cache.get(:hey) { Random.rand }
|
91
|
+
cache.get(:bye, lifetime: 0.01) { Random.rand }
|
92
|
+
sleep 0.1
|
93
|
+
cache.clean
|
94
|
+
end
|
95
|
+
assert(cache.exists?(:hey) == true)
|
96
|
+
assert(cache.exists?(:bye) == false)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_clean
|
100
|
+
cache = Zache.new
|
101
|
+
cache.get(:hey) { Random.rand }
|
102
|
+
cache.get(:bye, lifetime: 0.01) { Random.rand }
|
103
|
+
sleep 0.1
|
104
|
+
cache.clean
|
105
|
+
assert(cache.exists?(:hey) == true)
|
106
|
+
assert(cache.exists?(:bye) == false)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_clean_with_sync_false
|
110
|
+
cache = Zache.new(sync: false)
|
111
|
+
cache.get(:hey) { Random.rand }
|
112
|
+
cache.get(:bye, lifetime: 0.01) { Random.rand }
|
113
|
+
sleep 0.1
|
114
|
+
cache.clean
|
115
|
+
assert(cache.exists?(:hey) == true)
|
116
|
+
assert(cache.exists?(:bye) == false)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_remove_absent_key
|
120
|
+
cache = Zache.new
|
121
|
+
cache.remove(:hey)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_check_and_remove
|
125
|
+
cache = Zache.new
|
126
|
+
cache.get(:hey, lifetime: 0) { Random.rand }
|
127
|
+
assert(!cache.exists?(:hey))
|
128
|
+
end
|
55
129
|
end
|
data/zache.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.rubygems_version = '2.3.3'
|
32
32
|
s.required_ruby_version = '>=2.3'
|
33
33
|
s.name = 'zache'
|
34
|
-
s.version = '0.
|
34
|
+
s.version = '0.3.0'
|
35
35
|
s.license = 'MIT'
|
36
36
|
s.summary = 'In-memory Cache'
|
37
37
|
s.description = 'Zero-footprint in-memory thread-safe cache'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|