memstore 1.0.1 → 1.1.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/README.md +20 -18
- data/lib/memstore.rb +34 -3
- data/lib/memstore/version.rb +1 -1
- data/spec/memstore_spec.rb +53 -23
- metadata +1 -1
data/README.md
CHANGED
@@ -125,10 +125,10 @@ store << a << b << c
|
|
125
125
|
|
126
126
|
### Retrieving Items
|
127
127
|
|
128
|
-
`size` returns the current number of items:
|
128
|
+
`length` (or `size`) returns the current number of items:
|
129
129
|
|
130
130
|
```ruby
|
131
|
-
store.
|
131
|
+
store.length
|
132
132
|
# => 3
|
133
133
|
```
|
134
134
|
|
@@ -187,21 +187,27 @@ store.delete_keys(5..7, 9)
|
|
187
187
|
|
188
188
|
The following methods are available to query the data store:
|
189
189
|
|
190
|
-
- `find_all` (`find`)
|
190
|
+
- `find_all` (also available as `find`)
|
191
191
|
- `find_any`
|
192
192
|
- `find_one`
|
193
193
|
- `find_not_all`
|
194
194
|
- `find_none`
|
195
|
-
- `first_all` (`first`)
|
195
|
+
- `first_all` (also available as `first`)
|
196
196
|
- `first_any`
|
197
197
|
- `first_one`
|
198
198
|
- `first_not_all`
|
199
199
|
- `first_none`
|
200
|
+
- `count_all` (also available as `count`)
|
201
|
+
- `count_any`
|
202
|
+
- `count_one`
|
203
|
+
- `count_not_all`
|
204
|
+
- `count_none`
|
200
205
|
|
201
206
|
The first part indicates what is returned:
|
202
207
|
|
203
208
|
- `find_*` returns all matches.
|
204
209
|
- `first_*` returns the first match.
|
210
|
+
- `count_*` returns the number of matches.
|
205
211
|
|
206
212
|
The second part indicates how conditions are evaluated:
|
207
213
|
|
@@ -213,13 +219,11 @@ The second part indicates how conditions are evaluated:
|
|
213
219
|
|
214
220
|
In other words:
|
215
221
|
|
216
|
-
- `all` means `condition && condition &&
|
217
|
-
- `any` means `condition || condition ||
|
218
|
-
- `one` means `condition ^ condition ^ ...` (XOR)
|
219
|
-
- `not all` means `!(condition && condition && ...)` or `!condition || !condition ||
|
220
|
-
- `none` means `!(condition || condition || ...)` or `!condition && !condition &&
|
221
|
-
|
222
|
-
For convenience, `find` is aliased to `find_all` and `first` to `first_all`.
|
222
|
+
- `all` means `condition && condition && ...`.
|
223
|
+
- `any` means `condition || condition || ...`.
|
224
|
+
- `one` means `condition ^ condition ^ ...` (XOR).
|
225
|
+
- `not all` means `!(condition && condition && ...)` or `!condition || !condition || ...`.
|
226
|
+
- `none` means `!(condition || condition || ...)` or `!condition && !condition && ...`.
|
223
227
|
|
224
228
|
All variants take a `conditions` hash and an optional block.
|
225
229
|
|
@@ -242,17 +246,17 @@ class Array
|
|
242
246
|
end
|
243
247
|
end
|
244
248
|
|
245
|
-
store.find
|
249
|
+
store.find(age: [23, 25, 27])
|
246
250
|
```
|
247
251
|
|
248
|
-
The block is invoked with
|
249
|
-
Its return value is interpreted as a boolean value:
|
252
|
+
The block is invoked with the item *after* the conditions are evaluated. It should return a boolean value:
|
250
253
|
|
251
254
|
```ruby
|
252
|
-
store.find { |item| item.age - item.child.age > 20 }
|
255
|
+
store.find(age: 25) { |item| item.age - item.child.age > 20 }
|
256
|
+
# is evaluated as (item.age == 25) && (item.age - item.child.age > 20)
|
253
257
|
```
|
254
258
|
|
255
|
-
In addition to the evaluation logic, the arrays returned by all variants of `
|
259
|
+
In addition to the evaluation logic, the arrays returned by all variants of `find_*` can be merged:
|
256
260
|
|
257
261
|
```ruby
|
258
262
|
store.find(...) | store.find(...) | store.find(...)
|
@@ -263,8 +267,6 @@ Note that the pipe operator `|` already eliminates duplicates:
|
|
263
267
|
```ruby
|
264
268
|
[a, b, c] | [c, d, e]
|
265
269
|
# => [a, b, c, d, e]
|
266
|
-
# which is equal to
|
267
|
-
([a, b, c] + [c, d, e]).uniq
|
268
270
|
```
|
269
271
|
|
270
272
|
### Serialization
|
data/lib/memstore.rb
CHANGED
@@ -7,11 +7,11 @@ module MemStore
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.from_binary(binary)
|
10
|
-
|
10
|
+
ObjectStore.from_binary(binary)
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.from_file(file)
|
14
|
-
|
14
|
+
ObjectStore.from_file(file)
|
15
15
|
end
|
16
16
|
|
17
17
|
class ObjectStore
|
@@ -29,9 +29,11 @@ module MemStore
|
|
29
29
|
end
|
30
30
|
alias_method :<<, :insert
|
31
31
|
|
32
|
-
def
|
32
|
+
def length
|
33
33
|
@items.length
|
34
34
|
end
|
35
|
+
alias_method :size, :length
|
36
|
+
alias_method :count, :length
|
35
37
|
|
36
38
|
def [](*keys)
|
37
39
|
return @items[keys.first] if keys.length == 1 && !keys.first.is_a?(Range)
|
@@ -103,6 +105,35 @@ module MemStore
|
|
103
105
|
all.detect { |item| instance_exec(item, conditions, block, &FIND_NONE) }
|
104
106
|
end
|
105
107
|
|
108
|
+
def count_all(conditions={}, &block)
|
109
|
+
all.count { |item| instance_exec(item, conditions, block, &FIND_ALL) }
|
110
|
+
end
|
111
|
+
alias_method :count, :count_all
|
112
|
+
|
113
|
+
def count_any(conditions={}, &block)
|
114
|
+
all.count { |item| instance_exec(item, conditions, block, &FIND_ANY) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def count_one(conditions={}, &block)
|
118
|
+
all.count { |item| instance_exec(item, conditions, block, &FIND_ONE) }
|
119
|
+
end
|
120
|
+
|
121
|
+
def count_not_all(conditions={}, &block)
|
122
|
+
all.count { |item| !instance_exec(item, conditions, block, &FIND_ALL) }
|
123
|
+
end
|
124
|
+
|
125
|
+
def count_none(conditions={}, &block)
|
126
|
+
all.count { |item| instance_exec(item, conditions, block, &FIND_NONE) }
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.from_binary(binary)
|
130
|
+
begin Marshal.load(binary) rescue nil end
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.from_file(file)
|
134
|
+
begin self.from_binary(IO.read(file)) rescue nil end
|
135
|
+
end
|
136
|
+
|
106
137
|
def to_binary
|
107
138
|
Marshal.dump(self)
|
108
139
|
end
|
data/lib/memstore/version.rb
CHANGED
data/spec/memstore_spec.rb
CHANGED
@@ -48,19 +48,32 @@ describe MemStore::ObjectStore do
|
|
48
48
|
it "can be converted to and from binary" do
|
49
49
|
o = Dummy.new("custom key")
|
50
50
|
store = MemStore::ObjectStore.new(:id).insert(o)
|
51
|
-
restored = MemStore.from_binary(store.to_binary)
|
51
|
+
restored = MemStore::ObjectStore.from_binary(store.to_binary)
|
52
52
|
restored.must_be_instance_of MemStore::ObjectStore
|
53
53
|
restored.items.must_equal store.items
|
54
54
|
restored.instance_variable_get(:@key).must_equal :id
|
55
55
|
end
|
56
56
|
|
57
|
+
it "returns nil when conversion from binary fails" do
|
58
|
+
MemStore::ObjectStore.from_binary(nil).must_equal nil
|
59
|
+
end
|
60
|
+
|
57
61
|
it "can be serialized to and deserialized from a binary file" do
|
58
62
|
tmp = Tempfile.new("memstore")
|
59
|
-
|
60
|
-
MemStore.
|
63
|
+
o = Dummy.new("custom key")
|
64
|
+
store = MemStore::ObjectStore.new(:id).insert(o)
|
65
|
+
store.to_file(tmp)
|
66
|
+
restored = MemStore::ObjectStore.from_file(tmp)
|
67
|
+
restored.must_be_instance_of MemStore::ObjectStore
|
68
|
+
restored.items.must_equal store.items
|
69
|
+
restored.instance_variable_get(:@key).must_equal :id
|
61
70
|
tmp.unlink
|
62
71
|
end
|
63
72
|
|
73
|
+
it "returns nil when deserialization from binary file fails" do
|
74
|
+
MemStore::ObjectStore.from_file("does_not_exist").must_equal nil
|
75
|
+
end
|
76
|
+
|
64
77
|
end
|
65
78
|
|
66
79
|
describe MemStore::HashStore do
|
@@ -84,9 +97,8 @@ describe MemStore::HashStore do
|
|
84
97
|
end
|
85
98
|
|
86
99
|
it "can be converted to and from binary" do
|
87
|
-
store = MemStore::HashStore.new(:id)
|
88
|
-
|
89
|
-
restored = MemStore.from_binary(store.to_binary)
|
100
|
+
store = MemStore::HashStore.new(:id).insert({ id: "custom key" })
|
101
|
+
restored = MemStore::HashStore.from_binary(store.to_binary)
|
90
102
|
restored.must_be_instance_of MemStore::HashStore
|
91
103
|
restored.items.must_equal store.items
|
92
104
|
restored.instance_variable_get(:@key).must_equal :id
|
@@ -94,8 +106,12 @@ describe MemStore::HashStore do
|
|
94
106
|
|
95
107
|
it "can be serialized to and deserialized from a binary file" do
|
96
108
|
tmp = Tempfile.new("memstore")
|
97
|
-
MemStore::HashStore.new.
|
98
|
-
|
109
|
+
store = MemStore::HashStore.new(:id).insert({ id: "custom key" })
|
110
|
+
store.to_file(tmp)
|
111
|
+
restored = MemStore::HashStore.from_file(tmp)
|
112
|
+
restored.must_be_instance_of MemStore::HashStore
|
113
|
+
restored.items.must_equal store.items
|
114
|
+
restored.instance_variable_get(:@key).must_equal :id
|
99
115
|
tmp.unlink
|
100
116
|
end
|
101
117
|
|
@@ -122,6 +138,10 @@ describe MemStore do
|
|
122
138
|
10.times { |i| @store << i.to_f }
|
123
139
|
end
|
124
140
|
|
141
|
+
it "returns the overall number of items" do
|
142
|
+
@store.length.must_equal 10
|
143
|
+
end
|
144
|
+
|
125
145
|
it "returns a single item by itself" do
|
126
146
|
@store[3].must_equal 3.0
|
127
147
|
end
|
@@ -157,21 +177,6 @@ describe MemStore do
|
|
157
177
|
@store.all.must_equal [0.0, 1.0, 2.0, 7.0, 8.0, 9.0]
|
158
178
|
end
|
159
179
|
|
160
|
-
it "can be serialized to and deserialized from a binary file" do
|
161
|
-
tmp = Tempfile.new("memstore")
|
162
|
-
@store.to_file tmp
|
163
|
-
MemStore.from_file(tmp).items.must_equal @store.items
|
164
|
-
tmp.unlink
|
165
|
-
end
|
166
|
-
|
167
|
-
it "returns nil when conversion from binary fails" do
|
168
|
-
MemStore.from_binary(nil).must_equal nil
|
169
|
-
end
|
170
|
-
|
171
|
-
it "returns nil when deserialization from binary file fails" do
|
172
|
-
MemStore.from_file("does_not_exist").must_equal nil
|
173
|
-
end
|
174
|
-
|
175
180
|
end
|
176
181
|
|
177
182
|
describe MemStore do
|
@@ -235,4 +240,29 @@ describe MemStore do
|
|
235
240
|
match.id.must_equal 3
|
236
241
|
end
|
237
242
|
|
243
|
+
it "counts all items fulfilling all conditions" do
|
244
|
+
count = @store.count_all(id: 3..7, child: String)
|
245
|
+
count.must_equal [4, 6].length
|
246
|
+
end
|
247
|
+
|
248
|
+
it "counts all items fulfilling at least one condition" do
|
249
|
+
count = @store.count_any(id: 3..7, child: String)
|
250
|
+
count.must_equal [0, 2, 3, 4, 5, 6, 7, 8].length
|
251
|
+
end
|
252
|
+
|
253
|
+
it "counts all items fulfilling exactly one condition" do
|
254
|
+
count = @store.count_one(name: /o/, child: String)
|
255
|
+
count.must_equal [1, 4, 7, 9].length
|
256
|
+
end
|
257
|
+
|
258
|
+
it "counts all items violating at least one condition" do
|
259
|
+
count = @store.count_not_all(name: /o/, child: String)
|
260
|
+
count.must_equal [1, 3, 4, 5, 7, 9].length
|
261
|
+
end
|
262
|
+
|
263
|
+
it "counts all items violating all conditions" do
|
264
|
+
count = @store.count_none(name: /o/, child: String)
|
265
|
+
count.must_equal [3, 5].length
|
266
|
+
end
|
267
|
+
|
238
268
|
end
|