rubyMorphbank 0.2.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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = rubyMorphbank
2
+
3
+ A request/response library for the Morphbank (http://morphbank.net) API.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 mjy. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rubyMorphbank"
8
+ gem.summary = %Q{Simple Morphbank (http://morphbank.net) services accessor.}
9
+ gem.description = %Q{Uses the Morphbank API to query and return results from the Morphbank database.}
10
+ gem.email = "diapriid@gmail.com"
11
+ gem.homepage = "http://github.com/mjy/rubyMorphbank"
12
+ gem.authors = ["mjy"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.files += FileList['init.rb', 'lib/**/*.rb'].to_a
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/test_*.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "rubyMorphbank #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rubyMorphbank'
data/lib/request.rb ADDED
@@ -0,0 +1,53 @@
1
+ class Request
2
+
3
+ # defaults
4
+ METHOD = 'search'
5
+ OBJECTTYPE = 'Image'
6
+ LIMIT = 10
7
+ DEPTH = 1
8
+ FORMAT = 'id'
9
+
10
+ # a subset of VALID_OPTIONS, these are concatenated in the request
11
+ URI_PARAMS = [:limit, :format, :depth, :objecttype, :first_result, :keywords, :id]
12
+
13
+ # possible options for a Request instance
14
+ VALID_OPTIONS = {'v3' => URI_PARAMS + [:version, :method] }
15
+
16
+ attr_reader(:request_url, :request_options)
17
+
18
+ def initialize(options = {})
19
+ opt = {
20
+ :version => 'v3',
21
+ :method => METHOD,
22
+ :limit => LIMIT,
23
+ :format => FORMAT, # 'id' (brief results) or 'svc' (schema based results)
24
+ :depth => DEPTH,
25
+ :objecttype => OBJECTTYPE, # [nil, Taxon, Image, Character, Specimen, View, Matrix, Locality, Collection, OTU ] (nil = all)
26
+ :first_result => 0,
27
+ :keywords => ''
28
+ }.merge!(options)
29
+
30
+ # check for legal parameters
31
+ opt.keys.each do |p|
32
+ raise RubyMorphbankError, "#{p} is not a valid parameter" if !VALID_OPTIONS[opt[:version]].include?(p)
33
+ end
34
+
35
+
36
+ # create the request
37
+ @request_url = SERVICES_URI + "method=#{opt[:method]}" +
38
+ opt.keys.sort{|a,b| a.to_s <=> b.to_s}.collect{
39
+ |k| ( (URI_PARAMS.include?(k) && (!opt[k].nil? || opt[k].empty?)) ? "&#{k.to_s}=#{opt[k]}" : '')
40
+ }.join
41
+
42
+ # and some housekeepers
43
+ @request_options = opt
44
+ end
45
+
46
+ def get_response
47
+ Response.new(self)
48
+ end
49
+
50
+ # .root.elements.each(xpath){}.map do |row|
51
+
52
+ ## REXML::XPath.match(@xml, '//object/width').collect{|e| e.text.to_s}
53
+ end
data/lib/response.rb ADDED
@@ -0,0 +1,74 @@
1
+ class Response
2
+
3
+ attr_reader(
4
+ :response, # the Net:HTTP response
5
+ :doc, # the REXML:Document for :response
6
+ :request # cache the request object for reference in the response
7
+ )
8
+
9
+ # all the objects returned
10
+ attr :objects, true
11
+ attr :ids, true
12
+
13
+ attr :annotations
14
+ attr :images
15
+
16
+ def initialize(request = Request.new)
17
+
18
+
19
+ begin
20
+ @response = Net::HTTP.get_response(URI.parse(request.request_url)).body
21
+ rescue SocketError
22
+ raise "can not connect to socket, check SERVICES_URI"
23
+ end
24
+
25
+ # TODO: check that we're getting a legit XML document back before trying to parse it
26
+ @doc = REXML::Document.new(@response)
27
+
28
+ @request = request # TODO: can this be aliased some how?
29
+ self
30
+ end
31
+
32
+ # return an Array of ids representing morphbankIds to images
33
+ def mb_image_ids
34
+ if request.request_options[:format] == 'id'
35
+ REXML::XPath.match(@doc, "//id").collect{|e| e.text.to_s}
36
+ else
37
+ raise RubyMorphbankError, "you must use method='image' in requests to use the mb_image_ids method"
38
+ end
39
+ end
40
+
41
+ # get the Integer of the first match
42
+ def get_int(element_name)
43
+ REXML::XPath.first(@doc, "//#{element_name}").nil? ? 0 : REXML::XPath.first(@doc, "//#{element_name}").text.to_i
44
+ end
45
+
46
+ # get the String of the first match
47
+ def get_text(element_name)
48
+ REXML::XPath.first(@doc, "//#{element_name}").nil? ? 0 : REXML::XPath.first(@doc, "//#{element_name}").text
49
+ end
50
+
51
+ # return an Array of XML elements whose root is an object element
52
+ def objects
53
+ REXML::XPath.match(@doc, "//object")
54
+ end
55
+
56
+ # TODO: the has conversion is NOT optimal (no attributes, children of root only), see extension in rubyMorpbank
57
+ def hashified_objects
58
+ self.doc.records("//object")
59
+ end
60
+
61
+ # pagination
62
+ def link_forward?
63
+ ((get_int('numResultsReturned') + get_int('firstResult')) < get_int('numResults')) and return true
64
+ false
65
+ end
66
+
67
+ # pagination
68
+ def link_back?
69
+ (get_int('firstResult') > @request.request_options[:limit]) and return true
70
+ false
71
+ end
72
+
73
+ end
74
+
@@ -0,0 +1,71 @@
1
+ # Written by Matt Yoder, 2010
2
+ # see source on github
3
+
4
+ require 'ruby-debug'
5
+ require 'rexml/document'
6
+ require 'net/http'
7
+
8
+ module RubyMorphbank
9
+
10
+ # schema is at http://morphbank.net/schema/mbsvc3.xsd
11
+ # web interface to API is at http://services.morphbank.net/mb3
12
+
13
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/Request'))
14
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/Response'))
15
+
16
+ class RubyMorphbankError < StandardError
17
+ end
18
+
19
+ SERVICES_URI = 'http://services.morphbank.net/mb3/request?'
20
+
21
+ class Rmb
22
+ attr_accessor :opt
23
+
24
+ def initialize(options = {})
25
+ opt = {
26
+ }.merge!(options)
27
+ end
28
+
29
+ def request(options = {})
30
+ opt = {
31
+ }.merge!(options)
32
+ Request.new(opt)
33
+ end
34
+ end
35
+
36
+ # returns a Hash with properties set to values !! no attributes, nothing other than child elements of root (see extensions below) !!
37
+ def metadata_hash_for_one_image(image_id)
38
+ Rmb.new.request(:id => image_id, :format => 'svc', :objecttype => 'Image', :method => 'id', :limit => 1).get_response.doc.record('//object')
39
+ end
40
+
41
+ end
42
+
43
+
44
+ ## Base/REXML extension ##
45
+
46
+ # modified from http://snippets.dzone.com/posts/show/6181
47
+
48
+ # convert an array into a hash
49
+ class Array
50
+ def to_h
51
+ Hash[*self]
52
+ end
53
+ end
54
+
55
+ # neither of these extensions is particularly good, they don't recurse etc.
56
+ class REXML::Document
57
+ def record(xpath)
58
+ self.root.elements.each(xpath + '/*'){}.inject([]) do |r,node|
59
+ r << node.name.to_s << node.text.to_s.strip
60
+ end.to_h
61
+ end
62
+
63
+ def records(xpath)
64
+ self.root.elements.each(xpath){}.map do |row|
65
+ row.elements.each{}.inject([]) do |r,node|
66
+ r << node.name.to_s << node.text.to_s.strip
67
+ end.to_h
68
+ end
69
+ end
70
+ end
71
+
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'rubyMorphbank'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,93 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/rubyMorphbank'))
3
+
4
+ include RubyMorphbank
5
+
6
+
7
+ class TestRubyMorphbank < Test::Unit::TestCase
8
+
9
+ should "initialize a new instance without parameters" do
10
+ assert @bhl = Rmb.new()
11
+ end
12
+
13
+ should "return an hash object using get_metadata_for_one_image" do
14
+ # WARNING: this XML to hash is not a terribly useful conversion, the process drops all children and attributes
15
+ hash = metadata_hash_for_one_image(195815) # It's fixed data, not the best test, but if it's gone something is seriously wrong anyways
16
+ assert_equal '1360', hash['width']
17
+ end
18
+
19
+ end
20
+
21
+
22
+ class TestRequest < Test::Unit::TestCase
23
+
24
+ should "return a properly formatted request url with no options" do
25
+ @rmb = Rmb.new
26
+ assert @request = @rmb.request
27
+ assert_equal "http://services.morphbank.net/mb3/request?method=search&depth=1&first_result=0&format=id&keywords=&limit=10&objecttype=Image", @request.request_url
28
+ end
29
+
30
+ end
31
+
32
+
33
+
34
+ class TestResponse < Test::Unit::TestCase
35
+
36
+ should "return initialize with a unparameterized request" do
37
+ @request = Rmb.new.request
38
+ @response = @request.get_response
39
+ assert_equal 'mbresponse', @response.doc.elements.first.name
40
+ end
41
+
42
+ should "return 10 results when unparameterized" do
43
+ @request = Rmb.new.request
44
+ assert_equal 10, @request.get_response.get_int('numResultsReturned')
45
+ end
46
+
47
+ should "return many more than 10 results in MB when unparameterized" do
48
+ @request = Rmb.new.request
49
+ assert (10 < @request.get_response.get_int('numResults'))
50
+ end
51
+
52
+ should "should link_forward when unparameterized" do
53
+ @request = Rmb.new.request
54
+ assert @request.get_response.link_forward?
55
+ end
56
+
57
+ should "should not link_back when unparameterized" do
58
+ @request = Rmb.new.request
59
+ assert !@request.get_response.link_back?
60
+ end
61
+
62
+ should "return an array of morphbank image ids when using :format => id and mb_image_ids" do
63
+ @request = Rmb.new.request(:format => 'id')
64
+ @response = @request.get_response
65
+ assert @response.mb_image_ids.size == 10 # not a good test, but variable data return on a vanilla request
66
+ # this is an array of ids like ["32029", ... "32038"]
67
+ end
68
+
69
+ # test get_int
70
+ should "return a fixnum using get_int for element numResultsReturned" do
71
+ @request = Rmb.new.request()
72
+ assert_equal 10, @request.get_response.get_int('numResultsReturned')
73
+ end
74
+
75
+ # test get_text
76
+ should "return a mbresponse of objecttypes == Image by default" do
77
+ @request = Rmb.new.request()
78
+ assert_equal 'Image', @request.get_response.get_text('objecttypes')
79
+ end
80
+
81
+ # return a link to a numbnail in a call for a single image
82
+ should "return a URI to a thumb for a single object query" do
83
+ foo = Rmb.new.request(:format => 'svc', :id => 195815, :method => 'id')
84
+ assert_equal 'http://images.morphbank.net/?id=195815&imgType=thumb', foo.get_response.get_text('thumbUrl')
85
+ end
86
+
87
+ should "return an array of hashified array of Morphbank objects" do
88
+ foo = Rmb.new.request(:format => 'svc').get_response.hashified_objects
89
+ assert_equal 10, foo.size
90
+ end
91
+
92
+ end
93
+
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubyMorphbank
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
+ platform: ruby
11
+ authors:
12
+ - mjy
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-12 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thoughtbot-shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ description: Uses the Morphbank API to query and return results from the Morphbank database.
33
+ email: diapriid@gmail.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - README.rdoc
40
+ files:
41
+ - .document
42
+ - .gitignore
43
+ - README.rdoc
44
+ - Rakefile
45
+ - VERSION
46
+ - init.rb
47
+ - lib/request.rb
48
+ - lib/response.rb
49
+ - lib/rubyMorphbank.rb
50
+ - test/helper.rb
51
+ - test/test_rubyMorphbank.rb
52
+ has_rdoc: true
53
+ homepage: http://github.com/mjy/rubyMorphbank
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --charset=UTF-8
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.6
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Simple Morphbank (http://morphbank.net) services accessor.
82
+ test_files:
83
+ - test/helper.rb
84
+ - test/test_rubyMorphbank.rb