oba_client 2.0.3
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.
- data/.gitignore +6 -0
- data/History.md +54 -0
- data/Manifest.txt +6 -0
- data/README.md +103 -0
- data/Rakefile +74 -0
- data/Rakefile-2 +0 -0
- data/lib/oba_client.rb +282 -0
- data/test/test_oba_client.rb +91 -0
- metadata +101 -0
data/History.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
## 2.0.3 / 2010-07-17
|
2
|
+
Quick fix in docs.
|
3
|
+
|
4
|
+
## 2.0.2 / 2010-07-08
|
5
|
+
Parse version and nbAnnotation for ontologies.
|
6
|
+
|
7
|
+
## 2.0.1 / 2010-07-08
|
8
|
+
|
9
|
+
Rubyforge doesn't allow "_", so we have "oba-client", not "oba_client".
|
10
|
+
|
11
|
+
# 2.0.0 / 2010-07-08
|
12
|
+
|
13
|
+
* Parse XML entirely. See README for more information on the return value.
|
14
|
+
|
15
|
+
## 1.2.1 / 2010-07-08
|
16
|
+
|
17
|
+
* Link correctly (problem with using markdown-ed URL in README.md).
|
18
|
+
|
19
|
+
## 1.2.0 / 2010-07-08
|
20
|
+
|
21
|
+
* Parse statistics.
|
22
|
+
|
23
|
+
## 1.1.1 / 2010-07-08
|
24
|
+
|
25
|
+
* Rake or Hoe bug workaround.
|
26
|
+
|
27
|
+
## 1.1.0 / 2010-07-08
|
28
|
+
|
29
|
+
* Fully parse MGREP mappings.
|
30
|
+
|
31
|
+
## 1.0.5 / 2010-07-08
|
32
|
+
|
33
|
+
* Modify docs slightly.
|
34
|
+
|
35
|
+
## 1.0.4 / 2010-07-08
|
36
|
+
|
37
|
+
* Add all possible parameter values for the Annotator.
|
38
|
+
|
39
|
+
## 1.0.3 / 2010-07-07
|
40
|
+
|
41
|
+
* Add more tests.
|
42
|
+
|
43
|
+
## 1.0.2 / 2010-07-07
|
44
|
+
|
45
|
+
* Oops, no release notes.
|
46
|
+
|
47
|
+
## 1.0.1 / 2010-07-07
|
48
|
+
|
49
|
+
* Oops, fix a symbol bug.
|
50
|
+
|
51
|
+
# 1.0.0 / 2010-07-07
|
52
|
+
|
53
|
+
* Initial release.
|
54
|
+
* Does not yet parse statistics.
|
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# oba-client
|
2
|
+
|
3
|
+
* [RubyForge project](http://rubyforge.org/projects/oba-client "RubyForge project")
|
4
|
+
|
5
|
+
## DESCRIPTION:
|
6
|
+
|
7
|
+
A client for accessing the NCBO's Open Biomedical Annotator service.
|
8
|
+
See [the Annotator documentation](http://www.bioontology.org/wiki/index.php/Annotator_User_Guide "Documentation") for much more information.
|
9
|
+
|
10
|
+
## FEATURES:
|
11
|
+
|
12
|
+
* Many
|
13
|
+
|
14
|
+
## REQUIREMENTS:
|
15
|
+
|
16
|
+
* None
|
17
|
+
|
18
|
+
## INSTALL:
|
19
|
+
|
20
|
+
sudo gem install oba-client
|
21
|
+
gem install --user-install oba-client
|
22
|
+
|
23
|
+
## USAGE:
|
24
|
+
|
25
|
+
require "rubygems"
|
26
|
+
require "oba-client"
|
27
|
+
|
28
|
+
client = OBAClient.new
|
29
|
+
# As XML.
|
30
|
+
result = client.execute("some text string")
|
31
|
+
|
32
|
+
client2 = OBAClient.new({:parse_xml => true})
|
33
|
+
# Returns {:statistics => {information about the annotation},
|
34
|
+
# :annotations => [Array of annotations of text],
|
35
|
+
# :ontologies => [Array of ontologies used]}
|
36
|
+
# Like:
|
37
|
+
:statistics => {"MAPPING" => 1951, "MGREP" => 2319, "ISA_CLOSURE" => 30}
|
38
|
+
:annotations => [{
|
39
|
+
:score => 199,
|
40
|
+
:id => 203820,
|
41
|
+
:localConceptId => "42877/CARO:0000013",
|
42
|
+
:localOntologyId => 42877,
|
43
|
+
:isTopLevel => true,
|
44
|
+
:fullId => "http://purl.obolibrary.org/obo/FBbt_00007002",
|
45
|
+
:preferredName => "cell",
|
46
|
+
:synonyms => ["body cell"],
|
47
|
+
:definitions => ["a cell", "some other definition"],
|
48
|
+
|
49
|
+
:semanticTypes => [
|
50
|
+
{:id => 230820, :semanticType => "T043", :description => "desc"},
|
51
|
+
"etc..."
|
52
|
+
]
|
53
|
+
|
54
|
+
:context => {
|
55
|
+
:contextName => "MAPPING",
|
56
|
+
:isDirect => false,
|
57
|
+
:from => 10,
|
58
|
+
:to => 20,
|
59
|
+
:mappedConcept => {
|
60
|
+
"has" => "the same information as other annotations, minus score"
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
:mappingType => "Automatic"
|
65
|
+
}, "more annotations..."]
|
66
|
+
|
67
|
+
:ontologies => [{
|
68
|
+
:localOntologyId => 40404,
|
69
|
+
:name => "Ontology Name",
|
70
|
+
:virtualOntologyId => 1042,
|
71
|
+
:version => 1.1,
|
72
|
+
:nbAnnotation => 40
|
73
|
+
|
74
|
+
}, "more ontologies..."]
|
75
|
+
|
76
|
+
client2.execute("another text string, maybe longer this time.")
|
77
|
+
client2.execute("this is the second query for this client!")
|
78
|
+
|
79
|
+
# Or, parse some file you've already got lying about (pass as a string).
|
80
|
+
parsed = OBAClient::parse("<?xml version='1.0'>...</xml>")
|
81
|
+
|
82
|
+
## LICENSE:
|
83
|
+
|
84
|
+
Copyright (c) 2010 Rob Tirrell
|
85
|
+
|
86
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
87
|
+
of this software and associated documentation files (the "Software"), to deal
|
88
|
+
in the Software without restriction, including without limitation the rights
|
89
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
90
|
+
copies of the Software, and to permit persons to whom the Software is
|
91
|
+
furnished to do so, subject to the following conditions:
|
92
|
+
|
93
|
+
The above copyright notice and this permission notice shall be included in
|
94
|
+
all copies or substantial portions of the Software.
|
95
|
+
|
96
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
97
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
98
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
99
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
100
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
101
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
102
|
+
THE SOFTWARE.
|
103
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require File.dirname(__FILE__) + "/lib/oba_client.rb"
|
3
|
+
#require "hoe"
|
4
|
+
|
5
|
+
#Hoe.plugin :yard
|
6
|
+
|
7
|
+
#Hoe.spec "oba-client" do
|
8
|
+
# self.developer "Rob Tirrell", "rpt@stanford.edu"
|
9
|
+
# self.url = "http://rubyforge.org/projects/oba-client"
|
10
|
+
#
|
11
|
+
# self.yard_title = "OBAClient Documentation"
|
12
|
+
# self.yard_options = ["--default-return", "void"]
|
13
|
+
# self.yard_markup = "markdown"
|
14
|
+
# self.remote_yard_dir = ""
|
15
|
+
#
|
16
|
+
# self.rubyforge_name = "oba-client"
|
17
|
+
#end
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'rake'
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'jeweler'
|
24
|
+
Jeweler::Tasks.new do |gem|
|
25
|
+
gem.name = "oba_client"
|
26
|
+
gem.summary = "A client for the Open Biomedical Annotator."
|
27
|
+
gem.description = "See above."
|
28
|
+
gem.email = "rpt@stanford.edu"
|
29
|
+
gem.homepage = "http://github.com/rtirrell/oba_client"
|
30
|
+
gem.authors = ["Rob Tirrell"]
|
31
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
32
|
+
gem.add_development_dependency "yard", ">= 0"
|
33
|
+
gem.version = OBAClient::VERSION
|
34
|
+
|
35
|
+
|
36
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
37
|
+
end
|
38
|
+
Jeweler::GemcutterTasks.new
|
39
|
+
rescue LoadError
|
40
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
41
|
+
end
|
42
|
+
|
43
|
+
require 'rake/testtask'
|
44
|
+
Rake::TestTask.new(:test) do |test|
|
45
|
+
test.libs << 'lib' << 'test'
|
46
|
+
test.pattern = 'test/**/test_*.rb'
|
47
|
+
test.verbose = true
|
48
|
+
end
|
49
|
+
|
50
|
+
begin
|
51
|
+
require 'rcov/rcovtask'
|
52
|
+
Rcov::RcovTask.new do |test|
|
53
|
+
test.libs << 'test'
|
54
|
+
test.pattern = 'test/**/test_*.rb'
|
55
|
+
test.verbose = true
|
56
|
+
end
|
57
|
+
rescue LoadError
|
58
|
+
task :rcov do
|
59
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
task :test => :check_dependencies
|
64
|
+
|
65
|
+
task :default => :test
|
66
|
+
|
67
|
+
begin
|
68
|
+
require 'yard'
|
69
|
+
YARD::Rake::YardocTask.new
|
70
|
+
rescue LoadError
|
71
|
+
task :yardoc do
|
72
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
73
|
+
end
|
74
|
+
end
|
data/Rakefile-2
ADDED
File without changes
|
data/lib/oba_client.rb
ADDED
@@ -0,0 +1,282 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "nokogiri"
|
3
|
+
require "cgi"
|
4
|
+
require "net/http"
|
5
|
+
require "uri"
|
6
|
+
|
7
|
+
##
|
8
|
+
# A class for interacting with the Open Biomedical Annotator. There are two
|
9
|
+
# things we do: get text, and parse it. We can do both independently or
|
10
|
+
# serially.
|
11
|
+
class OBAClient
|
12
|
+
VERSION = "2.0.3"
|
13
|
+
|
14
|
+
##
|
15
|
+
# A high HTTP read timeout, as the service sometimes takes awhile to respond.
|
16
|
+
DEFAULT_TIMEOUT = 30
|
17
|
+
|
18
|
+
##
|
19
|
+
# The endpoint URI for the production version of the Annotator service.
|
20
|
+
DEFAULT_URI = "http://rest.bioontology.org/obs/annotator"
|
21
|
+
|
22
|
+
##
|
23
|
+
# The header for every request. There's no need to specify this per-instance.
|
24
|
+
HEADER = {"Content-Type" => "application/x-www-form-urlencoded"}
|
25
|
+
|
26
|
+
##
|
27
|
+
# Parameters the annotator accepts. Any one not in this list (excluding
|
28
|
+
# textToAnnotate) is not valid.
|
29
|
+
ANNOTATOR_PARAMETERS = [
|
30
|
+
:email,
|
31
|
+
:filterNumber,
|
32
|
+
:format,
|
33
|
+
:isStopWordsCaseSensitive,
|
34
|
+
:isVirtualOntologyID,
|
35
|
+
:levelMax,
|
36
|
+
:longestOnly,
|
37
|
+
:ontologiesToExpand,
|
38
|
+
:ontologiesToKeepInResult,
|
39
|
+
:mappingTypes,
|
40
|
+
:minTermSize,
|
41
|
+
:scored,
|
42
|
+
:semanticTypes,
|
43
|
+
:stopWords,
|
44
|
+
:wholeWordOnly,
|
45
|
+
:withDefaultStopWords,
|
46
|
+
:withSynonyms,
|
47
|
+
]
|
48
|
+
|
49
|
+
##
|
50
|
+
# Instantiate the class with a set of reused options. Options used by the
|
51
|
+
# method are:
|
52
|
+
#
|
53
|
+
# * {String} **uri**: the URI of the annotator service (default:
|
54
|
+
# {DEFAULT_URI}).
|
55
|
+
# * {Fixnum} **timeout**: the length of the read timeout (default:
|
56
|
+
# {DEFAULT_TIMEOUT}).
|
57
|
+
# * {Boolean} **parse_xml**: whether to parse the received text (default:
|
58
|
+
# false).
|
59
|
+
# * {Array}<{String}> **ontologies**: a pseudo-parameter which sets both
|
60
|
+
# ontologiesToExpand and ontologiesToKeepInResult.
|
61
|
+
# @param [Hash<String, String>] options Parameters for the annotation.
|
62
|
+
def initialize(options = {})
|
63
|
+
@uri = URI.parse(options.delete(:uri) || DEFAULT_URI)
|
64
|
+
@timeout = options.delete(:timeout) || DEFAULT_TIMEOUT
|
65
|
+
@parse_xml = options.delete(:parse_xml)
|
66
|
+
|
67
|
+
if ontologies = options.delete(:ontologies)
|
68
|
+
[:ontologiesToExpand, :ontologiesToKeepInResult].each do |k|
|
69
|
+
if options.include?(k)
|
70
|
+
puts "WARNING: specified both :ontologies and #{k}, ignoring #{k}."
|
71
|
+
end
|
72
|
+
options[k] = ontologies
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@options = {}
|
77
|
+
options.each do |k, v|
|
78
|
+
if !ANNOTATOR_PARAMETERS.include?(k)
|
79
|
+
puts "WARNING: #{k} is not a valid annotator parameter."
|
80
|
+
end
|
81
|
+
if v.is_a? Array
|
82
|
+
@options[k] = v.join(",")
|
83
|
+
else
|
84
|
+
@options[k] = v
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if !@options.include?(:email)
|
89
|
+
puts "TIP: as a courtesy, consider including your email in the " +
|
90
|
+
"request (:email => 'a@b.com')"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Perform the annotation.
|
96
|
+
# @param [String] text The text to annotate.
|
97
|
+
# @return [Hash<Symbol, Array>, String, nil] A Hash representing the parsed
|
98
|
+
# document, the raw XML if parsing is not requested, or nil if the
|
99
|
+
# request times out.
|
100
|
+
def execute(text)
|
101
|
+
request = Net::HTTP::Post.new(@uri.path, initheader=HEADER)
|
102
|
+
request.body = {:textToAnnotate => text}.merge(@options).map do |k, v|
|
103
|
+
"#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
104
|
+
end.join("&")
|
105
|
+
puts request.body if $DEBUG
|
106
|
+
|
107
|
+
begin
|
108
|
+
response = Net::HTTP.new(@uri.host, @uri.port).start do |http|
|
109
|
+
http.read_timeout = @timeout
|
110
|
+
http.request(request)
|
111
|
+
end
|
112
|
+
@parse_xml ? self.class.parse(response.body) : response.body
|
113
|
+
rescue Timeout::Error
|
114
|
+
puts "Request for #{text[0..10]}... timed-out at #{@timeout} seconds."
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
STATISTICS_BEANS_XPATH = "/success/data/annotatorResultBean/statistics/statisticsBean"
|
120
|
+
ANNOTATION_BEANS_XPATH = "/success/data/annotatorResultBean/annotations/annotationBean"
|
121
|
+
ONTOLOGY_BEANS_XPATH = "/success/data/annotatorResultBean/ontologies/ontologyUsedBean"
|
122
|
+
|
123
|
+
##
|
124
|
+
# Attributes for mapping concepts (only one type).
|
125
|
+
CONCEPT_ATTRIBUTES = {
|
126
|
+
:id => lambda {|c| c.xpath("id").text.to_i},
|
127
|
+
:localConceptId => lambda {|c| c.xpath("localConceptId").text},
|
128
|
+
:localOntologyId => lambda {|c| c.xpath("localOntologyId").text.to_i},
|
129
|
+
:isTopLevel => lambda {|c| to_b(c.xpath("isTopLevel").text)},
|
130
|
+
:fullId => lambda {|c| c.xpath("fullId").text},
|
131
|
+
:preferredName => lambda {|c| c.xpath("preferredName").text},
|
132
|
+
|
133
|
+
:synonyms => lambda do |c|
|
134
|
+
c.xpath("synonyms/synonym").map do |s|
|
135
|
+
s.xpath("string").text
|
136
|
+
end
|
137
|
+
end,
|
138
|
+
|
139
|
+
:semanticTypes => lambda do |c|
|
140
|
+
c.xpath("semanticTypes/semanticTypeBean").map do |s|
|
141
|
+
{
|
142
|
+
:id => s.xpath("id").text.to_i,
|
143
|
+
:semanticType => s.xpath("semanticType").text,
|
144
|
+
:description => s.xpath("description").text
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
}
|
149
|
+
|
150
|
+
|
151
|
+
##
|
152
|
+
# Attributes for mapping and mgrep contexts (both will add
|
153
|
+
# additional attributes).
|
154
|
+
CONTEXT_ATTRIBUTES = {
|
155
|
+
:contextName => lambda {|c| c.xpath("contextName").text},
|
156
|
+
:isDirect => lambda {|c| to_b(c.xpath("isDirect").text)},
|
157
|
+
:from => lambda {|c| c.xpath("from").text.to_i},
|
158
|
+
:to => lambda {|c| c.xpath("to").text.to_i},
|
159
|
+
}
|
160
|
+
|
161
|
+
##
|
162
|
+
# Attributes for annotation contexts.
|
163
|
+
ANNOTATION_CONTEXT_ATTRIBUTES = {
|
164
|
+
:score => lambda {|c| c.xpath("score").text.to_i},
|
165
|
+
:concept => lambda {|c| parse_concept(c.xpath("concept").first)},
|
166
|
+
:context => lambda {|c| parse_context(c.xpath("context").first)}
|
167
|
+
}
|
168
|
+
|
169
|
+
##
|
170
|
+
# Attributes for mapping contexts.
|
171
|
+
MAPPED_CONTEXT_ATTRIBUTES = CONTEXT_ATTRIBUTES.merge(
|
172
|
+
:mappingType => lambda {|c| c.xpath("mappingType").text},
|
173
|
+
:mappedConcept => lambda {|c| parse_concept(c.xpath("mappedConcept").first)}
|
174
|
+
)
|
175
|
+
|
176
|
+
##
|
177
|
+
# Attributes for mgrep contexts.
|
178
|
+
MGREP_CONTEXT_ATTRIBUTES = CONTEXT_ATTRIBUTES.merge(
|
179
|
+
:name => lambda {|c| c.xpath("term/name").text},
|
180
|
+
:localConceptId => lambda {|c| c.xpath("term/localConceptId").text},
|
181
|
+
:isPreferred => lambda {|c| to_b(c.xpath("term/isPreferred").text)},
|
182
|
+
:dictionaryId => lambda {|c| c.xpath("term/dictionaryId").text}
|
183
|
+
)
|
184
|
+
|
185
|
+
##
|
186
|
+
# Map the bean type to the set of attributes we parse from it.
|
187
|
+
CONTEXT_CLASSES = {
|
188
|
+
"annotationContextBean" => ANNOTATION_CONTEXT_ATTRIBUTES,
|
189
|
+
"mgrepContextBean" => MGREP_CONTEXT_ATTRIBUTES,
|
190
|
+
"mappingContextBean" => MAPPED_CONTEXT_ATTRIBUTES,
|
191
|
+
}
|
192
|
+
|
193
|
+
##
|
194
|
+
# Parse a context: an annotation, or a mapping/mgrep context bean.
|
195
|
+
#
|
196
|
+
# @param [Nokgiri::XML::Node] context The root node of the context.
|
197
|
+
#
|
198
|
+
# @return [Hash<Symbol, Object>] The parsed context.
|
199
|
+
def self.parse_context(context)
|
200
|
+
# Annotations (annotationBeans) do not have a class, so we'll refer to them
|
201
|
+
# as annotationContextBeans. context_class will be one of the types in
|
202
|
+
# {CONTEXT_CLASSES}.
|
203
|
+
context_class = if context.attribute("class").nil?
|
204
|
+
"annotationContextBean"
|
205
|
+
else
|
206
|
+
context.attribute("class").value
|
207
|
+
end
|
208
|
+
|
209
|
+
Hash[CONTEXT_CLASSES[context_class].map do |k, v|
|
210
|
+
[k, v.call(context)]
|
211
|
+
end]
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# Parse a concept: a toplevel annotation concept, or an annotation's
|
216
|
+
# mapping concept.
|
217
|
+
#
|
218
|
+
# @param [Nokogiri::XML::Node] concept The root node of the concept.
|
219
|
+
#
|
220
|
+
# @return [Hash<Symbol, Object>] The parsed concept.
|
221
|
+
def self.parse_concept(concept)
|
222
|
+
Hash[CONCEPT_ATTRIBUTES.map do |k, v|
|
223
|
+
[k, v.call(concept)]
|
224
|
+
end]
|
225
|
+
end
|
226
|
+
|
227
|
+
##
|
228
|
+
# Parse raw XML, returning a Hash with three elements: statistics,
|
229
|
+
# annotations, and ontologies. Respectively, these represent the annotation
|
230
|
+
# statistics (annotations by mapping type, etc., as a Hash), an Array of
|
231
|
+
# each annotation (as a Hash), and an Array of ontologies used (also as
|
232
|
+
# a Hash).
|
233
|
+
#
|
234
|
+
# @param [String] xml The XML we'll be parsing.
|
235
|
+
#
|
236
|
+
# @return [Hash<Symbol, Object>] A Hash representation of the XML, as
|
237
|
+
# described in the README.
|
238
|
+
def self.parse(xml)
|
239
|
+
puts "WARNING: text is empty!" if (xml.gsub(/\n/, "") == "")
|
240
|
+
doc = Nokogiri::XML.parse(xml)
|
241
|
+
|
242
|
+
statistics = Hash[doc.xpath(STATISTICS_BEANS_XPATH).map do |sb|
|
243
|
+
[sb.xpath("mapping").text, sb.xpath("nbAnnotation").text.to_i]
|
244
|
+
end]
|
245
|
+
|
246
|
+
annotations = doc.xpath(ANNOTATION_BEANS_XPATH).map do |annotation|
|
247
|
+
parse_context(annotation)
|
248
|
+
end
|
249
|
+
|
250
|
+
ontologies = doc.xpath(ONTOLOGY_BEANS_XPATH).map do |ontology|
|
251
|
+
{
|
252
|
+
:localOntologyId => ontology.xpath("localOntologyId").text.to_i,
|
253
|
+
:virtualOntologyId => ontology.xpath("virtualOntologyId").text.to_i,
|
254
|
+
:name => ontology.xpath("name").text,
|
255
|
+
:version => ontology.xpath("version").text.to_f,
|
256
|
+
:nbAnnotation => ontology.xpath("nbAnnotation").text.to_i
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
{
|
261
|
+
:statistics => statistics,
|
262
|
+
:annotations => annotations,
|
263
|
+
:ontologies => ontologies
|
264
|
+
}
|
265
|
+
end
|
266
|
+
|
267
|
+
##
|
268
|
+
# A little helper: convert a string true/false or 1/0 value to boolean.
|
269
|
+
# AFAIK, there's no better way to do this.
|
270
|
+
#
|
271
|
+
# @param [String] value The value to convert.
|
272
|
+
#
|
273
|
+
# @return [true, false]
|
274
|
+
def self.to_b(value)
|
275
|
+
case value
|
276
|
+
when "0" then false
|
277
|
+
when "1" then true
|
278
|
+
when "false" then false
|
279
|
+
when "true" then true
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "oba-client"
|
3
|
+
|
4
|
+
TEST_TEXTS = [
|
5
|
+
"Mexico,, Disease Thing \o\r\m\n\t\v\l\rzebrafish !!! cancer of the thorax. large intestine thorax",
|
6
|
+
%Q{LOROE aonuhaso unseu anoeuhs aeuhsaonuh asoneuhason uaosenuh aosenuhaose
|
7
|
+
aoneuhasonuhaoenuh anoeuhasn euhasoneu haosneuhaosenuhaoesunahoeusnaoeuteeano
|
8
|
+
aot tt t t t t t t tae \n!!@)$@(#)%@\#!)@# asoeuaohsenutahoeusaheou
|
9
|
+
}
|
10
|
+
]
|
11
|
+
|
12
|
+
class TestOBAClient < Test::Unit::TestCase
|
13
|
+
def test_reuse_instance
|
14
|
+
ann = OBAClient.new
|
15
|
+
TEST_TEXTS.each do |text|
|
16
|
+
xml = ann.execute(text)
|
17
|
+
assert xml[0..4] == "<?xml"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_reuse_instance_with_email
|
22
|
+
ann = OBAClient.new :email => "r.tirrell@gmail.com"
|
23
|
+
TEST_TEXTS.each do |text|
|
24
|
+
xml = ann.execute(text)
|
25
|
+
assert xml[0..4] == "<?xml"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_annotation_no_parameters
|
30
|
+
TEST_TEXTS.each do |text|
|
31
|
+
ann = OBAClient.new
|
32
|
+
xml = ann.execute(text)
|
33
|
+
assert xml[0..4] == "<?xml"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_annotation_parse
|
38
|
+
TEST_TEXTS.each do |text|
|
39
|
+
ann = OBAClient.new :parse_xml => true
|
40
|
+
parsed = ann.execute(text)
|
41
|
+
assert parsed[:statistics].is_a?(Hash)
|
42
|
+
assert parsed[:annotations].is_a?(Array)
|
43
|
+
assert parsed[:ontologies].is_a?(Array)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_annotation_keep_one_ontology
|
48
|
+
TEST_TEXTS.each do |text|
|
49
|
+
ann = OBAClient.new(
|
50
|
+
:ontologiesToKeepInResult => [42812],
|
51
|
+
:parse_xml => true
|
52
|
+
)
|
53
|
+
parsed = ann.execute(text)
|
54
|
+
assert parsed[:ontologies].all? {|o| o[:localOntologyId] == 42812}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_annotation_invalid_parameters
|
59
|
+
TEST_TEXTS.each do |text|
|
60
|
+
ann = OBAClient.new(
|
61
|
+
:ontologiesToKeepInResult => [42812],
|
62
|
+
:parse_xml => true,
|
63
|
+
:blah_blah => true,
|
64
|
+
:hoho => ["merry", "christmas"]
|
65
|
+
)
|
66
|
+
parsed = ann.execute(text)
|
67
|
+
assert parsed[:statistics].is_a?(Hash)
|
68
|
+
assert parsed[:annotations].is_a?(Array)
|
69
|
+
assert parsed[:ontologies].is_a?(Array)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_ontologies_pseudo_parameter
|
74
|
+
ann = OBAClient.new(:ontologies => [42812], :parse_xml => true)
|
75
|
+
TEST_TEXTS.each do |text|
|
76
|
+
parsed = ann.execute(text)
|
77
|
+
assert parsed[:ontologies].all? {|o| o[:localOntologyId] == 42812}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_parse
|
82
|
+
parsed = OBAClient::parse("<?xml version='1.0'></xml>")
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_with_print
|
86
|
+
ann = OBAClient.new(:ontologies => [42838, 35686], :parse_xml => false)
|
87
|
+
ann = OBAClient.new(:ontologies => [42838, 35686], :parse_xml => true)
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oba_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
- 3
|
10
|
+
version: 2.0.3
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Rob Tirrell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-16 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: thoughtbot-shoulda
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: yard
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
description: See above.
|
50
|
+
email: rpt@stanford.edu
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files:
|
56
|
+
- README.md
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- History.md
|
60
|
+
- Manifest.txt
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- Rakefile-2
|
64
|
+
- lib/oba_client.rb
|
65
|
+
- test/test_oba_client.rb
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: http://github.com/rtirrell/oba_client
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options:
|
72
|
+
- --charset=UTF-8
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 3
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.3.7
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: A client for the Open Biomedical Annotator.
|
100
|
+
test_files:
|
101
|
+
- test/test_oba_client.rb
|