commonchemistry 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 179b8b0132bd3294019e9e93e2e85a5ff0a23f3f12457734ea843f50efbe2f82
4
+ data.tar.gz: ae36ef95a8b3974b3b73e5cfd28e99fd4be1af47b4f5c7f6dea63c4da975f256
5
+ SHA512:
6
+ metadata.gz: eb82a95d20c50fac2400a7f5ff41c49b777fb95e52ca58d85b02eb24a320985ff6918b4b787bf171b49f5f3515bbcfff61bbb205f80e0654f7bdf3648af54ccd
7
+ data.tar.gz: 84e4dd2ab2d0ecd9edb57d9caa2e6737ebea4c7f9a1dc3abe4295c27b90ab717789fd8bc1d43ebd90e2a067cd1d3c34f990cb55ecca996e33729101563d8e3cb
@@ -0,0 +1,3 @@
1
+ module CommonChemistry
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,179 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ module CommonChemistry
5
+ # Base error class for CommonChemistry errors
6
+ class Error < StandardError; end
7
+
8
+ # Error raised when a request is invalid (400, 404)
9
+ class InvalidRequestError < Error; end
10
+
11
+ # Error raised when the server returns an internal error (500)
12
+ class ServerError < Error; end
13
+
14
+ # Error raised for unexpected responses
15
+ class UnexpectedResponseError < Error; end
16
+
17
+ # Client class to interact with the Common Chemistry API
18
+ class Client
19
+ include HTTParty
20
+ base_uri 'https://commonchemistry.cas.org/api'
21
+
22
+ def initialize
23
+ # TODO
24
+ end
25
+
26
+ # Searches for substances matching the query
27
+ #
28
+ # @param q [String] The search query
29
+ # @param offset [Integer, nil] The offset for pagination
30
+ # @param size [Integer, nil] The number of results to return
31
+ # @return [SearchResponse] The search results
32
+ # @raise [InvalidRequestError] if the request is invalid
33
+ # @raise [ServerError] if the server returns an error
34
+ # @raise [UnexpectedResponseError] for other errors
35
+ def search(q:, offset: nil, size: nil)
36
+ params = { q: q }
37
+ params[:offset] = offset if offset
38
+ params[:size] = size if size
39
+
40
+ response = self.class.get('/search', query: params)
41
+ handle_response(response) do
42
+ SearchResponse.new(response.parsed_response)
43
+ end
44
+ end
45
+
46
+ # Retrieves detailed information about a substance
47
+ #
48
+ # @param cas_rn [String, nil] The CAS registry number
49
+ # @param uri [String, nil] The URI of the substance
50
+ # @return [DetailResult] The detailed substance information
51
+ # @raise [InvalidRequestError] if the request is invalid
52
+ # @raise [ServerError] if the server returns an error
53
+ # @raise [UnexpectedResponseError] for other errors
54
+ def detail(cas_rn: nil, uri: nil)
55
+ params = {}
56
+ params[:cas_rn] = cas_rn if cas_rn
57
+ params[:uri] = uri if uri
58
+
59
+ response = self.class.get('/detail', query: params)
60
+ handle_response(response) do
61
+ DetailResult.new(response.parsed_response)
62
+ end
63
+ end
64
+
65
+ # Exports substance data
66
+ #
67
+ # @param uri [String] The URI of the substance
68
+ # @param return_as_attachment [Boolean] Whether to return as attachment
69
+ # @return [String] The exported data
70
+ # @raise [InvalidRequestError] if the request is invalid
71
+ # @raise [ServerError] if the server returns an error
72
+ # @raise [UnexpectedResponseError] for other errors
73
+ def export(uri:, return_as_attachment: false)
74
+ params = { uri: uri, returnAsAttachment: return_as_attachment }
75
+ response = self.class.get('/export', query: params)
76
+ handle_response(response) do
77
+ response.body # Since the response is text/plain
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def handle_response(response)
84
+ case response.code
85
+ when 200
86
+ yield
87
+ when 400, 404
88
+ raise InvalidRequestError, "Invalid Request (#{response.code})"
89
+ when 500
90
+ raise ServerError, "Internal Server Error (#{response.code})"
91
+ else
92
+ raise UnexpectedResponseError, "Unexpected response code: #{response.code}"
93
+ end
94
+ end
95
+ end
96
+
97
+ # Represents a search response from the API
98
+ class SearchResponse
99
+ attr_reader :count, :results
100
+
101
+ def initialize(data)
102
+ @count = data['count'].to_i
103
+ @results = (data['results'] || []).map { |result| SearchResult.new(result) }
104
+ end
105
+ end
106
+
107
+ # Represents an individual search result
108
+ class SearchResult
109
+ attr_reader :rn, :name, :image
110
+
111
+ def initialize(data)
112
+ @rn = data['rn']
113
+ @name = data['name']
114
+ @image = data['image']
115
+ end
116
+
117
+ # Saves the SVG image to a file
118
+ #
119
+ # @param filename [String] The filename to save the image as
120
+ def save_image(filename)
121
+ File.open(filename, 'w') { |file| file.write(@image) }
122
+ end
123
+ end
124
+
125
+ # Represents detailed information about a substance
126
+ class DetailResult
127
+ attr_reader :uri, :rn, :name, :image, :inchi, :inchi_key, :smile,
128
+ :canonical_smile, :molecular_formula, :molecular_mass,
129
+ :experimental_properties, :property_citations,
130
+ :synonyms, :replaced_rns
131
+
132
+ def initialize(data)
133
+ @uri = data['uri']
134
+ @rn = data['rn']
135
+ @name = data['name']
136
+ @image = data['image']
137
+ @inchi = data['inchi']
138
+ @inchi_key = data['inchiKey']
139
+ @smile = data['smile']
140
+ @canonical_smile = data['canonicalSmile']
141
+ @molecular_formula = data['molecularFormula']
142
+ @molecular_mass = data['molecularMass']
143
+ @experimental_properties = (data['experimentalProperties'] || []).map { |prop| ExperimentalProperty.new(prop) }
144
+ @property_citations = (data['propertyCitations'] || []).map { |citation| PropertyCitation.new(citation) }
145
+ @synonyms = data['synonyms'] || []
146
+ @replaced_rns = data['replacedRns'] || []
147
+ end
148
+
149
+ # Saves the SVG image to a file
150
+ #
151
+ # @param filename [String] The filename to save the image as
152
+ def save_image(filename)
153
+ File.open(filename, 'w') { |file| file.write(@image) }
154
+ end
155
+ end
156
+
157
+ # Represents an experimental property of a substance
158
+ class ExperimentalProperty
159
+ attr_reader :name, :property, :source_number
160
+
161
+ def initialize(data)
162
+ @name = data['name']
163
+ @property = data['property']
164
+ @source_number = data['sourceNumber']
165
+ end
166
+ end
167
+
168
+ # Represents a property citation
169
+ class PropertyCitation
170
+ attr_reader :doc_uri, :source_number, :source
171
+
172
+ def initialize(data)
173
+ @doc_uri = data['docUri']
174
+ @source_number = data['sourceNumber']
175
+ @source = data['source']
176
+ end
177
+ end
178
+ end
179
+
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: commonchemistry
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - coderobe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-11-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.22.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.22.0
27
+ description: commonchemistry api module
28
+ email:
29
+ - git@coderobe.net
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/commonchemistry.rb
35
+ - lib/commonchemistry/version.rb
36
+ homepage: https://github.com/coderobe/ruby-commonchemistry
37
+ licenses: []
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.5.4
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: commonchemistry.cas.org api wrapper
58
+ test_files: []