oba-client 1.0.0

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/.autotest ADDED
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2010-07-07
2
+
3
+ * 1 Initial release
4
+
5
+ * Does not yet parse statistics.
6
+
data/Manifest.txt ADDED
@@ -0,0 +1,8 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/oba_client
7
+ lib/oba_client.rb
8
+ test/test_oba_client.rb
data/README.txt ADDED
@@ -0,0 +1,57 @@
1
+ = oba_client
2
+
3
+ * http://rubyforge.org/oba-client
4
+
5
+ == DESCRIPTION:
6
+
7
+ FIX (describe your package)
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * FIX (list of features or problems)
12
+
13
+ == SYNOPSIS:
14
+
15
+ FIX (code sample of usage)
16
+
17
+ == REQUIREMENTS:
18
+
19
+ * None
20
+
21
+ == INSTALL:
22
+
23
+ * FIX (sudo gem install, anything else)
24
+
25
+ == DEVELOPERS:
26
+
27
+ After checking out the source, run:
28
+
29
+ $ rake newb
30
+
31
+ This task will install any missing dependencies, run the tests/specs,
32
+ and generate the RDoc.
33
+
34
+ == LICENSE:
35
+
36
+ (The MIT License)
37
+
38
+ Copyright (c) 2010 FIX
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining
41
+ a copy of this software and associated documentation files (the
42
+ 'Software'), to deal in the Software without restriction, including
43
+ without limitation the rights to use, copy, modify, merge, publish,
44
+ distribute, sublicense, and/or sell copies of the Software, and to
45
+ permit persons to whom the Software is furnished to do so, subject to
46
+ the following conditions:
47
+
48
+ The above copyright notice and this permission notice shall be
49
+ included in all copies or substantial portions of the Software.
50
+
51
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
52
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
53
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
54
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
55
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
56
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
57
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "rubygems"
2
+ require "hoe"
3
+
4
+ Hoe.spec "oba-client" do
5
+ developer("Rob Tirrell", "rpt@stanford.edu")
6
+
7
+ self.rubyforge_name = "oba-client"
8
+ end
9
+
data/bin/oba_client ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
data/lib/oba_client.rb ADDED
@@ -0,0 +1,137 @@
1
+ require "rubygems"
2
+ require "nokogiri"
3
+ require "cgi"
4
+ require "net/http"
5
+ require "uri"
6
+
7
+ class OBAClient
8
+ VERSION = "1.0.0"
9
+
10
+ # A high HTTP read timeout, as the service sometimes takes awhile to respond.
11
+ DEFAULT_TIMEOUT = 30
12
+
13
+ # The endpoint URI for the production version of the Annotator service.
14
+ DEFAULT_URI = "http://rest.bioontology.org/obs/annotator"
15
+
16
+ # The header for every request. There's no need to specify this per-instance.
17
+ HEADER = {"Content-Type" => "application/x-www-form-urlencoded"}
18
+
19
+ # Parameters the annotator accepts. Any one not in this list (excluding
20
+ # textToAnnotate) is not valid.
21
+ ANNOTATOR_PARAMETERS = %w{
22
+ wholeWordOnly
23
+ scored
24
+ ontologiesToExpand
25
+ ontologiesToKeepInResult
26
+ semanticTypes
27
+ withDefaultStopWords
28
+ format
29
+ levelMax
30
+ mappingTypes
31
+ email
32
+ }
33
+
34
+ # Annotate a blob of text. Method options are:
35
+ # - [String] uri: the URI of the annotator service (default: {DEFAULT_URI}).
36
+ # - [Fixnum] timeout: the length of the read timeout (default: {DEFAULT_TIMEOUT}).
37
+ # - [Boolean] parse_xml: whether to parse the received text (default: false).
38
+ # @param [Hash<String, String>] options Parameters for the annotation.
39
+ def initialize(options = {})
40
+ @uri = URI.parse(options.delete(:uri) || DEFAULT_URI)
41
+ @timeout = options.delete(:timeout) || DEFAULT_TIMEOUT
42
+ @parse_xml = options.delete(:parse_xml)
43
+
44
+ @options = {}
45
+ options.each do |k, v|
46
+ if !ANNOTATOR_PARAMETERS.include?(k)
47
+ puts "WARNING: #{k} is not a valid annotator parameter."
48
+ end
49
+ if v.is_a? Array
50
+ @options[k] = v.join(",")
51
+ else
52
+ @options[k] = v
53
+ end
54
+ end
55
+
56
+ if !@options.include?(:email)
57
+ puts "TIP: as a courtesy, consider including your email in the request."
58
+ end
59
+ end
60
+
61
+ # Perform the annotation.
62
+ # @param [String] text The text to annotate.
63
+ # @return [Hash<Symbol, Array>, String, nil] A Hash representing the parsed
64
+ # document, the raw XML if parsing is not requested, or nil if the
65
+ # request times out.
66
+ def execute(text)
67
+ request = Net::HTTP::Post.new(@uri.path, initheader=HEADER)
68
+ request.body = {:textToAnnotate => text}.merge(@options).map do |k, v|
69
+ "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
70
+ end.join("&")
71
+
72
+ begin
73
+ response = Net::HTTP.new(@uri.host, @uri.port).start do |http|
74
+ http.read_timeout = @timeout
75
+ http.request(request)
76
+ end
77
+ @parse_xml ? self.class.parse(response.body) : response.body
78
+ rescue Timeout::Error
79
+ puts "Request for #{text[0..10]} timed-out at #{@timeout} seconds."
80
+ end
81
+ end
82
+
83
+ # Parse the raw XML, returning a Hash with three elements: statistics,
84
+ # annotations, and ontologies. Respectively, these represent the annotation
85
+ # statistics (annotations by mapping type, etc., as a Hash), an Array of
86
+ # each annotation (as a Hash), and an Array of ontologies used (also as
87
+ # a Hash).
88
+ # @param [String] xml The XMl we'll be parsing.
89
+ # @return [Hash<Symbol, Object>] A Hash representation of the XML, as
90
+ # described above.
91
+ def self.parse(xml)
92
+ statistics = []
93
+ annotations = []
94
+ ontologies = []
95
+ doc = Nokogiri::XML.parse(xml)
96
+
97
+ doc.xpath("//annotationBean").each do |ann|
98
+ parsed = {}
99
+ parsed[:score] = ann.xpath("score").text.to_i
100
+ parsed[:id] = ann.xpath("concept/id").text.to_i
101
+ parsed[:localConceptId] = ann.xpath("concept/localConceptId")
102
+ parsed[:localOntologyId] = ann.xpath("concept/localOntologyId").text.to_i
103
+ parsed[:isTopLevel] = ann.xpath("concept/isTopLevel").text.to_i
104
+ parsed[:fullId] = ann.xpath("concept/fullId").text
105
+ parsed[:preferredName] = ann.xpath("concept/preferredName").text
106
+
107
+ synonyms = ann.xpath("concept/synonyms/synonym")
108
+ parsed[:synonyms] = synonyms.map do |synonym|
109
+ synonym.xpath("string").text
110
+ end
111
+
112
+ semanticTypeBeans = ann.xpath("concept/semanticTypes/semanticTypeBean")
113
+ parsed[:semanticTypes] = semanticTypeBeans.map do |semanticType|
114
+ {
115
+ :id => semanticType.xpath("id").text.to_i,
116
+ :semanticType => semanticType.xpath("semanticType").text,
117
+ :description => semanticType.xpath("description").text
118
+ }
119
+ end
120
+ annotations << parsed
121
+ end
122
+
123
+ doc.xpath("//ontologyUsedBean").each do |ontology|
124
+ parsed = {}
125
+ parsed[:localOntologyId] = ontology.xpath("localOntologyId").text
126
+ parsed[:virtualOntologyId] = ontology.xpath("virtualOntologyId").text
127
+ parsed[:name] = ontology.xpath("name").text
128
+ ontologies << parsed
129
+ end
130
+
131
+ {
132
+ :statistics => statistics,
133
+ :annotations => annotations,
134
+ :ontologies => ontologies
135
+ }
136
+ end
137
+ end
@@ -0,0 +1,68 @@
1
+ require "test/unit"
2
+ require "oba_client"
3
+
4
+ TEST_TEXTS = [
5
+ "hello I am a monkeyfish with a benign neoplastic....\t\n\\n",
6
+ "zebrafish echo delta tango TURN <?xml MY VOLUME UP cancer of the thorax.",
7
+ "zebrafish DROP TABLE !!! TURN MY VOLUME UP cancer of the thorax.",
8
+ %Q{LOROE aonuhaso unseu anoeuhs aeuhsaonuh asoneuhason uaosenuh aosenuhaose
9
+ aoneuhasonuhaoenuh anoeuhasn euhasoneu haosneuhaosenuhaoesunahoeusnaoeuteeano
10
+ aot tt t t t t t t tae \n!!@)$@(#)%@#!)@# asoeuaohsenutahoeusaheou
11
+ }
12
+ ]
13
+
14
+ class TestOBAClient < Test::Unit::TestCase
15
+ def test_reuse_annotator_instance
16
+ ann = OBAClient.new
17
+ TEST_TEXTS.each do |text|
18
+ xml = ann.execute(text)
19
+ assert xml[0..4] == "<?xml"
20
+ end
21
+ end
22
+
23
+ def test_annotation_no_parameters
24
+ TEST_TEXTS.each do |text|
25
+ ann = OBAClient.new
26
+ xml = ann.execute(text)
27
+ assert xml[0..4] == "<?xml"
28
+ end
29
+ end
30
+
31
+ def test_annotation_parse
32
+ TEST_TEXTS.each do |text|
33
+ ann = OBAClient.new :parse_xml => true
34
+ parsed = ann.execute(text)
35
+ assert parsed[:statistics].is_a?(Array)
36
+ assert parsed[:annotations].is_a?(Array)
37
+ assert parsed[:ontologies].is_a?(Array)
38
+ end
39
+ end
40
+
41
+ def test_annotation_keep_one_ontology
42
+ TEST_TEXTS.each do |text|
43
+ ann = OBAClient.new(
44
+ :ontologiesToKeepInResult => [42812],
45
+ :parse_xml => true
46
+ )
47
+ parsed = ann.execute(text)
48
+ assert parsed[:statistics].is_a?(Array)
49
+ assert parsed[:annotations].is_a?(Array)
50
+ assert parsed[:ontologies].is_a?(Array)
51
+ end
52
+ end
53
+
54
+ def test_annotation_invalid_parameters
55
+ TEST_TEXTS.each do |text|
56
+ ann = OBAClient.new(
57
+ :ontologiesToKeepInResult => [42812],
58
+ :parse_xml => true,
59
+ :blah_blah => true,
60
+ :hoho => ["merry", "christmas"]
61
+ )
62
+ parsed = ann.execute(text)
63
+ assert parsed[:statistics].is_a?(Array)
64
+ assert parsed[:annotations].is_a?(Array)
65
+ assert parsed[:ontologies].is_a?(Array)
66
+ end
67
+ end
68
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oba-client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Rob Tirrell
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-08 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rubyforge
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ - 0
33
+ - 4
34
+ version: 2.0.4
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: hoe
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 21
46
+ segments:
47
+ - 2
48
+ - 6
49
+ - 1
50
+ version: 2.6.1
51
+ type: :development
52
+ version_requirements: *id002
53
+ description: FIX (describe your package)
54
+ email:
55
+ - rpt@stanford.edu
56
+ executables:
57
+ - oba_client
58
+ extensions: []
59
+
60
+ extra_rdoc_files:
61
+ - History.txt
62
+ - Manifest.txt
63
+ - README.txt
64
+ files:
65
+ - .autotest
66
+ - History.txt
67
+ - Manifest.txt
68
+ - README.txt
69
+ - Rakefile
70
+ - bin/oba_client
71
+ - lib/oba_client.rb
72
+ - test/test_oba_client.rb
73
+ has_rdoc: true
74
+ homepage: http://rubyforge.org/oba-client
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --main
80
+ - README.txt
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ requirements: []
102
+
103
+ rubyforge_project: oba-client
104
+ rubygems_version: 1.3.7
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: FIX (describe your package)
108
+ test_files:
109
+ - test/test_oba_client.rb