mudis 0.6.0 → 0.7.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.
@@ -1,33 +1,33 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Mudis Memory Guardrails" do
6
- before do
7
- Mudis.reset!
8
- Mudis.stop_expiry_thread
9
- Mudis.instance_variable_set(:@buckets, 1)
10
- Mudis.instance_variable_set(:@stores, [{}])
11
- Mudis.instance_variable_set(:@mutexes, [Mutex.new])
12
- Mudis.instance_variable_set(:@lru_heads, [nil])
13
- Mudis.instance_variable_set(:@lru_tails, [nil])
14
- Mudis.instance_variable_set(:@lru_nodes, [{}])
15
- Mudis.instance_variable_set(:@current_bytes, [0])
16
-
17
- Mudis.max_value_bytes = nil
18
- Mudis.instance_variable_set(:@threshold_bytes, 1_000_000)
19
- Mudis.hard_memory_limit = true
20
- Mudis.instance_variable_set(:@max_bytes, 100)
21
- end
22
-
23
- it "rejects writes that exceed max memory" do
24
- big_value = "a" * 90
25
- Mudis.write("a", big_value)
26
- expect(Mudis.read("a")).to eq(big_value)
27
-
28
- big_value2 = "b" * 90
29
- Mudis.write("b", big_value2)
30
- expect(Mudis.read("b")).to be_nil
31
- expect(Mudis.metrics[:rejected]).to be > 0
32
- end
33
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Mudis Memory Guardrails" do
6
+ before do
7
+ Mudis.reset!
8
+ Mudis.stop_expiry_thread
9
+ Mudis.instance_variable_set(:@buckets, 1)
10
+ Mudis.instance_variable_set(:@stores, [{}])
11
+ Mudis.instance_variable_set(:@mutexes, [Mutex.new])
12
+ Mudis.instance_variable_set(:@lru_heads, [nil])
13
+ Mudis.instance_variable_set(:@lru_tails, [nil])
14
+ Mudis.instance_variable_set(:@lru_nodes, [{}])
15
+ Mudis.instance_variable_set(:@current_bytes, [0])
16
+
17
+ Mudis.max_value_bytes = nil
18
+ Mudis.instance_variable_set(:@threshold_bytes, 1_000_000)
19
+ Mudis.hard_memory_limit = true
20
+ Mudis.instance_variable_set(:@max_bytes, 100)
21
+ end
22
+
23
+ it "rejects writes that exceed max memory" do
24
+ big_value = "a" * 90
25
+ Mudis.write("a", big_value)
26
+ expect(Mudis.read("a")).to eq(big_value)
27
+
28
+ big_value2 = "b" * 90
29
+ Mudis.write("b", big_value2)
30
+ expect(Mudis.read("b")).to be_nil
31
+ expect(Mudis.metrics[:rejected]).to be > 0
32
+ end
33
+ end
data/spec/metrics_spec.rb CHANGED
@@ -1,34 +1,34 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "spec_helper"
4
-
5
- RSpec.describe "Mudis Metrics" do # rubocop:disable Metrics/BlockLength
6
- it "tracks hits and misses" do
7
- Mudis.write("hit_me", "value")
8
- Mudis.read("hit_me")
9
- Mudis.read("miss_me")
10
- metrics = Mudis.metrics
11
- expect(metrics[:hits]).to eq(1)
12
- expect(metrics[:misses]).to eq(1)
13
- end
14
-
15
- it "includes per-bucket stats" do
16
- Mudis.write("a", "x" * 50)
17
- metrics = Mudis.metrics
18
- expect(metrics).to include(:buckets)
19
- expect(metrics[:buckets]).to be_an(Array)
20
- expect(metrics[:buckets].first).to include(:index, :keys, :memory_bytes, :lru_size)
21
- end
22
-
23
- it "resets only the metrics without clearing cache" do
24
- Mudis.write("metrics_key", "value")
25
- Mudis.read("metrics_key")
26
- Mudis.read("missing_key")
27
- expect(Mudis.metrics[:hits]).to eq(1)
28
- expect(Mudis.metrics[:misses]).to eq(1)
29
- Mudis.reset_metrics!
30
- expect(Mudis.metrics[:hits]).to eq(0)
31
- expect(Mudis.metrics[:misses]).to eq(0)
32
- expect(Mudis.read("metrics_key")).to eq("value")
33
- end
34
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "spec_helper"
4
+
5
+ RSpec.describe "Mudis Metrics" do # rubocop:disable Metrics/BlockLength
6
+ it "tracks hits and misses" do
7
+ Mudis.write("hit_me", "value")
8
+ Mudis.read("hit_me")
9
+ Mudis.read("miss_me")
10
+ metrics = Mudis.metrics
11
+ expect(metrics[:hits]).to eq(1)
12
+ expect(metrics[:misses]).to eq(1)
13
+ end
14
+
15
+ it "includes per-bucket stats" do
16
+ Mudis.write("a", "x" * 50)
17
+ metrics = Mudis.metrics
18
+ expect(metrics).to include(:buckets)
19
+ expect(metrics[:buckets]).to be_an(Array)
20
+ expect(metrics[:buckets].first).to include(:index, :keys, :memory_bytes, :lru_size)
21
+ end
22
+
23
+ it "resets only the metrics without clearing cache" do
24
+ Mudis.write("metrics_key", "value")
25
+ Mudis.read("metrics_key")
26
+ Mudis.read("missing_key")
27
+ expect(Mudis.metrics[:hits]).to eq(1)
28
+ expect(Mudis.metrics[:misses]).to eq(1)
29
+ Mudis.reset_metrics!
30
+ expect(Mudis.metrics[:hits]).to eq(0)
31
+ expect(Mudis.metrics[:misses]).to eq(0)
32
+ expect(Mudis.read("metrics_key")).to eq("value")
33
+ end
34
+ end
data/spec/mudis_spec.rb CHANGED
@@ -1,183 +1,183 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "spec_helper"
4
-
5
- RSpec.describe Mudis do # rubocop:disable Metrics/BlockLength
6
- before(:each) do
7
- Mudis.stop_expiry_thread
8
- Mudis.instance_variable_set(:@buckets, nil)
9
- Mudis.instance_variable_set(:@stores, Array.new(Mudis.buckets) { {} })
10
- Mudis.instance_variable_set(:@mutexes, Array.new(Mudis.buckets) { Mutex.new })
11
- Mudis.instance_variable_set(:@lru_heads, Array.new(Mudis.buckets) { nil })
12
- Mudis.instance_variable_set(:@lru_tails, Array.new(Mudis.buckets) { nil })
13
- Mudis.instance_variable_set(:@lru_nodes, Array.new(Mudis.buckets) { {} })
14
- Mudis.instance_variable_set(:@current_bytes, Array.new(Mudis.buckets, 0))
15
- Mudis.instance_variable_set(:@metrics, { hits: 0, misses: 0, evictions: 0, rejected: 0 })
16
- Mudis.serializer = JSON
17
- Mudis.compress = false
18
- Mudis.max_value_bytes = nil
19
- end
20
-
21
- describe ".write and .read" do
22
- it "writes and reads a value" do
23
- Mudis.write("foo", { bar: "baz" })
24
- result = Mudis.read("foo")
25
- expect(result).to eq({ "bar" => "baz" })
26
- end
27
-
28
- it "returns nil for non-existent keys" do
29
- expect(Mudis.read("nope")).to be_nil
30
- end
31
- end
32
-
33
- describe ".exists?" do
34
- it "returns true if key exists" do
35
- Mudis.write("check", [1, 2, 3])
36
- expect(Mudis.exists?("check")).to be true
37
- end
38
-
39
- it "returns false if key does not exist" do
40
- expect(Mudis.exists?("missing")).to be false
41
- end
42
- end
43
-
44
- describe ".delete" do
45
- it "deletes a key" do
46
- Mudis.write("temp", 42)
47
- Mudis.delete("temp")
48
- expect(Mudis.read("temp")).to be_nil
49
- end
50
- end
51
-
52
- describe ".update" do
53
- it "updates a cached value" do
54
- Mudis.write("counter", 5)
55
- Mudis.update("counter") { |v| v + 1 }
56
- expect(Mudis.read("counter")).to eq(6)
57
- end
58
- end
59
-
60
- describe ".fetch" do
61
- it "returns cached value if exists" do
62
- Mudis.write("k", 123)
63
- result = Mudis.fetch("k", expires_in: 60) { 999 } # fix: use keyword arg
64
- expect(result).to eq(123)
65
- end
66
-
67
- it "writes and returns block result if missing" do
68
- Mudis.delete("k")
69
- result = Mudis.fetch("k", expires_in: 60) { 999 } # fix
70
- expect(result).to eq(999)
71
- expect(Mudis.read("k")).to eq(999)
72
- end
73
-
74
- it "forces overwrite if force: true" do
75
- Mudis.write("k", 100)
76
- result = Mudis.fetch("k", force: true) { 200 } # fix
77
- expect(result).to eq(200)
78
- end
79
- end
80
-
81
- describe ".clear" do
82
- it "removes a key from the cache" do
83
- Mudis.write("to_clear", 123)
84
- expect(Mudis.read("to_clear")).to eq(123)
85
- Mudis.clear("to_clear")
86
- expect(Mudis.read("to_clear")).to be_nil
87
- end
88
- end
89
-
90
- describe ".replace" do
91
- it "replaces value only if key exists" do
92
- Mudis.write("to_replace", 100)
93
- Mudis.replace("to_replace", 200)
94
- expect(Mudis.read("to_replace")).to eq(200)
95
-
96
- Mudis.delete("to_replace")
97
- Mudis.replace("to_replace", 300)
98
- expect(Mudis.read("to_replace")).to be_nil
99
- end
100
- end
101
-
102
- describe ".inspect" do
103
- it "returns metadata for a cached key" do
104
- Mudis.write("key1", "abc", expires_in: 60)
105
- meta = Mudis.inspect("key1")
106
-
107
- expect(meta).to include(:key, :bucket, :expires_at, :created_at, :size_bytes, :compressed)
108
- expect(meta[:key]).to eq("key1")
109
- expect(meta[:compressed]).to eq(false)
110
- end
111
-
112
- it "returns nil for missing key" do
113
- expect(Mudis.inspect("unknown")).to be_nil
114
- end
115
- end
116
-
117
- describe "expiry handling" do
118
- it "expires values after specified time" do
119
- Mudis.write("short_lived", "gone soon", expires_in: 1)
120
- sleep 2
121
- expect(Mudis.read("short_lived")).to be_nil
122
- end
123
- end
124
-
125
- describe ".all_keys" do
126
- it "lists all stored keys" do
127
- Mudis.write("k1", 1)
128
- Mudis.write("k2", 2)
129
- expect(Mudis.all_keys).to include("k1", "k2")
130
- end
131
- end
132
-
133
- it "respects max_bytes when updated externally" do
134
- Mudis.max_bytes = 100
135
- expect(Mudis.send(:max_bytes)).to eq(100)
136
- end
137
-
138
- describe ".current_memory_bytes" do
139
- it "returns a non-zero byte count after writes" do
140
- Mudis.configure do |c|
141
- c.max_value_bytes = nil
142
- c.hard_memory_limit = false
143
- end
144
-
145
- Mudis.write("size_test", "a" * 100)
146
- expect(Mudis.current_memory_bytes).to be > 0
147
- end
148
- end
149
-
150
- describe ".least_touched" do
151
- it "returns keys with lowest read access counts" do
152
- Mudis.reset!
153
- Mudis.write("a", 1)
154
- Mudis.write("b", 2)
155
- Mudis.write("c", 3)
156
-
157
- Mudis.read("a")
158
- Mudis.read("a")
159
- Mudis.read("b")
160
-
161
- least = Mudis.least_touched(2)
162
- expect(least.map(&:first)).to include("c") # Never read
163
- expect(least.first.last).to eq(0)
164
- end
165
- end
166
-
167
- describe ".configure" do
168
- it "applies configuration settings correctly" do
169
- Mudis.configure do |c|
170
- c.serializer = JSON
171
- c.compress = true
172
- c.max_value_bytes = 12_345
173
- c.hard_memory_limit = true
174
- c.max_bytes = 987_654
175
- end
176
-
177
- expect(Mudis.compress).to eq(true)
178
- expect(Mudis.max_value_bytes).to eq(12_345)
179
- expect(Mudis.hard_memory_limit).to eq(true)
180
- expect(Mudis.max_bytes).to eq(987_654)
181
- end
182
- end
183
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "spec_helper"
4
+
5
+ RSpec.describe Mudis do # rubocop:disable Metrics/BlockLength
6
+ before(:each) do
7
+ Mudis.stop_expiry_thread
8
+ Mudis.instance_variable_set(:@buckets, nil)
9
+ Mudis.instance_variable_set(:@stores, Array.new(Mudis.buckets) { {} })
10
+ Mudis.instance_variable_set(:@mutexes, Array.new(Mudis.buckets) { Mutex.new })
11
+ Mudis.instance_variable_set(:@lru_heads, Array.new(Mudis.buckets) { nil })
12
+ Mudis.instance_variable_set(:@lru_tails, Array.new(Mudis.buckets) { nil })
13
+ Mudis.instance_variable_set(:@lru_nodes, Array.new(Mudis.buckets) { {} })
14
+ Mudis.instance_variable_set(:@current_bytes, Array.new(Mudis.buckets, 0))
15
+ Mudis.instance_variable_set(:@metrics, { hits: 0, misses: 0, evictions: 0, rejected: 0 })
16
+ Mudis.serializer = JSON
17
+ Mudis.compress = false
18
+ Mudis.max_value_bytes = nil
19
+ end
20
+
21
+ describe ".write and .read" do
22
+ it "writes and reads a value" do
23
+ Mudis.write("foo", { bar: "baz" })
24
+ result = Mudis.read("foo")
25
+ expect(result).to eq({ "bar" => "baz" })
26
+ end
27
+
28
+ it "returns nil for non-existent keys" do
29
+ expect(Mudis.read("nope")).to be_nil
30
+ end
31
+ end
32
+
33
+ describe ".exists?" do
34
+ it "returns true if key exists" do
35
+ Mudis.write("check", [1, 2, 3])
36
+ expect(Mudis.exists?("check")).to be true
37
+ end
38
+
39
+ it "returns false if key does not exist" do
40
+ expect(Mudis.exists?("missing")).to be false
41
+ end
42
+ end
43
+
44
+ describe ".delete" do
45
+ it "deletes a key" do
46
+ Mudis.write("temp", 42)
47
+ Mudis.delete("temp")
48
+ expect(Mudis.read("temp")).to be_nil
49
+ end
50
+ end
51
+
52
+ describe ".update" do
53
+ it "updates a cached value" do
54
+ Mudis.write("counter", 5)
55
+ Mudis.update("counter") { |v| v + 1 }
56
+ expect(Mudis.read("counter")).to eq(6)
57
+ end
58
+ end
59
+
60
+ describe ".fetch" do
61
+ it "returns cached value if exists" do
62
+ Mudis.write("k", 123)
63
+ result = Mudis.fetch("k", expires_in: 60) { 999 } # fix: use keyword arg
64
+ expect(result).to eq(123)
65
+ end
66
+
67
+ it "writes and returns block result if missing" do
68
+ Mudis.delete("k")
69
+ result = Mudis.fetch("k", expires_in: 60) { 999 } # fix
70
+ expect(result).to eq(999)
71
+ expect(Mudis.read("k")).to eq(999)
72
+ end
73
+
74
+ it "forces overwrite if force: true" do
75
+ Mudis.write("k", 100)
76
+ result = Mudis.fetch("k", force: true) { 200 } # fix
77
+ expect(result).to eq(200)
78
+ end
79
+ end
80
+
81
+ describe ".clear" do
82
+ it "removes a key from the cache" do
83
+ Mudis.write("to_clear", 123)
84
+ expect(Mudis.read("to_clear")).to eq(123)
85
+ Mudis.clear("to_clear")
86
+ expect(Mudis.read("to_clear")).to be_nil
87
+ end
88
+ end
89
+
90
+ describe ".replace" do
91
+ it "replaces value only if key exists" do
92
+ Mudis.write("to_replace", 100)
93
+ Mudis.replace("to_replace", 200)
94
+ expect(Mudis.read("to_replace")).to eq(200)
95
+
96
+ Mudis.delete("to_replace")
97
+ Mudis.replace("to_replace", 300)
98
+ expect(Mudis.read("to_replace")).to be_nil
99
+ end
100
+ end
101
+
102
+ describe ".inspect" do
103
+ it "returns metadata for a cached key" do
104
+ Mudis.write("key1", "abc", expires_in: 60)
105
+ meta = Mudis.inspect("key1")
106
+
107
+ expect(meta).to include(:key, :bucket, :expires_at, :created_at, :size_bytes, :compressed)
108
+ expect(meta[:key]).to eq("key1")
109
+ expect(meta[:compressed]).to eq(false)
110
+ end
111
+
112
+ it "returns nil for missing key" do
113
+ expect(Mudis.inspect("unknown")).to be_nil
114
+ end
115
+ end
116
+
117
+ describe "expiry handling" do
118
+ it "expires values after specified time" do
119
+ Mudis.write("short_lived", "gone soon", expires_in: 1)
120
+ sleep 2
121
+ expect(Mudis.read("short_lived")).to be_nil
122
+ end
123
+ end
124
+
125
+ describe ".all_keys" do
126
+ it "lists all stored keys" do
127
+ Mudis.write("k1", 1)
128
+ Mudis.write("k2", 2)
129
+ expect(Mudis.all_keys).to include("k1", "k2")
130
+ end
131
+ end
132
+
133
+ it "respects max_bytes when updated externally" do
134
+ Mudis.max_bytes = 100
135
+ expect(Mudis.send(:max_bytes)).to eq(100)
136
+ end
137
+
138
+ describe ".current_memory_bytes" do
139
+ it "returns a non-zero byte count after writes" do
140
+ Mudis.configure do |c|
141
+ c.max_value_bytes = nil
142
+ c.hard_memory_limit = false
143
+ end
144
+
145
+ Mudis.write("size_test", "a" * 100)
146
+ expect(Mudis.current_memory_bytes).to be > 0
147
+ end
148
+ end
149
+
150
+ describe ".least_touched" do
151
+ it "returns keys with lowest read access counts" do
152
+ Mudis.reset!
153
+ Mudis.write("a", 1)
154
+ Mudis.write("b", 2)
155
+ Mudis.write("c", 3)
156
+
157
+ Mudis.read("a")
158
+ Mudis.read("a")
159
+ Mudis.read("b")
160
+
161
+ least = Mudis.least_touched(2)
162
+ expect(least.map(&:first)).to include("c") # Never read
163
+ expect(least.first.last).to eq(0)
164
+ end
165
+ end
166
+
167
+ describe ".configure" do
168
+ it "applies configuration settings correctly" do
169
+ Mudis.configure do |c|
170
+ c.serializer = JSON
171
+ c.compress = true
172
+ c.max_value_bytes = 12_345
173
+ c.hard_memory_limit = true
174
+ c.max_bytes = 987_654
175
+ end
176
+
177
+ expect(Mudis.compress).to eq(true)
178
+ expect(Mudis.max_value_bytes).to eq(12_345)
179
+ expect(Mudis.hard_memory_limit).to eq(true)
180
+ expect(Mudis.max_bytes).to eq(987_654)
181
+ end
182
+ end
183
+ end
@@ -1,69 +1,69 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe "Mudis Namespace Operations" do # rubocop:disable Metrics/BlockLength
6
- before(:each) do
7
- Mudis.reset!
8
- end
9
-
10
- it "uses thread-local namespace in block" do
11
- Mudis.with_namespace("test") do
12
- Mudis.write("foo", "bar")
13
- end
14
- expect(Mudis.read("foo", namespace: "test")).to eq("bar")
15
- expect(Mudis.read("foo")).to be_nil
16
- end
17
-
18
- it "supports explicit namespace override" do
19
- Mudis.write("x", 1, namespace: "alpha")
20
- Mudis.write("x", 2, namespace: "beta")
21
- expect(Mudis.read("x", namespace: "alpha")).to eq(1)
22
- expect(Mudis.read("x", namespace: "beta")).to eq(2)
23
- expect(Mudis.read("x")).to be_nil
24
- end
25
-
26
- describe ".keys" do
27
- it "returns only keys for the given namespace" do
28
- Mudis.write("user:1", "Alice", namespace: "users")
29
- Mudis.write("user:2", "Bob", namespace: "users")
30
- Mudis.write("admin:1", "Charlie", namespace: "admins")
31
-
32
- result = Mudis.keys(namespace: "users")
33
- expect(result).to contain_exactly("user:1", "user:2")
34
- end
35
-
36
- it "returns an empty array if no keys exist for namespace" do
37
- expect(Mudis.keys(namespace: "nonexistent")).to eq([])
38
- end
39
-
40
- it "raises an error if namespace is missing" do
41
- expect { Mudis.keys(namespace: nil) }.to raise_error(ArgumentError, /namespace is required/)
42
- end
43
- end
44
-
45
- describe ".clear_namespace" do
46
- it "deletes all keys in the given namespace" do
47
- Mudis.write("a", 1, namespace: "ns1")
48
- Mudis.write("b", 2, namespace: "ns1")
49
- Mudis.write("x", 9, namespace: "ns2")
50
-
51
- expect(Mudis.read("a", namespace: "ns1")).to eq(1)
52
- expect(Mudis.read("b", namespace: "ns1")).to eq(2)
53
-
54
- Mudis.clear_namespace(namespace: "ns1")
55
-
56
- expect(Mudis.read("a", namespace: "ns1")).to be_nil
57
- expect(Mudis.read("b", namespace: "ns1")).to be_nil
58
- expect(Mudis.read("x", namespace: "ns2")).to eq(9)
59
- end
60
-
61
- it "does nothing if namespace has no keys" do
62
- expect { Mudis.clear_namespace(namespace: "ghost") }.not_to raise_error
63
- end
64
-
65
- it "raises an error if namespace is nil" do
66
- expect { Mudis.clear_namespace(namespace: nil) }.to raise_error(ArgumentError, /namespace is required/)
67
- end
68
- end
69
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Mudis Namespace Operations" do # rubocop:disable Metrics/BlockLength
6
+ before(:each) do
7
+ Mudis.reset!
8
+ end
9
+
10
+ it "uses thread-local namespace in block" do
11
+ Mudis.with_namespace("test") do
12
+ Mudis.write("foo", "bar")
13
+ end
14
+ expect(Mudis.read("foo", namespace: "test")).to eq("bar")
15
+ expect(Mudis.read("foo")).to be_nil
16
+ end
17
+
18
+ it "supports explicit namespace override" do
19
+ Mudis.write("x", 1, namespace: "alpha")
20
+ Mudis.write("x", 2, namespace: "beta")
21
+ expect(Mudis.read("x", namespace: "alpha")).to eq(1)
22
+ expect(Mudis.read("x", namespace: "beta")).to eq(2)
23
+ expect(Mudis.read("x")).to be_nil
24
+ end
25
+
26
+ describe ".keys" do
27
+ it "returns only keys for the given namespace" do
28
+ Mudis.write("user:1", "Alice", namespace: "users")
29
+ Mudis.write("user:2", "Bob", namespace: "users")
30
+ Mudis.write("admin:1", "Charlie", namespace: "admins")
31
+
32
+ result = Mudis.keys(namespace: "users")
33
+ expect(result).to contain_exactly("user:1", "user:2")
34
+ end
35
+
36
+ it "returns an empty array if no keys exist for namespace" do
37
+ expect(Mudis.keys(namespace: "nonexistent")).to eq([])
38
+ end
39
+
40
+ it "raises an error if namespace is missing" do
41
+ expect { Mudis.keys(namespace: nil) }.to raise_error(ArgumentError, /namespace is required/)
42
+ end
43
+ end
44
+
45
+ describe ".clear_namespace" do
46
+ it "deletes all keys in the given namespace" do
47
+ Mudis.write("a", 1, namespace: "ns1")
48
+ Mudis.write("b", 2, namespace: "ns1")
49
+ Mudis.write("x", 9, namespace: "ns2")
50
+
51
+ expect(Mudis.read("a", namespace: "ns1")).to eq(1)
52
+ expect(Mudis.read("b", namespace: "ns1")).to eq(2)
53
+
54
+ Mudis.clear_namespace(namespace: "ns1")
55
+
56
+ expect(Mudis.read("a", namespace: "ns1")).to be_nil
57
+ expect(Mudis.read("b", namespace: "ns1")).to be_nil
58
+ expect(Mudis.read("x", namespace: "ns2")).to eq(9)
59
+ end
60
+
61
+ it "does nothing if namespace has no keys" do
62
+ expect { Mudis.clear_namespace(namespace: "ghost") }.not_to raise_error
63
+ end
64
+
65
+ it "raises an error if namespace is nil" do
66
+ expect { Mudis.clear_namespace(namespace: nil) }.to raise_error(ArgumentError, /namespace is required/)
67
+ end
68
+ end
69
+ end