asciichem 0.31.11 → 0.31.13

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: 0c34f02af4a10568830f6c8b7eec3c81e9d3b3477940c10e60b9f3d0c67a1c43
4
- data.tar.gz: 925739226d852f4f9f014fece5d97867f2447122c7d604e569b4b7369b3751b2
3
+ metadata.gz: 13b35ffffbfa3349f95961b56e7dae9e74d55a116554a76c1175f3f74e347183
4
+ data.tar.gz: ea78a952280a73728fbd27cff80af8e3eebf163e45b8428ece6171a588471b55
5
5
  SHA512:
6
- metadata.gz: dced2b7d4bccf54c4ab258c6024bb8732bb1e5d5c4241eabc1a041117aa13252ccc67b01890e22f8f784d96152d5afb4d4e7ecbfc701dad50d953701213dc872
7
- data.tar.gz: 0c963559e1116042a17a1434c6d56949de632dc1d744e44a66bc3d5b3dde3394baa3818b73c9f231aeefdbf01fe0db46d557ae19bd4de8137d912fea6d285e49
6
+ metadata.gz: 538a97d2151764c9c84026ecccf32380ca82393158ac56d85af050aceab459ca47eb23a7828fb48bb5ed9fbe8289b11d2a5583bd8bd8b96f40ee20002247d5d8
7
+ data.tar.gz: 6edff89d3e29935de3227db81ef9126d6d7ce46cf0c39d58343114522d88205de9d969d99f760e6bd8602bc71f85fd80310b8730684769c31ec9aa21fa8f0413
data/CHANGELOG.md CHANGED
@@ -3,6 +3,32 @@
3
3
  All notable changes to AsciiChem are documented here.
4
4
  This project follows [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [0.31.13] - 2026-11-11
7
+
8
+ ### Fixed
9
+ - `Resolver.resolve_all` isolates source-level failures: a live probe
10
+ found the Common Chemistry API now answers 401 without an API key
11
+ (CAS key-gated the endpoint); with it registered by default, that
12
+ 401 raised through the multi-source fan-out and took the other
13
+ sources down with it. A source-level error now skips that source —
14
+ callers see what answered.
15
+
16
+ ### Changed
17
+ - The README documents the full capability surface: structures,
18
+ lint, local identity, resolution with provenance, citations, and
19
+ the command line.
20
+
21
+ ## [0.31.12] - 2026-11-11
22
+
23
+ ### Changed
24
+ - CAS Common Chemistry resolves by default (maintainer decision:
25
+ CC BY-NC 4.0 acceptable on by default). The adapter self-registers
26
+ like the other sources; every result still carries the required
27
+ attribution. `Citation.for_molecule` accepts a `sources:`
28
+ allow-list so callers can keep resolution NC-free — the
29
+ metanorma plugin exposes it as the `asciichem-sources` document
30
+ attribute.
31
+
6
32
  ## [0.31.11] - 2026-11-10
7
33
 
8
34
  ### Added
data/README.adoc CHANGED
@@ -45,6 +45,91 @@ formula.to_mathml # => "<math>...</math>"
45
45
  formula.to_text # => "H_2O" (round trip)
46
46
  ----
47
47
 
48
+ The parsed model is the canonical form: MathML, HTML, LaTeX, text,
49
+ linear and 2D structural SVG, and CML are views over the same tree.
50
+
51
+ === Structures: SMILES and molfile in, AsciiChem out
52
+
53
+ [source,ruby]
54
+ ----
55
+ formula = AsciiChem.parse_smiles("CC(=O)Oc1ccccc1C(=O)O")
56
+ formula.to_structural_svg # 2D depiction, deterministic layout
57
+ formula.to_smiles # canonical aromatic SMILES
58
+ formula.to_text # AsciiChem text
59
+
60
+ formula = AsciiChem.parse_molfile(molfile_text) # V2000 in and out
61
+ ----
62
+
63
+ === Lint
64
+
65
+ [source,ruby]
66
+ ----
67
+ AsciiChem::Linter.run(formula) # chemistry diagnostics: balance,
68
+ # valence, charge, isotopes, rings,
69
+ # identifier consistency, ...
70
+ AsciiChem::Linter.errors?(formula) # => true/false
71
+ ----
72
+
73
+ === Local identity: InChI, AuxInfo, InChIKey
74
+
75
+ [source,ruby]
76
+ ----
77
+ require "asciichem/inchi"
78
+
79
+ # the native chemomer engine (byte-exact vs the IUPAC oracle;
80
+ # CHEMOMER_LIB points at the built cdylib) or the IUPAC binary:
81
+ AsciiChem::Inchi.engine = AsciiChem::Inchi::NativeEngine.new
82
+
83
+ identity = AsciiChem::Inchi.identity_for(molecule)
84
+ identity.inchi # "InChI=1S/C9H8O4/..."
85
+ identity.inchikey # "BSYNRYMUTXBXSQ-UHFFFAOYSA-N"
86
+ ----
87
+
88
+ === Resolution: identifiers to substance records
89
+
90
+ [source,ruby]
91
+ ----
92
+ require "asciichem/resolver"
93
+
94
+ substance = AsciiChem::Resolver.resolve(value: "50-78-2", convention: "cas")
95
+ substance.preferred_name # => "Aspirin"
96
+ substance.structure.to_smiles # from the source record
97
+ substance.identifiers.first.provenance.source # "common_chemistry"
98
+
99
+ # all shipped sources (PubChem, OPSIN, CAS Common Chemistry) resolve
100
+ # by default; attribution rides every record. Limit the set when a
101
+ # use must stay NC-free:
102
+ AsciiChem::Resolver.resolve(value: "50-78-2", convention: "cas",
103
+ sources: [:pubchem, :opsin])
104
+ ----
105
+
106
+ === Citations: dataset bibitems with provenance
107
+
108
+ [source,ruby]
109
+ ----
110
+ require "asciichem/citation"
111
+
112
+ molecule = AsciiChem.parse("CC(=O)OC1=CC=CC=C1C(=O)O @cas(\"50-78-2\") @cite(\"pubchem\")").nodes.first
113
+ AsciiChem::Citation.for_molecule(molecule)
114
+ # => [["pubchem", #<Relaton bibitem>]] - one dataset-type bibitem per
115
+ # (substance, source), anchored by InChIKey, with a provenance note
116
+ # (retrieved from, version, attribution).
117
+ ----
118
+
119
+ == Command line
120
+
121
+ [source,sh]
122
+ ----
123
+ asciichem convert -i "H_2O" -t mathml # also: --from smiles|molfile
124
+ asciichem identity -i aspirin.smiles --from smiles
125
+ asciichem resolve --cas 50-78-2 --source common_chemistry
126
+ asciichem validate -i 'H_2O @cas("50-78-2")'
127
+ asciichem cite --cas 50-78-2 -t model-json
128
+ asciichem lint -i "2H_2 + O_2 -> 2H_2O"
129
+ asciichem roundtrip -i "C_6H_12O_6"
130
+ asciichem parse-cml -i formula.xml
131
+ ----
132
+
48
133
  == Conformance
49
134
 
50
135
  The reference implementation of https://www.asciichem.org[the AsciiChem
@@ -60,7 +145,7 @@ a level without the green corpus run behind it does not ship.
60
145
  |L1 semantics |yes |wire form validates against the v1 schemas and round-trips; the perception pass (implicit hydrogens, aromatic rings) is corpus-gated
61
146
  |L2 render |yes |MathML byte-goldens, canonical text, and the wire form for every construct
62
147
  |L3 stereo |yes |tetrahedral chirality, directional bonds, wedge/hash; parity-correct canonical SMILES including ring closures
63
- |L4 identity |partial |opt-in InChI engine with stereo layers, OPSIN adapter, identifier cross-check, citation bibitems; CAS source decision pending
148
+ |L4 identity |yes |opt-in InChI engine (binary or native) with stereo layers, OPSIN adapter, identifier cross-check, resolver (PubChem, OPSIN, and Common Chemistry on by default — CC BY-NC attribution carried everywhere; limit sources with `Resolver.resolve(sources:)`), citation bibitems
64
149
  |===
65
150
 
66
151
  TypeScript and Python claim the same levels they pass; see their
@@ -84,9 +84,15 @@ module AsciiChem
84
84
  #
85
85
  # AsciiChem.parse('H_2O @name("water") @cite("pubchem")')
86
86
  # AsciiChem::Citation.for_molecule(formula.nodes.first).map(&:last)
87
- def for_molecule(molecule, cache: nil, fetch: nil)
88
- sources = citation_sources(molecule)
89
- return [] if sources.empty?
87
+ #
88
+ # `sources:` limits the citable set (an allow-list): cited
89
+ # sources outside it are skipped — the document pipeline (the
90
+ # metanorma plugin's `asciichem-sources` attribute) warns about
91
+ # the exclusions; the gem stays silent and total.
92
+ def for_molecule(molecule, cache: nil, fetch: nil, sources: nil)
93
+ citable = citation_sources(molecule)
94
+ citable &= Array(sources).map(&:to_s) if sources
95
+ return [] if citable.empty?
90
96
 
91
97
  convention, value = lookup_key(molecule)
92
98
  unless value
@@ -95,7 +101,7 @@ module AsciiChem
95
101
  '(annotate @cas/@inchikey/@smiles or @name)'
96
102
  end
97
103
 
98
- sources.filter_map do |source|
104
+ citable.filter_map do |source|
99
105
  substance = AsciiChem::Resolver[source].new.resolve(
100
106
  value: value, convention: convention, cache: cache, fetch: fetch
101
107
  )
@@ -7,16 +7,15 @@ module AsciiChem
7
7
  module Resolver
8
8
  # CAS Common Chemistry source adapter (TODO.impl 40; TODO.v2 07).
9
9
  #
10
- # License posture (maintainer sign-off 2026-09-13): Common
11
- # Chemistry data is CC BY-NC 4.0 — this adapter is OPT-IN and never
12
- # self-registers; users register it explicitly:
13
- #
14
- # AsciiChem::Resolver.register(:common_chemistry,
15
- # AsciiChem::Resolver::CommonChemistry)
16
- #
17
- # Every result carries the required attribution.
10
+ # License posture (maintainer decision 2026-11-11): Common
11
+ # Chemistry data is CC BY-NC 4.0 — acceptable to enable by
12
+ # default; every result carries the required attribution, and the
13
+ # citation track carries it into rendered documents. Documents
14
+ # that must stay NC-free limit sources with the
15
+ # `asciichem-sources` attribute (metanorma-plugin-asciichem) or
16
+ # `Resolver.resolve(sources:)`.
18
17
  class CommonChemistry < Adapter
19
- source_name :common_chemistry, register: false
18
+ source_name :common_chemistry
20
19
  supports "cas"
21
20
 
22
21
  BASE = "https://commonchemistry.cas.org/api/detail"
@@ -9,10 +9,13 @@ module AsciiChem
9
9
  # citation track (TODO.v2 08) emits one bibitem per (substance,
10
10
  # source) the user chooses to cite.
11
11
  #
12
- # Sources are opt-in adapters that self-register (OCP, same pattern
13
- # as the linter checks). NC-licensed sources are never registered by
14
- # default — Common Chemistry ships only after the maintainer
15
- # sign-off recorded in TODO.v2 07.
12
+ # Sources are adapters that self-register (OCP, same pattern
13
+ # as the linter checks). All shipped sources are on by default;
14
+ # every result carries its source's required attribution (Common
15
+ # Chemistry: CC BY-NC 4.0 — default-on per the maintainer decision
16
+ # of 2026-11-11). Callers limit the set explicitly:
17
+ # `Resolver.resolve(sources:)` or the metanorma plugin's
18
+ # `asciichem-sources` attribute for NC-free documents.
16
19
  module Resolver
17
20
  autoload :Adapter, "asciichem/resolver/adapter"
18
21
  autoload :Cache, "asciichem/resolver/cache"
@@ -40,16 +43,23 @@ module AsciiChem
40
43
  raise Error, "unknown resolver source #{name.inspect} (registered: #{adapters.keys.sort.join(', ')})"
41
44
  end
42
45
 
43
- # Resolves against every opt-in source, returning one Substance
44
- # per source that answers (nil entries dropped). Sources answer
45
- # in registration order.
46
+ # Resolves against every registered source (or the selected
47
+ # subset), returning one Substance per source that answers (nil
48
+ # entries dropped). Sources answer in registration order. A
49
+ # source-level failure (HTTP error, rejected request) skips that
50
+ # source — one dead or key-gated endpoint must not poison the
51
+ # others; callers see what answered.
46
52
  def resolve_all(value:, convention:, sources: nil, fetch: nil, cache: nil, refresh: false)
47
53
  selected = sources ? Array(sources).map { |s| self[s] } : adapters.values
48
54
  selected.filter_map do |adapter_class|
49
55
  adapter = adapter_class.new
50
56
  next unless adapter.supports?(convention)
51
57
 
52
- adapter.resolve(value: value, convention: convention, fetch: fetch, cache: cache, refresh: refresh)
58
+ begin
59
+ adapter.resolve(value: value, convention: convention, fetch: fetch, cache: cache, refresh: refresh)
60
+ rescue AsciiChem::Error
61
+ nil
62
+ end
53
63
  end
54
64
  end
55
65
 
@@ -71,9 +81,10 @@ module AsciiChem
71
81
  end
72
82
  end
73
83
 
74
- # Open, permissive sources register eagerly. CommonChemistry is
75
- # CC BY-NC 4.0: it loads (autoload) but never self-registers —
76
- # users opt in explicitly via Resolver.register.
84
+ # Every shipped source self-registers eagerly (autoload fires the
85
+ # class bodies). CommonChemistry is CC BY-NC 4.0 and default-on
86
+ # per the maintainer decision of 2026-11-11; callers that need
87
+ # NC-free resolution limit sources explicitly.
77
88
  adapters
78
89
  constants.each { |c| const_get(c) unless c == :Conflict }
79
90
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AsciiChem
4
- VERSION = "0.31.11"
4
+ VERSION = "0.31.13"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciichem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.31.11
4
+ version: 0.31.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.