namo 0.24.0 → 0.24.1

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: 9e1ecaf29846a7876a59dae0d82c6c9d4e1fddd84b0c6a101941214ed6544517
4
- data.tar.gz: 4245b13c3485a504ab5c365803de282cb508579b2ca9aec0799df0f1ce653d68
3
+ metadata.gz: 017c3006832fa49d8e63c5de42d927e0e2bb661f05ff322b002a3d1ba18758e2
4
+ data.tar.gz: 65a1c6b04337361f3b692423e85e8066f598ddbd028e0349e4c85b6ebabc183f
5
5
  SHA512:
6
- metadata.gz: 41156dc96b98f59f8ff0dcf0d78f3b80ed895f402e11af9a53ba2e6cdb13d8bf39f1a38f48f2457bfe8bcf9082d146b73dafa4663e068816b2339d6888fd25af
7
- data.tar.gz: e9c1f033e17fd2b10ffab984ea6349b7641de8abf0f04f23f85c893793242abd9e795847244855ad18b8c3f74b5876cce16dd212b2d1d2a6d327998657c9a4dc
6
+ metadata.gz: 989fbb45527739717202af6f6b74df7549488045c41acd3429ea190f7ec5ac4b54e527f684bba86201704ffd3647f2446b282c8f0cc48f2ca68677548e9e1c8b
7
+ data.tar.gz: '00494397772996dd29cf099c7c019d0909d5d61eafaa2dec42a827cc79cad7db0c60fc3ab5172a63acab77dd2034b4a6ad7a7a6440c94485870754563ba94e9f'
data/CHANGELOG CHANGED
@@ -1,6 +1,17 @@
1
1
  CHANGELOG
2
2
  _________
3
3
 
4
+ 20260629
5
+ 0.24.1: ~ Namo#add_row — guard row-append against a data/formula name collision.
6
+
7
+ 0.24.0 left row-append (the Hash/Row arms of <<) unguarded, on the reasoning that the data/formula exclusivity invariant was []='s to keep. That reasoning had a hole: when an appended row carries a key matching an existing formula name and lands as @data.first (e.g. the first row streamed into an empty formulary-bearing Namo), bulk values reads the raw datum (data_dimensions keys off @data.first.keys) while per-Row access derives the formula (Row#[] checks @formulae first) — the two access paths disagree, the precise split the invariant exists to prevent. So add_row now raises rather than admitting the collision, symmetric with attach's guard: a row is a bulk append you didn't name column-by-column, so refusing is safer than []='s call-site eviction.
8
+
9
+ 1. ~ lib/namo.rb: ~ private add_row(row) — + a guard: collisions = row.keys & derived_dimensions; raise ArgumentError naming them unless empty, before appending. A non-colliding row appends and returns self as before. << is otherwise unchanged: Module→attach, Row→add_row(row.to_h), Hash→add_row(row), else→TypeError.
10
+ 2. ~ test/namo_test.rb: + the "#<<" describe gains two guard cases — an appended Hash whose keys collide with a formula raises ArgumentError naming the collision, and an appended Row likewise. The existing non-colliding row/chain tests are unchanged.
11
+ 3. ~ README.md: ~ the Formularies << note — the row arm now states the guard (a row colliding with a formula name raises, symmetric with attach), replacing the 0.24.0 "surfaces live per existing precedence" wording, which held only when the colliding key was not @data.first.
12
+ 4. ~ ROADMAP.md: + the 0.24.1 release entry; current-state bumped to 0.24.1; the 0.24.0 "not guarded" note annotated as guarded at 0.24.1.
13
+ 5. ~ Namo::VERSION: /0.24.0/0.24.1/
14
+
4
15
  20260629
5
16
  0.24.0: ~ Namo#<<, Namo::Collection#<< — widen from a formulary-only alias into a polymorphic "append a constituent" operator.
6
17
 
data/README.md CHANGED
@@ -751,7 +751,7 @@ flows.values(:cum_delta) # => [20, -20, -20]
751
751
  flows.derived_dimensions # => [:signed_volume, :cum_delta]
