asciichem 0.31.14 → 0.31.15
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 +13 -0
- data/README.adoc +4 -2
- data/lib/asciichem/resolver/adapter.rb +4 -3
- data/lib/asciichem/resolver/common_chemistry.rb +27 -12
- data/lib/asciichem/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3246a177690e1019834ab1e177da12f75aee9a7a75cdaa6caecaa3e7a721b227
|
|
4
|
+
data.tar.gz: e2194852b615ef5e61ddea0726e8b279543c6cbad326991a6238adf791e8d87c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9fb5e64c26d57111cb9a742388228e225a99da2965d5ac7793cf8ec2366367a3c3b4ed24c14aab1c173f03d324309bd0f34919c52d29a0ee569cb34de88d1012
|
|
7
|
+
data.tar.gz: cc604167f949bac08b2f47c1dd6ec69e76d1b85ec9d2158ed7d0004a1c0f60c368ec5c1c5a6544fec68f6cc9f71ffec197d1fc2eb165c7da3ea6062e039db7f1
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
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.15] - 2026-11-12
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- Common Chemistry speaks its real key contract (CAS's access
|
|
10
|
+
email): `GET /direct-api/detail` with the token as the
|
|
11
|
+
`X-API-KEY` header plus `x-origin` and `accept` headers — not
|
|
12
|
+
the `apikey` query parameter 0.31.14 guessed. The key resolves
|
|
13
|
+
from `COMMON_CHEMISTRY_API_KEY` or the token's stored location
|
|
14
|
+
(`~/.config/cas-common-chemistry-api.key`); explicit nil means
|
|
15
|
+
no key. Verified live: formaldehyde resolves from production.
|
|
16
|
+
- The fetch contract grows `get(url, headers = {})`; redirects
|
|
17
|
+
keep the headers.
|
|
18
|
+
|
|
6
19
|
## [0.31.14] - 2026-11-12
|
|
7
20
|
|
|
8
21
|
### Added
|
data/README.adoc
CHANGED
|
@@ -104,8 +104,10 @@ AsciiChem::Resolver.resolve(value: "50-78-2", convention: "cas",
|
|
|
104
104
|
----
|
|
105
105
|
|
|
106
106
|
CAS key-gated the Common Chemistry API: live lookups there need a
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
personal token (request one at cas.org/services/commonchemistry-api,
|
|
108
|
+
valid 12 months). Export it as `COMMON_CHEMISTRY_API_KEY` or store
|
|
109
|
+
it at `~/.config/cas-common-chemistry-api.key` — the adapter sends
|
|
110
|
+
it as the `X-API-KEY` header. Without a key, that source answers 401
|
|
109
111
|
and is skipped — PubChem and OPSIN keep resolving.
|
|
110
112
|
|
|
111
113
|
=== Citations: dataset bibitems with provenance
|
|
@@ -78,18 +78,19 @@ module AsciiChem
|
|
|
78
78
|
|
|
79
79
|
# Minimal stdlib HTTP transport. No runtime gem dependencies.
|
|
80
80
|
class NetFetch
|
|
81
|
-
def get(url, limit = 3)
|
|
81
|
+
def get(url, headers = {}, limit = 3)
|
|
82
82
|
raise Error, "too many redirects" if limit.zero?
|
|
83
83
|
|
|
84
84
|
uri = URI(url)
|
|
85
|
+
merged = { "User-Agent" => "asciichem-resolver" }.merge(headers)
|
|
85
86
|
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true,
|
|
86
87
|
open_timeout: 5, read_timeout: 10) do |http|
|
|
87
|
-
http.request(Net::HTTP::Get.new(uri.request_uri,
|
|
88
|
+
http.request(Net::HTTP::Get.new(uri.request_uri, merged))
|
|
88
89
|
end
|
|
89
90
|
|
|
90
91
|
case response
|
|
91
92
|
when Net::HTTPSuccess then response.body
|
|
92
|
-
when Net::HTTPRedirection then get(URI.join(uri, response["location"]).to_s, limit - 1)
|
|
93
|
+
when Net::HTTPRedirection then get(URI.join(uri, response["location"]).to_s, headers, limit - 1)
|
|
93
94
|
when Net::HTTPNotFound then nil
|
|
94
95
|
else
|
|
95
96
|
raise Error, "HTTP #{response.code}: #{response.message}"
|
|
@@ -16,30 +16,40 @@ module AsciiChem
|
|
|
16
16
|
# `Resolver.resolve(sources:)`.
|
|
17
17
|
#
|
|
18
18
|
# API access: CAS key-gated the API (401 without a key; request
|
|
19
|
-
# one at cas.org/services/commonchemistry-api
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
19
|
+
# one at cas.org/services/commonchemistry-api). The access email
|
|
20
|
+
# defines the contract: GET /direct-api/detail with the token as
|
|
21
|
+
# the X-API-KEY header plus x-origin and accept headers. The key
|
|
22
|
+
# comes per instance (`api_key:`), from
|
|
23
|
+
# COMMON_CHEMISTRY_API_KEY, or from
|
|
24
|
+
# ~/.config/cas-common-chemistry-api.key (the token's stored
|
|
25
|
+
# location). Tokens are personal and expire after 12 months
|
|
26
|
+
# (CAS emails a renewal notice). Without a key, live lookups
|
|
27
|
+
# answer 401 and the resolver skips this source; seeded caches
|
|
28
|
+
# keep working.
|
|
26
29
|
class CommonChemistry < Adapter
|
|
27
30
|
source_name :common_chemistry
|
|
28
31
|
supports "cas"
|
|
29
32
|
|
|
30
|
-
BASE = "https://commonchemistry.cas.org/api/detail"
|
|
33
|
+
BASE = "https://commonchemistry.cas.org/direct-api/detail"
|
|
34
|
+
ORIGIN = "https://commonchemistry.cas.org/api-overview"
|
|
35
|
+
KEY_FILE = File.expand_path("~/.config/cas-common-chemistry-api.key")
|
|
31
36
|
|
|
32
37
|
attr_reader :api_key
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
# Explicit nil means no key; the env/file lookup runs only when
|
|
40
|
+
# the argument is omitted.
|
|
41
|
+
def initialize(api_key: default_api_key)
|
|
35
42
|
super()
|
|
36
43
|
@api_key = api_key
|
|
37
44
|
end
|
|
38
45
|
|
|
39
46
|
def fetch_record(value:, convention:, fetch:)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
headers = {
|
|
48
|
+
"Accept" => "application/json",
|
|
49
|
+
"x-origin" => ORIGIN
|
|
50
|
+
}
|
|
51
|
+
headers["X-API-KEY"] = api_key if api_key
|
|
52
|
+
body = fetch.get("#{BASE}?cas_rn=#{CGI.escape(value.to_s)}", headers)
|
|
43
53
|
return nil unless body
|
|
44
54
|
|
|
45
55
|
data = JSON.parse(body)
|
|
@@ -56,6 +66,11 @@ module AsciiChem
|
|
|
56
66
|
|
|
57
67
|
private
|
|
58
68
|
|
|
69
|
+
def default_api_key
|
|
70
|
+
ENV.fetch("COMMON_CHEMISTRY_API_KEY", nil) ||
|
|
71
|
+
(File.read(KEY_FILE).strip if File.readable?(KEY_FILE))
|
|
72
|
+
end
|
|
73
|
+
|
|
59
74
|
def substance_from(data)
|
|
60
75
|
provenance = default_provenance
|
|
61
76
|
identifiers = [Identifier.new(value: data["rn"], convention: "cas",
|
data/lib/asciichem/version.rb
CHANGED