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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2959666eaa2d603b1877d42863ddadae9e021aceb753a60009579a2dbe2d7aa4
4
- data.tar.gz: ac865863705a2ca58c815eed073227a39ebb479358fea0590e4f76a5f6b0813c
3
+ metadata.gz: ff324711fe932145ecc01cedadee6453f80fe6610d162783a7dea053d2f35fc0
4
+ data.tar.gz: ec993e96d3ac5f1053eaa0f6c933347914209ed84423e78e3c4e5a4843c22915
5
5
  SHA512:
6
- metadata.gz: '09cc42eba9f306b4316a70140bb9642dc025c39d4bc3a502b21bee28058709b8b55609093d9979e27e2799d1bdad1efd60d829a71931502abc8e7cde71f1a1c7'
7
- data.tar.gz: 3952f6470d2f5dc8aeb733034d8c7cbf6214b909453f3b26e7ac29480388b79d345efba1ff925ce4617c64c7a9c2f1e578f2e8938f2e51def0d378109f65d276
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
@@ -2,5 +2,5 @@
2
2
  # Namo::VERSION
3
3
 
4
4
  class Namo
5
- VERSION = '0.9.2'
5
+ VERSION = '0.10.0'
6
6
  end
@@ -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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: namo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran