chemomer 0.1.0.1
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 +7 -0
- data/.github/workflows/ci.yml +35 -0
- data/.github/workflows/release.yml +50 -0
- data/.gitignore +6 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +84 -0
- data/chemomer.gemspec +31 -0
- data/lib/chemomer/bindings.rb +112 -0
- data/lib/chemomer/error.rb +8 -0
- data/lib/chemomer/version.rb +9 -0
- data/lib/chemomer.rb +94 -0
- metadata +71 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 142c9b75a559a70f3da42867d5fc666612991c6163592487c3dc62ff60c19c95
|
|
4
|
+
data.tar.gz: 7e3ee8a8f611b0090ef9bd98c893778dfae022365edeeb7d89c95f55161b9d51
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ac5e6ecbc4797c78a90ed6b7331181ce3d274f7f8b47afa70237faa421561f9055cee5fe3b17c8b814129c3a1c4c080758ddfa136797491a6b8e49dab9e6125e
|
|
7
|
+
data.tar.gz: d87604de945779f7260cbe29d8cfc950c4d74828e40d353c5d02669da1db8060dd8e212a272738b680bf4654f4f68fd2822be5352c09fb28c56a23098d9b926a
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
rspec:
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: false
|
|
12
|
+
matrix:
|
|
13
|
+
os: [ubuntu-latest, macos-latest]
|
|
14
|
+
ruby: ["3.3", "3.4"]
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
- uses: ruby/setup-ruby@v1
|
|
19
|
+
with:
|
|
20
|
+
ruby-version: ${{ matrix.ruby }}
|
|
21
|
+
bundler-cache: true
|
|
22
|
+
# The gem drives the engine through its C ABI — no engine code is
|
|
23
|
+
# vendored, so CI builds the cdylib from the engine's main (the
|
|
24
|
+
# shared contract) and points the suite at it. Specs that need
|
|
25
|
+
# the dylib gate on CHEMOMER_LIB; the rest run everywhere.
|
|
26
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
27
|
+
- name: Build the chemomer cdylib
|
|
28
|
+
run: |
|
|
29
|
+
git clone --depth 1 https://github.com/chemomer/chemomer engine
|
|
30
|
+
cargo build --release --manifest-path engine/Cargo.toml
|
|
31
|
+
- name: Point CHEMOMER_LIB at the built dylib
|
|
32
|
+
run: |
|
|
33
|
+
lib=$(ls engine/target/release/libchemomer.dylib engine/target/release/libchemomer.so 2>/dev/null | head -1)
|
|
34
|
+
echo "CHEMOMER_LIB=$PWD/$lib" >> "$GITHUB_ENV"
|
|
35
|
+
- run: bundle exec rspec
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: "Version to release (must match lib/chemomer/version.rb)"
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
release:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
# Trusted publishing (OIDC): the publisher registered on RubyGems.org
|
|
15
|
+
# is repository chemomer/chemomer-ruby + workflow release.yml, with
|
|
16
|
+
# no environment — so this job must not claim one.
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
id-token: write
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v7
|
|
22
|
+
with:
|
|
23
|
+
ref: main
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
- name: Verify version matches input
|
|
26
|
+
run: |
|
|
27
|
+
actual=$(ruby -e 'require "./lib/chemomer/version"; print Chemomer::VERSION')
|
|
28
|
+
if [ "$actual" != "${{ inputs.version }}" ]; then
|
|
29
|
+
echo "Version mismatch: input=${{ inputs.version }}, lib/chemomer/version.rb=$actual"
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
echo "Releasing $actual"
|
|
33
|
+
- uses: ruby/setup-ruby@v1
|
|
34
|
+
with:
|
|
35
|
+
ruby-version: "3.4"
|
|
36
|
+
bundler-cache: true
|
|
37
|
+
# CI never pushes to git (read-only contents). `rake release`
|
|
38
|
+
# attempts `git push origin main` after publishing unless the
|
|
39
|
+
# version tag already exists locally — bundler then prints
|
|
40
|
+
# "Tag vX has already been created" and skips its git stage
|
|
41
|
+
# entirely. Pre-create the tag so the gem push is the only
|
|
42
|
+
# remote operation; tags on the remote remain the maintainer's.
|
|
43
|
+
- name: Pre-create the release tag (skips rake's git stage)
|
|
44
|
+
run: git tag "v${{ inputs.version }}"
|
|
45
|
+
# Builds and pushes using the GitHub OIDC identity — no API keys.
|
|
46
|
+
- uses: rubygems/release-gem@v1
|
|
47
|
+
- name: Summary
|
|
48
|
+
run: |
|
|
49
|
+
echo "Released chemomer ${{ inputs.version }} to RubyGems"
|
|
50
|
+
echo "https://rubygems.org/gems/chemomer"
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AsciiChem contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# chemomer
|
|
2
|
+
|
|
3
|
+
The **Ruby binding for the [chemomer](https://github.com/chemomer/chemomer)
|
|
4
|
+
engine** — molfile in, InChI identifier / InChIKey out, driven through
|
|
5
|
+
the engine's C ABI with [FFI](https://github.com/ffi/ffi).
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
require "chemomer"
|
|
9
|
+
|
|
10
|
+
inchi, inchikey = Chemomer.from_molfile(molfile_text)
|
|
11
|
+
aux = Chemomer.aux_from_molfile(molfile_text)
|
|
12
|
+
Chemomer.ffi_version # => 1
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
A thin wrapper by design: the engine (the byte-exact InChI port, gated
|
|
16
|
+
by the shared oracle corpus
|
|
17
|
+
[inchi-tests](https://github.com/chemomer/inchi-tests)) lives in the
|
|
18
|
+
chemomer repo; this gem owns only the FFI signatures and the packaging
|
|
19
|
+
— no engine code is vendored. The cdylib is a runtime artifact: build
|
|
20
|
+
it once and point the gem at it.
|
|
21
|
+
|
|
22
|
+
## The library
|
|
23
|
+
|
|
24
|
+
The gem resolves the cdylib in this order:
|
|
25
|
+
|
|
26
|
+
1. `CHEMOMER_LIB` — the path to the built cdylib.
|
|
27
|
+
2. The platform default sonames (`libchemomer.dylib` on macOS,
|
|
28
|
+
`libchemomer.so` on Linux), resolved through the loader's search
|
|
29
|
+
path — install the dylib on `LD_LIBRARY_PATH` /
|
|
30
|
+
`DYLD_LIBRARY_PATH` or into a standard lib dir for zero-config use.
|
|
31
|
+
|
|
32
|
+
Build the cdylib from an engine checkout:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cargo build --release # in the chemomer repo
|
|
36
|
+
export CHEMOMER_LIB=$PWD/target/release/libchemomer.dylib
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Errors surface as `Chemomer::Error` — engine failures carry the C
|
|
40
|
+
ABI's thread-local `chemomer_last_error` message, resolution failures
|
|
41
|
+
carry the remedy.
|
|
42
|
+
|
|
43
|
+
## Versioning
|
|
44
|
+
|
|
45
|
+
Runtime packages track the engine: `{engine semver}.{runtime version}`
|
|
46
|
+
(the same scheme as chemomer-py). This gem is `0.1.0.1` — engine
|
|
47
|
+
`0.1.0`, runtime `1`. An engine bump resets the counter (`0.2.0.1`);
|
|
48
|
+
a runtime-only fix increments it (`0.1.0.2`).
|
|
49
|
+
|
|
50
|
+
## AuxInfo
|
|
51
|
+
|
|
52
|
+
`aux_from_molfile` needs the `chemomer_aux_from_molfile` C export,
|
|
53
|
+
which the engine's 0.1.0 ABI does not ship yet (the Python binding
|
|
54
|
+
reaches AuxInfo through the Rust API directly). The gem attaches the
|
|
55
|
+
symbol on first use: once an engine cdylib exports it, the method
|
|
56
|
+
works with no gem change; against a 0.1.0 cdylib it raises
|
|
57
|
+
`Chemomer::Error` saying exactly that.
|
|
58
|
+
|
|
59
|
+
## Test
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bundle install
|
|
63
|
+
CHEMOMER_LIB=$PWD/../chemomer/target/release/libchemomer.dylib bundle exec rspec
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Specs that need the cdylib gate on `CHEMOMER_LIB` and skip cleanly
|
|
67
|
+
without it; the rest run everywhere. CI builds the engine's main
|
|
68
|
+
cdylib and runs the full suite on ubuntu + macos.
|
|
69
|
+
|
|
70
|
+
## Publishing
|
|
71
|
+
|
|
72
|
+
`release.yml` is dispatch-only: a version input (verified against
|
|
73
|
+
`lib/chemomer/version.rb`), the pre-created-tag trick, then
|
|
74
|
+
`rubygems/release-gem@v1` — trusted publishing (OIDC), no stored
|
|
75
|
+
credentials, no environment.
|
|
76
|
+
|
|
77
|
+
The first publish of the gem name needs the RubyGems trusted publisher
|
|
78
|
+
registered first — gem `chemomer`, owner `chemomer`, repository
|
|
79
|
+
`chemomer/chemomer-ruby`, workflow `release.yml`, no environment — or
|
|
80
|
+
a local `gem push` for the very first version.
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT, same as the engine.
|
data/chemomer.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/chemomer/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "chemomer"
|
|
7
|
+
spec.version = Chemomer::VERSION
|
|
8
|
+
spec.authors = ["Ribose Inc."]
|
|
9
|
+
spec.email = ["open.source@ribose.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Ruby bindings for the chemomer InChI engine — molfile in, identifier / InChIKey out."
|
|
12
|
+
spec.description = "Chemomer drives the native chemomer engine — the Rust InChI port gated by the " \
|
|
13
|
+
"shared oracle corpus — through its C ABI via FFI. from_molfile returns the " \
|
|
14
|
+
"InChI identifier and the InChIKey; aux_from_molfile returns the AuxInfo line. " \
|
|
15
|
+
"No engine code is vendored: the cdylib is a runtime artifact."
|
|
16
|
+
spec.homepage = "https://github.com/chemomer/chemomer-ruby"
|
|
17
|
+
spec.license = "MIT"
|
|
18
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.3.0")
|
|
19
|
+
|
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/chemomer/chemomer-ruby"
|
|
21
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
22
|
+
|
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
25
|
+
f.match(%r{^(test|spec|features)/})
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
spec.require_paths = ["lib"]
|
|
29
|
+
|
|
30
|
+
spec.add_dependency "ffi"
|
|
31
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemomer
|
|
4
|
+
# The FFI surface of the chemomer cdylib: one anonymous module per
|
|
5
|
+
# library (attach_function binds the symbols once), cached per
|
|
6
|
+
# candidate list — the shape of asciichem-ruby's NativeEngine.
|
|
7
|
+
#
|
|
8
|
+
# The documented C ABI of chemomer 0.1.0:
|
|
9
|
+
#
|
|
10
|
+
# chemomer_from_molfile molfile → identifier string (null on error)
|
|
11
|
+
# chemomer_inchikey molfile → InChIKey string (null on error)
|
|
12
|
+
# chemomer_string_free releases a string returned by the ABI
|
|
13
|
+
# chemomer_last_error → the calling thread's last error, or null
|
|
14
|
+
# chemomer_ffi_version → the ABI version (1)
|
|
15
|
+
module Bindings
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
# The main surface: attaches eagerly (every symbol is part of the
|
|
19
|
+
# documented ABI) and caches per candidate list.
|
|
20
|
+
def for(*names)
|
|
21
|
+
bindings[names] ||= attach(names)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# AuxInfo: the 0.1.0 ABI does not export chemomer_aux_from_molfile
|
|
25
|
+
# (the Python binding reaches AuxInfo through the Rust API
|
|
26
|
+
# directly). The symbol is attached on first use, so the gem
|
|
27
|
+
# lights up without a change the moment an engine cdylib ships the
|
|
28
|
+
# export; against a dylib without it, a clear Chemomer::Error
|
|
29
|
+
# explains the gap.
|
|
30
|
+
def aux(*names)
|
|
31
|
+
aux_bindings[names] ||= attach_aux(names)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def bindings
|
|
35
|
+
@bindings ||= {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def aux_bindings
|
|
39
|
+
@aux_bindings ||= {}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def attach(names)
|
|
43
|
+
guard_readable(names)
|
|
44
|
+
Module.new do
|
|
45
|
+
extend FFI::Library
|
|
46
|
+
|
|
47
|
+
ffi_lib(*names)
|
|
48
|
+
attach_function :chemomer_from_molfile, %i[string], :pointer
|
|
49
|
+
attach_function :chemomer_inchikey, %i[string], :pointer
|
|
50
|
+
attach_function :chemomer_string_free, %i[pointer], :void
|
|
51
|
+
attach_function :chemomer_last_error, [], :pointer
|
|
52
|
+
attach_function :chemomer_ffi_version, [], :uint32
|
|
53
|
+
|
|
54
|
+
# The message of the last error on the calling thread, or nil.
|
|
55
|
+
def self.last_error
|
|
56
|
+
pointer = chemomer_last_error
|
|
57
|
+
pointer.null? ? nil : pointer.read_string
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
rescue LoadError => e
|
|
61
|
+
raise Error, load_failure(e)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def attach_aux(names)
|
|
65
|
+
guard_readable(names)
|
|
66
|
+
Module.new do
|
|
67
|
+
extend FFI::Library
|
|
68
|
+
|
|
69
|
+
ffi_lib(*names)
|
|
70
|
+
attach_function :chemomer_aux_from_molfile, %i[string], :pointer
|
|
71
|
+
# The call path needs the companions too — they exist in every
|
|
72
|
+
# engine ABI version, so attaching them here is version-safe;
|
|
73
|
+
# only the aux symbol above is the version-sensitive one.
|
|
74
|
+
attach_function :chemomer_string_free, %i[pointer], :void
|
|
75
|
+
attach_function :chemomer_last_error, [], :pointer
|
|
76
|
+
|
|
77
|
+
def self.last_error
|
|
78
|
+
pointer = chemomer_last_error
|
|
79
|
+
pointer.null? ? nil : pointer.read_string
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
rescue FFI::NotFoundError
|
|
83
|
+
raise Error,
|
|
84
|
+
"chemomer: the cdylib does not export chemomer_aux_from_molfile — " \
|
|
85
|
+
"AuxInfo needs an engine that ships the export " \
|
|
86
|
+
"(github.com/chemomer/chemomer, src/ffi.rs)"
|
|
87
|
+
rescue LoadError => e
|
|
88
|
+
raise Error, load_failure(e)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# An explicit CHEMOMER_LIB path is one candidate; a missing or
|
|
92
|
+
# unreadable file deserves the direct message rather than the
|
|
93
|
+
# loader's. The default soname list is searched by the loader
|
|
94
|
+
# instead — nothing to check here.
|
|
95
|
+
def guard_readable(names)
|
|
96
|
+
return unless names.one?
|
|
97
|
+
|
|
98
|
+
path = names.first
|
|
99
|
+
return if File.readable?(path)
|
|
100
|
+
|
|
101
|
+
raise Error,
|
|
102
|
+
"chemomer: #{path} is not readable — set CHEMOMER_LIB to the built " \
|
|
103
|
+
"cdylib (cargo build --release in the chemomer checkout)"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def load_failure(error)
|
|
107
|
+
"chemomer: could not load the cdylib (#{error.message}). Set CHEMOMER_LIB " \
|
|
108
|
+
"to the built cdylib (cargo build --release in the chemomer checkout) or " \
|
|
109
|
+
"install it on the loader path."
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemomer
|
|
4
|
+
# The single error type of the gem: engine failures (raised from the
|
|
5
|
+
# C ABI's thread-local last_error) and library-resolution failures
|
|
6
|
+
# alike, so callers rescue one thing.
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemomer
|
|
4
|
+
# The {engine semver}.{runtime version} scheme (shared with
|
|
5
|
+
# chemomer-py): the chemomer engine release this gem wraps (0.1.0)
|
|
6
|
+
# plus the gem's own runtime counter (1). An engine bump resets the
|
|
7
|
+
# counter (0.2.0.1); a runtime-only fix increments it (0.1.0.2).
|
|
8
|
+
VERSION = "0.1.0.1"
|
|
9
|
+
end
|
data/lib/chemomer.rb
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ffi"
|
|
4
|
+
require "rbconfig"
|
|
5
|
+
|
|
6
|
+
# Chemomer drives the native chemomer engine — the Rust InChI port
|
|
7
|
+
# gated by the shared oracle corpus (chemomer/chemomer) — through its
|
|
8
|
+
# C ABI via FFI. A thin wrapper by design: no engine code is vendored,
|
|
9
|
+
# the gem owns only the FFI signatures and the packaging. The cdylib
|
|
10
|
+
# is a runtime artifact: build it once from an engine checkout and
|
|
11
|
+
# point CHEMOMER_LIB at it, or install it on the loader path for the
|
|
12
|
+
# default soname resolution.
|
|
13
|
+
#
|
|
14
|
+
# Chemomer.from_molfile(molfile) # => [inchi, inchikey]
|
|
15
|
+
# Chemomer.aux_from_molfile(molfile) # => aux line
|
|
16
|
+
# Chemomer.ffi_version # => 1
|
|
17
|
+
module Chemomer
|
|
18
|
+
autoload :VERSION, "chemomer/version"
|
|
19
|
+
autoload :Bindings, "chemomer/bindings"
|
|
20
|
+
autoload :Error, "chemomer/error"
|
|
21
|
+
|
|
22
|
+
# Fallback sonames tried in order when CHEMOMER_LIB is unset; the
|
|
23
|
+
# OS loader resolves them from its search path (LD_LIBRARY_PATH /
|
|
24
|
+
# DYLD_LIBRARY_PATH, /usr/local/lib, ...).
|
|
25
|
+
DEFAULT_LIB_NAMES = {
|
|
26
|
+
darwin: %w[libchemomer.dylib chemomer.dylib],
|
|
27
|
+
linux: %w[libchemomer.so chemomer.so],
|
|
28
|
+
windows: %w[chemomer.dll libchemomer.dll]
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
module_function
|
|
32
|
+
|
|
33
|
+
# The library candidates to attach: CHEMOMER_LIB when set, else
|
|
34
|
+
# this platform's default sonames.
|
|
35
|
+
def lib
|
|
36
|
+
env = ENV.fetch("CHEMOMER_LIB", nil)
|
|
37
|
+
env ? [env] : DEFAULT_LIB_NAMES.fetch(platform)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# molfile → [InChI identifier, InChIKey].
|
|
41
|
+
#
|
|
42
|
+
# Chemomer.from_molfile(water_molfile)
|
|
43
|
+
# # => ["InChI=1S/H2O/h1H2", "XLYOFNOQVPJJNP-UHFFFAOYSA-N"]
|
|
44
|
+
def from_molfile(molfile)
|
|
45
|
+
bindings = Bindings.for(*lib)
|
|
46
|
+
inchi = call(bindings, molfile, :chemomer_from_molfile)
|
|
47
|
+
inchikey = call(bindings, molfile, :chemomer_inchikey)
|
|
48
|
+
[inchi, inchikey]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# molfile → the AuxInfo line (per-component canonical numbering,
|
|
52
|
+
# reversibility block). Needs the chemomer_aux_from_molfile export —
|
|
53
|
+
# attached on first use, so it lights up the moment an engine cdylib
|
|
54
|
+
# ships it.
|
|
55
|
+
def aux_from_molfile(molfile)
|
|
56
|
+
bindings = Bindings.aux(*lib)
|
|
57
|
+
call(bindings, molfile, :chemomer_aux_from_molfile)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The C ABI version of the attached cdylib (1 today).
|
|
61
|
+
def ffi_version
|
|
62
|
+
Bindings.for(*lib).chemomer_ffi_version
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# The C ABI contract: null return on error (the message sits on the
|
|
66
|
+
# calling thread's last_error slot), the returned string freed right
|
|
67
|
+
# after reading it.
|
|
68
|
+
def call(bindings, molfile, function)
|
|
69
|
+
pointer = bindings.public_send(function, molfile)
|
|
70
|
+
# A null return arrives as a non-nil FFI::Pointer whose address is
|
|
71
|
+
# 0 — the truthiness test would sail past it, so null? is the
|
|
72
|
+
# guard.
|
|
73
|
+
if pointer.nil? || pointer.null?
|
|
74
|
+
raise Error, "chemomer: #{bindings.last_error || 'call failed'}"
|
|
75
|
+
end
|
|
76
|
+
value = pointer.read_string
|
|
77
|
+
bindings.chemomer_string_free(pointer)
|
|
78
|
+
value
|
|
79
|
+
end
|
|
80
|
+
private_class_method :call
|
|
81
|
+
|
|
82
|
+
def platform
|
|
83
|
+
case RbConfig::CONFIG["host_os"]
|
|
84
|
+
when /darwin/ then :darwin
|
|
85
|
+
when /linux/ then :linux
|
|
86
|
+
when /mswin|mingw|cygwin/ then :windows
|
|
87
|
+
else
|
|
88
|
+
raise Error,
|
|
89
|
+
"chemomer: no default soname for #{RbConfig::CONFIG['host_os']} — " \
|
|
90
|
+
"set CHEMOMER_LIB to the built cdylib"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
private_class_method :platform
|
|
94
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: chemomer
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ribose Inc.
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ffi
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
description: 'Chemomer drives the native chemomer engine — the Rust InChI port gated
|
|
27
|
+
by the shared oracle corpus — through its C ABI via FFI. from_molfile returns the
|
|
28
|
+
InChI identifier and the InChIKey; aux_from_molfile returns the AuxInfo line. No
|
|
29
|
+
engine code is vendored: the cdylib is a runtime artifact.'
|
|
30
|
+
email:
|
|
31
|
+
- open.source@ribose.com
|
|
32
|
+
executables: []
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- ".github/workflows/ci.yml"
|
|
37
|
+
- ".github/workflows/release.yml"
|
|
38
|
+
- ".gitignore"
|
|
39
|
+
- Gemfile
|
|
40
|
+
- LICENSE
|
|
41
|
+
- README.md
|
|
42
|
+
- chemomer.gemspec
|
|
43
|
+
- lib/chemomer.rb
|
|
44
|
+
- lib/chemomer/bindings.rb
|
|
45
|
+
- lib/chemomer/error.rb
|
|
46
|
+
- lib/chemomer/version.rb
|
|
47
|
+
homepage: https://github.com/chemomer/chemomer-ruby
|
|
48
|
+
licenses:
|
|
49
|
+
- MIT
|
|
50
|
+
metadata:
|
|
51
|
+
source_code_uri: https://github.com/chemomer/chemomer-ruby
|
|
52
|
+
rubygems_mfa_required: 'true'
|
|
53
|
+
rdoc_options: []
|
|
54
|
+
require_paths:
|
|
55
|
+
- lib
|
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 3.3.0
|
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
requirements: []
|
|
67
|
+
rubygems_version: 4.0.23
|
|
68
|
+
specification_version: 4
|
|
69
|
+
summary: Ruby bindings for the chemomer InChI engine — molfile in, identifier / InChIKey
|
|
70
|
+
out.
|
|
71
|
+
test_files: []
|