namo 0.21.0 → 0.22.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: 07d3c62244d72800b8f533d4618c8f51b4161338c37dc439ad26f67557a7315f
4
- data.tar.gz: 7b8c6c808068b97555bb8f98a1d1ecb55a399e16fc51e475b61f13cbad4f0cef
3
+ metadata.gz: e6342f1cab3b5811a97d92be8ef7ba34a81191bd97a6ee2c606f8adc7d9a0d47
4
+ data.tar.gz: ce7db23d2907e33a80d1e263b4b9987645a6c1c47979b7f3311bf519d8f9e738
5
5
  SHA512:
6
- metadata.gz: 58db7e089c9a6be6e9d050a549cf5df98983227d3a3d218d0d5f61ee2684009a1af5f4069cb16376fe8211425060fe2b1d609fb5b6770236726782fa57a35b20
7
- data.tar.gz: a4327a3484ffc1b30755ed38f94c2e432f0d6e338f5348a75b854c1cdebcfedebab4a742441d5e542c832d4a0aa517dc67a51f8b926462f2c0ab4ecad4a990d8
6
+ metadata.gz: 5c6c26eda0a637af215eef9cab0fe369769af3e945b3a1cf980788bd34be97abeefb3cf29fb208012556c5df9e46c212c9476dc222b0f3917404c7db3003f21a
7
+ data.tar.gz: f71fd3ed7b8e8068b55fbb8379cd361c91c84ca1cb4fe823ff72af9fe1c9b8e1247468fb9fd818aa865cac709aa2d22e63f2c866030cacee22bf25c5930e7758
data/CHANGELOG CHANGED
@@ -1,6 +1,32 @@
1
1
  CHANGELOG
2
2
  _________
3
3
 
4
+ 20260626
5
+ 0.22.0: + Formulae#derive — move formula invocation out of Row#[] and into Formulae. [] keeps its meaning (the stored callable, as at 0.21.0); the new derive(name, row, namo, *arguments) resolves a named formula to its value. derive over call: the receiver is the collection, not the callable, so the verb says the collection derives a value via the named rule rather than borrowing Proc#call's "invoke the receiver"; and the result is whatever the proc returns, not necessarily numeric, which a neutral verb leaves open. Indexing a Formulae is storage access, not a Namo operation, so [] returning the callable carries no inconsistency with the dimension-value [] of Namo and Row — different domains, same spelling. Behaviour-preserving at the usage level: row[:revenue], namo[:x] = formula, values, and selections are unchanged.
6
+
7
+ 1. ~ lib/Namo/Formulae.rb: + derive(name, row, namo, *arguments), the formula resolver —
8
+ invocation mechanics lifted whole from Row's formula branch (collection-scoped formulae
9
+ are called (row, namo, *arguments), row-only formulae (row)). + required_parameter_count(name),
10
+ public, a property of the stored callable. collection_scoped? and raise_unless_namo_context
11
+ move in as private; the latter takes namo as a parameter rather than closing over Row's
12
+ @namo. [] and []= are untouched — [] still returns the stored callable.
13
+ 2. ~ lib/Namo/Row.rb: #[] delegates formula resolution to
14
+ @formulae.derive(name, self, @namo, *arguments); Row keeps only the fail-fast argument
15
+ guard, the formula-vs-data dispatch (@formulae.key?), and the data fallback (@row[name]).
16
+ collection_scoped?, required_parameter_count, and raise_unless_namo_context are gone
17
+ (now Formulae's). expected_argument_counts sources the count from
18
+ @formulae.required_parameter_count and the fixed-vs-variadic check from
19
+ @formulae[name].arity.
20
+ 3. + test/Namo/Formulae_test.rb: + #derive tests (row-only to value, collection-scoped with
21
+ namo context, missing-namo-context raise, parameterised with arguments) and +
22
+ #required_parameter_count tests (row-only, collection-scoped, parameterised, variadic).
23
+ The #[] and #[]= blocks are unchanged — [] still returns the callable.
24
+ 4. ~ test/Namo/Row_test.rb: the formulae fixture is a Namo::Formulae, not a bare {} — Row
25
+ now delegates formula resolution to its collaborator (call, required_parameter_count),
26
+ which production always wraps (lib/namo.rb initialize). The data-only equality/match
27
+ tests keep their {} literals: they never resolve a formula, so Hash#key? alone answers.
28
+ 5. ~ Namo::VERSION: /0.21.0/0.22.0/
29
+
4
30
  20260625
5
31
  0.21.0: + Namo::Formulae; @formulae: /Hash/Namo::Formulae/. Behaviour-preserving: no new capability, just an object for the formula collection to accrete behaviour onto later, mirroring the 0.1.0 extraction of Row.
6
32
 
data/lib/Namo/Formulae.rb CHANGED
@@ -13,6 +13,21 @@ class Namo
13
13
  @store[name] = callable
14
14
  end
15
15
 
16
+ def derive(name, row, namo, *arguments)
17
+ formula = self[name]
18
+ if collection_scoped?(name)
19
+ raise_unless_namo_context(name, namo)
20
+ formula.call(row, namo, *arguments)
21
+ else
22
+ formula.call(row)
23
+ end
24
+ end
25
+
26
+ def required_parameter_count(name)
27
+ formula = self[name]
28
+ formula.arity >= 0 ? formula.arity : -formula.arity - 1
29
+ end
30
+
16
31
  def keys
