bio-ensembl-rest 0.1.0

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