asciichem 0.24.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d733aab290b1e54dfd0139d75a92888dfb8fc2af088544a07cc4395e523e583f
4
- data.tar.gz: 5dfe21e949307366a6afbcc94bf2c52f9e9cfedb4a1f328996fbde3a20b5ec99
3
+ metadata.gz: 7748aa7fb152b3dad47ff42c2debe7335af35a2a36c21d2248ff4f5a5231c575
4
+ data.tar.gz: 4352b4fe40fc6998f9860d155e791d7cf2c4f3cd48f0184696346ba934adaa57
5
5
  SHA512:
6
- metadata.gz: cdeb663f26df5189cd73df0d7c5f6a9ad3918d981d924ec08f1a781728415af474840de566a8d8f1075cb0cdc0d7086f41f92b80250efee6f71ebd11cdc62680
7
- data.tar.gz: 371e88363eb2e143b2b8a1b3f1a3cbc339d3eb81d5bcd521fdc00d02fd90e6068c769864185198c8e35e5ae6e2fc95b0088885d760844f527118a50469eaa9fb
6
+ metadata.gz: 6a22a8e911ec6a04498285f949f79c1ea5e7e6870d464e3229c3e783e744d151f0506b5200dba58e4e06f23177983dd80b24d172c6d5528e960907da821db64a
7
+ data.tar.gz: 9d57bab57705518c6f2b40d28f40b0b62c20237d26b9daf20ae4d65bd9b60ad8497ea304c60c163878c412cc6cf61a3c99a6a9179b027bef527e524758b87085
data/CHANGELOG.md CHANGED
@@ -3,6 +3,15 @@
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
+
6
15
  ## [0.24.0] - 2026-09-13
7
16
 
8
17
  ### Added
@@ -426,7 +435,8 @@ This project follows [Semantic Versioning](https://semver.org/).
426
435
  `version`.
427
436
  - Comprehensive RSpec suite with round-trip conformance.
428
437
 
429
- [Unreleased]: https://github.com/asciichem/asciichem-ruby/compare/v0.24.0...HEAD
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
430
440
  [0.24.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.23.0...v0.24.0
431
441
  [0.23.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.22.0...v0.23.0
432
442
  [0.22.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.21.0...v0.22.0
@@ -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
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AsciiChem
4
- VERSION = "0.24.0"
4
+ VERSION = "0.25.0"
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.24.0
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -172,8 +172,10 @@ files:
172
172
  - RELEASING.md
173
173
  - Rakefile
174
174
  - asciichem.gemspec
175
+ - benchmarks/README.md
175
176
  - benchmarks/RESULTS.md
176
177
  - benchmarks/benchmark.rb
178
+ - benchmarks/engines.rb
177
179
  - exe/asciichem
178
180
  - lib/asciichem.rb
179
181
  - lib/asciichem/citation.rb