17
32
  @store.keys
18
33
  end
@@ -67,5 +82,15 @@ class Namo
67
82
  def initialize(store = {})
68
83
  @store = store
69
84
  end
85
+
86
+ def collection_scoped?(name)
87
+ required_parameter_count(name) >= 2
88
+ end
89
+
90
+ def raise_unless_namo_context(name, namo)
91
+ unless namo
92
+ raise ArgumentError, "collection-scoped formula #{name.inspect} requires a Namo context, but this Row has none"
93
+ end
94
+ end
70
95
  end
71
96
  end
data/lib/Namo/Row.rb CHANGED
@@ -6,13 +6,7 @@ class Namo
6
6
  def [](name, *arguments)
7
7
  raise_unless_expected_arguments(name, arguments)
8
8
  if @formulae.key?(name)
9
- formula = @formulae[name]
10
- if collection_scoped?(formula)
11
- raise_unless_namo_context(name)
12
- formula.call(self, @namo, *arguments)
13
- else
14
- formula.call(self)
15
- end
9
+ @formulae.derive(name, self, @namo, *arguments)
16
10
  else
17
11
  @row[name]
18
12
  end
@@ -57,19 +51,12 @@ class Namo
57
51
  @namo = namo
58
52
  end
59
53
 
60
- def collection_scoped?(formula)
61
- required_parameter_count(formula) >= 2
62
- end
63
-
64
- def required_parameter_count(formula)
65
- formula.arity >= 0 ? formula.arity : -formula.arity - 1
66
- end
67
-
68
54
  def expected_argument_counts(name)
69
- formula = @formulae[name]
70
- return [0, 0] unless formula && collection_scoped?(formula)
71
- minimum = required_parameter_count(formula) - 2
72
- maximum = formula.arity >= 0 ? minimum : nil
55
+ return [0, 0] unless @formulae.key?(name)
56
+ count = @formulae.required_parameter_count(name)
57
+ return [0, 0] unless count >= 2
58
+ minimum = count - 2
59
+ maximum = @formulae[name].arity >= 0 ? minimum : nil
73
60
  [minimum, maximum]
74
61
  end
75
62
 
@@ -79,11 +66,5 @@ class Namo
79
66
  expected = maximum.nil? ? "#{minimum}+" : minimum.to_s
80
67
  raise ArgumentError, "wrong number of arguments for #{name.inspect} (given #{arguments.length}, expected #{expected})"
81
68
  end
82
-
83
- def raise_unless_namo_context(name)
84
- unless @namo
85
- raise ArgumentError, "collection-scoped formula #{name.inspect} requires a Namo context, but this Row has none"
86
- end
87
- end
88
69
  end
89
70
  end
data/lib/Namo/VERSION.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Namo::VERSION
3
3
 
4
4
  class Namo
5
- VERSION = '0.21.0'
5
+ VERSION = '0.22.0'
6
6
  end
@@ -26,6 +26,54 @@ describe Namo::Formulae do
26
26
  end
27
27
  end
28
28
 
29
+ describe "#derive" do
30
+ let(:row) do
31
+ {price: 10.0, quantity: 100}
32
+ end
33
+
34
+ it "resolves a row-only formula to its value" do
35
+ _(formulae.derive(:revenue, row, nil)).must_equal 1000.0
36
+ end
37
+
38
+ it "resolves a collection-scoped formula with the namo context" do
39
+ namo = Object.new
40
+ formulae[:context] = ->(r, n){n}
41
+ _(formulae.derive(:context, row, namo)).must_be_same_as namo
42
+ end
43
+
44
+ it "raises ArgumentError naming the formula when a collection-scoped formula has no namo context" do
45
+ formulae[:context] = ->(r, n){n}
46
+ error = _(proc{formulae.derive(:context, row, nil)}).must_raise ArgumentError
47
+ _(error.message).must_match(/context/)
48
+ end
49
+
50
+ it "resolves a parameterised formula with arguments" do
51
+ formulae[:scaled] = ->(r, n, factor){r[:price] * factor}
52
+ _(formulae.derive(:scaled, row, Object.new, 3)).must_equal 30.0
53
+ end
54
+ end
55
+
56
+ describe "#required_parameter_count" do
57
+ it "counts a row-only formula" do
58
+ _(formulae.required_parameter_count(:revenue)).must_equal 1
59
+ end
60
+
61
+ it "counts a collection-scoped formula" do
62
+ formulae[:context] = ->(r, n){n}
63
+ _(formulae.required_parameter_count(:context)).must_equal 2
64
+ end
65
+
66
+ it "counts a parameterised formula" do
67
+ formulae[:scaled] = ->(r, n, factor){r[:price] * factor}
68
+ _(formulae.required_parameter_count(:scaled)).must_equal 3
69
+ end
70
+
71
+ it "excludes the splat when counting a variadic formula" do
72
+ formulae[:variadic] = ->(r, n, *rest){rest}
73
+ _(formulae.required_parameter_count(:variadic)).must_equal 2
74
+ end
75
+ end
76
+
29
77
  describe "#[]=" do
30
78
  it "stores a callable under a name" do
31
79
  formulae[:cost] = cost
@@ -10,7 +10,7 @@ describe Namo::Row do
10
10
  end
11
11
 
12
12
  let(:formulae) do
13
- {}
13
+ Namo::Formulae.new
14
14
  end
15
15
 
16
16
  let(:row) 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.21.0
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran