namo 0.32.3 → 0.32.5

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: 1cd9dd8978eec2325228fe1c867977bb3a7d3392d97884da2cd92b497f7defd3
4
- data.tar.gz: 71c01853d939dfecfb060e796b16ee8f29e050e2509657a68078f136f752299b
3
+ metadata.gz: fca34f0fc6464ae1bbb80a5df45f40b63c496369b7cfbc6b32090e26bf0938f3
4
+ data.tar.gz: f156784556a7fcd2a28cef6f44178e0c4b115617cd5e64f173cfb42ca768fb53
5
5
  SHA512:
6
- metadata.gz: 9c8f2926ab8e9f94c06a72873c0b20d65754fc1bc5a08f76aeac791bcbb24b12c8909a89d62d7a89df313115f575821eea707ee7836df2d4fe0e682ea9794efc
7
- data.tar.gz: 9cea051b58185b3ba6d64d737d1d2da6f72378d628cfd7fe196e80f82619cc5ccfcfc06af02ba3400500d45b62dc85e6c51ae92e4f48e2a2570491fb6328a40b
6
+ metadata.gz: e47d75b0e5a23a4f131de7d8d3865dc27ad74ef91a2e87cb7c8d36a2c127784a11cf1b767978ec54b6fabf48c99f25f9a09839e229d3abd36f3851d801549257
7
+ data.tar.gz: c1f4a2ae0e3946c4c02e1f4d643b18666214224b58602ffd9185410f7e66ea949d96a1521582f98b095b9cf7b703f665014e8e42f43ed7ef65a4647da3b8efc5
data/CHANGELOG CHANGED
@@ -1,7 +1,27 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 20261003
4
+
5
+ 0.32.5: Documentation clean up.
6
+
7
+ 1. ~ README.md: + what Symbol#-@ costs, and why `/` dedupes.
8
+ 2. ~ COMPARISON.md: decomposition is relational projection, dedup and all.
9
+ 3. ~ ROADMAP.md: + the 0.9.0 memoir's 2026-10 note and the "How the demonstration ships" section.
10
+ 4. ~ lib/namo.rb: the inspected_rows comment corrected.
11
+ 5. ~ namo.gemspec: the gem name heads the file list.
12
+ 6. ~ CHANGELOG: the 0.21.0, 0.22.0 and 0.23.0 entries aligned with the commit message for each.
13
+ 7. ~ Namo::VERSION: /0.32.4/0.32.5/
14
+
3
15
  ## 20260828
4
16
 
17
+ 0.32.4: ~ README.md: + Console, the command the gem has shipped since 0.32.0 going unmentioned until now.
18
+
19
+ 1. ~ README.md: + Console. `namo console` and `namo setup` had appeared nowhere: the gem gained an executable at 0.32.0 and the README named install.sh once, in the curl line, and the command not at all. Someone taking `gem install namo`, the first line of Installation, arrived at the library without learning that the console existed.
20
+ 2. ~ README.md: + the clone route, `git clone` and ./install.sh, which is the route the adjacent-bin/namo handover of 0.32.3 was written for and the one route no line described.
21
+ 3. ~ README.md: `gem install` and the Gemfile line say what they leave undone — the command is on the PATH only where gem's own directory is, which Homebrew's Ruby is the case against, and measurand arrives by `namo setup` rather than with the gem, a gemspec having no way to name a companion which is optional.
22
+ 4. ~ CHANGELOG: the 20260828 releases gather under one heading, as 20260824 and 20260826 gather theirs. Four releases in a day had taken a heading each.
23
+ 5. ~ Namo::VERSION: /0.32.3/0.32.4/
24
+
5
25
  0.32.3: ~ install.sh: + ruby-install, for a machine with no package manager at all; the handover is to a clone's own bin/namo where the script was run from one.
6
26
 
7
27
  1. ~ install.sh: + install_ruby_install, + ruby_from_ruby_install. Where no package manager is found and Homebrew is declined, ruby-install is offered — fetched from its latest release rather than a pinned version, built with make as root, and used to build Ruby. It is the last thing tried and the only route here which builds Ruby rather than fetching it.
