asciichem 0.23.0 → 0.25.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 +4 -4
- data/CHANGELOG.md +27 -1
- data/asciichem.gemspec +1 -0
- data/benchmarks/README.md +46 -0
- data/benchmarks/engines.rb +31 -0
- data/lib/asciichem/citation.rb +98 -0
- data/lib/asciichem/cli.rb +27 -0
- data/lib/asciichem/resolver/adapter.rb +4 -2
- data/lib/asciichem/resolver/common_chemistry.rb +82 -0
- data/lib/asciichem/resolver.rb +5 -3
- data/lib/asciichem/version.rb +1 -1
- data/lib/asciichem.rb +1 -0
- metadata +25 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7748aa7fb152b3dad47ff42c2debe7335af35a2a36c21d2248ff4f5a5231c575
|
|
4
|
+
data.tar.gz: 4352b4fe40fc6998f9860d155e791d7cf2c4f3cd48f0184696346ba934adaa57
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a22a8e911ec6a04498285f949f79c1ea5e7e6870d464e3229c3e783e744d151f0506b5200dba58e4e06f23177983dd80b24d172c6d5528e960907da821db64a
|
|
7
|
+
data.tar.gz: 9d57bab57705518c6f2b40d28f40b0b62c20237d26b9daf20ae4d65bd9b60ad8497ea304c60c163878c412cc6cf61a3c99a6a9179b027bef527e524758b87085
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
All notable changes to AsciiChem are documented here.
|
|
4
4
|
This project follows [Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [0.25.0] - 2026-09-14
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- CLI `cite` — resolve a substance and emit the dataset-type Relaton
|
|
10
|
+
bibitem XML (the citation track's user-facing entry point).
|
|
11
|
+
- Cross-engine parsing benchmarks (`benchmarks/engines.rb`,
|
|
12
|
+
README with Ruby/TS/Python numbers) and the parsanol investigation
|
|
13
|
+
verdict (compat shim ~6x slower than parslet; not adopted).
|
|
14
|
+
|
|
15
|
+
## [0.24.0] - 2026-09-13
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `AsciiChem::Citation` (TODO.impl 44): one dataset-type Relaton
|
|
19
|
+
bibitem per (substance, source) — the citation track's core
|
|
20
|
+
contract. Source-specific fields live in per-source profiles
|
|
21
|
+
(PubChem, Common Chemistry); every identifier rides along as a
|
|
22
|
+
keyword so citations are machine-checkable. Runtime dependency:
|
|
23
|
+
relaton-bib (classic model).
|
|
24
|
+
- `Resolver::CommonChemistry` (TODO.impl 40, maintainer sign-off
|
|
25
|
+
2026-09-13): CAS RN lookups against CAS Common Chemistry. CC BY-NC
|
|
26
|
+
4.0 posture is enforced in code — the adapter never self-registers;
|
|
27
|
+
users opt in explicitly, and every result carries the required
|
|
28
|
+
attribution.
|
|
29
|
+
|
|
6
30
|
## [0.23.0] - 2026-09-12
|
|
7
31
|
|
|
8
32
|
### Added
|
|
@@ -411,7 +435,9 @@ This project follows [Semantic Versioning](https://semver.org/).
|
|
|
411
435
|
`version`.
|
|
412
436
|
- Comprehensive RSpec suite with round-trip conformance.
|
|
413
437
|
|
|
414
|
-
[Unreleased]: https://github.com/asciichem/asciichem-ruby/compare/v0.
|
|
438
|
+
[Unreleased]: https://github.com/asciichem/asciichem-ruby/compare/v0.25.0...HEAD
|
|
439
|
+
[0.25.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.24.0...v0.25.0
|
|
440
|
+
[0.24.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.23.0...v0.24.0
|
|
415
441
|
[0.23.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.22.0...v0.23.0
|
|
416
442
|
[0.22.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.21.0...v0.22.0
|
|
417
443
|
[0.21.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.20.0...v0.21.0
|
data/asciichem.gemspec
CHANGED
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
|
|
|
38
38
|
spec.add_dependency "lutaml-model", ">= 0.8", "< 2"
|
|
39
39
|
spec.add_dependency "nokogiri", "~> 1.16"
|
|
40
40
|
spec.add_dependency "parslet", "~> 2.0"
|
|
41
|
+
spec.add_dependency "relaton-bib", ">= 0.1", "< 2"
|
|
41
42
|
spec.add_dependency "plurimath", "~> 0.8"
|
|
42
43
|
spec.add_dependency "thor", "~> 1.3"
|
|
43
44
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Parsing benchmarks
|
|
2
|
+
|
|
3
|
+
Shared workload (identical inputs in every implementation) so numbers
|
|
4
|
+
are comparable across engines:
|
|
5
|
+
|
|
6
|
+
```ruby
|
|
7
|
+
WORKLOAD = ["H_2O", "Ca^2+", "SO_4^2-", "(R)-CH_3CH(OH)COOH",
|
|
8
|
+
"2H_2 + O_2 -> 2H_2O", "N_2 + 3H_2 <=>[Fe][400C] 2NH_3",
|
|
9
|
+
"C1-C-C-C-C-C1", "CH_3-CH_2-OH",
|
|
10
|
+
"^14C @name(\"carbon-14\") @cas(\"14104-86-4\")",
|
|
11
|
+
"A ->[heat] B ->[cool] C"]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Engine | Batch (10 inputs) | Per input | Notes |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| Ruby (parslet), 3.4.8 arm64 | 29.1 ms | ~2.9 ms | `bundle exec ruby benchmarks/engines.rb` |
|
|
17
|
+
| Ruby + parse+text | 35.3 ms | ~3.5 ms | round-trip adds the formatter |
|
|
18
|
+
| TypeScript (peggy), Node 24 | 0.19 ms | ~19 µs | `npm run bench` (asciichem-ts) |
|
|
19
|
+
| Python (RD), 3.10 | 3.94 ms | ~394 µs | `python benchmarks/engines.py` (asciichem-py) |
|
|
20
|
+
|
|
21
|
+
The peggy engine is ~15x faster than parslet and ~20x faster than the
|
|
22
|
+
Python recursive-descent parser on this workload — the grammar-port
|
|
23
|
+
TS implementation did not trade away speed. Same machine (arm64),
|
|
24
|
+
single-run medians; treat as order-of-magnitude comparison.
|
|
25
|
+
|
|
26
|
+
## Parsanol investigation (2026-09-14)
|
|
27
|
+
|
|
28
|
+
[Parsanol](https://github.com/parsanol/parsanol-ruby) (Ribose's
|
|
29
|
+
parslet-alternative PEG library with a Rust native core) was evaluated
|
|
30
|
+
as a drop-in speedup for the reference grammar:
|
|
31
|
+
|
|
32
|
+
1. **Parslet-compat shim** (zero code change — re-parent the grammar
|
|
33
|
+
onto `Parsanol::Parslet::Parser`): the identical grammar runs
|
|
34
|
+
unchanged (10/10 workload inputs), but measures **~6x slower**
|
|
35
|
+
than parslet (12.2 s vs 2.05 s per 300x10 parses, Ruby 3.4.8,
|
|
36
|
+
arm64). The shim is a compatibility layer, not the fast path.
|
|
37
|
+
2. **Native Parsanol DSL** (subset micro-benchmark): constructs run,
|
|
38
|
+
but boundary semantics differ from parslet on greedy-regex +
|
|
39
|
+
`maybe`/`repeat` interaction (`SO_4^2-` parses under parslet,
|
|
40
|
+
fails under Parsanol native). A full port would need per-rule
|
|
41
|
+
revalidation against the whole corpus with no measured win to
|
|
42
|
+
justify it yet.
|
|
43
|
+
|
|
44
|
+
**Verdict: not adopted.** Revisit when Parsanol's native backend can
|
|
45
|
+
be engaged for full grammars and shows measured wins on this
|
|
46
|
+
workload; the shim path is a documented no.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Cross-engine parsing benchmark (shared inputs across Ruby/TS/Python
|
|
4
|
+
# so numbers are comparable). Measures full parse (+ Text round-trip
|
|
5
|
+
# where cheap) over the canonical workload, reporting ops/sec and
|
|
6
|
+
# µs/op. Run: bundle exec ruby benchmarks/engines.rb
|
|
7
|
+
require "benchmark/ips"
|
|
8
|
+
require "asciichem"
|
|
9
|
+
|
|
10
|
+
WORKLOAD = [
|
|
11
|
+
"H_2O",
|
|
12
|
+
"Ca^2+",
|
|
13
|
+
"SO_4^2-",
|
|
14
|
+
"(R)-CH_3CH(OH)COOH",
|
|
15
|
+
"2H_2 + O_2 -> 2H_2O",
|
|
16
|
+
"N_2 + 3H_2 <=>[Fe][400C] 2NH_3",
|
|
17
|
+
"C1-C-C-C-C-C1",
|
|
18
|
+
"CH_3-CH_2-OH",
|
|
19
|
+
"^14C @name(\"carbon-14\") @cas(\"14104-86-4\")",
|
|
20
|
+
"A ->[heat] B ->[cool] C",
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
Benchmark.ips do |x|
|
|
24
|
+
x.report("parse x10 (parslet)") do
|
|
25
|
+
WORKLOAD.each { |s| AsciiChem.parse(s) }
|
|
26
|
+
end
|
|
27
|
+
x.report("parse+text x10") do
|
|
28
|
+
WORKLOAD.each { |s| AsciiChem.parse(s).to_text }
|
|
29
|
+
end
|
|
30
|
+
x.compare!
|
|
31
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "relaton_bib"
|
|
4
|
+
|
|
5
|
+
module AsciiChem
|
|
6
|
+
# Citation track (TODO.v2 08; TODO.impl 44): a bibitem is a function
|
|
7
|
+
# of (substance, source) — one dataset-type Relaton bibitem per
|
|
8
|
+
# source the user chooses to cite, because two databases agreeing on
|
|
9
|
+
# a substance are still two different documents.
|
|
10
|
+
#
|
|
11
|
+
# Source-specific fields (link shape, publisher string, docidentifier
|
|
12
|
+
# scheme) live in PROFILES; adding a source is one entry (OCP).
|
|
13
|
+
module Citation
|
|
14
|
+
# Source-specific citation profile. Default fields fall back to
|
|
15
|
+
# the substance's provenance.
|
|
16
|
+
Profile = Struct.new(:publisher, :link_for, :identifier_for, keyword_init: true)
|
|
17
|
+
|
|
18
|
+
PROFILES = {
|
|
19
|
+
"pubchem" => Profile.new(
|
|
20
|
+
publisher: "PubChem, U.S. National Library of Medicine",
|
|
21
|
+
link_for: ->(substance) do
|
|
22
|
+
cid = substance.identifier_value("pubchem-cid")
|
|
23
|
+
"https://pubchem.ncbi.nlm.nih.gov/compound/#{cid}" if cid
|
|
24
|
+
end,
|
|
25
|
+
identifier_for: ->(substance) do
|
|
26
|
+
cid = substance.identifier_value("pubchem-cid")
|
|
27
|
+
"PubChem CID #{cid}" if cid
|
|
28
|
+
end
|
|
29
|
+
),
|
|
30
|
+
"common_chemistry" => Profile.new(
|
|
31
|
+
publisher: "CAS Common Chemistry",
|
|
32
|
+
link_for: ->(substance) do
|
|
33
|
+
cas = substance.identifier_value("cas")
|
|
34
|
+
"https://commonchemistry.cas.org/detail?cas_rn=#{cas}" if cas
|
|
35
|
+
end,
|
|
36
|
+
identifier_for: ->(substance) do
|
|
37
|
+
cas = substance.identifier_value("cas")
|
|
38
|
+
"CAS RN #{cas}" if cas
|
|
39
|
+
end
|
|
40
|
+
)
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
DEFAULT_PROFILE = Profile.new(
|
|
44
|
+
publisher: nil,
|
|
45
|
+
link_for: ->(_substance) { nil },
|
|
46
|
+
identifier_for: ->(substance) do
|
|
47
|
+
key = substance.identifiers.first
|
|
48
|
+
"#{key.convention}: #{key.value}" if key
|
|
49
|
+
end
|
|
50
|
+
).freeze
|
|
51
|
+
private_constant :DEFAULT_PROFILE
|
|
52
|
+
|
|
53
|
+
class << self
|
|
54
|
+
# Builds a Relaton dataset-type bibitem for the substance as
|
|
55
|
+
# cited from its recorded source. Raises when the substance
|
|
56
|
+
# carries no provenance (hand-built, not resolved).
|
|
57
|
+
def bibitem(substance)
|
|
58
|
+
provenance = substance.provenance
|
|
59
|
+
unless provenance&.source
|
|
60
|
+
raise Error, "substance has no provenance - resolve it first (AsciiChem::Resolver)"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
profile = PROFILES.fetch(provenance.source, DEFAULT_PROFILE)
|
|
64
|
+
RelatonBib::BibliographicItem.new(
|
|
65
|
+
type: "dataset",
|
|
66
|
+
title: [{ type: "main",
|
|
67
|
+
content: "#{title_base(substance)} - #{profile.publisher || provenance.source} substance record" }],
|
|
68
|
+
docid: [RelatonBib::DocumentIdentifier.new(
|
|
69
|
+
id: profile.identifier_for.call(substance) || "#{provenance.source} substance",
|
|
70
|
+
type: provenance.source)],
|
|
71
|
+
contributor: [{ entity: RelatonBib::Organization.new(name: profile.publisher || provenance.source),
|
|
72
|
+
role: [{ type: "publisher" }] }],
|
|
73
|
+
date: [{ type: "accessed", on: accessed_on(provenance) }],
|
|
74
|
+
link: [{ type: "src", content: profile.link_for.call(substance) }].compact,
|
|
75
|
+
keyword: substance.identifiers.map { |i| "#{i.convention}=#{i.value}" }
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Convenience: bibitem XML (what a document pipeline embeds).
|
|
80
|
+
def to_xml(substance)
|
|
81
|
+
bibitem(substance).to_xml
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def title_base(substance)
|
|
87
|
+
substance.preferred_name || substance.identifier_value("cas") ||
|
|
88
|
+
substance.identifier_value("inchikey") || "Substance"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def accessed_on(provenance)
|
|
92
|
+
return provenance.retrieved_at[0, 10] if provenance.retrieved_at
|
|
93
|
+
|
|
94
|
+
Time.now.utc.strftime("%Y-%m-%d")
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/lib/asciichem/cli.rb
CHANGED
|
@@ -119,6 +119,33 @@ module AsciiChem
|
|
|
119
119
|
exit 3
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
+
desc "cite --cas X | --name X | ...", "Resolve a substance and emit a dataset-type Relaton bibitem (XML)"
|
|
123
|
+
method_option :cas, type: :string, desc: "CAS registry number"
|
|
124
|
+
method_option :name, type: :string, desc: "Substance name"
|
|
125
|
+
method_option :cid, type: :string, desc: "PubChem CID"
|
|
126
|
+
method_option :inchikey, type: :string, desc: "InChIKey"
|
|
127
|
+
method_option :smiles, type: :string, desc: "SMILES"
|
|
128
|
+
method_option :source, type: :string, default: "pubchem", desc: "Resolver source"
|
|
129
|
+
method_option :refresh, type: :boolean, default: false, desc: "Bypass the cache"
|
|
130
|
+
def cite
|
|
131
|
+
convention, value = %i[cas name cid inchikey smiles]
|
|
132
|
+
.filter_map { |k| [k, options[k.to_s]] if options[k.to_s] }
|
|
133
|
+
.first
|
|
134
|
+
raise AsciiChem::Error, "give one of --cas/--name/--cid/--inchikey/--smiles" unless value
|
|
135
|
+
|
|
136
|
+
convention = { cas: "cas", name: "name", cid: "pubchem-cid",
|
|
137
|
+
inchikey: "inchikey", smiles: "smiles" }.fetch(convention)
|
|
138
|
+
substance = AsciiChem::Resolver[options[:source]].new.resolve(
|
|
139
|
+
value: value, convention: convention, refresh: options[:refresh]
|
|
140
|
+
)
|
|
141
|
+
raise AsciiChem::Error, "#{options[:source]} does not know #{value.inspect}" unless substance
|
|
142
|
+
|
|
143
|
+
puts AsciiChem::Citation.to_xml(substance)
|
|
144
|
+
rescue AsciiChem::Error => e
|
|
145
|
+
warn "Cite error: #{e.message}"
|
|
146
|
+
exit 4
|
|
147
|
+
end
|
|
148
|
+
|
|
122
149
|
desc "validate -i INPUT", "Offline identifier validation"
|
|
123
150
|
method_option :input, aliases: "-i", type: :string, required: true
|
|
124
151
|
def validate
|
|
@@ -17,11 +17,13 @@ module AsciiChem
|
|
|
17
17
|
# Declares the source name and registers the adapter (called
|
|
18
18
|
# from the class body — `inherited` fires before the body
|
|
19
19
|
# runs, so it cannot see the subclass configuration).
|
|
20
|
-
|
|
20
|
+
# `register: false` for opt-in sources (NC-licensed): the
|
|
21
|
+
# adapter exists but users must register it explicitly.
|
|
22
|
+
def source_name(name = nil, register: true)
|
|
21
23
|
return @source_name if name.nil?
|
|
22
24
|
|
|
23
25
|
@source_name = name.to_s
|
|
24
|
-
AsciiChem::Resolver.register(@source_name, self)
|
|
26
|
+
AsciiChem::Resolver.register(@source_name, self) if register
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def supports(*conventions)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module AsciiChem
|
|
7
|
+
module Resolver
|
|
8
|
+
# CAS Common Chemistry source adapter (TODO.impl 40; TODO.v2 07).
|
|
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.
|
|
18
|
+
class CommonChemistry < Adapter
|
|
19
|
+
source_name :common_chemistry, register: false
|
|
20
|
+
supports "cas"
|
|
21
|
+
|
|
22
|
+
BASE = "https://commonchemistry.cas.org/api/detail"
|
|
23
|
+
|
|
24
|
+
def fetch_record(value:, convention:, fetch:)
|
|
25
|
+
body = fetch.get("#{BASE}?cas_rn=#{CGI.escape(value.to_s)}")
|
|
26
|
+
return nil unless body
|
|
27
|
+
|
|
28
|
+
data = JSON.parse(body)
|
|
29
|
+
return nil if data.empty?
|
|
30
|
+
|
|
31
|
+
substance_from(data)
|
|
32
|
+
rescue JSON::ParserError => e
|
|
33
|
+
raise Error, "common_chemistry returned malformed JSON: #{e.message}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def attribution
|
|
37
|
+
"CAS Common Chemistry (CC BY-NC 4.0)"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def substance_from(data)
|
|
43
|
+
provenance = default_provenance
|
|
44
|
+
identifiers = [Identifier.new(value: data["rn"], convention: "cas",
|
|
45
|
+
provenance: provenance)]
|
|
46
|
+
add_identifier(identifiers, data, "inchikey", "inchikey", provenance)
|
|
47
|
+
add_identifier(identifiers, data, "smiles", "canonical-smiles", provenance)
|
|
48
|
+
add_identifier(identifiers, data, "inchi", "inchi", provenance)
|
|
49
|
+
add_identifier(identifiers, data, "iupacName", "iupac-name", provenance)
|
|
50
|
+
|
|
51
|
+
Substance.new(
|
|
52
|
+
preferred_name: data["name"],
|
|
53
|
+
formula: data["formula"],
|
|
54
|
+
identifiers: identifiers,
|
|
55
|
+
properties: [
|
|
56
|
+
Property.new(name: "molecular-formula", value: data["formula"], provenance: provenance),
|
|
57
|
+
Property.new(name: "molecular-weight", value: data["molecularMass"]&.to_s,
|
|
58
|
+
units: "g/mol", provenance: provenance)
|
|
59
|
+
].compact,
|
|
60
|
+
# Best effort within the supported SMILES subset; the SMILES
|
|
61
|
+
# stays as an identifier when stereo keeps it out.
|
|
62
|
+
structure: parse_structure(data["smiles"])
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def add_identifier(list, data, key, convention, provenance)
|
|
67
|
+
return unless data[key]
|
|
68
|
+
|
|
69
|
+
list << Identifier.new(value: data[key], convention: convention,
|
|
70
|
+
provenance: provenance)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def parse_structure(smiles)
|
|
74
|
+
return nil unless smiles
|
|
75
|
+
|
|
76
|
+
AsciiChem.parse_smiles(smiles).nodes.first
|
|
77
|
+
rescue AsciiChem::ParseError
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
data/lib/asciichem/resolver.rb
CHANGED
|
@@ -17,6 +17,7 @@ module AsciiChem
|
|
|
17
17
|
autoload :Adapter, "asciichem/resolver/adapter"
|
|
18
18
|
autoload :Cache, "asciichem/resolver/cache"
|
|
19
19
|
autoload :PubChem, "asciichem/resolver/pubchem"
|
|
20
|
+
autoload :CommonChemistry, "asciichem/resolver/common_chemistry"
|
|
20
21
|
autoload :Substance, "asciichem/resolver/substance"
|
|
21
22
|
|
|
22
23
|
# Raised when sources disagree on substance identity (cross-check
|
|
@@ -69,9 +70,10 @@ module AsciiChem
|
|
|
69
70
|
end
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
# Open, permissive sources register eagerly
|
|
73
|
-
#
|
|
74
|
-
|
|
73
|
+
# Open, permissive sources register eagerly. CommonChemistry is
|
|
74
|
+
# CC BY-NC 4.0: it loads (autoload) but never self-registers —
|
|
75
|
+
# users opt in explicitly via Resolver.register.
|
|
76
|
+
adapters
|
|
75
77
|
constants.each { |c| const_get(c) unless c == :Conflict }
|
|
76
78
|
end
|
|
77
79
|
end
|
data/lib/asciichem/version.rb
CHANGED
data/lib/asciichem.rb
CHANGED
|
@@ -10,6 +10,7 @@ require "plurimath"
|
|
|
10
10
|
# AsciiChem::Cli.start # CLI dispatch
|
|
11
11
|
module AsciiChem
|
|
12
12
|
autoload :Cli, "asciichem/cli"
|
|
13
|
+
autoload :Citation, "asciichem/citation"
|
|
13
14
|
autoload :Cml, "asciichem/cml"
|
|
14
15
|
autoload :Error, "asciichem/errors"
|
|
15
16
|
autoload :ParseError, "asciichem/errors"
|
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.
|
|
4
|
+
version: 0.25.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -85,6 +85,26 @@ dependencies:
|
|
|
85
85
|
- - "~>"
|
|
86
86
|
- !ruby/object:Gem::Version
|
|
87
87
|
version: '2.0'
|
|
88
|
+
- !ruby/object:Gem::Dependency
|
|
89
|
+
name: relaton-bib
|
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '0.1'
|
|
95
|
+
- - "<"
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '2'
|
|
98
|
+
type: :runtime
|
|
99
|
+
prerelease: false
|
|
100
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: '0.1'
|
|
105
|
+
- - "<"
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: '2'
|
|
88
108
|
- !ruby/object:Gem::Dependency
|
|
89
109
|
name: plurimath
|
|
90
110
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -152,10 +172,13 @@ files:
|
|
|
152
172
|
- RELEASING.md
|
|
153
173
|
- Rakefile
|
|
154
174
|
- asciichem.gemspec
|
|
175
|
+
- benchmarks/README.md
|
|
155
176
|
- benchmarks/RESULTS.md
|
|
156
177
|
- benchmarks/benchmark.rb
|
|
178
|
+
- benchmarks/engines.rb
|
|
157
179
|
- exe/asciichem
|
|
158
180
|
- lib/asciichem.rb
|
|
181
|
+
- lib/asciichem/citation.rb
|
|
159
182
|
- lib/asciichem/cli.rb
|
|
160
183
|
- lib/asciichem/cml.rb
|
|
161
184
|
- lib/asciichem/cml/conditions_extensions.rb
|
|
@@ -231,6 +254,7 @@ files:
|
|
|
231
254
|
- lib/asciichem/resolver.rb
|
|
232
255
|
- lib/asciichem/resolver/adapter.rb
|
|
233
256
|
- lib/asciichem/resolver/cache.rb
|
|
257
|
+
- lib/asciichem/resolver/common_chemistry.rb
|
|
234
258
|
- lib/asciichem/resolver/pubchem.rb
|
|
235
259
|
- lib/asciichem/resolver/substance.rb
|
|
236
260
|
- lib/asciichem/ring_bonds.rb
|