rubyMorphbank 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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