solvebio 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +13 -0
  3. data/Gemfile +4 -0
  4. data/Gemspec +3 -0
  5. data/LICENSE +21 -0
  6. data/Makefile +17 -0
  7. data/README.md +64 -0
  8. data/Rakefile +59 -0
  9. data/bin/solvebio.rb +36 -0
  10. data/demo/README.md +14 -0
  11. data/demo/dataset/facets.rb +13 -0
  12. data/demo/dataset/field.rb +13 -0
  13. data/demo/depository/README.md +24 -0
  14. data/demo/depository/all.rb +13 -0
  15. data/demo/depository/retrieve.rb +13 -0
  16. data/demo/depository/versions-all.rb +13 -0
  17. data/demo/query/query-filter.rb +30 -0
  18. data/demo/query/query.rb +13 -0
  19. data/demo/query/range-filter.rb +18 -0
  20. data/demo/test-api.rb +98 -0
  21. data/lib/apiresource.rb +130 -0
  22. data/lib/cli/auth.rb +122 -0
  23. data/lib/cli/help.rb +13 -0
  24. data/lib/cli/irb.rb +58 -0
  25. data/lib/cli/irbrc.rb +53 -0
  26. data/lib/cli/options.rb +75 -0
  27. data/lib/client.rb +152 -0
  28. data/lib/credentials.rb +67 -0
  29. data/lib/errors.rb +81 -0
  30. data/lib/filter.rb +312 -0
  31. data/lib/help.rb +46 -0
  32. data/lib/locale.rb +47 -0
  33. data/lib/main.rb +37 -0
  34. data/lib/query.rb +415 -0
  35. data/lib/resource.rb +414 -0
  36. data/lib/solvebio.rb +14 -0
  37. data/lib/solveobject.rb +101 -0
  38. data/lib/tabulate.rb +706 -0
  39. data/solvebio.gemspec +75 -0
  40. data/test/data/netrc-save +6 -0
  41. data/test/helper.rb +3 -0
  42. data/test/test-auth.rb +54 -0
  43. data/test/test-client.rb +27 -0
  44. data/test/test-error.rb +36 -0
  45. data/test/test-filter.rb +70 -0
  46. data/test/test-netrc.rb +42 -0
  47. data/test/test-query-batch.rb +60 -0
  48. data/test/test-query-init.rb +29 -0
  49. data/test/test-query-paging.rb +123 -0
  50. data/test/test-query.rb +88 -0
  51. data/test/test-resource.rb +47 -0
  52. data/test/test-solveobject.rb +27 -0
  53. data/test/test-tabulate.rb +127 -0
  54. metadata +158 -0