@@ -12,9 +32,6 @@
12
32
  6. ~ install.sh: + repository, and hand_over takes the clone it was given. install_namo is the bootstrap for the handover and nothing else — a way to have a namo command to run — so a script run from a checkout hands over to that checkout's bin/namo and leaves the gem to `namo setup`, which installs it as its own first act. A checkout with the gem not yet installed now works as it stands, and the gem is named once rather than by both scripts in turn. 0.32.1 had taken the path lookup out for being unconditional, which failed piped from curl where the working directory is not a checkout; it is guarded now on $0 being a readable file beside both bin/namo and the gemspec, none of which holds for the shell's own name, so the curl route finds nothing and installs the gem as it did.
13
33
  7. ~ Namo::VERSION: /0.32.2/0.32.3/
14
34
 
15
-
16
- ## 20260828
17
-
18
35
  0.32.2: ~ install.sh: the one command ends with namo runnable from anywhere.
19
36
 
20
37
  1. ~ install.sh: + add_to_path, + gem_bin_directory, + shell_configuration_file. gem puts the command in a directory which is on the PATH on some machines and not on others — Homebrew's ruby puts it somewhere which is not — so the run ended by naming the directory and stopping. It now offers to add it to the shell's configuration file, and adds it to the PATH of the run itself so that `namo setup` happens rather than being left as a further instruction.
@@ -23,9 +40,6 @@
23
40
  4. ~ install.sh: + apt-get, dnf, pacman and zypper alongside Homebrew and MacPorts, so the script reaches a Ruby on Linux rather than offering to install Homebrew on a machine which has apt. + install_with_sudo, every package manager but Homebrew installing as root, so the password is asked for by name rather than arriving unannounced.
24
41
  5. ~ Namo::VERSION: /0.32.1/0.32.2/
25
42
 
26
-
27
- ## 20260828
28
-
29
43
  0.32.1: ~ install.sh: it runs the same piped from curl as from a clone, and forces no package manager; ~ README.md: + the one-line install.
30
44
 
31
45
  1. ~ install.sh: the handover is to `namo setup` on the PATH rather than to bin/namo beside the script. It had found bin/namo by its own path, so piped from curl it looked in the working directory and failed there. It now finds nothing by its path and so runs from anywhere. The check is for the namo command rather than for the gem, that being what the next step needs: an older namo installs no executable.
@@ -35,8 +49,6 @@
35
49
  5. ~ Namo::VERSION: /0.32.0/0.32.1/
36
50
 
37
51
 
38
- ## 20260828
39
-
40
52
  0.32.0: + bin/namo, the gem's first executable, and the gems it installs.
41
53
 
42
54
  1. + bin/namo: a setup subcommand which installs the gems Namo's scripts want — Namo itself, so that a clone leaves require 'namo' working, and measurand, which the demo's uncertainty section does without when it is missing — and a console subcommand which is bin/console. Each step asks first and says so when there is nothing to do.
data/README.md CHANGED
@@ -18,12 +18,42 @@ Or in your Gemfile:
18
18
  gem 'namo'
19
19
  ```
20
20
 
21
+ Either brings the `namo` command with it, where the directory gem installs commands into is one your PATH reaches — it is on a Ruby from ruby-install or rbenv, and is not on Homebrew's. `namo setup` then adds measurand, which the uncertainty examples want and which nothing else does.
22
+
23
+ Or from a clone, which wants none of it installed first:
24
+
25
+ ```
26
+ git clone https://github.com/thoran/namo.git
27
+ cd namo
28
+ ./install.sh
29
+ ```
30
+
21
31
  Or from nothing at all — Ruby, the gem, and the gems its scripts want, each step skipped where it is already there. Where Ruby is missing, whichever package manager is already installed supplies it — Homebrew, MacPorts, apt, dnf, pacman or zypper; where none is, you are asked before Homebrew is installed, and then before ruby-install is built from source; `-y` answers yes in advance, and a machine with nobody at the keyboard is taken to have said no. Where the gem's own directory is not on the PATH, it offers to add it to your shell's configuration, so that a new shell has `namo` in it:
22
32
 
23
33
  ```
