namo 0.9.2 → 0.10.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/CHANGELOG +11 -0
- data/README.md +12 -0
- data/lib/Namo/Row.rb +12 -0
- data/lib/Namo/VERSION.rb +1 -1
- data/test/Namo/Row_test.rb +77 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff324711fe932145ecc01cedadee6453f80fe6610d162783a7dea053d2f35fc0
|
|
4
|
+
data.tar.gz: ec993e96d3ac5f1053eaa0f6c933347914209ed84423e78e3c4e5a4843c22915
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 863aa8aeb8432d3fed7da33218ce14790a24a5e4a4b1c70a09b44aa495ef7ebe1bba36954622a1629990ff61cd892904725ee2293613e63c51ca48e0e6d05c18
|
|
7
|
+
data.tar.gz: 343949804d61f4dd93a636a961d6c097f9f1c20f7010044d67fbab34aaba75f1b3c9b33cd42f2f74f1ce189fd9324e6a18398b7b595fda11ca2fc44cfbcfc1c0
|
data/CHANGELOG
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
_________
|
|
3
3
|
|
|
4
|
+
20260528
|
|
5
|
+
0.10.0: + Row value semantics: ==, eql?, hash
|
|
6
|
+
|
|
7
|
+
1. + Namo::Row#==: Data equality. Two Rows are equal iff the other is a Row and their `@row` hashes are `==`. Class identity not gated (Row has no subclass hierarchy with included modules); formulae ignored (a formula is a property of the surrounding Namo, not of the row's identity). Mirrors `Namo#==` one level down.
|
|
8
|
+
2. + Namo::Row#eql?: Strict data equality. Same shape as `==` but uses `Hash#eql?` on `@row`, matching Ruby's numeric-type-strict convention (`{n: 1}` Row is `eql?` to another `{n: 1}` Row, but not to a `{n: 1.0}` Row, just as `1.eql?(1.0)` is false).
|
|
9
|
+
3. + Namo::Row#hash: Returns `@row.hash`. Consistent with `eql?` — Rows that are `eql?` produce equal hashes, so Rows participate correctly in Hash keys, Set members, and Array#uniq.
|
|
10
|
+
4. ~ test/Namo/Row_test.rb: + `#==` tests (equal/different `@row`, non-Row operand, formulae ignored). + `#eql?` tests (equal `@row`, non-Row operand, `Hash#eql?` numeric-type strictness vs `==`, formulae ignored). + `#hash` tests (hash equality for `eql?` Rows, Rows as Hash keys, Rows as Set members deduplicating equal Rows).
|
|
11
|
+
5. ~ README.md: + Note in the Equality section that Row participates in value semantics (`==`, `eql?`, `hash`) on the same data-only basis as `Namo#==`, ignoring formulae.
|
|
12
|
+
6. ~ ROADMAP.md: Promote 0.10.0 from upcoming to shipped under "Current state: 0.10.0"; revise Summary to point "next phase" at 0.11.0+ and note Row value semantics among the algebra-completing pieces.
|
|
13
|
+
7. ~ Namo::VERSION: /0.9.2/0.10.0/
|
|
14
|
+
|
|
4
15
|
20260525
|
|
5
16
|
0.9.2: ~ Auto-load Namo::VERSION
|
|
6
17
|
|
data/README.md
CHANGED
|
@@ -486,6 +486,18 @@ The two `:revenue` procs are independently-written and not the same object — `
|
|
|
486
486
|
|
|
487
487
|
Each comparison operator answers a distinct question: `eql?` is strictest (class + data + formula names); `==` is data identity; `===` is analytical identity; the subset operators are data containment.
|
|
488
488
|
|
|
489
|
+
Rows participate in value semantics on the same data-only basis. `Row#==`, `Row#eql?`, and `Row#hash` compare the underlying row hash and ignore the surrounding Namo's formulae — two Rows with the same data are equal regardless of which Namo yielded them. This makes Rows usable as Hash keys and Set members, and underwrites whole-row deduplication on the Enumerable side:
|
|
490
|
+
|
|
491
|
+
```ruby
|
|
492
|
+
a = Namo.new([{x: 1}]).first
|
|
493
|
+
b = Namo.new([{x: 1}]).first
|
|
494
|
+
a == b # => true
|
|
495
|
+
a.eql?(b) # => true
|
|
496
|
+
{a => :found}[b] # => :found
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
The omission of `Row#===` and Row-level `<`/`<=`/`>`/`>=` is deliberate: a Row is a record, not a collection, so the set-theoretic operators don't translate. The value-semantics trio (`==`, `eql?`, `hash`) is what a hash-shaped value needs to behave correctly in Ruby's collection machinery; that's the whole Row-comparison story.
|
|
500
|
+
|
|
489
501
|
### Subset and Superset
|
|
490
502
|
|
|
491
503
|
`<`, `<=`, `>`, `>=` are multiset subset and superset relations on rows.
|
data/lib/Namo/Row.rb
CHANGED
|
@@ -11,6 +11,18 @@ class Namo
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def ==(other)
|
|
15
|
+
other.is_a?(Row) && @row == other.to_h
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def eql?(other)
|
|
19
|
+
other.is_a?(Row) && @row.eql?(other.to_h)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def hash
|
|
23
|
+
@row.hash
|
|
24
|
+
end
|
|
25
|
+
|
|
14
26
|
def match?(selections)
|
|
15
27
|
selections.all? do |dimension, coordinate|
|
|
16
28
|
case coordinate
|
data/lib/Namo/VERSION.rb
CHANGED
data/test/Namo/Row_test.rb
CHANGED
|
@@ -215,4 +215,81 @@ describe Namo::Row do
|
|
|
215
215
|
_(row.to_h).must_equal row_data
|
|
216
216
|
end
|
|
217
217
|
end
|
|
218
|
+
|
|
219
|
+
describe "#==" do
|
|
220
|
+
it "is true for two Rows with equal @row" do
|
|
221
|
+
a = Namo::Row.new({product: 'Widget', price: 10.0}, {})
|
|
222
|
+
b = Namo::Row.new({product: 'Widget', price: 10.0}, {})
|
|
223
|
+
_(a == b).must_equal true
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "is false for two Rows with different @row" do
|
|
227
|
+
a = Namo::Row.new({product: 'Widget', price: 10.0}, {})
|
|
228
|
+
b = Namo::Row.new({product: 'Gadget', price: 10.0}, {})
|
|
229
|
+
_(a == b).must_equal false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "is false for a non-Row operand" do
|
|
233
|
+
a = Namo::Row.new({product: 'Widget'}, {})
|
|
234
|
+
_(a == {product: 'Widget'}).must_equal false
|
|
235
|
+
_(a == 'Widget').must_equal false
|
|
236
|
+
_(a == nil).must_equal false
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "ignores formulae" do
|
|
240
|
+
a = Namo::Row.new({price: 10.0, quantity: 100}, {})
|
|
241
|
+
b = Namo::Row.new({price: 10.0, quantity: 100}, {revenue: proc{|r| r[:price] * r[:quantity]}})
|
|
242
|
+
_(a == b).must_equal true
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
describe "#eql?" do
|
|
247
|
+
it "is true for two Rows with eql? @row" do
|
|
248
|
+
a = Namo::Row.new({product: 'Widget', price: 10.0}, {})
|
|
249
|
+
b = Namo::Row.new({product: 'Widget', price: 10.0}, {})
|
|
250
|
+
_(a.eql?(b)).must_equal true
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "is false for a non-Row operand" do
|
|
254
|
+
a = Namo::Row.new({product: 'Widget'}, {})
|
|
255
|
+
_(a.eql?({product: 'Widget'})).must_equal false
|
|
256
|
+
_(a.eql?(nil)).must_equal false
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it "distinguishes numeric types the way Hash#eql? does" do
|
|
260
|
+
a = Namo::Row.new({n: 1}, {})
|
|
261
|
+
b = Namo::Row.new({n: 1.0}, {})
|
|
262
|
+
_(a == b).must_equal true
|
|
263
|
+
_(a.eql?(b)).must_equal false
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it "ignores formulae" do
|
|
267
|
+
a = Namo::Row.new({price: 10.0, quantity: 100}, {})
|
|
268
|
+
b = Namo::Row.new({price: 10.0, quantity: 100}, {revenue: proc{|r| r[:price] * r[:quantity]}})
|
|
269
|
+
_(a.eql?(b)).must_equal true
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
describe "#hash" do
|
|
274
|
+
it "is equal for two Rows that are eql?" do
|
|
275
|
+
a = Namo::Row.new({product: 'Widget', price: 10.0}, {})
|
|
276
|
+
b = Namo::Row.new({product: 'Widget', price: 10.0}, {})
|
|
277
|
+
_(a.hash).must_equal b.hash
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "lets Rows work as Hash keys" do
|
|
281
|
+
a = Namo::Row.new({product: 'Widget'}, {})
|
|
282
|
+
b = Namo::Row.new({product: 'Gadget'}, {})
|
|
283
|
+
lookup = Namo::Row.new({product: 'Widget'}, {})
|
|
284
|
+
h = {a => :x, b => :y}
|
|
285
|
+
_(h[lookup]).must_equal :x
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
it "lets Array#uniq dedupe equal Rows" do
|
|
289
|
+
a = Namo::Row.new({product: 'Widget'}, {})
|
|
290
|
+
b = Namo::Row.new({product: 'Gadget'}, {})
|
|
291
|
+
duplicate_of_a = Namo::Row.new({product: 'Widget'}, {})
|
|
292
|
+
_([a, b, duplicate_of_a].uniq.length).must_equal 2
|
|
293
|
+
end
|
|
294
|
+
end
|
|
218
295
|
end
|