data/solvebio.gemspec ADDED
@@ -0,0 +1,75 @@
1
+ ## -*- Ruby -*-
2
+ ## This is the rakegem gemspec template. Make sure you read and understand
3
+ ## all of the comments. Some sections require modification, and others can
4
+ ## be deleted if you don't need them. Once you understand the contents of
5
+ ## this file, feel free to delete any comments that begin with two hash marks.
6
+ ## You can find comprehensive Gem::Specification documentation, at
7
+ ## http://docs.rubygems.org/read/chapter/20
8
+ Gem::Specification.new do |s|
9
+ s.specification_version = 2 if s.respond_to? :specification_version=
10
+ # s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ # s.rubygems_version = '1.3.5'
12
+
13
+ ## Leave these as is they will be modified for you by the rake gemspec task.
14
+ ## If your rubyforge_project name is different, then edit it and comment out
15
+ ## the sub! line in the Rakefile
16
+ s.name = 'solvebio'
17
+ s.version = '1.5.0'
18
+ s.date = '2014-08-16'
19
+
20
+ ## Make sure your summary is short. The description may be as long
21
+ ## as you like.
22
+ s.summary = "SolveBio Ruby bindings."
23
+
24
+ s.description = <<-EOD
25
+ SolveBio is a platform for biomedical datasets. With SolveBio you can
26
+ forget about parsing complex flat files and sifting through cryptic
27
+ datasets. Just use the Ruby Client and API to explore massive
28
+ datasets and automate just about any bioinformatics workflow.
29
+
30
+ See https://www.solvebio.com/docs/api/ for more information.
31
+ EOD
32
+
33
+ ## List the primary authors. If there are a bunch of authors, it's probably
34
+ ## better to set the email to an email list or something. If you don't have
35
+ ## a custom homepage, consider using your GitHub URL or the like.
36
+ s.authors = ['solvebio.com']
37
+ s.email = 'contact@solvebio.com'
38
+ s.homepage = 'https://www.solvebio.com'
39
+
40
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
41
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
42
+ s.require_paths = %w[lib]
43
+
44
+ s.required_ruby_version = Gem::Requirement.new(">= 1.9.0")
45
+
46
+ ## If your gem includes any executables, list them here.
47
+ s.executables = ['solvebio.rb']
48
+ s.default_executable = 'solvebio.rb'
49
+
50
+ ## Specify any RDoc options here. You'll want to add your README and
51
+ ## LICENSE files to the extra_rdoc_files list.
52
+ s.rdoc_options = ["--charset=UTF-8"]
53
+ s.extra_rdoc_files = %w[LICENSE]
54
+
55
+ ## List your runtime dependencies here. Runtime dependencies are those
56
+ ## that are needed for an end user to actually USE your code.
57
+ s.add_dependency('netrc', '>=0.7.7')
58
+ # s.add_dependency('openssl', '>=1.1.0')
59
+
60
+
61
+ # There is no way to specify optional dependencies.
62
+ # s.add_optional_dependency 'launchy' # opens URL in web browser for help
63
+ # s.add_optional_dependency 'bond' # better shell command completion
64
+
65
+ ## List your development dependencies here. Development dependencies are
66
+ ## those that are only needed during development
67
+ # s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
68
+ s.add_development_dependency('rake')
69
+ s.add_development_dependency('rdoc')
70
+ s.files = `git ls-files`.split($/)
71
+
72
+ ## Test files will be grabbed from the file list. Make sure the path glob
73
+ ## matches what you actually use.
74
+ s.test_files = s.files.grep(/^test/)
75
+ end
@@ -0,0 +1,6 @@
1
+ machine foo.bar
2
+ login a@example.com
3
+ password secret
4
+ machine api.solvebio.com
5
+ login rocky@example.com
6
+ password shhhh
data/test/helper.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/resource'
3
+ SolveBio.api_key = 'ce68f783a65275d3e81463621d825bad20eb20b0'
data/test/test-auth.rb ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = true
3
+ require 'test/unit'
4
+ require 'rbconfig'
5
+ require_relative '../lib/credentials'
6
+
7
+ class TestAuth < Test::Unit::TestCase
8
+
9
+ include SolveBio::Credentials
10
+
11
+ def run_it(cmd)
12
+ output = `#{cmd}`
13
+ assert_equal 0, $?.to_i, "Should be able to run #{cmd}"
14
+ output.chomp
15
+ end
16
+
17
+ def setup
18
+ ruby=RbConfig.ruby
19
+ @auth_prog = File.join(File.dirname(__FILE__),
20
+ '..', 'lib', 'cli', 'auth.rb')
21
+ @logout_cmd = "#{ruby} #{@auth_prog} logout"
22
+ @@whoami_cmd = "#{ruby} #{@auth_prog} whoami"
23
+
24
+ # Save who I was so we can compare at the end
25
+ @i_was = run_it @@whoami_cmd
26
+
27
+ begin
28
+ @@creds = get_credentials
29
+ rescue CredentialsError
30
+ @@creds = nil
31
+ end
32
+ end
33
+
34
+ def teardown
35
+ # Restore creds to what they were when we started
36
+ save_credentials(*@@creds) if @@creds
37
+ i_am = run_it @@whoami_cmd
38
+ assert_equal(@i_was, i_am,
39
+ 'get_credential and save_creditentials be idempotent')
40
+ end
41
+
42
+ # Integration test of logout
43
+ def test_logout
44
+
45
+ # Dunno if we are logged in or out - log out
46
+ output = run_it @logout_cmd
47
+ # We should be logged out. Try again, and check message.
48
+ output = run_it @logout_cmd
49
+ assert_equal 'You are not logged-in.', output
50
+ # We should be logged out. Try to get status
51
+ output = run_it @@whoami_cmd
52
+ assert_equal 'You are not logged-in.', output
53
+ end
54
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = true
3
+ require 'test/unit'
4
+ require 'fileutils'
5
+ require_relative '../lib/client'
6
+
7
+ # require 'trepanning'
8
+
9
+ class TestClient < Test::Unit::TestCase
10
+
11
+ def test_get
12
+ client = SolveBio::Client.new(nil, 'http://google.com')
13
+ assert client, 'Should be able to create a client'
14
+
15
+ # Can we get something from google?
16
+ output = `curl --silent http://www.google.com`
17
+ if $?.success? and output
18
+ assert(client.request('http', 'http://www.google.com', nil,
19
+ true), 'HTTP GET, google.com')
20
+ assert(client.request('https', 'https://www.google.com', nil,
21
+ true), 'HTTPS GET google.com')
22
+ else
23
+ skip('Are you connected to the Internet? www.google.com is unavailable')
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = true
3
+ require 'test/unit'
4
+ require 'net/http'
5
+ require_relative '../lib/errors'
6
+
7
+ # require 'trepanning'
8
+
9
+ $errors = []
10
+
11
+ class FakeLogger
12
+ def debug(mess)
13
+ $errors << mess
14
+ end
15
+ end
16
+
17
+ class TestError < Test::Unit::TestCase
18
+
19
+ def test_error
20
+ msg = "hi"
21
+ assert_equal msg, SolveBio::Error.new(nil, msg).to_s, "Error.to_s fn"
22
+ response = Net::HTTPUnauthorized.new('HTTP 1.1', '404', 'No creds')
23
+ old_logger = SolveBio.instance_variable_get('@logger')
24
+ logger = FakeLogger.new
25
+ SolveBio.instance_variable_set('@logger', logger)
26
+ old_verbose = $VERBOSE
27
+ $VERBOSE=false
28
+ SolveBio::Error.new(response)
29
+ $VERBOSE=old_verbose
30
+ assert_equal ["API Response (404): No content."], $errors
31
+ ensure
32
+ $VERBOSE = old_verbose if old_verbose
33
+ SolveBio.instance_variable_set('@logger', old_logger) if old_logger
34
+
35
+ end
36
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = true
3
+ require 'test/unit'
4
+ require_relative '../lib/filter'
5
+
6
+ class TestFilter < Test::Unit::TestCase
7
+
8
+ def test_filter_errors
9
+ assert_raises TypeError do
10
+ SolveBio::Filter.new(:style__gtt => 5)
11
+ end
12
+ assert_raises TypeError do
13
+ SolveBio::Filter.new(:style__between => 'a')
14
+ end
15
+ assert_raises TypeError do
16
+ SolveBio::Filter.new(:style__between => [5,10,15])
17
+ end
18
+ assert_raises IndexError do
19
+ SolveBio::Filter.new(:style__range => [10,5])
20
+ end
21
+ end
22
+
23
+ def test_filter
24
+ f = SolveBio::Filter.new
25
+ assert_equal('<SolveBio::Filter []>', f.inspect, 'empty filter')
26
+ assert_equal('<SolveBio::Filter []>',
27
+ (~f).inspect, '"not" of empty filter')
28
+ f2 = SolveBio::Filter.new({:style => 'Mexican', :price => 'Free'})
29
+ assert_equal('<SolveBio::Filter [{:and=>[[:price, "Free"], [:style, "Mexican"]]}]>',
30
+ f2.inspect, 'Hash to tuple sorting'
31
+ )
32
+ assert_equal('<SolveBio::Filter [{:not=>{:and=>[[:price, "Free"], [:style, "Mexican"]]}}]>',
33
+ (~f2).inspect, '~ of a non-nil filter')
34
+ assert_equal('<SolveBio::Filter [{:and=>[[:price, "Free"], [:style, "Mexican"]]}]>',
35
+ (~~f2).inspect, '~~ has no effect')
36
+
37
+ filters3 =
38
+ SolveBio::Filter.new(:omim_id => 144650) |
39
+ SolveBio::Filter.new(:omim_id => 144600) |
40
+ SolveBio::Filter.new(:omim_id => 145300)
41
+
42
+ assert_equal('<SolveBio::Filter [{:or=>[[:omim_id, 144650], [:omim_id, 144600], [:omim_id, 145300]]}]>',
43
+ filters3.inspect,
44
+ 'combining more than one of a connector (|)')
45
+
46
+ assert_equal('<SolveBio::Filter [[:style__between, [5, 10]]]>',
47
+ SolveBio::Filter.new(:style__between => (5...11)).inspect)
48
+ assert_equal('<SolveBio::Filter [[:style__between, [5, 10]]]>',
49
+ SolveBio::Filter.new(:style__between => (5..10)).inspect)
50
+
51
+ end
52
+
53
+ def test_range_filter
54
+ assert_equal('<RangeFilter [{:and=>[["hg38_start__range", ' +
55
+ '[32200000, 32500000]], ' +
56
+ '["hg38_end__range", [32200000, 32500000]], ' +
57
+ '["hg38_chromosome", "13"]]}]>',
58
+ SolveBio::RangeFilter.
59
+ new("hg38", "13", 32200000, 32500000).inspect)
60
+ end
61
+
62
+ def test_process_filters
63
+ # FIXME: add more and put in a loop.
64
+ filters = [[:omid, nil]]
65
+ expect = filters
66
+ assert_equal(expect.inspect,
67
+ SolveBio::Filter.process_filters(filters).inspect)
68
+ end
69
+
70
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = true
3
+ require 'test/unit'
4
+ require 'fileutils'
5
+ require_relative '../lib/credentials'
6
+
7
+ # Does .netrc reading and manipulation work?
8
+ class TestNetrc < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @netrc_path_save = ENV["NETRC_PATH"]
12
+ path = ENV["NETRC_PATH"] = File.join(File.dirname(__FILE__), 'data')
13
+ FileUtils.cp(File.join(path, 'netrc-save'), File.join(path, '.netrc'))
14
+ File.chmod(0600, "#{path}/.netrc")
15
+ end
16
+
17
+ def teardown
18
+ ENV["NETRC_PATH"] = @netrc_path_save
19
+ end
20
+
21
+ include SolveBio::Credentials
22
+
23
+ def test_netrc
24
+ assert netrc_path, 'Should get a location for .netrc'
25
+ end
26
+
27
+ def test_get_credentials
28
+ assert_equal ['rocky@example.com', 'shhhh'], get_credentials
29
+ end
30
+
31
+ def test_save_credentials
32
+ new_values = get_credentials.map{|x| x+"abc"}
33
+ save_credentials(*new_values)
34
+ assert_equal new_values, get_credentials, 'Should append "abc" to creds'
35
+ end
36
+
37
+ def test_delete_credentials
38
+ delete_credentials
39
+ assert_equal nil, get_credentials, 'Should be able to delete credentials'
40
+ end
41
+
42
+ end
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = true
3
+ require_relative 'helper'
4
+
5
+ class TestQueryBatch < Test::Unit::TestCase
6
+
7
+ TEST_DATASET_NAME = 'ClinVar/2.0.0-1/Variants'
8
+
9
+ if SolveBio::api_key
10
+
11
+ def setup
12
+ begin
13
+ @dataset = SolveBio::Dataset.retrieve(TEST_DATASET_NAME)
14
+ rescue SocketError
15
+ @dataset = nil
16
+ end
17
+ end
18
+
19
+ def test_invalid_batch_query
20
+ skip('Are you connected to the Internet?') unless @dataset
21
+ assert_raise SolveBio::Error do
22
+ SolveBio::BatchQuery
23
+ .new([
24
+ @dataset.query(:limit => 1, :fields => [:bogus_field]),
25
+ @dataset.query(:limit => 10).filter(:hg19_start__gt => 100000)
26
+ ]).execute
27
+ end
28
+
29
+ dataset2 = SolveBio::Dataset.retrieve('HGNC/1.0.0-1/HGNC')
30
+ results = SolveBio::BatchQuery
31
+ .new([
32
+ dataset2.query(:limit => 1),
33
+ @dataset.query(:limit => 10).filter(:hg19_start => 100000)
34
+ ]).execute
35
+ assert_equal(2, results.length)
36
+
37
+
38
+
39
+ end
40
+
41
+ def test_batch_query
42
+ skip('Are you connected to the Internet?') unless @dataset
43
+ queries = [
44
+ @dataset.query(:limit => 1),
45
+ @dataset.query(:limit => 10).filter(:hg19_start__gt => 100000)
46
+ ]
47
+ results = SolveBio::BatchQuery.new(queries).execute
48
+ assert_equal(2, results.size)
49
+ assert_equal(1, results[0]['results'].length)
50
+ assert_equal(10, results[1]['results'].size)
51
+ end
52
+
53
+
54
+ else
55
+ def test_skip
56
+ skip 'Please set SolveBio::api_key'
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,29 @@
1
+ $VERBOSE = true
2
+ require 'test/unit'
3
+ require_relative '../lib/query'
4
+
5
+ class TestQuery < Test::Unit::TestCase
6
+
7
+ def test_query_initialize
8
+ [SolveBio::PagingQuery, SolveBio::Query].each do |klass|
9
+ assert klass.new(5)
10
+ assert klass.new('5')
11
+ assert_raises TypeError do
12
+ # dataset id should be an Fixnum
13
+ klass.new(:limit => 10)
14
+ end
15
+ assert klass.new(5, :limit => 10)
16
+ assert klass.new(5.0, :limit => 10.0)
17
+ assert_raises RangeError do
18
+ # limit should be > 0
19
+ assert klass.new(5, :limit => -1)
20
+ end
21
+ assert_raises TypeError do
22
+ # limit should be a Fixnum
23
+ assert klass.new(5, :limit => 'a')
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+ end
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env ruby
2
+ $VERBOSE = true
3
+ require_relative 'helper'
4
+
5
+ class TestQueryPaging < Test::Unit::TestCase
6
+
7
+ TEST_DATASET_NAME = 'ClinVar/2.0.0-1/Variants'
8
+
9
+ if SolveBio::api_key
10
+
11
+ def setup
12
+ begin
13
+ @dataset = SolveBio::Dataset.retrieve(TEST_DATASET_NAME)
14
+ rescue SocketError
15
+ @dataset = nil
16
+ end
17
+ end
18
+
19
+ def test_query
20
+ skip('Are you connected to the Internet?') unless @dataset
21
+ results = @dataset.query(:paging=>true, :limit => 10)
22
+ # When paging is on, results.size should return the number
23
+ # of total number of results.
24
+ assert_equal(results.size, results.total,
25
+ 'results.size == results.total, paging=true')
26
+ end
27
+
28
+ # In paging queries, results.size should return the total number of
29
+ # results that exist. Yes, this is the same as test_query, but
30
+ # we revers the order of access, to make sure "warmup" is called.
31
+ def test_limit
32
+ skip('Are you connected to the Internet?') unless @dataset
33
+ limit = 10
34
+ results = @dataset.query(:paging=>true, :limit => limit)
35
+ assert_equal(results.total, results.length,
36
+ 'results.total == results.length, paging = true')
37
+ end
38
+
39
+
40
+ def test_paging
41
+ skip('Are you connected to the Internet?') unless @dataset
42
+ limit = 100
43
+ total = 7
44
+ results = @dataset.query(:paging => true, :limit => limit).
45
+ filter(:hg19_start__range => [140000000, 140050000])
46
+
47
+ assert_equal(total, results.size)
48
+
49
+ # Make sure we can iterate over the entire result set
50
+ i = 0
51
+ results.each_with_index do |val, j|
52
+ assert val, "Can retrieve filter item #{i}"
53
+ i = j
54
+ end
55
+ assert_equal(i, total-1)
56
+ end
57
+
58
+
59
+ def test_range
60
+ skip('Are you connected to the Internet?') unless @dataset
61
+ limit = 100
62
+ results = @dataset.query(:paging => true, :limit => limit).
63
+ filter(:hg19_start__range => [140000000, 140050000])[2..5]
64
+ assert_equal(3, results.size)
65
+
66
+ results = @dataset.query(:paging => true, :limit => limit).
67
+ filter(:hg19_start__range => [140000000, 140050000])[0..8]
68
+ assert_equal(7, results.size)
69
+ end
70
+
71
+ def test_paging_and_slice_equivalence
72
+ skip('Are you connected to the Internet?') unless @dataset
73
+ idx0 = 3
74
+ idx1 = 5
75
+
76
+ query = proc{
77
+ @dataset.query( :paging => true, :limit => 20).
78
+ filter(:hg19_start__range => [140000000, 140060000])[2..10]
79
+ }
80
+
81
+ results_slice = query.call()[idx0...idx1]
82
+ results_paging = []
83
+ query.call.each_with_index do |r, i|
84
+ break if i == idx1
85
+ results_paging << r if i >= idx0
86
+ end
87
+
88
+ assert_equal(results_slice.size, results_paging.size)
89
+
90
+ results_paging.size.times do |i|
91
+ id_a = results_paging[i][:hg19_start]
92
+ id_b = results_slice[i][:hg19_start]
93
+ assert_equal(id_a, id_b)
94
+ end
95
+ end
96
+
97
+
98
+ def test_caching
99
+ skip('Are you connected to the Internet?') unless @dataset
100
+ idx0 = 60
101
+ idx1 = 81
102
+
103
+ q = @dataset.query(:paging => true, :limit => 100)
104
+ # q = self.dataset.query(paging=True, limit=100) \
105
+ # .filter(omim_id__in=range(100000, 120000))
106
+ results_slice = q[idx0..idx1]
107
+ results_cached = q[idx0..idx1]
108
+
109
+ assert_equal(results_slice.size, results_cached.size)
110
+ results_slice.size-1.times do |i|
111
+ id_a = results_slice[i]['reference_allele']
112
+ id_b = results_cached[i]['reference_allele']
113
+ assert_equal(id_b, id_a)
114
+ end
115
+ end
116
+
117
+ else
118
+ def test_skip
119
+ skip 'Please set SolveBio::api_key'
120
+ end
121
+ end
122
+
123
+ end