opentox-client 0.0.1pre

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,17 @@
1
+ opentox-ruby-minimal
2
+ ====================
3
+
4
+ Thin Ruby wrapper for the [OpenTox](http://www.opentox.org) REST API
5
+
6
+ Installation
7
+ ------------
8
+
9
+ gem install opentox-client
10
+
11
+ [API documentation](http://rdoc.info/gems/opentox-client)
12
+ -------------------------------------------------------------------
13
+
14
+ Copyright
15
+ ---------
16
+
17
+ Copyright (c) 2009-2012 Christoph Helma, Martin Guetlein, Micha Rautenberg, Andreas Maunz, David Vorgrimmler, Denis Gebele. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require File.join(File.dirname(__FILE__),"lib","opentox-client.rb")
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'lib'
7
+ t.libs << 'test'
8
+ t.test_files = FileList['test/*.rb']
9
+ t.verbose = true
10
+ end
11
+
data/lib/algorithm.rb ADDED
@@ -0,0 +1,15 @@
1
+ module OpenTox
2
+
3
+ # Wrapper for OpenTox Algorithms
4
+ class Algorithm
5
+
6
+ # Execute algorithm with parameters, please consult the OpenTox API and the webservice documentation for acceptable parameters
7
+ # @param [optional,Hash] params Algorithm parameters
8
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
9
+ # @return [String] URI of new resource (dataset, model, ...)
10
+ def run params=nil
11
+ post params, {:accept => 'text/uri-list'}
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,392 @@
1
+ module OpenTox
2
+
3
+ #Module for Authorization and Authentication
4
+ #@example Authentication
5
+ # require "opentox-client"
6
+ # OpenTox::Authorization::AA_SERVER = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
7
+ # token = OpenTox::Authorization.authenticate("benutzer", "passwort")
8
+ #@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
9
+
10
+ module Authorization
11
+
12
+ #Helper Class AA to create and send default policies out of xml templates
13
+ #@example Creating a default policy to a URI
14
+ # aa=OpenTox::Authorization::AA.new(tok)
15
+ # xml=aa.get_xml('http://uri....')
16
+ # OpenTox::Authorization.create_policy(xml,tok)
17
+
18
+ class AA
19
+ attr_accessor :user, :subjectid, :policy
20
+
21
+ #Generates AA object - requires subjectid
22
+ # @param [String] subjectid
23
+ def initialize(subjectid)
24
+ @user = Authorization.get_user(subjectid)
25
+ @subjectid = subjectid
26
+ @policy = Policies.new()
27
+ end
28
+
29
+ #Cleans AA Policies and loads default xml file into policy attribute
30
+ #set uri and user, returns Policyfile(XML) for open-sso
31
+ # @param [String] URI to create a policy for
32
+ def get_xml(uri)
33
+ @policy.drop_policies
34
+ @policy.load_default_policy(@user, uri)
35
+ return @policy.to_xml
36
+ end
37
+
38
+ #Loads and sends Policyfile(XML) to open-sso server
39
+ # @param [String] URI to create a policy for
40
+ def send(uri)
41
+ xml = get_xml(uri)
42
+ ret = false
43
+ ret = Authorization.create_policy(xml, @subjectid)
44
+ @@logger.debug "Policy send with subjectid: #{@subjectid}"
45
+ @@logger.warn "Not created Policy is: #{xml}" if !ret
46
+ ret
47
+ end
48
+
49
+ end
50
+
51
+ #Returns the open-sso server set in the config file .opentox/config/[environment].yaml
52
+ # @return [String, nil] the openSSO server URI or nil
53
+ def self.server
54
+ return AA_SERVER
55
+ end
56
+
57
+ #Authentication against OpenSSO. Returns token. Requires Username and Password.
58
+ # @param [String, String]Username,Password
59
+ # @return [String, nil] gives subjectid or nil
60
+ def self.authenticate(user, pw)
61
+ return nil if !AA_SERVER
62
+ begin
63
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/authenticate")
64
+ out = resource.post(:username=>user, :password => pw).sub("token.id=","").sub("\n","")
65
+ return out
66
+ rescue
67
+ return nil
68
+ end
69
+ end
70
+
71
+ #Logout on opensso. Make token invalid. Requires token
72
+ # @param [String]subjectid the subjectid
73
+ # @return [Boolean] true if logout is OK
74
+ def self.logout(subjectid)
75
+ begin
76
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/logout")
77
+ resource.post(:subjectid => subjectid)
78
+ return true
79
+ rescue
80
+ return false
81
+ end
82
+ end
83
+
84
+ #Authorization against OpenSSO for a URI with request-method (action) [GET/POST/PUT/DELETE]
85
+ # @param [String,String,String]uri,action,subjectid
86
+ # @return [Boolean, nil] returns true, false or nil (if authorization-request fails).
87
+ def self.authorize(uri, action, subjectid)
88
+ return true if !AA_SERVER
89
+ begin
90
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/authorize")
91
+ return true if resource.post(:uri => uri, :action => action, :subjectid => subjectid) == "boolean=true\n"
92
+ rescue
93
+ return nil
94
+ end
95
+ end
96
+
97
+ #Checks if a token is a valid token
98
+ # @param [String]subjectid subjectid from openSSO session
99
+ # @return [Boolean] subjectid is valid or not.
100
+ def self.is_token_valid(subjectid)
101
+ return true if !AA_SERVER
102
+ begin
103
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/isTokenValid")
104
+ return true if resource.post(:tokenid => subjectid) == "boolean=true\n"
105
+ rescue
106
+ return false
107
+ end
108
+ end
109
+
110
+ #Returns array with all policies of the token owner
111
+ # @param [String]subjectid requires subjectid
112
+ # @return [Array, nil] returns an Array of policy names or nil if request fails
113
+ def self.list_policies(subjectid)
114
+ begin
115
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
116
+ out = resource.get(:subjectid => subjectid)
117
+ return out.split("\n")
118
+ rescue RestClient::InternalServerError => e
119
+ raise e.response
120
+ rescue
121
+ return nil
122
+ end
123
+ end
124
+
125
+ #Returns a policy in xml-format
126
+ # @param [String, String]policy,subjectid
127
+ # @return [String] XML of the policy
128
+ def self.list_policy(policy, subjectid)
129
+ begin
130
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
131
+ return resource.get(:subjectid => subjectid,:id => policy)
132
+ rescue
133
+ return nil
134
+ end
135
+ end
136
+
137
+ # Lists policies alongside with affected uris
138
+ # @param [String] subjectid
139
+ # @return [Hash] keys: all policies of the subjectid owner, values: uris affected by those policies
140
+ def self.list_policies_uris( subjectid )
141
+ names = list_policies(subjectid)
142
+ policies = {}
143
+ names.each do |n|
144
+ policies[n] = list_policy_uris( n, subjectid )
145
+ end
146
+ policies
147
+ end
148
+
149
+ # Lists policies alongside with affected uris
150
+ # @param [String] subjectid
151
+ # @return [Hash] keys: all policies of the subjectid owner, values: uris affected by those policies
152
+ def self.list_policy_uris( policy, subjectid )
153
+ p = OpenTox::Policies.new
154
+ p.load_xml( list_policy(policy, subjectid) )
155
+ p.uris
156
+ end
157
+
158
+ #Returns the owner (who created the first policy) of an URI
159
+ # @param [String, String]uri,subjectid
160
+ # return [String, nil]owner,nil returns owner of the URI
161
+ def self.get_uri_owner(uri, subjectid)
162
+ begin
163
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
164
+ return resource.get(:uri => uri, :subjectid => subjectid).sub("\n","")
165
+ rescue
166
+ return nil
167
+ end
168
+ end
169
+
170
+ #Checks if a policy exists to a URI. Requires URI and token.
171
+ # @param [String, String]uri,subjectid
172
+ # return [Boolean]
173
+ def self.uri_has_policy(uri, subjectid)
174
+ owner = get_uri_owner(uri, subjectid)
175
+ return true if owner and owner != "null"
176
+ false
177
+ end
178
+
179
+ #List all policynames for a URI. Requires URI and token.
180
+ # @param [String, String]uri,subjectid
181
+ # return [Array, nil] returns an Array of policy names or nil if request fails
182
+ def self.list_uri_policies(uri, subjectid)
183
+ begin
184
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
185
+ out = resource.get(:uri => uri, :polnames => true, :subjectid => subjectid)
186
+ policies = []; notfirstline = false
187
+ out.split("\n").each do |line|
188
+ policies << line if notfirstline
189
+ notfirstline = true
190
+ end
191
+ return policies
192
+ rescue
193
+ return nil
194
+ end
195
+ end
196
+
197
+ #Sends a policy in xml-format to opensso server. Requires policy-xml and token.
198
+ # @param [String, String]policyxml,subjectid
199
+ # return [Boolean] returns true if policy is created
200
+ def self.create_policy(policy, subjectid)
201
+ begin
202
+ resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
203
+ @@logger.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
204
+ return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
205
+ rescue
206
+ return false
207
+ end
208
+ end
209
+
210
+ #Deletes a policy
211
+ # @param [String, String]policyname,subjectid
212
+ # @return [Boolean,nil]
213
+ def self.delete_policy(policy, subjectid)
214
+ begin
215
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
216
+ @@logger.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
217
+ return true if resource.delete(:subjectid => subjectid, :id => policy)
218
+ rescue
219
+ return nil
220
+ end
221
+ end
222
+
223
+ #Returns array of all possible LDAP-Groups
224
+ # @param [String]subjectid
225
+ # @return [Array]
226
+ def self.list_groups(subjectid)
227
+ begin
228
+ resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/search")
229
+ grps = resource.post(:admin => subjectid, :attributes_names => "objecttype", :attributes_values_objecttype => "group")
230
+ grps = grps.split("\n").collect{|x| x.sub("string=","")}
231
+ grps.delete_if{|g|g=="MemberManagement"||g=="Webmasters"}
232
+ grps
233
+ rescue
234
+ []
235
+ end
236
+ end
237
+
238
+ #Returns array of the LDAP-Groups of an user
239
+ # @param [String]subjectid
240
+ # @return [Array] gives array of LDAP groups of a user
241
+ def self.list_user_groups(user, subjectid)
242
+ begin
243
+ resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/read")
244
+ out = resource.post(:name => user, :admin => subjectid, :attributes_names => "group")
245
+ grps = []
246
+ out.split("\n").each do |line|
247
+ grps << line.sub("identitydetails.group=","") if line.include?("identitydetails.group=")
248
+ end
249
+ return grps
250
+ rescue
251
+ []
252
+ end
253
+ end
254
+
255
+ #Returns the owner (user id) of a token
256
+ # @param [String]subjectid
257
+ # @return [String]user
258
+ def self.get_user(subjectid)
259
+ begin
260
+ resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/attributes")
261
+ out = resource.post(:subjectid => subjectid, :attributes_names => "uid")
262
+ user = ""; check = false
263
+ out.split("\n").each do |line|
264
+ if check
265
+ user = line.sub("userdetails.attribute.value=","") if line.include?("userdetails.attribute.value=")
266
+ check = false
267
+ end
268
+ check = true if line.include?("userdetails.attribute.name=uid")
269
+ end
270
+ return user
271
+ rescue
272
+ nil
273
+ end
274
+ end
275
+
276
+ #Send default policy with Authorization::AA class
277
+ # @param [String, String]URI,subjectid
278
+ def self.send_policy(uri, subjectid)
279
+ return true if !AA_SERVER
280
+ aa = Authorization::AA.new(subjectid)
281
+ ret = aa.send(uri)
282
+ @@logger.debug "OpenTox::Authorization send policy for URI: #{uri} | subjectid: #{subjectid} - policy created: #{ret}"
283
+ ret
284
+ end
285
+
286
+ #Deletes all policies of an URI
287
+ # @param [String, String]URI,subjectid
288
+ # @return [Boolean]
289
+ def self.delete_policies_from_uri(uri, subjectid)
290
+ policies = list_uri_policies(uri, subjectid)
291
+ if policies
292
+ policies.each do |policy|
293
+ ret = delete_policy(policy, subjectid)
294
+ @@logger.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
295
+ end
296
+ end
297
+ return true
298
+ end
299
+
300
+ # Checks (if subjectid is valid) if a policy exist and create default policy if not
301
+ # @param [String] uri
302
+ # @param [String] subjectid
303
+ # @return [Boolean] true if policy checked/created successfully (or no uri/subjectid given), false else
304
+ def self.check_policy(uri, subjectid)
305
+ return true unless uri and subjectid
306
+ token_valid = OpenTox::Authorization.is_token_valid(subjectid)
307
+ @@logger.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
308
+ # check if subjectid is valid
309
+ unless token_valid
310
+ # abort if invalid
311
+ @@logger.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
312
+ return false
313
+ end
314
+
315
+ if !uri_has_policy(uri, subjectid)
316
+ # if no policy exists, create a policy, return result of send policy
317
+ send_policy(uri, subjectid)
318
+ else
319
+ # if policy exists check for POST rights
320
+ if authorize(uri, "POST", subjectid)
321
+ true
322
+ else
323
+ @@logger.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
324
+ false
325
+ end
326
+ end
327
+ true
328
+ end
329
+
330
+ class << self
331
+ alias :token_valid? :is_token_valid
332
+ end
333
+
334
+ # Check Authorization for a resource (identified via URI) with method and subjectid.
335
+ # @param [String] uri
336
+ # @param [String] request_method, should be GET, POST, PUT, DELETE
337
+ # @param [String] subjectid
338
+ # @return [Boolean] true if access granted, else otherwise
339
+ def self.authorized?(uri, request_method, subjectid)
340
+ if CONFIG[:authorization][:free_request].include?(request_method)
341
+ #@@logger.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
342
+ true
343
+ elsif OpenTox::Authorization.free_uri?(uri, request_method)
344
+ #@@logger.debug "authorized? >>true<< (uris is free_uri), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
345
+ true
346
+ elsif CONFIG[:authorization][:authenticate_request].include?(request_method)
347
+ ret = OpenTox::Authorization.is_token_valid(subjectid)
348
+ @@logger.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
349
+ ret
350
+ elsif OpenTox::Authorization.authorize_exception?(uri, request_method)
351
+ ret = OpenTox::Authorization.is_token_valid(subjectid)
352
+ @@logger.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
353
+ ret
354
+ elsif CONFIG[:authorization][:authorize_request].include?(request_method)
355
+ ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
356
+ @@logger.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
357
+ ret
358
+ else
359
+ @@logger.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
360
+ false
361
+ end
362
+ end
363
+
364
+ private
365
+ def self.free_uri?(uri, request_method)
366
+ if CONFIG[:authorization][:free_uris]
367
+ CONFIG[:authorization][:free_uris].each do |request_methods,uris|
368
+ if request_methods and uris and request_methods.include?(request_method.to_sym)
369
+ uris.each do |u|
370
+ return true if u.match uri
371
+ end
372
+ end
373
+ end
374
+ end
375
+ return false
376
+ end
377
+
378
+ def self.authorize_exception?(uri, request_method)
379
+ if CONFIG[:authorization][:authorize_exceptions]
380
+ CONFIG[:authorization][:authorize_exceptions].each do |request_methods,uris|
381
+ if request_methods and uris and request_methods.include?(request_method.to_sym)
382
+ uris.each do |u|
383
+ return true if u.match uri
384
+ end
385
+ end
386
+ end
387
+ end
388
+ return false
389
+ end
390
+
391
+ end
392
+ end
data/lib/compound.rb ADDED
@@ -0,0 +1,170 @@
1
+ CACTUS_URI="http://cactus.nci.nih.gov/chemical/structure/"
2
+
3
+ module OpenTox
4
+
5
+ # Ruby wrapper for OpenTox Compound Webservices (http://opentox.org/dev/apis/api-1.2/structure).
6
+ class Compound
7
+
8
+ # Create a compound from smiles string
9
+ # @example
10
+ # compound = OpenTox::Compound.from_smiles("c1ccccc1")
11
+ # @param [String] smiles Smiles string
12
+ # @return [OpenTox::Compound] Compound
13
+ def self.from_smiles service_uri, smiles, subjectid=nil
14
+ Compound.new RestClientWrapper.post(service_uri, smiles, {:content_type => 'chemical/x-daylight-smiles', :subjectid => subjectid})
15
+ end
16
+
17
+ # Create a compound from inchi string
18
+ # @param [String] smiles InChI string
19
+ # @return [OpenTox::Compound] Compound
20
+ def self.from_inchi service_uri, inchi, subjectid=nil
21
+ Compound.new RestClientWrapper.post(service_uri, inchi, {:content_type => 'chemical/x-inchi', :subjectid => subjectid})
22
+ end
23
+
24
+ # Create a compound from sdf string
25
+ # @param [String] smiles SDF string
26
+ # @return [OpenTox::Compound] Compound
27
+ def self.from_sdf service_uri, sdf, subjectid=nil
28
+ Compound.new RestClientWrapper.post(service_uri, sdf, {:content_type => 'chemical/x-mdl-sdfile', :subjectid => subjectid})
29
+ end
30
+
31
+ # Create a compound from name. Relies on an external service for name lookups.
32
+ # @example
33
+ # compound = OpenTox::Compound.from_name("Benzene")
34
+ # @param [String] name name can be also an InChI/InChiKey, CAS number, etc
35
+ # @return [OpenTox::Compound] Compound
36
+ def self.from_name service_uri, name, subjectid=nil
37
+ Compound.new RestClientWrapper.post(service_uri, name, {:content_type => 'text/plain', :subjectid => subjectid})
38
+ end
39
+
40
+ # Get InChI
41
+ # @return [String] InChI string
42
+ def to_inchi
43
+ get(:accept => 'chemical/x-inchi').to_s.chomp if @uri
44
+ end
45
+
46
+ # Get (canonical) smiles
47
+ # @return [String] Smiles string
48
+ def to_smiles
49
+ get(:accept => 'chemical/x-daylight-smiles').chomp
50
+ end
51
+
52
+ # Get sdf
53
+ # @return [String] SDF string
54
+ def to_sdf
55
+ get(:accept => 'chemical/x-mdl-sdfile').chomp
56
+ end
57
+
58
+ # Get gif image
59
+ # @return [image/gif] Image data
60
+ def to_gif
61
+ get("#{CACTUS_URI}#{to_inchi}/image")
62
+ end
63
+
64
+ # Get png image
65
+ # @example
66
+ # image = compound.to_png
67
+ # @return [image/png] Image data
68
+ def to_png
69
+ get(File.join @uri, "image")
70
+ end
71
+
72
+ # Get URI of compound image
73
+ # @return [String] Compound image URI
74
+ def to_image_uri
75
+ File.join @uri, "image"
76
+ end
77
+
78
+ # Get all known compound names. Relies on an external service for name lookups.
79
+ # @example
80
+ # names = compound.to_names
81
+ # @return [String] Compound names
82
+ def to_names
83
+ begin
84
+ get("#{CACTUS_URI}#{to_inchi}/names").split("\n")
85
+ rescue
86
+ "not available"
87
+ end
88
+ end
89
+
90
+ =begin
91
+ # Match a smarts string
92
+ # @example
93
+ # compound = OpenTox::Compound.from_name("Benzene")
94
+ # compound.match?("cN") # returns false
95
+ # @param [String] smarts Smarts string
96
+ def match?(smarts)
97
+ obconversion = OpenBabel::OBConversion.new
98
+ obmol = OpenBabel::OBMol.new
99
+ obconversion.set_in_format('inchi')
100
+ obconversion.read_string(obmol,@inchi)
101
+ smarts_pattern = OpenBabel::OBSmartsPattern.new
102
+ smarts_pattern.init(smarts)
103
+ smarts_pattern.match(obmol)
104
+ end
105
+
106
+ # Match an array of smarts strings, returns array with matching smarts
107
+ # @example
108
+ # compound = OpenTox::Compound.from_name("Benzene")
109
+ # compound.match(['cc','cN']) # returns ['cc']
110
+ # @param [Array] smarts_array Array with Smarts strings
111
+ # @return [Array] Array with matching Smarts strings
112
+ def match(smarts_array)
113
+ # avoid recreation of OpenBabel objects
114
+ obconversion = OpenBabel::OBConversion.new
115
+ obmol = OpenBabel::OBMol.new
116
+ obconversion.set_in_format('inchi')
117
+ obconversion.read_string(obmol,@inchi)
118
+ smarts_pattern = OpenBabel::OBSmartsPattern.new
119
+ smarts_array.collect do |smarts|
120
+ smarts_pattern.init(smarts)
121
+ smarts if smarts_pattern.match(obmol)
122
+ end.compact
123
+ #smarts_array.collect { |s| s if match?(s)}.compact
124
+ end
125
+
126
+ # Get URI of compound image with highlighted fragments
127
+ #
128
+ # @param [Array] activating Array with activating Smarts strings
129
+ # @param [Array] deactivating Array with deactivating Smarts strings
130
+ # @return [String] URI for compound image with highlighted fragments
131
+ def matching_smarts_image_uri(activating, deactivating)
132
+ activating_smarts = URI.encode "\"#{activating.join("\"/\"")}\""
133
+ deactivating_smarts = URI.encode "\"#{deactivating.join("\"/\"")}\""
134
+ File.join @uri, "smarts/activating", URI.encode(activating_smarts),"deactivating", URI.encode(deactivating_smarts)
135
+ end
136
+
137
+
138
+ private
139
+
140
+ # Convert sdf to inchi
141
+ def self.sdf2inchi(sdf)
142
+ Compound.obconversion(sdf,'sdf','inchi')
143
+ end
144
+
145
+ # Convert smiles to inchi
146
+ def self.smiles2inchi(smiles)
147
+ Compound.obconversion(smiles,'smi','inchi')
148
+ end
149
+
150
+ # Convert smiles to canonical smiles
151
+ def self.smiles2cansmi(smiles)
152
+ Compound.obconversion(smiles,'smi','can')
153
+ end
154
+
155
+ # Convert identifier from OpenBabel input_format to OpenBabel output_format
156
+ def self.obconversion(identifier,input_format,output_format)
157
+ obconversion = OpenBabel::OBConversion.new
158
+ obmol = OpenBabel::OBMol.new
159
+ obconversion.set_in_and_out_formats input_format, output_format
160
+ obconversion.read_string obmol, identifier
161
+ case output_format
162
+ when /smi|can|inchi/
163
+ obconversion.write_string(obmol).gsub(/\s/,'').chomp
164
+ else
165
+ obconversion.write_string(obmol)
166
+ end
167
+ end
168
+ =end
169
+ end
170
+ end