zache 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![EO principles respected here](http://www.elegantobjects.org/badge.svg)](http://www.elegantobjects.org)
|
1
2
|
[![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/zache)](http://www.rultor.com/p/yegor256/zache)
|
2
3
|
[![We recommend RubyMine](http://www.elegantobjects.org/rubymine.svg)](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
|