namo 0.31.2 → 0.31.3

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: 820a3c18db30a81cef333ad6b6bd95cd3129610d8d237a0a4f14554d23bdd2e9
4
- data.tar.gz: 8b0c94985ae46c47e8b129eecd7fe7eba7d30f499aea917b2c9e80b1edf2ad7c
3
+ metadata.gz: 611590edfde52f5713b8fe41daf28b5986a26f4df3a5c28631dace995c31b98c
4
+ data.tar.gz: f098e612be772d3232598020963f6b3ed5c9a786f4827de25312e90aff23bc48
5
5
  SHA512:
6
- metadata.gz: a5631205eb63c196e4ba9d6b8cf5bf54807e61a462e55645e216aeb5515d767934413c226a0cb567ae0637002e6c3a80a3490c6db7c94397ae17da2c42ae8c8f
7
- data.tar.gz: 829d09221f044a4572ff7b97bc76c3a84cd7c8ce8e9e2ee8656b2ac5c82a3753d2f793223bdf3125a0e22d925bf86e19078680b78d6dcde7077248aef7488740
6
+ metadata.gz: a28b1d267f69eb14a9ee8d7a9cbdba9de57132be4577a39892e3f679e0ccee293a88a2d526ceda0ff6232317bdb8028ae3f04858160c7a38cbc4cb640c5fff16
7
+ data.tar.gz: e615d6be239ccd8a563922e3b51f5044a745733a4ef3f120b78ab5b07f84a4ff5be37373386853fb9d1484146471fc7034d58af9aee9172e4ae967e341ba0c39
data/CHANGELOG CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## 20260824
4
4
 
5
+ 0.31.3: ~ Namo#to_a: derived dimensions are carried alongside the stored ones.
6
+
7
+ 1. ~ Namo#to_a: each row carries the derived dimensions which can be materialised without arguments, in among its stored keys, so to_a agrees with to_h and with dimensions about what the Namo holds. A formula wanting arguments is omitted, the rule values, coordinates and to_h already follow. Namo#data is unchanged and remains the stored rows; Namo::Row#to_h is unchanged, Row#==, Row#eql? and Namo#<< all reading through it.
8
+ 2. ~ README.md: the Extracting data section, and the parameterised-formula rule which now names to_a.
9
+ 3. ~ ROADMAP.md: + 0.31.3; the open question on which conversions materialise closes for to_a and stays open for Namo::Row.
10
+ 4. ~ Namo::VERSION: /0.31.2/0.31.3/
11
+
12
+ Rebuilding a Namo from to_a now carries the derived dimensions in as stored data. Namo.new(other.to_a) followed by attaching the formulary which produced them raises, the 0.24.1 collision guard refusing the name twice over; []= accepts it, evicting the data. Where the stored rows are what is meant, data is the accessor for them. A formula whose inputs a projection has cut raises through to_a as it has always raised through to_h and values, which 0.16.0 settled as the caller's own choice.
13
+
14
+
5
15
  0.31.2: ~ Namo#inspect: the derived: suffix names only what the rows do not carry.
6
16
 
7
17
  1. ~ Namo#inspect: the derived: suffix names only the derived dimensions the rendered rows do not already carry, and is omitted where they all do. A formula which raises, a parameterised one which cannot be materialised without its arguments, and any formula on a Namo with no rows to render, are named as before, being nowhere else in the output. Namo::Collection renders no rows and so names every one of its own. Namo::Row is unchanged, naming its formulae in every case.
data/README.md CHANGED
@@ -717,7 +717,7 @@ prices.last[:sma] # ArgumentError: wrong number of arguments for :sma
717
717
  prices.last[:close, 20] # ArgumentError: wrong number of arguments for :close (given 1, expected 0)
718
718
  ```
719
719
 
720
- A formula that requires arguments can't be materialised without them. `values(:sma)`, `coordinates(:sma)`, naming `:sma` in a projection, and selecting on it all raise the same `ArgumentError`; the no-argument `values`, `coordinates`, and `to_h` omit the dimension, returning everything that can be materialised. `dimensions` and `derived_dimensions` still list it — it is queryable, with arguments. To materialise particular values, bind the arguments in a one-arity wrapper and ask for that:
720
+ A formula that requires arguments can't be materialised without them. `values(:sma)`, `coordinates(:sma)`, naming `:sma` in a projection, and selecting on it all raise the same `ArgumentError`; the no-argument `values`, `coordinates`, `to_h` and `to_a` omit the dimension, returning everything that can be materialised. `dimensions` and `derived_dimensions` still list it — it is queryable, with arguments. To materialise particular values, bind the arguments in a one-arity wrapper and ask for that:
721
721
 
722
722
  ```ruby
723
723
  prices[:sma_close_20] = proc{|row| row[:sma, :close, 20]}
