1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
#TODO: switch services to 1.2
RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
class String
def underscore
self.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end
module URI
def self.task? uri
uri =~ /task/ and URI.valid? uri
end
def self.dataset? uri, subjectid=nil
uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
end
def self.model? uri, subjectid=nil
uri =~ /model/ and URI.accessible? uri, subjectid=nil
end
def self.accessible? uri, subjectid=nil
Net::HTTP.get_response(URI.parse(uri))
true
rescue
false
end
def self.valid? uri
u = URI::parse(uri)
u.scheme!=nil and u.host!=nil
rescue URI::InvalidURIError
false
end
end
# defaults to stderr, may be changed to file output
$logger = OTLogger.new(STDERR) # no rotation
$logger.level = Logger::DEBUG
module OpenTox
attr_accessor :subjectid, :uri, :response
attr_writer :metadata
def initialize uri=nil, subjectid=nil
@uri = uri.chomp
@subjectid = subjectid
end
# Ruby interface
# override to read all error codes
def metadata reload=true
if reload
@metadata = {}
# ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
RestClient.get(@uri) do |response, request, result, &block|
$logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202 or URI.task? @uri
RDF::Reader.for(:rdfxml).new(response) do |reader|
reader.each_statement do |statement|
@metadata[statement.predicate] = statement.object if statement.subject == @uri
end
end
end
end
@metadata
end
def save
rdf = RDF::Writer.for(:rdfxml).buffer do |writer|
@metadata.each { |p,o| writer << RDF::Statement.new(RDF::URI.new(@uri), p, o) }
end
post rdf, { :content_type => 'application/rdf+xml'}
end
# REST API
def get params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
@response = RestClient.get @uri, params
end
def post payload={}, params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
@response = RestClient.post(@uri.to_s, payload, params)
begin
@response.to_s.to_object
rescue
@response
end
end
def put payload={}, params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
@response = RestClient.put(@uri.to_s, payload, params)
end
def delete params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
@response = RestClient.delete(@uri.to_s,:subjectid => @subjectid)
end
# class methods
module ClassMethods
def create service_uri, subjectid=nil
uri = RestClient.post(service_uri, {}, :subjectid => subjectid).chomp
subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
end
def from_file service_uri, file, subjectid=nil
RestClient.post(service_uri, :file => File.new(file), :subjectid => subjectid).chomp.to_object
end
def all service_uri, subjectid=nil
uris = RestClient.get(service_uri, {:accept => 'text/uri-list'}).split("\n").compact
uris.collect{|uri| subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")}
end
end
# create default classes
SERVICES.each do |s|
eval "class #{s}
include OpenTox
extend OpenTox::ClassMethods
end"
end
end
|