24
34
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/thoran/namo/master/install.sh)"
25
35
  ```
26
36
 
37
+ The two which run `install.sh` end at a `namo` which runs from anywhere. The first ends at one which runs where your PATH already reaches it.
38
+
39
+ ## Console
40
+
41
+ The gem ships one command.
42
+
43
+ ```
44
+ namo console
45
+ ```
46
+
47
+ An irb session with Namo loaded, for asking a question of the library without writing a file first.
48
+
49
+ ```
50
+ namo setup
51
+ ```
52
+
53
+ Installs the gems the scripts want — namo itself, and measurand — skipping whichever is already there and naming each and its version either way. `install.sh` runs it as the last of its own work, so it is here for a gem which arrived by `gem install`, and for adding measurand to an installation which went without it.
54
+
55
+ `namo` alone prints the usage, as `namo --help` does.
56
+
27
57
  ## Usage
28
58
 
29
59
  Create a Namo instance from an array of hashes:
@@ -184,6 +214,8 @@ The `-:price` syntax uses unary minus on Symbol to produce a negated dimension.
184
214
  sales[:product, -:price] # => ArgumentError
185
215
  ```
186
216
 
217
+ `-:price` is not a local trick: unary minus is defined on Symbol itself (`lib/Symbol.rb`), so once `namo` is loaded, every Symbol in the process has a `-@` it did not have before. Nothing in Ruby or its standard library reads a negated Symbol as anything — the ground was empty — so a collision would take another library claiming the same operator for its own purpose, and contraction is the part of Namo which yields if one does.
218
+
187
219
  Selection and contraction can be chained:
188
220
 
189
221
  ```ruby
@@ -467,7 +499,7 @@ combined / fundamentals
467
499
 
468
500
  The intersection of dimensions — here `:symbol` and `:pe` — is removed. Everything else stays. The projected rows are deduplicated, so `/` answers "what's left when these dimensions are factored out?" rather than "what rows survive a column drop?". Formulae carry through from the left-hand side.
469
501
 
470
- `/` has no precondition. When the two Namos share no dimensions, the intersection is empty, nothing is removed, and `self / other` returns a Namo equal to self:
502
+ `/` has no precondition. When the two Namos share no dimensions, the intersection is empty, nothing is removed, and `self / other` returns a Namo equal to self (multiplicity aside — the deduplication above still applies, so "equal" here means equal on duplicate-free rows):
471
503
 
472
504
  ```ruby
473
505
  shipments = Namo.new([{order_id: 1, weight: 10}])
@@ -477,7 +509,7 @@ shipments / weather
477
509
  # => #<Namo [{order_id: 1, weight: 10}]> — equal to shipments
478
510
  ```
479
511
 
480
- The round-trip identity holds for the `**` case exactly:
512
+ The round-trip identity holds for the `**` case exactly — again on duplicate-free rows, for the reason given below:
481
513
 
482
514
  ```ruby
483
515
  a = Namo.new([{symbol: 'BHP'}, {symbol: 'RIO'}])
@@ -495,7 +527,7 @@ b = Namo.new([{symbol: 'BHP', pe: 14.5}, {symbol: 'RIO', pe: 9.2}])
495
527
 
496
528
  (a * b) / b
497
529
  # => #<Namo [{close: 42.5}, {close: 118.3}]>
498
- # Equal to a[-:symbol]. :symbol was shared and is lost.
530
+ # Equal to a[-:symbol] on duplicate-free rows. :symbol was shared and is lost.
499
531
  ```
500
532
 
501
533
  The asymmetry is inherent: `/` operates only on the two values it receives and can't distinguish "shared dimension that belonged to both" from "exclusive dimension that belonged only to the right". Removing the intersection is the only rule expressible from the operands alone, and it gives clean recovery from `**` and well-defined (if lossy) recovery from `*`.
@@ -504,14 +536,20 @@ The asymmetry is inherent: `/` operates only on the two values it receives and c
504
536
 
505
537
  `*` and `**` raise when their preconditions are violated — combining unrelated Namos has no natural answer, and silently producing arbitrary output would turn a logic error into a large pile of nonsense rows. `/` is different: it's a projecting operator, not a combining one, and projecting away nothing returns the original. The no-precondition rule isn't a fallback; it's the structurally correct result.
506
538
 
507
- This earns `/` three properties a strict version would lose:
539
+ This earns `/` three properties a strict version would lose, each stated for duplicate-free rows (the projection deduplicates; see below):
508
540
 
509
541
  - **Identity test.** `combined / other == combined` exactly when the two have no shared dimensions — answers "are these Namos dimensionally independent?" without explicit introspection. Same shape as `a & b == a` answering subset from 0.6.0.
510
542
  - **Idempotence.** `(c / b) / b == c / b`. Once `b`'s dimensions are removed, removing them again does nothing.
511
- - **Pipeline composition.** A processing step that applies `/ separator` can run over any Namo regardless of whether the separator's dimensions apply. Uninvolved Namos pass through unchanged; involved Namos get stripped. The pipeline doesn't need to special-case applicability.
543
+ - **Pipeline composition.** A processing step that applies `/ separator` can run over any Namo regardless of whether the separator's dimensions apply. Uninvolved Namos pass through stripped of nothing but duplicate rows; involved Namos get their shared dimensions stripped. The pipeline doesn't need to special-case applicability.
512
544
 
513
545
  This is the same pattern that makes `Array#-` useful with arrays that aren't subsets: `[1, 2, 3] - [9] == [1, 2, 3]`, not an error. The no-op-on-non-applicable behaviour lets the operator compose into pipelines that don't know in advance whether the operation applies.