@@ -947,7 +947,7 @@ The transforming and reducing methods are deliberately left as Enumerable's defa
947
947
 
948
948
  ### Extracting data
949
949
 
950
- `to_a` returns an array of hashes — the row-oriented form:
950
+ `to_a` returns an array of hashes — the row-oriented form, carrying derived dimensions alongside the stored ones, so it agrees with `to_h` and with `dimensions` about what the Namo holds:
951
951
 
952
952
  ```ruby
953
953
  sales[:product, :quarter, :revenue].to_a
@@ -959,6 +959,8 @@ sales[:product, :quarter, :revenue].to_a
959
959
  # ]
960
960
  ```
961
961
 
962
+ `data` is the stored rows, without derived dimensions and without copying — it is the accessor for what the Namo was built from, where `to_a` is the conversion of what it can answer. A formula whose inputs a projection has cut raises through `to_a` as it does through `to_h` and `values`, which is [the caller's own choice](#projection-of-derived-dimensions) rather than a failure of the conversion.
963
+
962
964
  `to_h` returns a hash of arrays — the columnar form (see [Coordinates and values](#coordinates-and-values) above):
963
965
 
964
966
  ```ruby
data/lib/Namo/VERSION.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Namo::VERSION
3
3
 
4
4
  class Namo
5
- VERSION = '0.31.2'
5
+ VERSION = '0.31.3'
6
6
  end
data/lib/namo.rb CHANGED
@@ -241,10 +241,16 @@ class Namo
241
241
  other.subset_of_rows?(self)
242
242
  end
243
243
 
244
+ # Each row's own keys, in their own order, and then the derived dimensions which
245
+ # can be materialised without arguments — the rule values, coordinates and to_h
246
+ # already follow. data is the stored rows, and stays so.
244
247
  def to_a
245
- @data.map do |row|
246
- row.keys.each_with_object({}) do |key, hash|
247
- hash[key] = row[key]
248
+ materialising do
249
+ derived = materialisable_dimensions - data_dimensions
250
+ @data.map do |row|
251
+ subject = Row.new(row, @formulae, self)
252
+ stored = row.keys.each_with_object({}){|key, hash| hash[key] = row[key]}
253
+ derived.each_with_object(stored){|dimension, hash| hash[dimension] = subject[dimension]}
248
254
  end
249
255
  end
250
256
  end
data/test/console_test.rb CHANGED
@@ -33,7 +33,7 @@ describe 'script/console' do
33
33
 
34
34
  it "holds what the fixtures hold, so it cannot drift from the demo" do
35
35
  expected = eval(Fixtures.readings)
36
- _(console('readings.to_a == ' + expected.inspect)).must_match(/true/)
36
+ _(console('readings.data == ' + expected.inspect)).must_match(/true/)
37
37
  end
38
38
 
39
39
  it "starts without echoing its own source" do
data/test/namo_test.rb CHANGED
@@ -488,8 +488,8 @@ describe Namo do
488
488
  sales[:revenue] = proc{|r| r[:price] * r[:quantity]}
489
489
  result = sales[revenue: ->(v){v >= 1500.0}]
490
490
  _(result.to_a).must_equal [
491
- {product: 'Widget', quarter: 'Q2', price: 10.0, quantity: 150},
492
- {product: 'Gadget', quarter: 'Q2', price: 25.0, quantity: 60}
491
+ {product: 'Widget', quarter: 'Q2', price: 10.0, quantity: 150, revenue: 1500.0},
492
+ {product: 'Gadget', quarter: 'Q2', price: 25.0, quantity: 60, revenue: 1500.0}
493
493
  ]
494
494
  end
495
495
  end
@@ -571,8 +571,8 @@ describe Namo do
571
571
  sales[:revenue] = proc{|r| r[:price] * r[:quantity]}
572
572
  result = sales[revenue: 1200.0..]
573
573
  _(result.to_a).must_equal [
574
- {product: 'Widget', quarter: 'Q2', price: 10.0, quantity: 150},
575
- {product: 'Gadget', quarter: 'Q2', price: 25.0, quantity: 60}
574
+ {product: 'Widget', quarter: 'Q2', price: 10.0, quantity: 150, revenue: 1500.0},
575
+ {product: 'Gadget', quarter: 'Q2', price: 25.0, quantity: 60, revenue: 1500.0}
576
576
  ]
577
577
  end
578
578
  end
@@ -602,7 +602,7 @@ describe Namo do
602
602
  sales[:revenue] = proc{|r| r[:price] * r[:quantity]}
603
603
  sales[:cost] = proc{|r| r[:quantity] * 4.0}
604
604
  sales[:profit] = proc{|r| r[:revenue] - r[:cost]}
605
- _(sales[:product, :quarter, :profit].to_a).must_equal [
605
+ _(sales[:product, :quarter, :profit].data).must_equal [
606
606
  {product: "Widget", quarter: "Q1", profit: 600.0},
607
607
  {product: "Widget", quarter: "Q2", profit: 900.0},
608
608
  {product: "Gadget", quarter: "Q1", profit: 840.0},
@@ -1657,8 +1657,8 @@ describe Namo do
1657
1657
  sales[:revenue] = proc{|r| r[:price] * r[:quantity]}
1658
1658
  result = sales.select{|row| row[:revenue] >= 1500.0}
1659
1659
  _(result.to_a).must_equal [
1660
- {product: 'Widget', quarter: 'Q2', price: 10.0, quantity: 150},
1661
- {product: 'Gadget', quarter: 'Q2', price: 25.0, quantity: 60}
1660
+ {product: 'Widget', quarter: 'Q2', price: 10.0, quantity: 150, revenue: 1500.0},
1661
+ {product: 'Gadget', quarter: 'Q2', price: 25.0, quantity: 60, revenue: 1500.0}
1662
1662
  ]
1663
1663
  end
1664
1664
 
@@ -2458,7 +2458,7 @@ describe Namo do
2458
2458
  dated[:cutoff] = proc{|r| r[:date]}
2459
2459
  result = dated.*(quarterly){|row, candidates| candidates[quarter_end: ->(qe){qe <= row[:cutoff]}].sort_by{|f| f[:quarter_end]}.last(1)}
2460
2460
  _(result.to_a).must_equal [
2461
- {symbol: 'BHP', date: '2025-05-20', close: 44.0, quarter_end: '2025-03-31', eps: 1.2}
2461
+ {symbol: 'BHP', date: '2025-05-20', close: 44.0, quarter_end: '2025-03-31', eps: 1.2, cutoff: '2025-05-20'}
2462
2462
  ]
2463
2463
  end
2464
2464
 
@@ -2638,8 +2638,8 @@ describe Namo do
2638
2638
  weighted_tiers[:premium] = proc{|t| t[:max_weight] > 15}
2639
2639
  result = orders.**(weighted_tiers){|row, candidates| candidates[premium: ->(v){v}]}
2640
2640
  _(result.to_a).must_equal [
2641
- {order: 'A', weight: 5, tier: 'heavy', max_weight: 20},
2642
- {order: 'B', weight: 15, tier: 'heavy', max_weight: 20}
2641
+ {order: 'A', weight: 5, tier: 'heavy', max_weight: 20, premium: true},
2642
+ {order: 'B', weight: 15, tier: 'heavy', max_weight: 20, premium: true}
2643
2643
  ]
2644
2644
  end
2645
2645
 
@@ -3067,6 +3067,41 @@ describe Namo do
3067
3067
  it "returns the data as an array of hashes" do
3068
3068
  _(sales.to_a).must_equal sample_data
3069
3069
  end
3070
+
3071
+ it "carries a derived dimension alongside the stored ones" do
3072
+ sales[:revenue] = proc{|row| row[:price] * row[:quantity]}
3073
+ _(sales.to_a.first).must_equal(
3074
+ {product: 'Widget', quarter: 'Q1', price: 10.0, quantity: 100, revenue: 1000.0})
3075
+ end
3076
+
3077
+ it "agrees with to_h about which dimensions there are" do
3078
+ sales[:revenue] = proc{|row| row[:price] * row[:quantity]}
3079
+ _(sales.to_a.first.keys).must_equal sales.to_h.keys
3080
+ _(sales.to_a.first.keys).must_equal sales.dimensions
3081
+ end
3082
+
3083
+ it "omits a formula which cannot be materialised without its arguments" do
3084
+ sales[:revenue] = proc{|row| row[:price] * row[:quantity]}
3085
+ sales[:scaled] = proc{|row, namo, factor| row[:price] * factor}
3086
+ _(sales.to_a.first.keys).wont_include :scaled
3087
+ _(sales.to_a.first.keys).must_include :revenue
3088
+ _(sales.derived_dimensions).must_include :scaled
3089
+ end
3090
+
3091
+ it "raises where a carried formula's inputs were projected away, as 0.16.0 settled" do
3092
+ sales[:revenue] = proc{|row| row[:price] * row[:quantity]}
3093
+ _(->{sales[:product, :quarter].to_a}).must_raise NoMethodError
3094
+ end
3095
+
3096
+ it "leaves data as the stored rows" do
3097
+ sales[:revenue] = proc{|row| row[:price] * row[:quantity]}
3098
+ _(sales.data).must_equal sample_data
3099
+ _(sales.data.first.keys).wont_include :revenue
3100
+ end
3101
+
3102
+ it "returns fresh rows rather than the stored ones" do
3103
+ _(sales.to_a.first).wont_be_same_as sales.data.first
3104
+ end
3070
3105
  end
3071
3106
 
3072
3107
  describe "#group_by" 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.31.2
4
+ version: 0.31.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran