asciichem 0.31.8 → 0.31.10
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 +23 -0
- data/asciichem.gemspec +1 -1
- data/lib/asciichem/inchi/binary_engine.rb +1 -1
- data/lib/asciichem/inchi/native_engine.rb +80 -0
- data/lib/asciichem/inchi.rb +5 -1
- data/lib/asciichem/molfile/writer.rb +9 -6
- data/lib/asciichem/molfile.rb +2 -2
- data/lib/asciichem/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 11c430e97b570a9f7297e831904c6701db083757a092646536a29d4452a7b302
|
|
4
|
+
data.tar.gz: 21cb557a14d1914adec15dbbf8c9820160e7bf4a93bf3a853e6a81c61b4d595c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7b38cae89fed5fff85d89c9dd870915506cb9500b684281801ec2f4000c3da1c9bde273747b83438f7f85ed0a09eac5377499c977a05dd261360b7de57f038be
|
|
7
|
+
data.tar.gz: 1a9e53346bdc0d74f99ecc34f525e2a3358054fc8ef97849f23451370ec03841c4adc61c2813c5abb9cdd59b9190a3de2185708c92841c203815fda2000e336b
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
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.10] - 2026-11-05
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- The native engine binding points at the renamed **chemomer** crate
|
|
10
|
+
(chemomer/chemomer): the dylib is `libchemomer.dylib` with
|
|
11
|
+
`chemomer_*` symbols and `CHEMOMER_LIB` replaces `INCHI_RS_LIB`.
|
|
12
|
+
Same contract, new spelling.
|
|
13
|
+
- moxml is pinned to the 0.6 line from 0.6.1 (resolves to 0.6.2);
|
|
14
|
+
the full suite runs green against it.
|
|
15
|
+
|
|
16
|
+
## [0.31.9] - 2026-10-24
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- `AsciiChem::Inchi::NativeEngine`: the identity engine drives the
|
|
20
|
+
native inchi-rs Rust engine through its C ABI (model → molfile →
|
|
21
|
+
identifier + InChIKey). The library is an external artifact built
|
|
22
|
+
from the inchi-rs checkout and located via `INCHI_RS_LIB`; the
|
|
23
|
+
`ffi` gem loads lazily, so the core gem stays dependency-free.
|
|
24
|
+
Opt-in registration matches the BinaryEngine:
|
|
25
|
+
`AsciiChem::Inchi.engine = AsciiChem::Inchi::NativeEngine.new`.
|
|
26
|
+
- The install guide mentions the native path alongside the IUPAC
|
|
27
|
+
binary.
|
|
28
|
+
|
|
6
29
|
## [0.31.8] - 2026-10-22
|
|
7
30
|
|
|
8
31
|
### Fixed
|
data/asciichem.gemspec
CHANGED
|
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
|
|
|
39
39
|
spec.add_dependency "elkrb", "~> 2.0"
|
|
40
40
|
spec.add_dependency "lutaml-model", "~> 0.8"
|
|
41
41
|
spec.add_dependency "mml", "~> 2.3"
|
|
42
|
-
spec.add_dependency "moxml", "~> 0.
|
|
42
|
+
spec.add_dependency "moxml", "~> 0.6.1"
|
|
43
43
|
spec.add_dependency "parslet", "~> 2.0"
|
|
44
44
|
spec.add_dependency "relaton-bib", "~> 2.1"
|
|
45
45
|
spec.add_dependency "plurimath", "~> 0.11"
|
|
@@ -33,7 +33,7 @@ module AsciiChem
|
|
|
33
33
|
# the pipe: atom coordinates, charges and isotopes cross into
|
|
34
34
|
# the engine through the V2000 block.
|
|
35
35
|
def identity(molecule)
|
|
36
|
-
molfile = AsciiChem::Molfile.write(molecule)
|
|
36
|
+
molfile = AsciiChem::Molfile.write(molecule, layout: false)
|
|
37
37
|
out = execute(molfile)
|
|
38
38
|
inchi = out[/^InChI=\S+/]
|
|
39
39
|
raise AsciiChem::Error, "#{bin} produced no InChI:\n#{out}" unless inchi
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AsciiChem
|
|
4
|
+
module Inchi
|
|
5
|
+
# Engine that drives the native chemomer engine (the Rust port)
|
|
6
|
+
# through its C ABI. The library is a documented external
|
|
7
|
+
# artifact — nothing is vendored: build it once from the chemomer
|
|
8
|
+
# checkout (`cargo build --release`) and point CHEMOMER_LIB at
|
|
9
|
+
# the cdylib, the same opt-in shape as the BinaryEngine's
|
|
10
|
+
# ASCIICHEM_INCHI_BIN. The `ffi` gem loads lazily — the core gem
|
|
11
|
+
# stays dependency-free.
|
|
12
|
+
#
|
|
13
|
+
# AsciiChem::Inchi.engine = AsciiChem::Inchi::NativeEngine.new
|
|
14
|
+
# AsciiChem::Inchi.engine = AsciiChem::Inchi::NativeEngine.new(lib: "/path/libchemomer.dylib")
|
|
15
|
+
class NativeEngine < Engine
|
|
16
|
+
DEFAULT_LIB = ENV.fetch('CHEMOMER_LIB', nil)
|
|
17
|
+
|
|
18
|
+
attr_reader :lib
|
|
19
|
+
|
|
20
|
+
def initialize(lib: DEFAULT_LIB)
|
|
21
|
+
super()
|
|
22
|
+
@lib = lib
|
|
23
|
+
unless @lib
|
|
24
|
+
raise AsciiChem::Error,
|
|
25
|
+
'chemomer native engine: set CHEMOMER_LIB to the built cdylib ' \
|
|
26
|
+
'(cargo build --release in the chemomer checkout)'
|
|
27
|
+
end
|
|
28
|
+
return if File.readable?(@lib)
|
|
29
|
+
|
|
30
|
+
raise AsciiChem::Error, "chemomer native engine: #{@lib} is not readable"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# model → molfile → chemomer → Identity. The molfile emission is
|
|
34
|
+
# the pipe, exactly as in the BinaryEngine.
|
|
35
|
+
def identity(molecule)
|
|
36
|
+
molfile = AsciiChem::Molfile.write(molecule, layout: false)
|
|
37
|
+
inchi = call(molfile, :chemomer_from_molfile)
|
|
38
|
+
inchikey = call(molfile, :chemomer_inchikey)
|
|
39
|
+
Identity.new(inchi: inchi, inchikey: inchikey)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def call(molfile, function)
|
|
45
|
+
binding_class = self.class.binding_class(@lib)
|
|
46
|
+
pointer = binding_class.public_send(function, molfile)
|
|
47
|
+
unless pointer
|
|
48
|
+
message = binding_class.last_error
|
|
49
|
+
raise AsciiChem::Error, "chemomer native engine: #{message || 'call failed'}"
|
|
50
|
+
end
|
|
51
|
+
value = pointer.read_string
|
|
52
|
+
binding_class.chemomer_string_free(pointer)
|
|
53
|
+
value
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# One FFI module per library path, cached: attach_function
|
|
57
|
+
# defines the symbol bindings once.
|
|
58
|
+
def self.binding_class(path)
|
|
59
|
+
@binding_classes ||= {}
|
|
60
|
+
@binding_classes[path] ||= begin
|
|
61
|
+
require 'ffi'
|
|
62
|
+
Module.new do
|
|
63
|
+
extend FFI::Library
|
|
64
|
+
|
|
65
|
+
ffi_lib path
|
|
66
|
+
attach_function :chemomer_from_molfile, %i[string], :pointer
|
|
67
|
+
attach_function :chemomer_inchikey, %i[string], :pointer
|
|
68
|
+
attach_function :chemomer_string_free, %i[pointer], :void
|
|
69
|
+
attach_function :chemomer_last_error, [], :pointer
|
|
70
|
+
|
|
71
|
+
def self.last_error
|
|
72
|
+
pointer = chemomer_last_error
|
|
73
|
+
pointer.null? ? nil : pointer.read_string
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
data/lib/asciichem/inchi.rb
CHANGED
|
@@ -14,11 +14,15 @@ module AsciiChem
|
|
|
14
14
|
autoload :BinaryEngine, 'asciichem/inchi/binary_engine'
|
|
15
15
|
autoload :Engine, 'asciichem/inchi/engine'
|
|
16
16
|
autoload :Identity, 'asciichem/inchi/identity'
|
|
17
|
+
autoload :NativeEngine, 'asciichem/inchi/native_engine'
|
|
17
18
|
|
|
18
19
|
INSTALL_GUIDE = 'install the IUPAC InChI software ' \
|
|
19
20
|
'(https://www.inchi-trust.org/downloads/) and set ' \
|
|
20
21
|
'AsciiChem::Inchi.engine = AsciiChem::Inchi::BinaryEngine.new ' \
|
|
21
|
-
'(or pass bin: "path/to/inchi-1")'
|
|
22
|
+
'(or pass bin: "path/to/inchi-1") — or, for the native ' \
|
|
23
|
+
'Rust engine, build chemomer and set ' \
|
|
24
|
+
'AsciiChem::Inchi.engine = AsciiChem::Inchi::NativeEngine.new ' \
|
|
25
|
+
'(pointing CHEMOMER_LIB at the built cdylib)'
|
|
22
26
|
|
|
23
27
|
class << self
|
|
24
28
|
attr_accessor :engine
|
|
@@ -24,13 +24,16 @@ module AsciiChem
|
|
|
24
24
|
BOND_STEREO = { wedge: 1, hash: 6 }.freeze
|
|
25
25
|
CHIRALITY_PARITY = { 'TH1' => 1, 'TH2' => 2 }.freeze
|
|
26
26
|
|
|
27
|
-
def initialize(molecule, name: nil)
|
|
27
|
+
def initialize(molecule, name: nil, layout: true)
|
|
28
28
|
@molecule = molecule
|
|
29
29
|
@name = name
|
|
30
|
+
@layout = layout
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def write
|
|
33
|
-
atoms, edges = Structure::Graph.build!(@molecule)
|
|
34
|
+
@atoms, @edges = Structure::Graph.build!(@molecule)
|
|
35
|
+
atoms = @atoms
|
|
36
|
+
edges = @edges
|
|
34
37
|
raise ParseError, "molecule has no bonds — a formula is not a structure" if edges.empty? && atoms.length > 1
|
|
35
38
|
|
|
36
39
|
lines = []
|
|
@@ -100,11 +103,11 @@ module AsciiChem
|
|
|
100
103
|
|
|
101
104
|
# Authored coordinates win; otherwise positions from the
|
|
102
105
|
# deterministic 2D layout (same walk order as the graph).
|
|
103
|
-
def coordinates(atom, index,
|
|
104
|
-
return [
|
|
106
|
+
def coordinates(atom, index, _atoms)
|
|
107
|
+
return [0.0, 0.0] unless @layout
|
|
105
108
|
|
|
106
|
-
@
|
|
107
|
-
placed = @
|
|
109
|
+
@layout_positions ||= AsciiChem::Layout.layout(@molecule).atoms
|
|
110
|
+
placed = @layout_positions[index]
|
|
108
111
|
placed ? [placed.x, placed.y] : [0.0, 0.0]
|
|
109
112
|
end
|
|
110
113
|
|
data/lib/asciichem/molfile.rb
CHANGED
|
@@ -18,8 +18,8 @@ module AsciiChem
|
|
|
18
18
|
|
|
19
19
|
# Emits a V2000 molfile. Uses authored x2/y2 coordinates;
|
|
20
20
|
# computes a 2D layout otherwise.
|
|
21
|
-
def write(molecule, name: nil)
|
|
22
|
-
Writer.new(molecule, name: name).write
|
|
21
|
+
def write(molecule, name: nil, layout: true)
|
|
22
|
+
Writer.new(molecule, name: name, layout: layout).write
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
data/lib/asciichem/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.31.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -71,14 +71,14 @@ dependencies:
|
|
|
71
71
|
requirements:
|
|
72
72
|
- - "~>"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version:
|
|
74
|
+
version: 0.6.1
|
|
75
75
|
type: :runtime
|
|
76
76
|
prerelease: false
|
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
79
|
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version:
|
|
81
|
+
version: 0.6.1
|
|
82
82
|
- !ruby/object:Gem::Dependency
|
|
83
83
|
name: parslet
|
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -220,6 +220,7 @@ files:
|
|
|
220
220
|
- lib/asciichem/inchi/binary_engine.rb
|
|
221
221
|
- lib/asciichem/inchi/engine.rb
|
|
222
222
|
- lib/asciichem/inchi/identity.rb
|
|
223
|
+
- lib/asciichem/inchi/native_engine.rb
|
|
223
224
|
- lib/asciichem/layout.rb
|
|
224
225
|
- lib/asciichem/linter.rb
|
|
225
226
|
- lib/asciichem/linter/balance_check.rb
|