mudis 0.8.1 → 0.9.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/README.md +11 -5
- data/lib/mudis/expiry.rb +53 -0
- data/lib/mudis/lru.rb +66 -0
- data/lib/mudis/metrics.rb +42 -0
- data/lib/mudis/namespace.rb +47 -0
- data/lib/mudis/persistence.rb +113 -0
- data/lib/mudis/version.rb +1 -1
- data/lib/mudis.rb +15 -285
- data/lib/mudis_client.rb +63 -21
- data/lib/mudis_ipc_config.rb +13 -0
- data/lib/mudis_proxy.rb +2 -0
- data/lib/mudis_server.rb +73 -54
- data/sig/mudis.rbs +6 -0
- data/sig/mudis_client.rbs +3 -1
- data/sig/mudis_expiry.rbs +13 -0
- data/sig/mudis_ipc_config.rbs +10 -0
- data/sig/mudis_lru.rbs +21 -0
- data/sig/mudis_metrics.rbs +11 -0
- data/sig/mudis_namespace.rbs +13 -0
- data/sig/mudis_persistence.rbs +19 -0
- data/sig/mudis_server.rbs +12 -2
- data/spec/api_compatibility_spec.rb +155 -0
- data/spec/modules/expiry_spec.rb +170 -0
- data/spec/modules/lru_spec.rb +149 -0
- data/spec/modules/metrics_spec.rb +105 -0
- data/spec/modules/namespace_spec.rb +157 -0
- data/spec/modules/persistence_spec.rb +125 -0
- data/spec/mudis_client_spec.rb +15 -5
- data/spec/mudis_server_spec.rb +23 -17
- metadata +46 -2
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Mudis::Namespace do
|
|
6
|
+
let(:test_class) do
|
|
7
|
+
Class.new do
|
|
8
|
+
extend Mudis::Namespace
|
|
9
|
+
|
|
10
|
+
@buckets = 2
|
|
11
|
+
@mutexes = Array.new(2) { Mutex.new }
|
|
12
|
+
@stores = [
|
|
13
|
+
{ "ns1:key1" => {}, "ns1:key2" => {}, "key3" => {} },
|
|
14
|
+
{ "ns2:key1" => {}, "other" => {} }
|
|
15
|
+
]
|
|
16
|
+
@lru_nodes = Array.new(2) { {} }
|
|
17
|
+
@current_bytes = Array.new(2, 0)
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
attr_accessor :buckets, :mutexes, :stores, :lru_nodes, :current_bytes
|
|
21
|
+
|
|
22
|
+
def all_keys
|
|
23
|
+
@stores.flat_map(&:keys)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def evict_key(idx, key)
|
|
27
|
+
@stores[idx].delete(key)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#keys" do
|
|
34
|
+
it "returns all keys for a given namespace" do
|
|
35
|
+
keys = test_class.keys(namespace: "ns1")
|
|
36
|
+
|
|
37
|
+
expect(keys).to contain_exactly("key1", "key2")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "returns empty array if no keys exist for namespace" do
|
|
41
|
+
keys = test_class.keys(namespace: "nonexistent")
|
|
42
|
+
|
|
43
|
+
expect(keys).to eq([])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "raises error if namespace is nil" do
|
|
47
|
+
expect { test_class.keys(namespace: nil) }.to raise_error(ArgumentError, "namespace is required")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "strips namespace prefix from returned keys" do
|
|
51
|
+
keys = test_class.keys(namespace: "ns2")
|
|
52
|
+
|
|
53
|
+
expect(keys).to eq(["key1"])
|
|
54
|
+
expect(keys).not_to include("ns2:key1")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "#clear_namespace" do
|
|
59
|
+
it "deletes all keys in a given namespace" do
|
|
60
|
+
test_class.clear_namespace(namespace: "ns1")
|
|
61
|
+
|
|
62
|
+
expect(test_class.stores[0]).not_to have_key("ns1:key1")
|
|
63
|
+
expect(test_class.stores[0]).not_to have_key("ns1:key2")
|
|
64
|
+
expect(test_class.stores[0]).to have_key("key3") # non-namespaced key remains
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "does nothing if namespace has no keys" do
|
|
68
|
+
expect { test_class.clear_namespace(namespace: "nonexistent") }.not_to raise_error
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "raises error if namespace is nil" do
|
|
72
|
+
expect { test_class.clear_namespace(namespace: nil) }.to raise_error(ArgumentError, "namespace is required")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "only deletes keys with exact namespace prefix" do
|
|
76
|
+
test_class.stores[0]["ns1_similar"] = {}
|
|
77
|
+
|
|
78
|
+
test_class.clear_namespace(namespace: "ns1")
|
|
79
|
+
|
|
80
|
+
expect(test_class.stores[0]).to have_key("ns1_similar")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "#with_namespace" do
|
|
85
|
+
it "sets thread-local namespace for the block" do
|
|
86
|
+
test_class.with_namespace("test_ns") do
|
|
87
|
+
expect(Thread.current[:mudis_namespace]).to eq("test_ns")
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "restores previous namespace after block" do
|
|
92
|
+
Thread.current[:mudis_namespace] = "original"
|
|
93
|
+
|
|
94
|
+
test_class.with_namespace("temporary") do
|
|
95
|
+
# inside block
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
expect(Thread.current[:mudis_namespace]).to eq("original")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "restores namespace even if block raises error" do
|
|
102
|
+
Thread.current[:mudis_namespace] = "original"
|
|
103
|
+
|
|
104
|
+
expect do
|
|
105
|
+
test_class.with_namespace("temporary") do
|
|
106
|
+
raise "test error"
|
|
107
|
+
end
|
|
108
|
+
end.to raise_error("test error")
|
|
109
|
+
|
|
110
|
+
expect(Thread.current[:mudis_namespace]).to eq("original")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "returns the block's return value" do
|
|
114
|
+
result = test_class.with_namespace("test") do
|
|
115
|
+
"block_result"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
expect(result).to eq("block_result")
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe "#namespaced_key (private)" do
|
|
123
|
+
it "prefixes key with namespace" do
|
|
124
|
+
result = test_class.send(:namespaced_key, "mykey", "mynamespace")
|
|
125
|
+
|
|
126
|
+
expect(result).to eq("mynamespace:mykey")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "returns unprefixed key when namespace is nil" do
|
|
130
|
+
Thread.current[:mudis_namespace] = nil
|
|
131
|
+
|
|
132
|
+
result = test_class.send(:namespaced_key, "mykey", nil)
|
|
133
|
+
|
|
134
|
+
expect(result).to eq("mykey")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "uses thread-local namespace when explicit namespace is nil" do
|
|
138
|
+
Thread.current[:mudis_namespace] = "thread_ns"
|
|
139
|
+
|
|
140
|
+
result = test_class.send(:namespaced_key, "mykey", nil)
|
|
141
|
+
|
|
142
|
+
expect(result).to eq("thread_ns:mykey")
|
|
143
|
+
ensure
|
|
144
|
+
Thread.current[:mudis_namespace] = nil
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "prefers explicit namespace over thread-local" do
|
|
148
|
+
Thread.current[:mudis_namespace] = "thread_ns"
|
|
149
|
+
|
|
150
|
+
result = test_class.send(:namespaced_key, "mykey", "explicit_ns")
|
|
151
|
+
|
|
152
|
+
expect(result).to eq("explicit_ns:mykey")
|
|
153
|
+
ensure
|
|
154
|
+
Thread.current[:mudis_namespace] = nil
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Mudis::Persistence do
|
|
6
|
+
let(:test_class) do
|
|
7
|
+
Class.new do
|
|
8
|
+
extend Mudis::Persistence
|
|
9
|
+
|
|
10
|
+
@persistence_enabled = true
|
|
11
|
+
@persistence_path = "tmp/test_persistence.json"
|
|
12
|
+
@persistence_format = :json
|
|
13
|
+
@persistence_safe_write = true
|
|
14
|
+
@buckets = 2
|
|
15
|
+
@mutexes = Array.new(2) { Mutex.new }
|
|
16
|
+
@stores = Array.new(2) { {} }
|
|
17
|
+
@lru_nodes = Array.new(2) { {} }
|
|
18
|
+
@lru_heads = Array.new(2) { nil }
|
|
19
|
+
@lru_tails = Array.new(2) { nil }
|
|
20
|
+
@current_bytes = Array.new(2, 0)
|
|
21
|
+
@compress = false
|
|
22
|
+
@serializer = JSON
|
|
23
|
+
|
|
24
|
+
class << self
|
|
25
|
+
attr_accessor :persistence_enabled, :persistence_path, :persistence_format,
|
|
26
|
+
:persistence_safe_write, :buckets, :mutexes, :stores, :compress, :serializer
|
|
27
|
+
|
|
28
|
+
def decompress_and_deserialize(raw)
|
|
29
|
+
JSON.load(raw)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def write(key, value, expires_in: nil)
|
|
33
|
+
# Stub write method
|
|
34
|
+
@stores[0][key] = { value: JSON.dump(value), expires_at: nil, created_at: Time.now }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
after do
|
|
41
|
+
File.unlink(test_class.persistence_path) if File.exist?(test_class.persistence_path)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe "#save_snapshot!" do
|
|
45
|
+
it "saves cache data to disk" do
|
|
46
|
+
test_class.stores[0]["key1"] = {
|
|
47
|
+
value: JSON.dump("value1"),
|
|
48
|
+
expires_at: nil,
|
|
49
|
+
created_at: Time.now
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
test_class.save_snapshot!
|
|
53
|
+
|
|
54
|
+
expect(File.exist?(test_class.persistence_path)).to be true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "handles errors gracefully" do
|
|
58
|
+
allow(test_class).to receive(:snapshot_dump).and_raise("Test error")
|
|
59
|
+
|
|
60
|
+
expect { test_class.save_snapshot! }.to output(/Failed to save snapshot/).to_stderr
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "does nothing when persistence is disabled" do
|
|
64
|
+
test_class.persistence_enabled = false
|
|
65
|
+
|
|
66
|
+
test_class.save_snapshot!
|
|
67
|
+
|
|
68
|
+
expect(File.exist?(test_class.persistence_path)).to be false
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "#load_snapshot!" do
|
|
73
|
+
it "loads cache data from disk" do
|
|
74
|
+
data = [{ key: "test_key", value: "test_value", expires_in: nil }]
|
|
75
|
+
File.write(test_class.persistence_path, JSON.dump(data))
|
|
76
|
+
|
|
77
|
+
expect(test_class).to receive(:write).with("test_key", "test_value", expires_in: nil)
|
|
78
|
+
|
|
79
|
+
test_class.load_snapshot!
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "handles missing file gracefully" do
|
|
83
|
+
expect { test_class.load_snapshot! }.not_to raise_error
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "handles errors gracefully" do
|
|
87
|
+
File.write(test_class.persistence_path, "invalid json")
|
|
88
|
+
|
|
89
|
+
expect { test_class.load_snapshot! }.to output(/Failed to load snapshot/).to_stderr
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "does nothing when persistence is disabled" do
|
|
93
|
+
test_class.persistence_enabled = false
|
|
94
|
+
File.write(test_class.persistence_path, JSON.dump([]))
|
|
95
|
+
|
|
96
|
+
expect(test_class).not_to receive(:write)
|
|
97
|
+
|
|
98
|
+
test_class.load_snapshot!
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "#install_persistence_hook!" do
|
|
103
|
+
it "installs at_exit hook" do
|
|
104
|
+
expect(test_class).to receive(:at_exit)
|
|
105
|
+
|
|
106
|
+
test_class.install_persistence_hook!
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "only installs hook once" do
|
|
110
|
+
test_class.install_persistence_hook!
|
|
111
|
+
|
|
112
|
+
expect(test_class).not_to receive(:at_exit)
|
|
113
|
+
|
|
114
|
+
test_class.install_persistence_hook!
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "does nothing when persistence is disabled" do
|
|
118
|
+
test_class.persistence_enabled = false
|
|
119
|
+
|
|
120
|
+
expect(test_class).not_to receive(:at_exit)
|
|
121
|
+
|
|
122
|
+
test_class.install_persistence_hook!
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
data/spec/mudis_client_spec.rb
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
require_relative "spec_helper"
|
|
4
4
|
|
|
5
5
|
RSpec.describe MudisClient do # rubocop:disable Metrics/BlockLength
|
|
6
|
-
let(:socket_path) {
|
|
7
|
-
let(:
|
|
6
|
+
let(:socket_path) { MudisIPCConfig::SOCKET_PATH }
|
|
7
|
+
let(:socket_class) { MudisIPCConfig.use_tcp? ? TCPSocket : UNIXSocket }
|
|
8
|
+
let(:mock_socket) { instance_double(socket_class) }
|
|
8
9
|
let(:client) { MudisClient.new }
|
|
9
10
|
|
|
10
11
|
around do |example|
|
|
@@ -14,7 +15,12 @@ RSpec.describe MudisClient do # rubocop:disable Metrics/BlockLength
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
before do
|
|
17
|
-
|
|
18
|
+
if MudisIPCConfig.use_tcp?
|
|
19
|
+
allow(TCPSocket).to receive(:new).and_return(mock_socket)
|
|
20
|
+
else
|
|
21
|
+
allow(UNIXSocket).to receive(:open).and_yield(mock_socket)
|
|
22
|
+
end
|
|
23
|
+
allow(mock_socket).to receive(:close)
|
|
18
24
|
end
|
|
19
25
|
|
|
20
26
|
describe "#read" do
|
|
@@ -119,9 +125,13 @@ RSpec.describe MudisClient do # rubocop:disable Metrics/BlockLength
|
|
|
119
125
|
|
|
120
126
|
describe "error handling" do
|
|
121
127
|
it "warns when the socket is missing" do
|
|
122
|
-
|
|
128
|
+
if MudisIPCConfig.use_tcp?
|
|
129
|
+
allow(TCPSocket).to receive(:new).and_raise(Errno::ECONNREFUSED)
|
|
130
|
+
else
|
|
131
|
+
allow(UNIXSocket).to receive(:open).and_raise(Errno::ENOENT)
|
|
132
|
+
end
|
|
123
133
|
|
|
124
|
-
expect { client.read("test_key") }.to output(/
|
|
134
|
+
expect { client.read("test_key") }.to output(/Cannot connect/).to_stderr
|
|
125
135
|
expect(client.read("test_key")).to be_nil
|
|
126
136
|
end
|
|
127
137
|
|
data/spec/mudis_server_spec.rb
CHANGED
|
@@ -6,13 +6,15 @@ require "json"
|
|
|
6
6
|
require_relative "spec_helper"
|
|
7
7
|
|
|
8
8
|
RSpec.describe MudisServer do # rubocop:disable Metrics/BlockLength
|
|
9
|
+
let(:socket_path) { MudisIPCConfig::SOCKET_PATH }
|
|
10
|
+
|
|
9
11
|
before(:all) do
|
|
10
|
-
|
|
12
|
+
# Start the server once for all tests
|
|
13
|
+
Thread.new { MudisServer.start! }
|
|
14
|
+
sleep 0.2 # Allow the server to start
|
|
11
15
|
end
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
before do
|
|
17
|
+
before(:each) do
|
|
16
18
|
allow(Mudis).to receive(:read).and_return("mock_value")
|
|
17
19
|
allow(Mudis).to receive(:write)
|
|
18
20
|
allow(Mudis).to receive(:delete)
|
|
@@ -21,20 +23,23 @@ RSpec.describe MudisServer do # rubocop:disable Metrics/BlockLength
|
|
|
21
23
|
allow(Mudis).to receive(:metrics).and_return({ reads: 1, writes: 1 })
|
|
22
24
|
allow(Mudis).to receive(:reset_metrics!)
|
|
23
25
|
allow(Mudis).to receive(:reset!)
|
|
24
|
-
|
|
25
|
-
# Start the server in a separate thread
|
|
26
|
-
Thread.new { MudisServer.start! }
|
|
27
|
-
sleep 0.1 # Allow the server to start
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
after do
|
|
31
|
-
File.unlink(socket_path) if File.exist?(socket_path)
|
|
29
|
+
File.unlink(socket_path) if File.exist?(socket_path) && !MudisIPCConfig.use_tcp?
|
|
32
30
|
end
|
|
33
31
|
|
|
34
32
|
def send_request(request)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
if MudisIPCConfig.use_tcp?
|
|
34
|
+
TCPSocket.open(MudisIPCConfig::TCP_HOST, MudisIPCConfig::TCP_PORT) do |sock|
|
|
35
|
+
sock.puts(JSON.dump(request))
|
|
36
|
+
JSON.parse(sock.gets, symbolize_names: true)
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
UNIXSocket.open(socket_path) do |sock|
|
|
40
|
+
sock.puts(JSON.dump(request))
|
|
41
|
+
JSON.parse(sock.gets, symbolize_names: true)
|
|
42
|
+
end
|
|
38
43
|
end
|
|
39
44
|
end
|
|
40
45
|
|
|
@@ -46,13 +51,13 @@ RSpec.describe MudisServer do # rubocop:disable Metrics/BlockLength
|
|
|
46
51
|
|
|
47
52
|
it "handles the 'write' command" do
|
|
48
53
|
response = send_request({ cmd: "write", key: "test_key", value: "test_value", ttl: 60, namespace: "test_ns" })
|
|
49
|
-
expect(response).to eq({ ok: true })
|
|
54
|
+
expect(response).to eq({ ok: true, value: nil })
|
|
50
55
|
expect(Mudis).to have_received(:write).with("test_key", "test_value", expires_in: 60, namespace: "test_ns")
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
it "handles the 'delete' command" do
|
|
54
59
|
response = send_request({ cmd: "delete", key: "test_key", namespace: "test_ns" })
|
|
55
|
-
expect(response).to eq({ ok: true })
|
|
60
|
+
expect(response).to eq({ ok: true, value: nil })
|
|
56
61
|
expect(Mudis).to have_received(:delete).with("test_key", namespace: "test_ns")
|
|
57
62
|
end
|
|
58
63
|
|
|
@@ -77,18 +82,19 @@ RSpec.describe MudisServer do # rubocop:disable Metrics/BlockLength
|
|
|
77
82
|
|
|
78
83
|
it "handles the 'reset_metrics' command" do
|
|
79
84
|
response = send_request({ cmd: "reset_metrics" })
|
|
80
|
-
expect(response).to eq({ ok: true })
|
|
85
|
+
expect(response).to eq({ ok: true, value: nil })
|
|
81
86
|
expect(Mudis).to have_received(:reset_metrics!)
|
|
82
87
|
end
|
|
83
88
|
|
|
84
89
|
it "handles the 'reset' command" do
|
|
85
90
|
response = send_request({ cmd: "reset" })
|
|
86
|
-
expect(response).to eq({ ok: true })
|
|
91
|
+
expect(response).to eq({ ok: true, value: nil })
|
|
87
92
|
expect(Mudis).to have_received(:reset!)
|
|
88
93
|
end
|
|
89
94
|
|
|
90
95
|
it "handles unknown commands" do
|
|
91
96
|
response = send_request({ cmd: "unknown_command" })
|
|
92
|
-
expect(response).to
|
|
97
|
+
expect(response[:ok]).to be false
|
|
98
|
+
expect(response[:error]).to match(/unknown command/i)
|
|
93
99
|
end
|
|
94
100
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mudis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kiebor81
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-12-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: climate_control
|
|
@@ -38,6 +38,20 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '3.12'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: simplecov
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.22'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.22'
|
|
41
55
|
description: Mudis is a fast, thread-safe, in-memory, sharded LRU cache for Ruby applications.
|
|
42
56
|
Inspired by Redis, it provides value serialization, optional compression, per-key
|
|
43
57
|
expiry, and metric tracking in a lightweight, dependency-free package.
|
|
@@ -48,23 +62,47 @@ extra_rdoc_files:
|
|
|
48
62
|
- sig/mudis.rbs
|
|
49
63
|
- sig/mudis_client.rbs
|
|
50
64
|
- sig/mudis_config.rbs
|
|
65
|
+
- sig/mudis_expiry.rbs
|
|
66
|
+
- sig/mudis_ipc_config.rbs
|
|
67
|
+
- sig/mudis_lru.rbs
|
|
68
|
+
- sig/mudis_metrics.rbs
|
|
69
|
+
- sig/mudis_namespace.rbs
|
|
70
|
+
- sig/mudis_persistence.rbs
|
|
51
71
|
- sig/mudis_server.rbs
|
|
52
72
|
files:
|
|
53
73
|
- README.md
|
|
54
74
|
- lib/mudis.rb
|
|
75
|
+
- lib/mudis/expiry.rb
|
|
76
|
+
- lib/mudis/lru.rb
|
|
77
|
+
- lib/mudis/metrics.rb
|
|
78
|
+
- lib/mudis/namespace.rb
|
|
79
|
+
- lib/mudis/persistence.rb
|
|
55
80
|
- lib/mudis/version.rb
|
|
56
81
|
- lib/mudis_client.rb
|
|
57
82
|
- lib/mudis_config.rb
|
|
83
|
+
- lib/mudis_ipc_config.rb
|
|
58
84
|
- lib/mudis_proxy.rb
|
|
59
85
|
- lib/mudis_server.rb
|
|
60
86
|
- sig/mudis.rbs
|
|
61
87
|
- sig/mudis_client.rbs
|
|
62
88
|
- sig/mudis_config.rbs
|
|
89
|
+
- sig/mudis_expiry.rbs
|
|
90
|
+
- sig/mudis_ipc_config.rbs
|
|
91
|
+
- sig/mudis_lru.rbs
|
|
92
|
+
- sig/mudis_metrics.rbs
|
|
93
|
+
- sig/mudis_namespace.rbs
|
|
94
|
+
- sig/mudis_persistence.rbs
|
|
63
95
|
- sig/mudis_server.rbs
|
|
96
|
+
- spec/api_compatibility_spec.rb
|
|
64
97
|
- spec/eviction_spec.rb
|
|
65
98
|
- spec/guardrails_spec.rb
|
|
66
99
|
- spec/memory_guard_spec.rb
|
|
67
100
|
- spec/metrics_spec.rb
|
|
101
|
+
- spec/modules/expiry_spec.rb
|
|
102
|
+
- spec/modules/lru_spec.rb
|
|
103
|
+
- spec/modules/metrics_spec.rb
|
|
104
|
+
- spec/modules/namespace_spec.rb
|
|
105
|
+
- spec/modules/persistence_spec.rb
|
|
68
106
|
- spec/mudis_client_spec.rb
|
|
69
107
|
- spec/mudis_server_spec.rb
|
|
70
108
|
- spec/mudis_spec.rb
|
|
@@ -96,10 +134,16 @@ specification_version: 4
|
|
|
96
134
|
summary: A fast in-memory, thread-safe and high performance Ruby LRU cache with compression
|
|
97
135
|
and auto-expiry.
|
|
98
136
|
test_files:
|
|
137
|
+
- spec/api_compatibility_spec.rb
|
|
99
138
|
- spec/eviction_spec.rb
|
|
100
139
|
- spec/guardrails_spec.rb
|
|
101
140
|
- spec/memory_guard_spec.rb
|
|
102
141
|
- spec/metrics_spec.rb
|
|
142
|
+
- spec/modules/expiry_spec.rb
|
|
143
|
+
- spec/modules/lru_spec.rb
|
|
144
|
+
- spec/modules/metrics_spec.rb
|
|
145
|
+
- spec/modules/namespace_spec.rb
|
|
146
|
+
- spec/modules/persistence_spec.rb
|
|
103
147
|
- spec/mudis_client_spec.rb
|
|
104
148
|
- spec/mudis_server_spec.rb
|
|
105
149
|
- spec/mudis_spec.rb
|