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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 186b5dcd33ca13d027053e477dc378e8cd203d96e43257f591d8537d8b665c17
4
- data.tar.gz: c39d96fefe90f9b481bbd6acd49ac4d2cd7cd675d83462b53895a8fc2ef1f49a
3
+ metadata.gz: 8ad9aee02e0592400be73acb02cdf8878c314950df90fce1632ea00e7d07d396
4
+ data.tar.gz: 802eba8bf8ad6e027b17d85eb296957b0255fde72e9340713bad5b0b96e4dd67
5
5
  SHA512:
6
- metadata.gz: fd75a39fa850377dc87c9f6658e6bd03f49304a7b167ff6b6e59ba676ca6a6b727333a1cc83248fcd9b45dd3ad118911e092de60991d4fd4ed8c35a700a80dcc
7
- data.tar.gz: 110ad00c04c2d65c65bf9c875dd21c9b9e3254412eae28766cf53be3cad07ebe9e81a09de881f0aec1d2747fcf35ca0f461503bcc2a5c47dacd1f35dc29c47f3
6
+ metadata.gz: c756d6ba076c41371f3c47d1d2f825f06876ea9dea1d39a86f1d7f5f6b93a87d077427af2726e4dc211248e416b02dba26a130a54b1a40e74eeb8f3e64b982bc
7
+ data.tar.gz: af8e41d5048f8afa5275362d3e23da9b9276c6277f7f0db33d0353e40bac2e4223806da97f612621b5b587e9f8c964aa737310696a76b9829f242ec543b6fae1
data/.rultor.yml CHANGED
@@ -20,4 +20,7 @@ architect:
20
20
  - yegor256
21
21
  merge:
22
22
  commanders: []
23
+ script: |-
24
+ bundle install
25
+ rake
23
26
  deploy: {}
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
- # Cache.
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 !rec.nil? && rec[:start] < Time.now - rec[:lifetime]
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.2.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.2.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-01 00:00:00.000000000 Z
11
+ date: 2018-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest