mudis 0.8.0 → 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.
data/sig/mudis_client.rbs CHANGED
@@ -1,23 +1,25 @@
1
- class MudisClient
2
- SOCKET_PATH: String
3
-
4
- def initialize: () -> void
5
-
6
- def request: (payload: { cmd: String, key?: String, value?: untyped, ttl?: Integer?, namespace?: String? }) -> untyped
7
-
8
- def read: (key: String, namespace?: String?) -> untyped
9
-
10
- def write: (key: String, value: untyped, expires_in?: Integer?, namespace?: String?) -> untyped
11
-
12
- def delete: (key: String, namespace?: String?) -> untyped
13
-
14
- def exists?: (key: String, namespace?: String?) -> bool
15
-
16
- def fetch: (key: String, expires_in?: Integer?, namespace?: String?, &block: { () -> untyped }) -> untyped
17
-
18
- def metrics: () -> { reads: Integer, writes: Integer, deletes: Integer, exists: Integer }
19
-
20
- def reset_metrics!: () -> void
21
-
22
- def reset!: () -> void
1
+ class MudisClient
2
+ include MudisIPCConfig
3
+
4
+ def initialize: () -> void
5
+
6
+ def open_connection: () -> (TCPSocket | UNIXSocket)
7
+
8
+ def request: (payload: { cmd: String, key?: String, value?: untyped, ttl?: Integer?, namespace?: String? }) -> untyped
9
+
10
+ def read: (key: String, namespace?: String?) -> untyped
11
+
12
+ def write: (key: String, value: untyped, expires_in?: Integer?, namespace?: String?) -> untyped
13
+
14
+ def delete: (key: String, namespace?: String?) -> untyped
15
+
16
+ def exists?: (key: String, namespace?: String?) -> bool
17
+
18
+ def fetch: (key: String, expires_in?: Integer?, namespace?: String?, &block: { () -> untyped }) -> untyped
19
+
20
+ def metrics: () -> { reads: Integer, writes: Integer, deletes: Integer, exists: Integer }
21
+
22
+ def reset_metrics!: () -> void
23
+
24
+ def reset!: () -> void
23
25
  end
data/sig/mudis_config.rbs CHANGED
@@ -1,10 +1,10 @@
1
- class MudisConfig
2
- attr_accessor serializer: Object
3
- attr_accessor compress: bool
4
- attr_accessor max_value_bytes: Integer?
5
- attr_accessor hard_memory_limit: bool
6
- attr_accessor max_bytes: Integer
7
- attr_accessor max_ttl: Integer?
8
- attr_accessor default_ttl: Integer?
9
- attr_accessor buckets: Integer?
10
- end
1
+ class MudisConfig
2
+ attr_accessor serializer: Object
3
+ attr_accessor compress: bool
4
+ attr_accessor max_value_bytes: Integer?
5
+ attr_accessor hard_memory_limit: bool
6
+ attr_accessor max_bytes: Integer
7
+ attr_accessor max_ttl: Integer?
8
+ attr_accessor default_ttl: Integer?
9
+ attr_accessor buckets: Integer?
10
+ end
@@ -0,0 +1,13 @@
1
+ class Mudis
2
+ module Expiry
3
+ def start_expiry_thread: (?interval: Integer) -> void
4
+
5
+ def stop_expiry_thread: () -> void
6
+
7
+ def cleanup_expired!: () -> void
8
+
9
+ private
10
+
11
+ def effective_ttl: (?expires_in: Integer?) -> Integer?
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # Shared configuration for IPC mode (server and client)
2
+ module MudisIPCConfig
3
+ SOCKET_PATH: String
4
+
5
+ TCP_HOST: String
6
+
7
+ TCP_PORT: Integer
8
+
9
+ def self.use_tcp?: () -> bool
10
+ end
data/sig/mudis_lru.rbs ADDED
@@ -0,0 +1,21 @@
1
+ class Mudis
2
+ class LRUNode
3
+ attr_accessor key: String
4
+ attr_accessor prev: LRUNode?
5
+ attr_accessor next: LRUNode?
6
+
7
+ def initialize: (String) -> void
8
+ end
9
+
10
+ module LRU
11
+ private
12
+
13
+ def evict_key: (Integer, String) -> void
14
+
15
+ def insert_lru: (Integer, LRUNode) -> void
16
+
17
+ def promote_lru: (Integer, String) -> void
18
+
19
+ def remove_node: (Integer, LRUNode) -> void
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ class Mudis
2
+ module Metrics
3
+ def metrics: () -> Hash[Symbol, untyped]
4
+
5
+ def reset_metrics!: () -> void
6
+
7
+ private
8
+
9
+ def metric: (Symbol) -> void
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ class Mudis
2
+ module Namespace
3
+ def keys: (namespace: String) -> Array[String]
4
+
5
+ def clear_namespace: (namespace: String) -> void
6
+
7
+ def with_namespace: (namespace: String) { () -> untyped } -> untyped
8
+
9
+ private
10
+
11
+ def namespaced_key: (String, ?namespace: String?) -> String
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ class Mudis
2
+ module Persistence
3
+ def save_snapshot!: () -> void
4
+
5
+ def load_snapshot!: () -> void
6
+
7
+ def install_persistence_hook!: () -> void
8
+
9
+ private
10
+
11
+ def snapshot_dump: () -> Hash[String, untyped]
12
+
13
+ def snapshot_restore: (Hash[String, untyped]) -> void
14
+
15
+ def safe_write_snapshot: (Hash[String, untyped]) -> void
16
+
17
+ def read_snapshot: () -> Hash[String, untyped]
18
+ end
19
+ end
data/sig/mudis_server.rbs CHANGED
@@ -1,7 +1,17 @@
1
- class MudisServer
2
- SOCKET_PATH: String
3
-
4
- def self.start!: () -> void
5
-
6
- def self.handle_client: (sock: UNIXSocket) -> void
1
+ class MudisServer
2
+ include MudisIPCConfig
3
+
4
+ def self.start!: () -> void
5
+
6
+ def self.start_tcp_server!: () -> void
7
+
8
+ def self.start_unix_server!: () -> void
9
+
10
+ def self.accept_connections: (server: (TCPServer | UNIXServer)) -> void
11
+
12
+ def self.handle_client: (socket: (TCPSocket | UNIXSocket)) -> void
13
+
14
+ def self.process_request: (req: Hash[String, untyped]) -> Hash[Symbol, untyped]
15
+
16
+ def self.write_response: (socket: (TCPSocket | UNIXSocket), payload: Hash[Symbol, untyped]) -> void
7
17
  end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "spec_helper"
4
+
5
+ RSpec.describe "Mudis Public API" do
6
+ describe "ensures no breaking changes" do
7
+ it "exposes all core cache operations" do
8
+ expect(Mudis).to respond_to(:read)
9
+ expect(Mudis).to respond_to(:write)
10
+ expect(Mudis).to respond_to(:delete)
11
+ expect(Mudis).to respond_to(:exists?)
12
+ expect(Mudis).to respond_to(:update)
13
+ expect(Mudis).to respond_to(:fetch)
14
+ expect(Mudis).to respond_to(:clear)
15
+ expect(Mudis).to respond_to(:replace)
16
+ expect(Mudis).to respond_to(:inspect)
17
+ end
18
+
19
+ it "exposes all configuration methods" do
20
+ expect(Mudis).to respond_to(:configure)
21
+ expect(Mudis).to respond_to(:config)
22
+ expect(Mudis).to respond_to(:serializer)
23
+ expect(Mudis).to respond_to(:serializer=)
24
+ expect(Mudis).to respond_to(:compress)
25
+ expect(Mudis).to respond_to(:compress=)
26
+ expect(Mudis).to respond_to(:max_bytes)
27
+ expect(Mudis).to respond_to(:max_bytes=)
28
+ expect(Mudis).to respond_to(:max_value_bytes)
29
+ expect(Mudis).to respond_to(:max_value_bytes=)
30
+ expect(Mudis).to respond_to(:hard_memory_limit)
31
+ expect(Mudis).to respond_to(:hard_memory_limit=)
32
+ expect(Mudis).to respond_to(:max_ttl)
33
+ expect(Mudis).to respond_to(:max_ttl=)
34
+ expect(Mudis).to respond_to(:default_ttl)
35
+ expect(Mudis).to respond_to(:default_ttl=)
36
+ end
37
+
38
+ it "exposes all metrics methods" do
39
+ expect(Mudis).to respond_to(:metrics)
40
+ expect(Mudis).to respond_to(:reset_metrics!)
41
+ end
42
+
43
+ it "exposes all expiry methods" do
44
+ expect(Mudis).to respond_to(:start_expiry_thread)
45
+ expect(Mudis).to respond_to(:stop_expiry_thread)
46
+ expect(Mudis).to respond_to(:cleanup_expired!)
47
+ end
48
+
49
+ it "exposes all namespace methods" do
50
+ expect(Mudis).to respond_to(:keys)
51
+ expect(Mudis).to respond_to(:clear_namespace)
52
+ expect(Mudis).to respond_to(:with_namespace)
53
+ end
54
+
55
+ it "exposes all persistence methods" do
56
+ expect(Mudis).to respond_to(:save_snapshot!)
57
+ expect(Mudis).to respond_to(:load_snapshot!)
58
+ end
59
+
60
+ it "exposes all utility methods" do
61
+ expect(Mudis).to respond_to(:reset!)
62
+ expect(Mudis).to respond_to(:all_keys)
63
+ expect(Mudis).to respond_to(:current_memory_bytes)
64
+ expect(Mudis).to respond_to(:max_memory_bytes)
65
+ expect(Mudis).to respond_to(:least_touched)
66
+ expect(Mudis).to respond_to(:buckets)
67
+ end
68
+
69
+ it "maintains backward compatibility with method signatures" do
70
+ # Core operations accept namespace parameter
71
+ expect(Mudis.method(:read).parameters).to include([:key, :namespace])
72
+ expect(Mudis.method(:write).parameters).to include([:key, :namespace])
73
+ expect(Mudis.method(:delete).parameters).to include([:key, :namespace])
74
+ expect(Mudis.method(:exists?).parameters).to include([:key, :namespace])
75
+
76
+ # Fetch accepts expires_in, force, and namespace
77
+ expect(Mudis.method(:fetch).parameters).to include([:key, :expires_in])
78
+ expect(Mudis.method(:fetch).parameters).to include([:key, :force])
79
+ expect(Mudis.method(:fetch).parameters).to include([:key, :namespace])
80
+ end
81
+
82
+ it "verifies LRUNode class is still accessible" do
83
+ expect(defined?(Mudis::LRUNode)).to be_truthy
84
+ node = Mudis::LRUNode.new("test_key")
85
+ expect(node).to respond_to(:key)
86
+ expect(node).to respond_to(:prev)
87
+ expect(node).to respond_to(:next)
88
+ end
89
+
90
+ it "verifies all public methods work correctly" do
91
+ Mudis.reset!
92
+
93
+ # Write and read
94
+ Mudis.write("test", "value")
95
+ expect(Mudis.read("test")).to eq("value")
96
+
97
+ # Exists
98
+ expect(Mudis.exists?("test")).to be true
99
+
100
+ # Update
101
+ Mudis.update("test") { |v| v.upcase }
102
+ expect(Mudis.read("test")).to eq("VALUE")
103
+
104
+ # Fetch
105
+ result = Mudis.fetch("new_key") { "new_value" }
106
+ expect(result).to eq("new_value")
107
+
108
+ # Replace
109
+ Mudis.replace("test", "replaced")
110
+ expect(Mudis.read("test")).to eq("replaced")
111
+
112
+ # Inspect
113
+ meta = Mudis.inspect("test")
114
+ expect(meta).to include(:key, :bucket, :created_at, :size_bytes)
115
+
116
+ # Namespace operations
117
+ Mudis.write("k1", "v1", namespace: "ns1")
118
+ expect(Mudis.keys(namespace: "ns1")).to include("k1")
119
+
120
+ Mudis.with_namespace("ns2") do
121
+ Mudis.write("k2", "v2")
122
+ end
123
+ expect(Mudis.keys(namespace: "ns2")).to include("k2")
124
+
125
+ # Clear namespace
126
+ Mudis.clear_namespace(namespace: "ns1")
127
+ expect(Mudis.keys(namespace: "ns1")).to be_empty
128
+
129
+ # Metrics
130
+ metrics = Mudis.metrics
131
+ expect(metrics).to include(:hits, :misses, :evictions, :total_memory, :buckets)
132
+
133
+ # Least touched
134
+ touched = Mudis.least_touched(5)
135
+ expect(touched).to be_an(Array)
136
+
137
+ # All keys
138
+ keys = Mudis.all_keys
139
+ expect(keys).to be_an(Array)
140
+
141
+ # Memory tracking
142
+ expect(Mudis.current_memory_bytes).to be > 0
143
+ expect(Mudis.max_memory_bytes).to be > 0
144
+
145
+ # Delete
146
+ Mudis.delete("test")
147
+ expect(Mudis.exists?("test")).to be false
148
+
149
+ # Clear (alias for delete)
150
+ Mudis.write("to_clear", "value")
151
+ Mudis.clear("to_clear")
152
+ expect(Mudis.exists?("to_clear")).to be false
153
+ end
154
+ end
155
+ end
@@ -1,29 +1,29 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Mudis LRU Eviction" do
6
- before do
7
- Mudis.reset!
8
- Mudis.stop_expiry_thread
9
-
10
- Mudis.instance_variable_set(:@buckets, 1)
11
- Mudis.instance_variable_set(:@stores, [{}])
12
- Mudis.instance_variable_set(:@mutexes, [Mutex.new])
13
- Mudis.instance_variable_set(:@lru_heads, [nil])
14
- Mudis.instance_variable_set(:@lru_tails, [nil])
15
- Mudis.instance_variable_set(:@lru_nodes, [{}])
16
- Mudis.instance_variable_set(:@current_bytes, [0])
17
- Mudis.hard_memory_limit = false
18
- Mudis.instance_variable_set(:@threshold_bytes, 60)
19
- Mudis.max_value_bytes = 100
20
- end
21
-
22
- it "evicts old entries when size limit is reached" do
23
- Mudis.write("a", "a" * 50)
24
- Mudis.write("b", "b" * 50)
25
-
26
- expect(Mudis.read("a")).to be_nil
27
- expect(Mudis.read("b")).not_to be_nil
28
- end
29
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Mudis LRU Eviction" do
6
+ before do
7
+ Mudis.reset!
8
+ Mudis.stop_expiry_thread
9
+
10
+ Mudis.instance_variable_set(:@buckets, 1)
11
+ Mudis.instance_variable_set(:@stores, [{}])
12
+ Mudis.instance_variable_set(:@mutexes, [Mutex.new])
13
+ Mudis.instance_variable_set(:@lru_heads, [nil])
14
+ Mudis.instance_variable_set(:@lru_tails, [nil])
15
+ Mudis.instance_variable_set(:@lru_nodes, [{}])
16
+ Mudis.instance_variable_set(:@current_bytes, [0])
17
+ Mudis.hard_memory_limit = false
18
+ Mudis.instance_variable_set(:@threshold_bytes, 60)
19
+ Mudis.max_value_bytes = 100
20
+ end
21
+
22
+ it "evicts old entries when size limit is reached" do
23
+ Mudis.write("a", "a" * 50)
24
+ Mudis.write("b", "b" * 50)
25
+
26
+ expect(Mudis.read("a")).to be_nil
27
+ expect(Mudis.read("b")).not_to be_nil
28
+ end
29
+ end