514
546
 
547
+ #### Why `/` dedupes
548
+
549
+ `/` is the one operator outside the set family (`&`, `|`, `^`) and the explicitly collapsing verbs (`uniq`, `coordinates`) that drops multiplicities — everywhere else duplicate rows are data. The collapse is definitional, and is in fact what makes `/` the inverse of the composers at all: `**` with a multi-row right operand manufactures multiplicities on the left operand's rows, so any projection that kept them could never satisfy `(a ** b) / b == a`. Inversion is only a function once duplicates are collapsed.
550
+
551
+ Projection with multiplicities intact is one line of existing operators: `namo[*other.data_dimensions.map{|d| -d}]` — contraction over the other operand's dimensions. `[]`, contraction, and everything else in the row algebra are bag-faithful, so nothing essential goes unspellable; what `/` alone adds over the contraction spelling is operand-keying plus the collapse, which is to say, its role as the composition algebra's decomposer.
552
+
515
553
  ### Equality
516
554
 
517
555
  Comparison on Namos is **multiset-theoretic on rows**: the comparison operators — `==`, `eql?`, `===`, `<`, `<=`, `>`, `>=` — ignore row order, so two Namos holding the same rows in a different order compare equal, while row multiplicities count (they *are* data). That stance is shared across the equality, pattern-match, and subset/superset operators documented below. Row order is otherwise preserved: `to_h` and `values` depend on it for columnar alignment, and `each`, `first`, `last`, `take`, `drop`, and `+` all observe it. It is the comparison operators alone that treat the sequence of rows as a multiset.
data/lib/Namo/VERSION.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Namo::VERSION
3
3
 
4
4
  class Namo
5
- VERSION = '0.32.3'
5
+ VERSION = '0.32.5'
6
6
  end
data/lib/namo.rb CHANGED
@@ -306,9 +306,10 @@ class Namo
306
306
  @name.nil? ? '' : " #{@name.inspect}"
307
307
  end
308
308
 
309
- # The rows as they are stored, never the derived values: inspect is called
310
- # for every result in a console, and evaluating a formula there would cost a
311
- # pass over the data per access and raise whatever the formula raises.
309
+ # inspect is called for every result in a console, so evaluating the derived
310
+ # dimensions is bounded to the rows shown — INSPECTED_ROWS of them, one
311
+ # evaluation each — and a formula which raises renders no value rather than
312
+ # raising out of inspect. The cost is constant however large the data.
312
313
  def inspected_rows(rendered)
313
314
  return ' []' if @data.empty?
314
315
  shown = rendered.map{|row, derived| " #{row.merge(derived).inspect}"}.join(",\n")
data/namo.gemspec CHANGED
@@ -27,13 +27,13 @@ Gem::Specification.new do |spec|
27
27
  spec.require_paths = ['lib']
28
28
 
29
29
  spec.files = [
30
+ 'namo.gemspec',
30
31
  Dir['bin/*'],
31
32
  Dir['lib/**/*.rb'],
32
33
  Dir['test/**/*.rb'],
33
34
  'CHANGELOG',
34
35
  'Gemfile',
35
36
  'LICENSE',
36
- 'namo.gemspec',
37
37
  'Rakefile',
38
38
  'README.md',
39
39
  ].flatten
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.32.3
4
+ version: 0.32.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubygems_version: 4.0.19
108
+ rubygems_version: 4.0.21
109
109
  specification_version: 4
110
110
  summary: Named dimensional data for Ruby.
111
111
  test_files: []