bio-ensembl-rest 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e112aedd2a2a78c4f241301731d39e2a3f094942
4
+ data.tar.gz: 483b616adf1743cac1b35088b59fa4d68e85e915
5
+ SHA512:
6
+ metadata.gz: 7fa0521d7923a7b9aafe1427258037a27b3794c736f36b9c0bec00d2b68b051b22195abbb3bec34307735a8274fcd9e58bfbb55b02ca2db745f76748f19dd90c
7
+ data.tar.gz: f91ecf17d9f0a267851e936efa1d4522160d54b56ba892ef1c2ad7f659f8fcdd1e1ed0a1301cc464f519566eedaf1c5894292791acc31144116dc68caf4cb07f
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+
6
+ matrix:
7
+ allow_failures:
8
+ - jruby-19mode
9
+ - rbx-19mode
10
+
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "bio", ">= 1.4.3"
7
+ gem "libxml-ruby", ">= 2" if RUBY_PLATFORM != 'java'
8
+
9
+ # Add dependencies to develop your gem here.
10
+ # Include everything needed to run rake, tests, features, etc.
11
+ group :development do
12
+ gem "shoulda", ">= 0"
13
+ gem "rdoc", "~> 3.12"
14
+ gem "bundler", "~> 1.3.5"
15
+ gem "jeweler", "~> 1.8.4"
16
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Alberto Donizetti
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ Ensembl Rest
2
+ ================
3
+
4
+ A Ruby library for the RESTful Ensembl API.
5
+
6
+ [![Build Status](https://api.travis-ci.org/ALTree/ensembl-rest.png)](https://travis-ci.org/ALTree/ensembl-rest)
7
+
8
+ Obtaining
9
+ ---------
10
+
11
+ ```sh
12
+ gem install ensembl-rest
13
+ ```
14
+ for the repository:
15
+ ```sh
16
+ git clone git://github.com/ALTree/bio-ensembl-rest
17
+ ```
18
+
19
+ Usage
20
+ -----
21
+
22
+ Each of the endpoint group listed in the Ensembl REST [documentation](http://beta.rest.ensembl.org/) has its own ruby module with the same name (except for Ontologies and Taxonomy, wich is split in two modules).
23
+
24
+ **A full list of modules and methods, with documentation, is available [here](https://github.com/ALTree/bio-ensembl-rest/wiki/modules-and-methods-list)**.
25
+
26
+ To make a request to an endpoint, use the appropriate method in the relative module. For example, to access the `sequence/region/:species/:region ` endpoint in the Sequence group, use the `sequence_region` method in the `Sequence` module:
27
+
28
+ ```ruby
29
+ require 'bio-ensembl-rest'
30
+ include EnsemblRest
31
+
32
+ EnsemblRest.connect_db # connect to database
33
+ puts Sequence.sequence_region 'Homo sapiens', 'X:1000000..1000025:1'
34
+
35
+ # GAAACAGCTACTTGGAAGGCTGAAGC
36
+ ```
37
+
38
+ Documentation
39
+ -----------
40
+ See the [ensembl-rest wiki page](https://github.com/ALTree/bio-ensembl-rest/wiki).
41
+
42
+ ## Known issues
43
+
44
+ ### version-specific issues
45
+
46
+ * On jruby-1.7, methods in the ComparativeGenomics module fail if called with `response: ruby`,
47
+ due to a C dependency in the 'bio' gem.
48
+
49
+ * On rubinius, methods in the ComparativeGenomics module fail if called with `response: ruby`,
50
+ due to a C dependency in the 'bio' gem.
51
+
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ gem.name = "bio-ensembl-rest"
17
+ gem.version = '0.1.0'
18
+ gem.homepage = "http://github.com/ALTree/bio-ensembl-rest"
19
+ gem.license = "MIT"
20
+ gem.summary = "Ruby Ensembl REST api"
21
+ gem.description = "A Ruby library for the RESTful Ensembl API."
22
+ gem.email = "alb.donizetti@gmail.com"
23
+ gem.authors = ["Alberto Donizetti"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'test'
31
+ test.test_files = FileList['test/test-*.rb']
32
+ test.verbose = true
33
+ end
34
+
35
+ task :default => :test
36
+
37
+ require 'rdoc/task'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "ensembl-rest #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
@@ -0,0 +1,19 @@
1
+ # Please require your code below, respecting the naming conventions in the
2
+ # bioruby directory tree.
3
+ #
4
+ # For example, say you have a plugin named bio-plugin, the only uncommented
5
+ # line in this file would be
6
+ #
7
+ # require 'bio/bio-plugin/plugin'
8
+ #
9
+ # In this file only require other files. Avoid other source code.
10
+
11
+ require 'bio'
12
+ require 'net/http'
13
+ require 'open-uri'
14
+ require 'json'
15
+
16
+ Dir[File.dirname(__FILE__) + '/bio-ensembl-rest/*.rb'].each do |file|
17
+ require file
18
+ end
19
+
@@ -0,0 +1,117 @@
1
+ module EnsemblRest
2
+ module ComparativeGenomics
3
+
4
+ ##
5
+ # Retrieves Gene Tree dumps for a given Gene Tree stable identifier
6
+ def self.genetree_id(id, opts = {})
7
+ return _genetree_generic id, 'id', opts
8
+ end
9
+
10
+ ##
11
+ # Retrieves the Gene Tree that contains the given stable identifier
12
+ def self.genetree_member_id(id, opts = {})
13
+ return _genetree_generic id, 'member', opts
14
+ end
15
+
16
+ # generic method used by genetree_id and genetree_member_id
17
+ def self._genetree_generic(id, type, opts = {}) # :nodoc:
18
+ opts = EnsemblRest.parse_options opts
19
+ url = type == 'id' ? "/genetree/id/#{id}" : "/genetree/member/id/#{id}"
20
+ path = EnsemblRest.build_path url, opts
21
+
22
+ if opts['content-type'] == 'ruby'
23
+ plain_opts = opts.clone
24
+ plain_opts['content-type'] = 'text/x-phyloxml+xml'
25
+ return Bio::PhyloXML::Parser.new _genetree_generic id, type, plain_opts
26
+ end
27
+
28
+ return EnsemblRest.fetch_data path, opts, 'compara'
29
+ end
30
+
31
+
32
+ ##
33
+ # Retrieves a Gene Tree containing the Gene identified by the given symbol
34
+ def self.genetree_member_symbol(species, symbol, opts = {})
35
+ opts = EnsemblRest.parse_options opts
36
+ path = EnsemblRest.build_path "/genetree/member/symbol/#{species}/#{symbol}", opts
37
+
38
+ if opts['content-type'] == 'ruby'
39
+ plain_opts = opts.clone
40
+ plain_opts['content-type'] = 'text/x-phyloxml+xml'
41
+ return Bio::PhyloXML::Parser.new genetree_member_symbol(species, symbol, plain_opts)
42
+ end
43
+
44
+ return EnsemblRest.fetch_data path, opts, 'compara'
45
+ end
46
+
47
+
48
+ ##
49
+ # Retrieves homology information by ensembl gene id
50
+ def self.homology_id(id, opts = {})
51
+ opts = EnsemblRest.parse_options opts
52
+ path = EnsemblRest.build_path "/homology/id/#{id}", opts
53
+
54
+ if opts['content-type'] == 'ruby'
55
+ plain_opts = opts.clone
56
+ plain_opts['content-type'] = 'application/json'
57
+ data = JSON.parse ComparativeGenomics.homology_id id, plain_opts
58
+ return build_homology_class data
59
+ end
60
+
61
+ return EnsemblRest.fetch_data path, opts, 'compara'
62
+ end
63
+
64
+
65
+ ##
66
+ # Retrieves homology information by symbol
67
+ def self.homology_symbol(species, symbol, opts = {})
68
+ opts = EnsemblRest.parse_options opts
69
+ path = EnsemblRest.build_path "/homology/symbol/#{species}/#{symbol}", opts
70
+
71
+ if opts['content-type'] == 'ruby'
72
+ plain_opts = opts.clone
73
+ plain_opts['content-type'] = 'application/json'
74
+ data = JSON.parse ComparativeGenomics.homology_symbol species, symbol, plain_opts
75
+ return build_homology_class data
76
+ end
77
+
78
+ return EnsemblRest.fetch_data path, opts, 'compara'
79
+
80
+ end
81
+
82
+
83
+ # here we define the Homology class
84
+ Object.const_set("Homology", Class.new)
85
+
86
+ def self.build_homology_class(json_data) # :nodoc:
87
+ # extract the homologies list (homology = ruby hash obj)
88
+ homologies_data = json_data['data'][0]['homologies'] # this is a list of hashes
89
+
90
+ # retrieve homology keys to make a list of methods
91
+ homology_methods = []
92
+ homologies_data.first.each { |k, _| homology_methods << k.to_sym }
93
+
94
+ # we define an attr_accessor for each symbol in homology_methods
95
+ # and a 'bio_methods' attribute with all the newly defined methods
96
+ homology_methods.each { |k, _| Homology.class_eval "attr_accessor :#{k}" }
97
+ Homology.class_eval "attr_accessor :bio_methods"
98
+
99
+ # we will return a list of homology objects
100
+ homologies = []
101
+
102
+ # let's build the list
103
+ homologies_data.each do |hom| # cycle over the homologies we were given
104
+ h = Homology.new # we instantiate an Homology obj
105
+ hom.each do |k, v| # for each key,value in the homology hash
106
+ h.send "#{k}=".to_sym, v # we use the 'key=' method to set 'value'
107
+ end
108
+ h.send :bio_methods=, homology_methods # set the bio_methods param
109
+ homologies << h # add the obj to the list to be returned
110
+ end
111
+
112
+ return homologies
113
+ end
114
+
115
+
116
+ end
117
+ end
@@ -0,0 +1,55 @@
1
+ module EnsemblRest
2
+ module CrossReference
3
+
4
+ ##
5
+ # Perform lookups of Ensembl Identifiers and retrieve their external cross
6
+ # references in other databases
7
+ def self.xrefs_id(id, opts = {})
8
+ opts = EnsemblRest.parse_options opts
9
+ path = EnsemblRest.build_path "/xrefs/id/#{id}", opts
10
+
11
+ if opts['content-type'] == 'ruby'
12
+ plain_opts = opts.clone
13
+ plain_opts['content-type'] = 'application/json'
14
+ return JSON.parse xrefs_id id, plain_opts
15
+ end
16
+
17
+ return EnsemblRest.fetch_data path, opts, 'crossreference'
18
+ end
19
+
20
+
21
+ ##
22
+ # Performs a lookup based upon the primary accession or display label of
23
+ # an external reference and returning the information we hold about the entry
24
+ def self.xrefs_name(species, name, opts = {})
25
+ opts = EnsemblRest.parse_options opts
26
+ path = EnsemblRest.build_path "/xrefs/name/#{species}/#{name}", opts
27
+
28
+ if opts['content-type'] == 'ruby'
29
+ plain_opts = opts.clone
30
+ plain_opts['content-type'] = 'application/json'
31
+ return JSON.parse xrefs_name species, name, plain_opts
32
+ end
33
+
34
+ return EnsemblRest.fetch_data path, opts, 'crossreference'
35
+ end
36
+
37
+
38
+ ##
39
+ # Looks up an external symbol and returns all Ensembl objects linked to it
40
+ def self.xrefs_symbol(species, symbol, opts = {})
41
+ opts = EnsemblRest.parse_options opts
42
+ path = EnsemblRest.build_path "/xrefs/symbol/#{species}/#{symbol}", opts
43
+
44
+ if opts['content-type'] == 'ruby'
45
+ plain_opts = opts.clone
46
+ plain_opts['content-type'] = 'application/json'
47
+ return JSON.parse xrefs_symbol species, symbol, plain_opts
48
+ end
49
+
50
+ return EnsemblRest.fetch_data path, opts, 'crossreference'
51
+ end
52
+
53
+
54
+ end
55
+ end
@@ -0,0 +1,108 @@
1
+ module EnsemblRest
2
+ ## start HTTP database connection ##
3
+
4
+ def self.connect_db
5
+ $SERVER = URI.parse 'http://beta.rest.ensembl.org'
6
+ $HTTP_CONNECTION = Net::HTTP.new($SERVER.host, $SERVER.port)
7
+ end
8
+
9
+
10
+ ## parse options stuff ##
11
+ def self.parse_options(opts) # :nodoc:
12
+ parsed_opts = {}
13
+ opts.each {|k, v| parsed_opts[k.to_s] = v}
14
+
15
+ parse_format parsed_opts
16
+ parse_true_false parsed_opts
17
+ end
18
+
19
+ def self.parse_true_false(opts) # :nodoc:
20
+ opts.each do |k, v|
21
+ if v.instance_of?(TrueClass)
22
+ opts[k] = 1
23
+ elsif v.instance_of?(FalseClass)
24
+ opts[k] = 0
25
+ end
26
+ end
27
+ end
28
+
29
+ def self.parse_format(opts) # :nodoc:
30
+ supported_formats = {
31
+ 'text' => 'text/plain',
32
+ 'fasta' => 'text/x-fasta',
33
+ 'gff3' => 'ext/x-gff3',
34
+ 'json' => 'application/json',
35
+ 'msgpack' => 'application/x-msgpack',
36
+ 'nh' => 'text/x-nh',
37
+ 'seqxml' => 'text/x-seqxml+xml',
38
+ 'sereal' => 'application/x-sereal',
39
+ 'phyloxml' => 'text/x-phyloxml+xml',
40
+ 'xml' => 'text/xml',
41
+ 'yaml' => 'text/x-yaml'
42
+ }
43
+ if opts.has_key?('response')
44
+ req = opts['response']
45
+ if supported_formats[req]
46
+ opts['content-type'] = supported_formats[req]
47
+ else
48
+ opts['content-type'] = req
49
+ end
50
+ opts.delete 'response'
51
+ end
52
+ opts
53
+ end
54
+
55
+
56
+ ## HTTP request stuff ##
57
+
58
+ def self.build_path(home, opts) # :nodoc:
59
+ path = home + '?'
60
+ opts.each { |k,v| path << "#{k}=#{v};" if k != 'content-type' }
61
+ path[-1] = '' if not opts
62
+ URI::encode path
63
+ end
64
+
65
+ # TODO: add tests to check if this default stuff is ok
66
+ def self.fetch_data(path, opts, mod) # :nodoc:
67
+ # what we should set as content-type in the header
68
+ # to keep ensembl happy when the the user does not
69
+ # use the format parameter to set the return type
70
+ default_types = {
71
+ 'sequence' => 'text/plain',
72
+ 'compara' => 'text/xml',
73
+ 'crossreference' => 'application/json',
74
+ 'features' => 'application/json',
75
+ 'information' => 'application/json',
76
+ 'lookup' => 'application/json',
77
+ 'mapping' => 'application/json',
78
+ 'ontologies' => 'application/json',
79
+ 'taxonomy' => 'application/json',
80
+ 'variation' => 'application/json'
81
+ }
82
+ request = Net::HTTP::Get.new path
83
+ request.content_type = opts['content-type'] || default_types[mod]
84
+ response = $HTTP_CONNECTION.request request
85
+ return check_response response
86
+ end
87
+
88
+ def self.check_response(response) # :nodoc:
89
+ case response.code
90
+ when '200'
91
+ return response.body
92
+ when '400'
93
+ raise 'Bad request: ' + response.body
94
+ when '404'
95
+ raise 'Not Found'
96
+ when '415'
97
+ raise 'Unsupported Media Type'
98
+ when '429'
99
+ raise 'Too many requests'
100
+ when '503'
101
+ raise 'Service Unavailable'
102
+ else
103
+ raise "Bad response code: #{response.code}"
104
+ end
105
+ end
106
+
107
+
108
+ end