opentox-ruby-api-wrapper 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +674 -0
- data/README.rdoc +23 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/lib/algorithm.rb +37 -0
- data/lib/compound.rb +67 -0
- data/lib/dataset.rb +94 -0
- data/lib/environment.rb +33 -0
- data/lib/feature.rb +48 -0
- data/lib/helper.rb +26 -0
- data/lib/model.rb +71 -0
- data/lib/opentox-ruby-api-wrapper.rb +13 -0
- data/lib/opentox.rb +27 -0
- data/lib/spork.rb +81 -0
- data/lib/task.rb +55 -0
- data/lib/tasks/opentox.rb +135 -0
- data/lib/tasks/redis.rb +125 -0
- data/lib/templates/config.ru +23 -0
- data/lib/templates/config.yaml +10 -0
- data/lib/utils.rb +9 -0
- metadata +84 -0
data/README.rdoc
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
= opentox-ruby-api-wrapper
|
2
|
+
|
3
|
+
Ruby wrapper for the OpenTox REST API (http://www.opentox.org)
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Run the following if you haven't already:
|
8
|
+
|
9
|
+
gem sources -a http://gems.github.com
|
10
|
+
|
11
|
+
Install the gem:
|
12
|
+
|
13
|
+
sudo gem install helma-opentox-ruby-api-wrapper
|
14
|
+
|
15
|
+
== Usage
|
16
|
+
|
17
|
+
- set the environment variables OPENTOX_COMPOUNDS, OPENTOX_FEATURES, OPENTOX_DATASETS, OPENTOX_FMINER to the base URI of the OpenTox REST webservices
|
18
|
+
- require 'opentox-ruby-api-wrapper' in your ruby application
|
19
|
+
- consult the rdoc API documentation for details
|
20
|
+
|
21
|
+
== Copyright
|
22
|
+
|
23
|
+
Copyright (c) 2009 Christoph Helma. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "opentox-ruby-api-wrapper"
|
8
|
+
gem.summary = %Q{Ruby wrapper for the OpenTox REST API}
|
9
|
+
gem.description = %Q{Ruby wrapper for the OpenTox REST API (http://www.opentox.org)}
|
10
|
+
gem.email = "helma@in-silico.ch"
|
11
|
+
gem.homepage = "http://github.com/helma/opentox-ruby-api-wrapper"
|
12
|
+
gem.authors = ["Christoph Helma"]
|
13
|
+
gem.add_dependency "technoweenie-rest-client"
|
14
|
+
gem.add_dependency "sinatra"
|
15
|
+
gem.add_dependency "rack"
|
16
|
+
gem.add_dependency "rack-contrib"
|
17
|
+
gem.add_dependency "thin"
|
18
|
+
gem.add_dependency "cucumber"
|
19
|
+
gem.add_dependency "ezmobius-redis-rb"
|
20
|
+
gem.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*", 'lib/jeweler/templates/.gitignore']
|
21
|
+
gem.files.include %w(lib/tasks/opentox.rb, lib/tasks/redis.rb, lib/environment.rb, lib/algorithm.rb, lib/compound.rb, lib/dataset.rb, lib/feature.rb, lib/model.rb, lib/utils.rb, lib/templates/*)
|
22
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
23
|
+
end
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/*_test.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
begin
|
36
|
+
require 'rcov/rcovtask'
|
37
|
+
Rcov::RcovTask.new do |test|
|
38
|
+
test.libs << 'test'
|
39
|
+
test.pattern = 'test/**/*_test.rb'
|
40
|
+
test.verbose = true
|
41
|
+
end
|
42
|
+
rescue LoadError
|
43
|
+
task :rcov do
|
44
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
task :test => :check_dependencies
|
49
|
+
|
50
|
+
task :default => :test
|
51
|
+
|
52
|
+
require 'rake/rdoctask'
|
53
|
+
Rake::RDocTask.new do |rdoc|
|
54
|
+
if File.exist?('VERSION')
|
55
|
+
version = File.read('VERSION')
|
56
|
+
else
|
57
|
+
version = ""
|
58
|
+
end
|
59
|
+
|
60
|
+
rdoc.rdoc_dir = 'rdoc'
|
61
|
+
rdoc.title = "opentox-ruby-api-wrapper #{version}"
|
62
|
+
rdoc.rdoc_files.include('README*')
|
63
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
64
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.1.0
|
data/lib/algorithm.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module OpenTox
|
2
|
+
module Algorithm
|
3
|
+
|
4
|
+
class Fminer < OpenTox
|
5
|
+
# Create a new dataset with BBRC features
|
6
|
+
def self.create(params)
|
7
|
+
puts params[:dataset_uri]
|
8
|
+
uri = RestClient.post File.join(@@config[:services]["opentox-algorithm"],'fminer'), :dataset_uri => params[:dataset_uri]
|
9
|
+
print "fminer finsihed "
|
10
|
+
puts uri
|
11
|
+
uri
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Similarity < OpenTox
|
16
|
+
|
17
|
+
def self.tanimoto(dataset1,compound1,dataset2,compound2)
|
18
|
+
RestClient.get File.join(@@config[:services]["opentox-algorithm"], 'tanimoto/dataset',dataset1.name,compound1.inchi,'dataset',dataset2.name,compound2.inchi)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.weighted_tanimoto(dataset1,compound1,dataset2,compound2)
|
22
|
+
# URI.escape does not work here
|
23
|
+
uri = File.join(@@config[:services]["opentox-algorithm"], 'weighted_tanimoto/dataset',CGI.escape(dataset1.name),'compound',CGI.escape(compound1.inchi),'dataset',CGI.escape(dataset2.name),'compound',CGI.escape(compound2.inchi))
|
24
|
+
RestClient.get uri
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class Lazar < OpenTox
|
30
|
+
# Create a new prediction model from a dataset
|
31
|
+
def self.create(params)
|
32
|
+
RestClient.post File.join(@@config[:services]["opentox-algorithm"],"lazar_classification"), params
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/compound.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module OpenTox
|
2
|
+
|
3
|
+
# uri: /compound/:inchi
|
4
|
+
class Compound < OpenTox
|
5
|
+
|
6
|
+
attr_reader :inchi
|
7
|
+
|
8
|
+
# Initialize with <tt>:uri => uri</tt>, <tt>:smiles => smiles</tt> or <tt>:name => name</tt> (name can be also an InChI/InChiKey, CAS number, etc)
|
9
|
+
def initialize(params)
|
10
|
+
@@cactus_uri="http://cactus.nci.nih.gov/chemical/structure/"
|
11
|
+
if params[:smiles]
|
12
|
+
@inchi = smiles2inchi(params[:smiles])
|
13
|
+
@uri = File.join(@@config[:services]["opentox-compound"],URI.escape(@inchi))
|
14
|
+
elsif params[:inchi]
|
15
|
+
@inchi = params[:inchi]
|
16
|
+
@uri = File.join(@@config[:services]["opentox-compound"],URI.escape(@inchi))
|
17
|
+
elsif params[:name]
|
18
|
+
@inchi = RestClient.get "#{@@cactus_uri}#{params[:name]}/stdinchi"
|
19
|
+
@uri = File.join(@@config[:services]["opentox-compound"],URI.escape(@inchi))
|
20
|
+
elsif params[:uri]
|
21
|
+
@inchi = params[:uri].sub(/^.*InChI/, 'InChI')
|
22
|
+
@uri = params[:uri]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get the (canonical) smiles
|
27
|
+
def smiles
|
28
|
+
obconversion(@inchi,'inchi','can')
|
29
|
+
end
|
30
|
+
|
31
|
+
def sdf
|
32
|
+
obconversion(@inchi,'inchi','sdf')
|
33
|
+
end
|
34
|
+
|
35
|
+
# Matchs a smarts string
|
36
|
+
def match?(smarts)
|
37
|
+
obconversion = OpenBabel::OBConversion.new
|
38
|
+
obmol = OpenBabel::OBMol.new
|
39
|
+
obconversion.set_in_format('inchi')
|
40
|
+
obconversion.read_string(obmol,@inchi)
|
41
|
+
smarts_pattern = OpenBabel::OBSmartsPattern.new
|
42
|
+
smarts_pattern.init(smarts)
|
43
|
+
smarts_pattern.match(obmol)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Match an array of smarts features, returns matching features
|
47
|
+
def match(smarts_dataset)
|
48
|
+
smarts_dataset.all_features.collect{ |uri| uri if self.match?(Feature.new(:uri => uri).name) }.compact
|
49
|
+
end
|
50
|
+
|
51
|
+
def smiles2inchi(smiles)
|
52
|
+
obconversion(smiles,'smi','inchi')
|
53
|
+
end
|
54
|
+
|
55
|
+
def smiles2cansmi(smiles)
|
56
|
+
obconversion(smiles,'smi','can')
|
57
|
+
end
|
58
|
+
|
59
|
+
def obconversion(identifier,input_format,output_format)
|
60
|
+
obconversion = OpenBabel::OBConversion.new
|
61
|
+
obmol = OpenBabel::OBMol.new
|
62
|
+
obconversion.set_in_and_out_formats input_format, output_format
|
63
|
+
obconversion.read_string obmol, identifier
|
64
|
+
obconversion.write_string(obmol).gsub(/\s/,'').chomp
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/dataset.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module OpenTox
|
2
|
+
|
3
|
+
# key: /datasets
|
4
|
+
# set: dataset uris
|
5
|
+
# key: /dataset/:dataset/compounds
|
6
|
+
# set: compound uris
|
7
|
+
# key: /dataset/:dataset/compound/:inchi
|
8
|
+
# set: feature uris
|
9
|
+
class Dataset < OpenTox
|
10
|
+
|
11
|
+
# Initialize with <tt>:uri => uri</tt> or <tt>:name => name</tt> (creates a new dataset)
|
12
|
+
def initialize(uri)
|
13
|
+
super(uri)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.create(params)
|
17
|
+
uri = RestClient.post @@config[:services]["opentox-dataset"], :name => params[:name]
|
18
|
+
Dataset.new(uri.to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find(params)
|
22
|
+
begin
|
23
|
+
if params[:name]
|
24
|
+
uri = File.join(@@config[:services]["opentox-dataset"], URI.encode(params[:name]))
|
25
|
+
elsif params[:uri]
|
26
|
+
uri = params[:uri]
|
27
|
+
end
|
28
|
+
RestClient.get uri # check if the resource is available
|
29
|
+
Dataset.new(uri) if uri
|
30
|
+
rescue
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.find_or_create(params)
|
36
|
+
self.create(params) unless self.find(params)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.base_uri
|
40
|
+
@@config[:services]["opentox-dataset"]
|
41
|
+
end
|
42
|
+
|
43
|
+
def import(params)
|
44
|
+
if params[:csv]
|
45
|
+
# RestClient seems not to work for file uploads
|
46
|
+
#RestClient.post @uri + '/import', :compound_format => params[:compound_format], :content_type => "text/csv", :file => File.new(params[:csv])
|
47
|
+
`curl -X POST -F "file=@#{params[:csv]};type=text/csv" -F compound_format=#{params[:compound_format]} #{@uri + '/import'}`
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def add(features)
|
52
|
+
RestClient.put @uri, :features => features
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get all compounds from a dataset
|
56
|
+
def compound_uris
|
57
|
+
RestClient.get(File.join(@uri, 'compounds')).split("\n")
|
58
|
+
end
|
59
|
+
|
60
|
+
def compounds
|
61
|
+
compound_uris.collect{|uri| Compound.new(:uri => uri)}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get all features for a compound
|
65
|
+
def feature_uris(compound)
|
66
|
+
uri = File.join(@uri, 'compound', CGI.escape(compound.inchi)) # URI.encode does not work here
|
67
|
+
RestClient.get(uri).split("\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
# Get all features for a compound
|
71
|
+
def features(compound)
|
72
|
+
feature_uris(compound).collect{|uri| Feature.new(:uri => uri)}
|
73
|
+
end
|
74
|
+
|
75
|
+
def all_features
|
76
|
+
RestClient.get(File.join(@uri, 'features')).split("\n")
|
77
|
+
end
|
78
|
+
|
79
|
+
# Delete a dataset
|
80
|
+
def delete
|
81
|
+
RestClient.delete @uri
|
82
|
+
end
|
83
|
+
|
84
|
+
def tanimoto(dataset)
|
85
|
+
RestClient.get(File.join(@uri,'tanimoto',dataset.path))
|
86
|
+
end
|
87
|
+
|
88
|
+
def weighted_tanimoto(dataset)
|
89
|
+
RestClient.get(File.join(@uri,'weighted_tanimoto',dataset.path))
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
data/lib/environment.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# set default environment
|
2
|
+
ENV['RACK_ENV'] = 'test' unless ENV['RACK_ENV']
|
3
|
+
|
4
|
+
# load configuration
|
5
|
+
basedir = File.join(ENV['HOME'], ".opentox")
|
6
|
+
config_dir = File.join(basedir, "config")
|
7
|
+
@@tmp_dir = File.join(basedir, "tmp")
|
8
|
+
config_file = File.join(config_dir, "#{ENV['RACK_ENV']}.yaml")
|
9
|
+
|
10
|
+
if File.exist?(config_file)
|
11
|
+
@@config = YAML.load_file(config_file)
|
12
|
+
else
|
13
|
+
FileUtils.mkdir_p config_dir
|
14
|
+
FileUtils.mkdir_p @@tmp_dir
|
15
|
+
FileUtils.cp(File.join(File.dirname(__FILE__), 'templates/config.yaml'), config_file)
|
16
|
+
puts "Please edit #{config_file} and restart your application."
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
|
20
|
+
# configure redis database
|
21
|
+
begin
|
22
|
+
case ENV['RACK_ENV']
|
23
|
+
when 'production'
|
24
|
+
@@redis = Redis.new :db => 0
|
25
|
+
when 'development'
|
26
|
+
@@redis = Redis.new :db => 1
|
27
|
+
when 'test'
|
28
|
+
@@redis = Redis.new :db => 2
|
29
|
+
@@redis.flush_db
|
30
|
+
end
|
31
|
+
rescue
|
32
|
+
puts "Redis database not running, please start it with 'rake redis:start'."
|
33
|
+
end
|
data/lib/feature.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module OpenTox
|
2
|
+
|
3
|
+
# uri: /feature/:name/:property_name/:property_value/...
|
4
|
+
class Feature < OpenTox
|
5
|
+
|
6
|
+
attr_accessor :name, :values
|
7
|
+
|
8
|
+
def initialize(params)
|
9
|
+
if params[:uri]
|
10
|
+
@uri = params[:uri]
|
11
|
+
items = URI.split(@uri)[5].split(/\//)
|
12
|
+
@name = items[1]
|
13
|
+
@values = {}
|
14
|
+
i = 2
|
15
|
+
while i < items.size
|
16
|
+
@values[items[i]] = items[i+1]
|
17
|
+
i += 2
|
18
|
+
end
|
19
|
+
else
|
20
|
+
@name = params[:name]
|
21
|
+
@values = {}
|
22
|
+
params.each do |k,v|
|
23
|
+
@values[k] = v unless k.to_s == 'name'
|
24
|
+
end
|
25
|
+
@uri = File.join(@@config[:services]["opentox-feature"],path)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def values_path
|
30
|
+
path = ''
|
31
|
+
@values.each do |k,v|
|
32
|
+
path = File.join path, URI.encode(k.to_s), URI.encode(v.to_s)
|
33
|
+
end
|
34
|
+
path
|
35
|
+
end
|
36
|
+
|
37
|
+
def path
|
38
|
+
File.join(URI.encode(@name),values_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def value(property)
|
42
|
+
items = @uri.split(/\//)
|
43
|
+
i = items.index(property)
|
44
|
+
items[i+1]
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
helpers do
|
2
|
+
|
3
|
+
# Authentification
|
4
|
+
def protected!
|
5
|
+
response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth") and \
|
6
|
+
throw(:halt, [401, "Not authorized\n"]) and \
|
7
|
+
return unless authorized?
|
8
|
+
end
|
9
|
+
|
10
|
+
def authorized?
|
11
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
12
|
+
@auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['api', API_KEY]
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
=begin
|
17
|
+
def xml(object)
|
18
|
+
builder do |xml|
|
19
|
+
xml.instruct!
|
20
|
+
object.to_xml
|
21
|
+
end
|
22
|
+
end
|
23
|
+
=end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
data/lib/model.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module OpenTox
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
class LazarClassification < OpenTox
|
6
|
+
|
7
|
+
# Create a new prediction model from a dataset
|
8
|
+
def initialize(uri)
|
9
|
+
super(uri)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.create(params)
|
13
|
+
uri = RestClient.post File.join(@@config[:services]["opentox-model"], 'lazar_classification'), params
|
14
|
+
puts "URI: " + uri
|
15
|
+
LazarClassification.new(uri.to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find(name)
|
19
|
+
uri = RestClient.get File.join(@@config[:services]["opentox-model"], 'lazar_classification', URI.encode(params[:name]))
|
20
|
+
LazarClassification.new(uri)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.find_all
|
24
|
+
RestClient.get File.join(@@config[:services]["opentox-model"], 'lazar_classification')#.split("\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Predict a compound
|
28
|
+
def predict(compound)
|
29
|
+
LazarPrediction.new(:uri => RestClient.post(@uri, :compound_uri => compound.uri))
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.base_uri
|
33
|
+
@@config[:services]["opentox-model"]
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
module Prediction
|
41
|
+
|
42
|
+
module Classification
|
43
|
+
|
44
|
+
class Lazar < OpenTox
|
45
|
+
|
46
|
+
def initialize(params)
|
47
|
+
super(params[:uri])
|
48
|
+
end
|
49
|
+
|
50
|
+
def classification
|
51
|
+
YAML.load(RestClient.get @uri)[:classification]
|
52
|
+
end
|
53
|
+
|
54
|
+
def confidence
|
55
|
+
YAML.load(RestClient.get @uri)[:confidence]
|
56
|
+
end
|
57
|
+
|
58
|
+
def neighbors
|
59
|
+
RestClient.get @uri + '/neighbors'
|
60
|
+
end
|
61
|
+
|
62
|
+
def features
|
63
|
+
RestClient.get @uri + '/features'
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|