752
752
  ```
753
753
 
754
- `<<` appends a *constituent*. For a base Namo the constituents are formularies and rows: a **module** attaches (the operator form of `attach`, so `flows << OrderFlow` reads the same as `flows.attach(OrderFlow)`); a **Hash** appends as a data row; a **Row** (one drawn from another Namo) appends its underlying hash as a row. It returns the Namo, so the arms chain freely: `flows << OrderFlow << {date: 4, buys: 10, sells: 5} << Scoring`. Two things `<<` deliberately does not take: a bare callable (formula *registration* stays with `[]=`, which dispatches callable-vs-scalar and enforces data/formula exclusivity) and a whole Namo (combining collections is `+`'s job) — both raise. A bare Hash is therefore always a row, never a body of formulae. Appending a row is a data mutation that does not pass through `[]=`, so it does not trigger formula-eviction; a row carrying a formula-named key is your data, surfacing live through the formula on access per the usual precedence.
754
+ `<<` appends a *constituent*. For a base Namo the constituents are formularies and rows: a **module** attaches (the operator form of `attach`, so `flows << OrderFlow` reads the same as `flows.attach(OrderFlow)`); a **Hash** appends as a data row; a **Row** (one drawn from another Namo) appends its underlying hash as a row. It returns the Namo, so the arms chain freely: `flows << OrderFlow << {date: 4, buys: 10, sells: 5} << Scoring`. Two things `<<` deliberately does not take: a bare callable (formula *registration* stays with `[]=`, which dispatches callable-vs-scalar and enforces data/formula exclusivity) and a whole Namo (combining collections is `+`'s job) — both raise. A bare Hash is therefore always a row, never a body of formulae. Appending a row whose keys collide with an existing formula name **raises** an `ArgumentError` naming the collision — a name is data or derived, never both. The guard is symmetric with `attach`'s: `[]=` names one column at the call site, so its scalar form evicts a same-named formula as your explicit intent, but a row is a bulk append you didn't name column-by-column, so the safe response is to refuse rather than let data and a formula of the same name disagree on access. Contract or rename first, then append.
755
755
 
756
756
  A module brands itself a formulary by including `Namo::Formulary`. The marker is mandatory — `attach` raises `ArgumentError` for an untagged module, so an ordinary module of helpers can't be mistaken for a body of derivations. Within a formulary, the public methods are the derivations and `private` methods are helpers: `net` above never appears in `derived_dimensions` and never resolves as a dimension. The separation needs no per-method declaration — public or private says it.
757
757
 
data/lib/Namo/VERSION.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Namo::VERSION
3
3
 
4
4
  class Namo
5
- VERSION = '0.24.0'
5
+ VERSION = '0.24.1'
6
6
  end
data/lib/namo.rb CHANGED
@@ -260,6 +260,10 @@ class Namo
260
260
  end
261
261
 
262
262
  def add_row(row)
263
+ collisions = row.keys & derived_dimensions
264
+ unless collisions.empty?
265
+ raise ArgumentError, "row keys collide with formulae: #{collisions.inspect}"
266
+ end
263
267
  @data << row
264
268
  self
265
269
  end
data/test/namo_test.rb CHANGED
@@ -794,6 +794,18 @@ describe Namo do
794
794
  _(namo.values(:date)).must_equal [1, 2, 3, 4, 5]
795
795
  _(namo.values(:signed_volume)).must_equal [20, -40, 0, 5, 0]
796
796
  end
797
+
798
+ it "raises an ArgumentError when an appended Hash's keys collide with a formula" do
799
+ namo = Namo.new(flow_data).attach(delta)
800
+ error = _(proc{namo << {date: 4, buys: 10, sells: 5, signed_volume: 999}}).must_raise ArgumentError
801
+ _(error.message).must_match(/signed_volume/)
802
+ end
803
+
804
+ it "raises likewise when an appended Row's keys collide with a formula" do
805
+ namo = Namo.new(flow_data).attach(delta)
806
+ row = Namo.new([{date: 4, buys: 10, sells: 5, signed_volume: 999}]).entries.first
807
+ _(proc{namo << row}).must_raise ArgumentError
808
+ end
797
809
  end
798
810
 
799
811
  describe "#derived_dimensions" do
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.24.0
4
+ version: 0.24.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran