intermine 0.99.03 → 1.00.00

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,14 +1,14 @@
1
1
  require 'rubygems'
2
2
  require 'rubygems/specification' unless defined?(Gem::Specification)
3
+ require 'rubygems/package_task'
3
4
  require 'rake/testtask'
4
- require 'rake/gempackagetask'
5
5
 
6
- gem 'rdoc', '=2.1.0'
7
- require 'rdoc/rdoc'
8
- require 'rake/rdoctask'
9
-
10
- gem 'darkfish-rdoc'
11
- require 'darkfish-rdoc'
6
+ #gem 'rdoc'# , '=2.1.0'
7
+ #require 'rdoc/rdoc'
8
+ #require 'rake/rdoctask'
9
+ #
10
+ #gem 'darkfish-rdoc'
11
+ #require 'darkfish-rdoc'
12
12
 
13
13
  def gemspec
14
14
  @gemspec ||= begin
@@ -38,30 +38,44 @@ task :release => :package do
38
38
  sh "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
39
39
  end
40
40
 
41
- Rake::GemPackageTask.new(gemspec) do |pkg|
41
+ Gem::PackageTask.new(gemspec) do |pkg|
42
42
  pkg.need_zip = true
43
43
  pkg.need_tar = true
44
-
45
44
  end
46
45
 
47
- Rake::TestTask.new do |t|
48
- t.libs << "test"
49
- t.test_files = FileList['test/unit_tests.rb']
50
- t.verbose = true
51
- end
52
46
 
53
- Rake::TestTask.new(:live_tests) do |t|
54
- t.libs << "test"
55
- t.test_files = FileList['test/live_test.rb'] << FileList['test/live_summary_test.rb'] << FileList['test/live_results.rb']
56
- t.verbose = true
57
- end
58
47
 
59
- Rake::RDocTask.new do |t|
60
- t.title = 'InterMine Webservice Client Documentation'
61
- t.rdoc_files.include 'README.rdoc'
62
- t.rdoc_files.include 'lib/**/*rb'
63
- t.main = 'README.rdoc'
64
- t.options += ['-SHN', '-f', 'darkfish']
48
+ namespace :test do
49
+
50
+ desc "Run the unit-tests"
51
+ Rake::TestTask.new(:unit) do |t|
52
+ t.libs << "test"
53
+ t.test_files = FileList['test/unit_tests.rb']
54
+ t.verbose = true
55
+ puts "Running UNIT TESTS"
56
+ end
57
+
58
+ desc "Run the live integration tests"
59
+ Rake::TestTask.new(:live) do |t|
60
+ t.libs << "test"
61
+ t.test_files = FileList['test/live_test.rb'] << FileList['test/live_summary_test.rb'] << FileList['test/live_results.rb']
62
+ t.verbose = false
63
+ puts "Running LIVE INTEGRATION TESTS"
64
+ end
65
+
66
+ desc "Run all tests"
67
+ task :all => [:unit, :live]
65
68
  end
66
69
 
70
+ desc "Run the default test-suite"
71
+ task :test => ["test:all"]
72
+
73
+ #Rake::RDocTask.new do |t|
74
+ # t.title = 'InterMine Webservice Client Documentation'
75
+ # t.rdoc_files.include 'README.rdoc'
76
+ # t.rdoc_files.include 'lib/**/*rb'
77
+ # t.main = 'README.rdoc'
78
+ # t.options += ['-SHN', '-f', 'darkfish']
79
+ #end
80
+
67
81
 
@@ -312,6 +312,54 @@ module InterMine::Lists
312
312
  @tags = @manager.tags_for(self)
313
313
  end
314
314
 
315
+ ENRICHMENT_DEFAULTS = {:correction => "Holm-Bonferroni", :maxp => 0.05}
316
+
317
+ # Retrieve the results of an enrichment calculation
318
+ #
319
+ # Get the results of an enrichment calculate_enrichment with the default parameter values:
320
+ #
321
+ # calculate_enrichment(widget)
322
+ #
323
+ # Pass optional parameters to the enrichment service:
324
+ #
325
+ # calculate_enrichment(widget, :correction => "Benjamini-Hochberg", :maxp => 0.1)
326
+ #
327
+ # The optional parameters are: :correction, :maxp, :filter
328
+ #
329
+ # Each result returned by the enrichment service is a hash with the following
330
+ # keys: "p-value", "identifier", "matches", "description". The Hash returned also allows
331
+ # key access with symbols.
332
+ #
333
+ def calculate_enrichment(widget, opts = {})
334
+ s = @manager.service
335
+ params = s.params.merge(ENRICHMENT_DEFAULTS).merge(opts).merge(:widget => widget, :list => @name)
336
+ uri = URI.parse(s.root + Service::LIST_ENRICHMENT_PATH)
337
+ res = Net::HTTP.post_form(uri, params)
338
+ return case res
339
+ when Net::HTTPSuccess
340
+ JSON.parse(res.body)["results"].map {|row| SymbolAcceptingHash[row] }
341
+ else
342
+ begin
343
+ container = JSON.parse(res.body)
344
+ raise ServiceError, container["error"]
345
+ rescue
346
+ res.error!
347
+ end
348
+ end
349
+ end
350
+
351
+ class SymbolAcceptingHash < Hash
352
+
353
+ def [](key)
354
+ return case key
355
+ when Symbol
356
+ return super(key.to_s.gsub(/[_]/, '-'))
357
+ else
358
+ return super(key)
359
+ end
360
+ end
361
+ end
362
+
315
363
  private
316
364
 
317
365
  # Used to interpret arguments to add and remove
@@ -675,10 +723,13 @@ module InterMine::Lists
675
723
  def make_list_names(objs)
676
724
  current_names = list_names
677
725
  return objs.map do |x|
678
- case
679
- when x.is_a?(List) then x.name
680
- when x.respond_to?(:list_upload_uri) then create_list(x).name
681
- when current_names.include?(x.to_s) then x.to_s
726
+ case x
727
+ when List
728
+ x.name
729
+ when x.respond_to?(:list_upload_uri)
730
+ create_list(x).name
731
+ when current_names.include?(x.to_s)
732
+ x.to_s
682
733
  else
683
734
  raise ArgumentError, "#{x} is not a list you can access"
684
735
  end
@@ -708,17 +759,15 @@ module InterMine::Lists
708
759
  else
709
760
  begin
710
761
  container = JSON.parse(response.body)
711
- err = container["error"]
762
+ raise ServiceError, container["error"]
712
763
  rescue
713
764
  response.error!
714
765
  end
715
- raise ServiceError, container["error"]
716
766
  end
717
767
  end
718
768
 
719
769
  # Routine for creating a list from a PathQuery::Query
720
770
  def create_list_from_query(query, tags=[], name=nil, description=nil)
721
- query = get_listable_query(query)
722
771
  uri = query.list_upload_uri
723
772
  list_params = {
724
773
  "listName" => name,
@@ -730,19 +779,6 @@ module InterMine::Lists
730
779
  return Net::HTTP.post_form(URI.parse(uri), params)
731
780
  end
732
781
 
733
- def get_listable_query(query)
734
- clone = query.clone()
735
- views = clone.views
736
- selected_classes = views.map {|x| x.prefix}.uniq {|p| p.to_s}
737
- if selected_classes.size == 1
738
- return clone.select(selected_classes.first.append("id"))
739
- elsif selected_classes.size == 0
740
- return clone.select("#{clone.root.name}.id")
741
- end
742
- # Bound to fail, but let the service provide the message.
743
- return clone
744
- end
745
-
746
782
  # Routine for creating a List in a webservice from a list of Ids.
747
783
  def create_list_from_ids(ids, type, tags=[], name=nil, description=nil)
748
784
  if @service.model.get_cd(type).nil?
@@ -402,46 +402,6 @@ module Metadata
402
402
  return q
403
403
  end
404
404
 
405
- # call-seq:
406
- # find(*attributes) => Enumerable[InterMineObject]
407
- #
408
- # Get the items in the database matching the identifiers.
409
- #
410
- # zen = model.table("Gene").find("zen")
411
- # puts zen.length, zen.organism.name
412
- #
413
- # find may retrun multiple results:
414
- #
415
- # genes = model.table("Gene").find("zen", "eve", "r", "h")
416
- #
417
- # The search mechanism used is a "lookup" constraint, so extra-values
418
- # may be provided to distinguish search terms by passing key-value pairs:
419
- #
420
- # starting_with_c = model.table("Gene").find("c*" => "D. melanogaster")
421
- #
422
- def find(*attrs)
423
- q = new_query
424
- q.select("*")
425
- attrs.each do |attr|
426
- if attr.is_a? Hash
427
- attr.each do |term, extra|
428
- q.or(@root, "LOOKUP", term, extra)
429
- end
430
- else
431
- q.or(@root, "LOOKUP", attr)
432
- end
433
- end
434
-
435
- c = q.count()
436
- if c < 1
437
- raise ItemNotFoundError
438
- elsif c == 1
439
- return q.results.first
440
- else
441
- return q.results
442
- end
443
- end
444
-
445
405
  # call-seq:
446
406
  # where(*constraints) => PathQuery::Query
447
407
  #
@@ -487,8 +447,13 @@ module Metadata
487
447
  # attributes (ie. columns that can hold values, rather than references to
488
448
  # other tables.)
489
449
  #
450
+ # The array returned will be sorted in alphabetical order by field-name.
451
+ #
490
452
  def attributes
491
- return @fields.select {|k, v| v.is_a?(AttributeDescriptor)}.map {|pair| pair[1]}
453
+ return @fields.
454
+ select {|_, v| v.is_a?(AttributeDescriptor)}.
455
+ sort {|(k0, _), (k1, _)| k0 <=> k1}.
456
+ map {|(_, v)| v}
492
457
  end
493
458
 
494
459
  # Returns a human readable string
@@ -580,11 +545,8 @@ module Metadata
580
545
  klass.class_eval do
581
546
  define_method(fd.name) do
582
547
  if instance_variable_get("@" + fd.name).nil?
583
- q = __cd__.select("id", fd.name + ".*").where(:id => objectId).outerjoin(fd.name)
584
- instance_var = q.results.first.instance_variable_get('@' + fd.name)
585
- if fd.is_a?(CollectionDescriptor) and instance_var.nil?
586
- instance_var = []
587
- end
548
+ q = __cd__.select(fd.name + ".*").where(:id => objectId)
549
+ instance_var = q.results.first[fd.name]
588
550
  instance_variable_set("@" + fd.name, instance_var)
589
551
  end
590
552
  return instance_variable_get("@" + fd.name)
@@ -614,16 +576,14 @@ module Metadata
614
576
  type = fd.referencedType
615
577
  if fd.is_a?(CollectionDescriptor)
616
578
  instance_var = []
617
- if not val.nil?
618
- val.each do |item|
619
- if item.is_a?(Hash)
620
- item = type.model.make_new(type.name, item)
621
- end
622
- if !item.is_a?(type)
623
- raise ArgumentError, "Arguments to #{fd.name} in #{@name} must be #{type.name}s"
624
- end
625
- instance_var << item
579
+ val.each do |item|
580
+ if item.is_a?(Hash)
581
+ item = type.model.make_new(type.name, item)
626
582
  end
583
+ if !item.is_a?(type)
584
+ raise ArgumentError, "Arguments to #{fd.name} in #{@name} must be #{type.name}s"
585
+ end
586
+ instance_var << item
627
587
  end
628
588
  instance_variable_set("@" + fd.name, instance_var)
629
589
  else
@@ -794,55 +754,11 @@ module Metadata
794
754
  end
795
755
  end
796
756
 
797
- # call-seq:
798
- # end => ClassDescriptor | ReferenceDescriptor | AttributeDescriptor
799
- #
800
- # Return the last element of this path
801
- #
802
- def end
803
- return @elements.last
804
- end
805
-
806
- # call-seq:
807
- # prefix => Path
808
- #
809
- # Return the Path one above this.
810
- def prefix
811
- if @elements.size == 1
812
- raise PathException, "Root paths do not have a prefix"
813
- end
814
- new_str = @elements[0, @elements.size - 1].map {|x| x.name}.join(".")
815
- return Path.new(new_str, @model, @subclasses)
816
- end
817
-
818
- # call-seq:
819
- # append(part, ...) => Path
820
- #
821
- # Return a new path by adding elements to this path.
822
- #
823
- def append(*parts)
824
- new_str = self.to_s + "." + parts.join(".")
825
- return Path.new(new_str, @model, @subclasses)
826
- end
827
-
828
757
  # Two paths can be said to be equal when they stringify to the same representation.
829
758
  def ==(other)
830
759
  return self.to_s == other.to_s
831
760
  end
832
761
 
833
- # Two paths are identical when they have the same everything.
834
- def eql?(other)
835
- begin
836
- return (self == other) && @model.eql?(other.model) && @subclasses.eql?(other.subclasses)
837
- rescue
838
- return false
839
- end
840
- end
841
-
842
- def hash
843
- return 17 * @model.hash * 11 * @subclasses.hash * 3 * to_s.hash
844
- end
845
-
846
762
  # Get the number of elements in the path
847
763
  def length
848
764
  return @elements.length
@@ -969,9 +885,6 @@ module Metadata
969
885
  end
970
886
  end
971
887
  end
972
-
973
- class ItemNotFoundError < RuntimeError
974
- end
975
888
  end
976
889
  end
977
890
 
@@ -616,10 +616,7 @@ module InterMine::PathQuery
616
616
  if y.end_with?("*")
617
617
  prefix = y.chomp(".*")
618
618
  path = make_path(prefix)
619
- attrs = path.end_cd.attributes.map {|x|
620
- prefix + "." + x.name
621
- }
622
- add_views(attrs)
619
+ add_views(path.end_cd.attributes.map {|x| prefix + "." + x.name})
623
620
  else
624
621
  path = make_path(y)
625
622
  path = make_path(y.to_s + ".id") unless path.is_attribute?
@@ -723,11 +720,8 @@ module InterMine::PathQuery
723
720
  #
724
721
  def add_sort_order(path, direction="ASC")
725
722
  p = self.path(path)
726
- selected = @views.map {|v| v.prefix}
727
- selected.push(@constraints.map {|c| c.path.is_attribute? ? c.path.prefix : c.path })
728
- selected.uniq!
729
- if !selected.include? p.prefix
730
- raise ArgumentError, "Sort order (#{p}) not on a selected class (#{selected.map {|v| v.to_s}.inspect} in #{self.name || 'unnamed query'})"
723
+ if !@views.include? p
724
+ raise ArgumentError, "Sort order (#{p}) not in view (#{@views.map {|v| v.to_s}.inspect} in #{self.name || 'unnamed query'})"
731
725
  end
732
726
  @sort_order << SortOrder.new(p, direction)
733
727
  return self
@@ -765,32 +759,6 @@ module InterMine::PathQuery
765
759
  @constraints << con
766
760
  return con
767
761
  end
768
-
769
- def or(*parameters)
770
- logic = @logic
771
- new_con = add_constraint(*parameters)
772
-
773
- if logic
774
- set_logic(LogicGroup.new(logic, "OR", new_con))
775
- elsif @constraints.size > 1
776
- set_logic(@constraints.map {|c| c.code }.join(" or "))
777
- end
778
-
779
- return self
780
- end
781
-
782
- def and(*parameters)
783
- logic = @logic
784
- new_con = add_constraint(*parameters)
785
-
786
- if logic
787
- set_logic(LogicGroup.new(logic, "AND", new_con))
788
- elsif @constraints.size > 1
789
- set_logic(@constraints.map {|c| c.code }.join(" and "))
790
- end
791
-
792
- return self
793
- end
794
762
 
795
763
  # Returns a Path object constructed from the given path-string,
796
764
  # taking the current state of the query into account (its data-model
@@ -855,7 +823,7 @@ module InterMine::PathQuery
855
823
  end
856
824
  parameters[:values] = subv.to_a
857
825
  elsif subv.is_a?(Lists::List)
858
- if subk == "=" or subk == "<" or subk == "<="
826
+ if subk == "="
859
827
  parameters[:op] = "IN"
860
828
  elsif subk == "!="
861
829
  parameters[:op] = "NOT IN"
@@ -863,19 +831,6 @@ module InterMine::PathQuery
863
831
  parameters[:op] = normalised_k
864
832
  end
865
833
  parameters[:value] = subv.name
866
- elsif subv.is_a? Query
867
- if subk == "=" or subk == "<" or subk == "<="
868
- parameters[:op] = "IN"
869
- elsif subk == "!="
870
- parameters[:op] = "NOT IN"
871
- else
872
- parameters[:op] = normalised_k
873
- end
874
- s = subv.service
875
- l = s.create_list(subv)
876
-
877
- parameters[:value] = l.name
878
-
879
834
  else
880
835
  parameters[:op] = normalised_k
881
836
  parameters[:value] = subv
@@ -988,7 +943,7 @@ module InterMine::PathQuery
988
943
  @classes = [
989
944
  SingleValueConstraint,
990
945
  SubClassConstraint,
991
- LookupConstraint, MultiValueConstraint,
946
+ LookupConstraint, MultiValueConstraint, RangeConstraint,
992
947
  UnaryConstraint, LoopConstraint, ListConstraint]
993
948
 
994
949
  @query = query
@@ -1014,14 +969,9 @@ module InterMine::PathQuery
1014
969
 
1015
970
  attr_keys = parameters.keys
1016
971
  suitable_classes = @classes.select { |cls|
1017
- is_suitable = true
1018
- attr_keys.each { |key|
1019
- is_suitable = is_suitable && (cls.method_defined?(key))
1020
- if key.to_s == "op"
1021
- is_suitable = is_suitable && cls.valid_ops.include?(parameters[key])
1022
- end
1023
- }
1024
- is_suitable
972
+ attr_keys.reduce(true) do |suitable, k|
973
+ suitable && cls.method_defined?(k) && (k.to_s != "op" or cls.valid_ops.include?(parameters[k]))
974
+ end
1025
975
  }
1026
976
  if suitable_classes.size > 1
1027
977
  raise ArgumentError, "More than one class found for #{parameters.inspect}"
@@ -1402,10 +1352,31 @@ module InterMine::PathQuery
1402
1352
  end
1403
1353
  end
1404
1354
 
1355
+ class RangeConstraint < MultiValueConstraint
1356
+
1357
+ VALID_OPS = [
1358
+ "WITHIN", "OUTSIDE",
1359
+ "CONTAINS", "DOES NOT CONTAIN",
1360
+ "OVERLAPS", "DOES NOT OVERLAP"
1361
+ ]
1362
+
1363
+ def self.valid_ops
1364
+ return VALID_OPS
1365
+ end
1366
+
1367
+ def validate
1368
+ # no-op
1369
+ end
1370
+ end
1371
+
1405
1372
  class TemplateMultiValueConstraint < MultiValueConstraint
1406
1373
  include TemplateConstraint
1407
1374
  end
1408
1375
 
1376
+ class TemplateRangeConstraint < RangeConstraint
1377
+ include TemplateConstraint
1378
+ end
1379
+
1409
1380
  class SortOrder
1410
1381
  include PathFeature
1411
1382
  attr_accessor :direction
@@ -85,12 +85,12 @@ module InterMine::Results
85
85
  def [](arg, length=nil)
86
86
  unless length.nil?
87
87
  raise ArgumentError, "when providing a length, the first argument must be an Integer" unless arg.is_a? Integer
88
- return @results[arg, length].map {|x| value_of(x)}
88
+ return @results[arg, length].map {|x| x["value"]}
89
89
  end
90
90
 
91
91
  case arg
92
92
  when Range
93
- return @results[arg].map {|x| value_of(x)}
93
+ return @results[arg].map {|x| x["value"]}
94
94
  when Integer
95
95
  idx = arg
96
96
  else
@@ -101,19 +101,19 @@ module InterMine::Results
101
101
 
102
102
  cell = @results[idx]
103
103
 
104
- raise IndexError, "Argument out of range" if @columns[idx].nil?
104
+ raise IndexError, "Argument out of range" if cell.nil?
105
105
 
106
- return value_of(cell)
106
+ return cell["value"]
107
107
  end
108
108
 
109
109
  # Returns the first value in this row
110
110
  def first
111
- return value_of(@results[0])
111
+ return @results[0]["value"]
112
112
  end
113
113
 
114
114
  # Returns the last value in this row
115
115
  def last
116
- return value_of(@results.last)
116
+ return @results.last["value"]
117
117
  end
118
118
 
119
119
  # Iterate over the values in this row in the
@@ -134,11 +134,9 @@ module InterMine::Results
134
134
  def each(&block)
135
135
  if block
136
136
  if block.arity == 1
137
- @results.each {|x| block.call(value_of(x))}
137
+ @results.each {|x| block.call(x["value"])}
138
138
  else block.arity == 2
139
- (0 ... @results.size).to_a.each {|i|
140
- block.call(@columns[i], value_of(@results[i]))
141
- }
139
+ (0 ... @results.size).to_a.each {|i| block.call(@columns[i], @results[i]["value"])}
142
140
  end
143
141
  end
144
142
  return self
@@ -156,7 +154,7 @@ module InterMine::Results
156
154
 
157
155
  # Return an Array version of the row.
158
156
  def to_a
159
- return @results.map {|x| value_of(x)}
157
+ return @results.map {|x| x["value"]}
160
158
  end
161
159
 
162
160
  # Return a Hash version of the row. All keys in this
@@ -187,15 +185,11 @@ module InterMine::Results
187
185
  # CSV or TSV file. The optional separator argument will be used to delimit
188
186
  # columns
189
187
  def to_csv(sep="\t")
190
- return @results.map {|x| value_of(x).inspect}.join(sep)
188
+ return @results.map {|x| x["value"].inspect}.join(sep)
191
189
  end
192
190
 
193
191
  private
194
192
 
195
- def value_of(cell)
196
- return cell["value"]
197
- end
198
-
199
193
  # Return the index for a string or symbol key.
200
194
  def index_for(key)
201
195
  if @indexes.nil?
@@ -215,13 +209,6 @@ module InterMine::Results
215
209
  end
216
210
  end
217
211
 
218
- class NewResultRow < ResultsRow
219
-
220
- def value_of(cell)
221
- return cell
222
- end
223
- end
224
-
225
212
  # The class responsible for retrieving results and processing them
226
213
  #
227
214
  # query.each_row do |row|
@@ -263,13 +250,11 @@ module InterMine::Results
263
250
 
264
251
  # Iterate over the result set one ResultsRow at a time
265
252
  def each_row
266
- cls = @query.service.version >= 8 ? NewResultRow : ResultsRow
267
- format = @query.service.version >= 8 ? "json" : "jsonrows"
268
253
  processor = lambda {|line|
269
254
  x = line.chomp.chomp(",")
270
- x.empty? ? nil : cls.new(x, @query.views)
255
+ x.empty? ? nil : ResultsRow.new(x, @query.views)
271
256
  }
272
- read_result_set(params(format), processor) {|x|
257
+ read_result_set(params("jsonrows"), processor) {|x|
273
258
  yield x
274
259
  }
275
260
  end
@@ -109,6 +109,7 @@ module InterMine
109
109
  LIST_INTERSECTION_PATH = "/lists/intersect/json"
110
110
  LIST_SUBTRACTION_PATH = "/lists/subtract/json"
111
111
  LIST_TAG_PATH = "/list/tags/json"
112
+ LIST_ENRICHMENT_PATH = "/list/enrichment"
112
113
 
113
114
  # The webservice version. An integer that
114
115
  # supplies information about what features are supported.
@@ -3,6 +3,9 @@ module Intermine
3
3
  # Webservice Client Version number
4
4
  #
5
5
  # Changes:
6
+ # 1.00.00 - Up to make use of new features of the InterMine 1.0 API
7
+ # * Enrichment queries
8
+ # * Range constraints
6
9
  # 0.98.11 - * InterMineObjects now lazily fetch their references
7
10
  # if nil. Note that while extremely convenient,
8
11
  # explicit prefetching will be much more efficient
@@ -12,10 +15,5 @@ module Intermine
12
15
  # 0.98.10 - Added status property to lists
13
16
  # 0.98.09 - Major changes to results - now with thorough-going Enumerable support
14
17
  # 0.98.08 - Added column summary support
15
- # 0.99.00 - Added coercion from query to lists in "IN/NOT IN" constraints
16
- # - Added support for "json" format (performance) improvement
17
- # 0.99.01 - Added support for sort-orders on selected classes which are not in the view
18
- # 0.99.02 - Fixed bug with null values in new result rows (resulting commonly from outer joins)
19
- # 0.99.03 - Fixed handling of null references and empty collections in lazy reference fetching.
20
- VERSION = "0.99.03"
18
+ VERSION = "1.00.00"
21
19
  end
@@ -0,0 +1,164 @@
1
+ require File.dirname(__FILE__) + "/test_helper.rb"
2
+
3
+ require "test/unit"
4
+ require "intermine/service"
5
+ require "intermine/results"
6
+
7
+ class LiveResultsTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @service = Service.new("http://localhost/intermine-test")
11
+ @max = 50
12
+ @q = @service.query("Employee").select("*", "department.*").where(:age => {:lt => @max})
13
+ @empty = @service.query("Employee").where(:name => "some-non-existant-value")
14
+ @exp_count = 82
15
+ @expected_last = "Didier Legu\303\251lec"
16
+ @expected_last_summary = "Vincent"
17
+ @expected_last_obj = "Both Quotes '\""
18
+ @expected_target = 37.02439
19
+ @expected_two_vowels = 31
20
+ @exp_trideps = 5
21
+ @exp_s_deps = 29
22
+ @exp_row_size = 7
23
+ @rows_args = []
24
+ @results_args = []
25
+ @summary_args = []
26
+ @count_args = []
27
+ @dep_size = 3
28
+ end
29
+
30
+ def testRowIteration
31
+ count = 0
32
+ @q.rows(*@rows_args).each do |row|
33
+ assert_equal(@exp_row_size, row.size)
34
+ assert(row["age"].is_a? Fixnum)
35
+ assert(row["age"] < @max)
36
+ assert(row["name"].is_a? String)
37
+ count += 1
38
+ end
39
+ assert_equal(@exp_count, count)
40
+ end
41
+
42
+ def testEmptyRows
43
+ count = 0
44
+ @empty.rows.each do
45
+ count += 1
46
+ end
47
+ assert_equal(0, count)
48
+ end
49
+
50
+ def testRowMapping
51
+ names = @q.rows(*@rows_args).map {|r| r["name"]}
52
+ assert_equal(@exp_count, names.length)
53
+ assert_equal(@expected_last, names.last)
54
+ end
55
+
56
+ def testRowFolding
57
+ average = @q.rows(*@rows_args).reduce(0.0) {|m, i| m + i["age"]} / @q.count(*@count_args)
58
+ target = @expected_target
59
+ assert(average > target * 0.999999)
60
+ assert(average < target * 1.000001)
61
+ end
62
+
63
+ def testRowFiltering
64
+ two_vowels = @q.rows(*@rows_args).select {|r| r["name"].match(/[aeiou]{2}/) }
65
+ assert_equal(@expected_two_vowels, two_vowels.length)
66
+ end
67
+
68
+ def testObjectIteration
69
+ count = 0
70
+ @q.results(*@results_args).each do |emp|
71
+ assert(emp.is_a? @q.model.table("Employee"))
72
+ assert(emp.age.is_a? Fixnum)
73
+ assert(emp.age < @max)
74
+ assert(emp.name.is_a? String)
75
+ count += 1
76
+ end
77
+ assert_equal(@exp_count, count)
78
+ end
79
+
80
+ def testEmptyObjects
81
+ count = 0
82
+ @empty.results.each do
83
+ count += 1
84
+ end
85
+ assert_equal(0, count)
86
+ end
87
+
88
+ def testObjectMapping
89
+ names = @q.results(*@results_args).map {|r| r.name}
90
+ assert_equal(@exp_count, names.length)
91
+ assert_equal(@expected_last_obj, names.last)
92
+ end
93
+
94
+ def testObjectFolding
95
+ average = @q.results(*@results_args).reduce(0.0) {|m, i| m + i.age} / @q.count(*@count_args)
96
+ target = @expected_target
97
+ assert(average > target * 0.999999, "Checking lower bound on #{average}")
98
+ assert(average < target * 1.000001, "Checking upper bound on #{average}")
99
+ end
100
+
101
+ def testObjectFiltering
102
+ emps_in_s_deps = @q.results(*@results_args).select {|o| o.department.name.start_with? "S"}
103
+ assert_equal(@exp_s_deps, emps_in_s_deps.length)
104
+ end
105
+
106
+ def testSummaryIteration
107
+ count = 0
108
+ @q.summaries("name", *@summary_args).each do |summary|
109
+ assert_equal(1, summary["count"])
110
+ count += 1
111
+ end
112
+ assert_equal(@exp_count, count)
113
+ end
114
+
115
+ def testEmptySummaries
116
+ count = 0
117
+ @empty.summaries("name").each do
118
+ count += 1
119
+ end
120
+ assert_equal(0, count)
121
+ end
122
+
123
+ def testSummaryMapping
124
+ names = @q.summaries("name", *@summary_args).map {|s| s["item"]}
125
+ assert_equal(@exp_count, names.length)
126
+ assert_equal(@expected_last_summary, names.last)
127
+ end
128
+
129
+ def testSummaryFolding
130
+ sum = @q.summaries("name", *@summary_args).reduce(0) {|m, i| m + i["count"]}
131
+ assert_equal(@q.count(*@count_args), sum)
132
+ end
133
+
134
+ def testSummaryFiltering
135
+ trideps = @q.summaries("department.name", *@summary_args).select {|s| s["count"] == @dep_size}
136
+ assert_equal(@exp_trideps, trideps.length)
137
+ end
138
+ end
139
+
140
+ class LiveTemplateResultsTest < LiveResultsTest
141
+
142
+ def setup
143
+ @service = Service.new("http://localhost/intermine-test")
144
+ @q = @service.template("employeesOverACertainAgeFromDepartmentA")
145
+ @empty = @q
146
+ @exp_count = 18
147
+ @expected_last = "Tim Canterbury"
148
+ @expected_last_summary = "Tim Canterbury"
149
+ @expected_last_obj = "Fatou"
150
+ @expected_target = 47.277778
151
+ @expected_two_vowels = 4
152
+ @dep_size = 18
153
+ @exp_trideps = 1
154
+ @exp_s_deps = 18
155
+ @max = 69
156
+ @rows_args = [{"B" => "Sales"}]
157
+ @results_args = [{"B" => "Sales"}]
158
+ @summary_args = [{"B" => "Sales"}]
159
+ @count_args = [{"B" => "Sales"}]
160
+ @exp_row_size = 3
161
+
162
+ end
163
+ end
164
+
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + "/test_helper.rb"
2
+
3
+ require "test/unit"
4
+ require "intermine/service"
5
+
6
+ class LiveSummaryTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ @service = Service.new("http://localhost/intermine-test")
10
+ @query = @service.query("Employee").where(:age => {:lt => 50})
11
+ end
12
+
13
+ def testIteration
14
+ @query.summaries("age").each {|summary|
15
+ assert_equal("37.0243902439024390", summary["average"])
16
+ assert(summary["max"] < 50)
17
+ }
18
+
19
+ count = 0
20
+ @query.summaries("name").each {|summary|
21
+ assert_equal(1, summary["count"])
22
+ count += 1
23
+ }
24
+ assert_equal(count, @query.count)
25
+
26
+ end
27
+
28
+ def testNumericSummary
29
+ summary = @query.summarise("age")
30
+ assert(summary["max"] < 50)
31
+ # Work around float comparison errors, grrr
32
+ assert(summary["average"] > 37.024)
33
+ assert(summary["average"] < 37.025)
34
+ end
35
+
36
+ def testNonNumericSummary
37
+ summary = @query.summarise("name")
38
+ assert_equal(1, summary["Tim Canterbury"])
39
+ end
40
+
41
+ def testTop
42
+ summary = @query.summaries("department.name")
43
+ top = summary.first
44
+ assert_equal("Warehouse", top["item"])
45
+ assert_equal(12, top["count"])
46
+ end
47
+
48
+ def testTemplateSummary
49
+ template = @service.template("CEO_Rivals")
50
+ template_params = {"A" => {"!=" => "Charles Miner"}}
51
+
52
+ summary = template.summarise("salary", template_params)
53
+ assert_equal(529119.4, summary["average"])
54
+
55
+ summary = template.summarise("company.name", template_params)
56
+ assert_equal(1, summary["Gogirep"])
57
+ end
58
+
59
+ end
data/test/live_test.rb CHANGED
@@ -6,7 +6,7 @@ require "intermine/service"
6
6
  class LiveDemoTest < Test::Unit::TestCase
7
7
 
8
8
  def setup
9
- @service = Service.new("localhost/intermine-test", "test-user-token")
9
+ @service = Service.new("http://localhost/intermine-test", "test-user-token")
10
10
  @temp_lists = []
11
11
  end
12
12
 
@@ -48,10 +48,10 @@ class LiveDemoTest < Test::Unit::TestCase
48
48
  def testListEnumerability
49
49
  list = @service.list("My-Favourite-Employees")
50
50
  names = list.map {|emp| emp.name }
51
- exp = ["David Brent", "Neil Godwin", "Bernd Stromberg", "Timo Becker"]
51
+ exp = [ "David Brent", "Neil Godwin", "Bernd Stromberg", "Timo Becker"]
52
52
  assert_equal(exp, names)
53
53
 
54
- old = list.select {|emp| emp.age > 42}
54
+ old = list.select {|emp| emp.age > 43}
55
55
  assert_equal(1, old.size)
56
56
  assert_equal("Neil Godwin", old.first.name)
57
57
 
@@ -63,23 +63,23 @@ class LiveDemoTest < Test::Unit::TestCase
63
63
  list = @service.list("My-Favourite-Employees")
64
64
 
65
65
  deps = list.map {|emp| emp.department.name }
66
- exp = ["Sales", "Human Resources",
67
- "Schadensregulierung M-Z", "Schadensregulierung"]
66
+ exp = ["Sales", "Human Resources", "Schadensregulierung M-Z", "Schadensregulierung"]
68
67
  assert_equal(exp, deps)
69
68
 
70
69
  comps = list.map {|emp| emp.department.company.name }
71
- exp = [ "Wernham-Hogg","Wernham-Hogg",
72
- "Capitol Versicherung AG", "Capitol Versicherung AG"]
70
+ exp = ["Wernham-Hogg", "Wernham-Hogg", "Capitol Versicherung AG", "Capitol Versicherung AG"]
73
71
  assert_equal(exp, comps)
74
72
  end
75
73
 
76
74
  def testLazyCollectionFetching
77
75
  list = @service.list("My-Favourite-Employees")
78
76
  emps = list.map {|manager| manager.department.employees.map {|employee| employee.age} }
79
- exp = [[41, 36, 55, 34, 61, 61],
80
- [44, 49, 62],
81
- [37, 45, 30, 64, 46, 58],
82
- [37, 49, 39, 57, 36, 59]]
77
+ exp = [
78
+ [34, 36, 41, 55, 61, 61],
79
+ [44, 49, 62],
80
+ [30, 37, 45, 46, 58, 64],
81
+ [36, 37, 39, 49, 57, 59]
82
+ ]
83
83
  assert_equal(exp, emps)
84
84
 
85
85
  sum = list.reduce(0) {|m, manager| m + manager.department.employees.reduce(0) {|n, emp| n + emp.age}}
@@ -130,15 +130,10 @@ class LiveDemoTest < Test::Unit::TestCase
130
130
  assert_equal(tags.sort, new_list.tags.sort)
131
131
  end
132
132
 
133
- def testCoercingQueriesToLists
134
- q1 = @service.query("Bank")
135
- q2 = @service.query("Bank").where("corporateCustomers.id" => {'!=' => nil})
136
-
137
- assert_equal(2, @service.query("Bank").where("Bank" => {:not_in => q2}).count)
138
-
139
- l = @service.subtract([q1], [q2])
140
- @temp_lists << l
141
- assert_equal(2, l.size)
133
+ def testEnrichment
134
+ l = @service.list("My-Favourite-Employees")
135
+ contractors = l.calculate_enrichment :contractor_enrichment, :maxp => 1.0
136
+ assert_equal("Vikram", contractors.first[:identifier])
142
137
  end
143
138
 
144
139
  end
data/test/test_query.rb CHANGED
@@ -640,6 +640,20 @@ class TestQuery < Test::Unit::TestCase
640
640
  assert_equal(conA.values, %w{Sales Marketing Janitorial})
641
641
  end
642
642
 
643
+ def test_range_constraints
644
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
645
+ query.add_constraint({
646
+ :path => "age",
647
+ :op => "WITHIN",
648
+ :values => %w{1..10 30..35}
649
+ })
650
+
651
+ conA = query.constraints.first
652
+ assert_equal(conA.path.to_s, "Employee.age")
653
+ assert_equal(conA.op, "WITHIN")
654
+ assert_equal(conA.values, ["1..10", "30..35"])
655
+ end
656
+
643
657
  def test_bad_multi_constraint
644
658
  query = InterMine::PathQuery::Query.new(@model, "Employee")
645
659
  assert_raise ArgumentError do
@@ -848,12 +862,6 @@ class TestQuery < Test::Unit::TestCase
848
862
 
849
863
  assert_equal(query.sort_order.last.path, "Employee.name")
850
864
  assert_equal(query.sort_order.last.direction, "DESC")
851
-
852
- query.add_sort_order("fullTime")
853
-
854
- assert_equal(query.sort_order.last.path, "Employee.fullTime")
855
- assert_equal(query.sort_order.last.direction, "ASC")
856
-
857
865
  end
858
866
 
859
867
  def test_subclassed_sort_order
@@ -981,6 +989,11 @@ class TestQuery < Test::Unit::TestCase
981
989
  :value => "zop",
982
990
  :extra_value => "zip"
983
991
  })
992
+ query.add_constraint({
993
+ :path => "age",
994
+ :op => "WITHIN",
995
+ :values => %w{1..10 30..35}
996
+ })
984
997
  query.add_constraint({
985
998
  :path => "Employee",
986
999
  :sub_class => "Manager"
@@ -998,6 +1011,9 @@ class TestQuery < Test::Unit::TestCase
998
1011
  "<constraint loopPath='Employee.department.manager' op='=' code='E' path='Employee'/>" +
999
1012
  "<constraint op='LOOKUP' code='F' value='quux' path='Employee'/>" +
1000
1013
  "<constraint extraValue='zip' op='LOOKUP' code='G' value='zop' path='Employee'/>" +
1014
+ "<constraint op='WITHIN' code='H' path='Employee.age'>" +
1015
+ "<value>1..10</value><value>30..35</value>" +
1016
+ "</constraint>" +
1001
1017
  "</query>"
1002
1018
 
1003
1019
  compare_xml(expected, query.to_xml.to_s)
@@ -12,14 +12,9 @@ class TestResults < Test::Unit::TestCase
12
12
  super
13
13
  file = File.new(
14
14
  File.dirname(__FILE__) + "/data/resultrow.json", "r")
15
- file2 = File.new(
16
- File.dirname(__FILE__) + "/data/resultrow_new.json", "r")
17
15
  @data = file.read
18
- @data2 = file2.read
19
16
  @json = JSON.parse(@data)
20
- @json2 = JSON.parse(@data2)
21
17
  @view = ["Company.departments.name","Company.departments.manager.name", "Company.departments.manager.age"]
22
- @view2 = ["Company.departments.name","Company.departments.manager.name", "Company.departments.manager.age", "Company.address.address"]
23
18
  @bad_view = ["Company.departments.name","Company.departments.manager.name"]
24
19
  end
25
20
 
@@ -47,31 +42,6 @@ class TestResults < Test::Unit::TestCase
47
42
  end
48
43
  end
49
44
 
50
- def test_array_access2
51
-
52
- rr = NewResultRow.new(@data2, @view2)
53
-
54
- assert_equal(rr[0], "DepartmentA1")
55
- assert_equal(rr[1], "EmployeeA1")
56
-
57
- rr = NewResultRow.new(@json2, @view2)
58
-
59
- assert_equal(rr[0], "DepartmentA1")
60
- assert_equal(rr[1], "EmployeeA1")
61
-
62
- assert_equal(rr[1..2], ["EmployeeA1", 33])
63
- assert_equal(rr[0, 2], ["DepartmentA1", "EmployeeA1"])
64
-
65
- assert_equal(rr.first, "DepartmentA1")
66
- assert_equal(rr[3], nil)
67
- assert_equal(rr.last, nil)
68
-
69
- assert_raise IndexError do
70
- rr[4]
71
- end
72
-
73
- end
74
-
75
45
  def test_array_access
76
46
 
77
47
  rr = ResultsRow.new(@data, @view)
data/test/test_sugar.rb CHANGED
@@ -32,13 +32,14 @@ class TestQuerySugar < Test::Unit::TestCase
32
32
 
33
33
  def test_view_expansion
34
34
  q = @model.table("Employee").select("*", "department.*")
35
- expected = ["Employee.name",
35
+ expected = [
36
+ "Employee.age",
36
37
  "Employee.end",
37
- "Employee.id",
38
38
  "Employee.fullTime",
39
- "Employee.age",
40
- "Employee.department.name",
41
- "Employee.department.id"]
39
+ "Employee.id",
40
+ "Employee.name",
41
+ "Employee.department.id",
42
+ "Employee.department.name"]
42
43
 
43
44
  assert_equal(expected, q.views.map {|x| x.to_s})
44
45
  end
@@ -50,7 +51,7 @@ class TestQuerySugar < Test::Unit::TestCase
50
51
  where(:name => {"=" => nil}).
51
52
  where(:fullTime => {"!=" => nil})
52
53
 
53
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
54
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
54
55
  "<constraint op='IS NULL' code='A' path='Employee.age'/>" +
55
56
  "<constraint op='IS NULL' code='B' path='Employee.name'/>" +
56
57
  "<constraint op='IS NOT NULL' code='C' path='Employee.fullTime'/>" +
@@ -68,7 +69,7 @@ class TestQuerySugar < Test::Unit::TestCase
68
69
  where("department.name" => {:contains => "foo"}).
69
70
  where(:name => {"!=" => "bar"})
70
71
 
71
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
72
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
72
73
  "<constraint op='=' code='A' value='foo' path='Employee.name'/>" +
73
74
  "<constraint op='=' code='B' value='10' path='Employee.age'/>" +
74
75
  "<constraint op='&lt;' code='C' value='200' path='Employee.end'/>" +
@@ -90,7 +91,7 @@ class TestQuerySugar < Test::Unit::TestCase
90
91
  where(:name => {:ne => "bar"}).
91
92
  where(:name => {:== => "zop"})
92
93
 
93
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
94
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
94
95
  "<constraint op='&lt;' code='A' value='100' path='Employee.age'/>" +
95
96
  "<constraint op='&gt;' code='B' value='200' path='Employee.age'/>" +
96
97
  "<constraint op='&lt;=' code='C' value='300' path='Employee.age'/>" +
@@ -110,7 +111,7 @@ class TestQuerySugar < Test::Unit::TestCase
110
111
  where(:department => {:lookup => "foo"}).
111
112
  where("department.company" => {:lookup => "foo", :with => "extra"})
112
113
 
113
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
114
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
114
115
  "<constraint op='LOOKUP' code='A' value='foo' path='Employee.department'/>" +
115
116
  "<constraint extraValue='extra' op='LOOKUP' code='B' value='foo' path='Employee.department.company'/>" +
116
117
  "</query>"
@@ -127,7 +128,7 @@ class TestQuerySugar < Test::Unit::TestCase
127
128
  where("Employee.department" => {:in => "a list"}).
128
129
  where("Employee.department.company" => {:not_in => "a list"})
129
130
 
130
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
131
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
131
132
  "<constraint op='IN' code='A' value='test-list' path='Employee'/>" +
132
133
  "<constraint op='IN' code='B' value='test-list' path='Employee.department.manager'/>" +
133
134
  "<constraint op='NOT IN' code='C' value='test-list' path='Employee.department.manager'/>" +
@@ -152,7 +153,7 @@ class TestQuerySugar < Test::Unit::TestCase
152
153
  where("department.manager.age" => {:none_of => [46, 47]}).
153
154
  where("department.manager.end" => {:one_of => [56, 57]})
154
155
 
155
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
156
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
156
157
  "<constraint op='ONE OF' code='A' path='Employee.age'>" +
157
158
  "<value>30</value><value>31</value><value>32</value><value>33</value><value>34</value><value>35</value>" +
158
159
  "</constraint>" +
@@ -194,7 +195,7 @@ class TestQuerySugar < Test::Unit::TestCase
194
195
  where("department.company.CEO" => {:is => "department.manager"}).
195
196
  where("department.company.CEO" => {:is_not => "department.employees"})
196
197
 
197
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
198
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
198
199
  "<constraint op='=' loopPath='Employee.department.manager' code='A' path='Employee.department.company.CEO'/>" +
199
200
  "<constraint op='!=' loopPath='Employee.department.employees' code='B' path='Employee.department.company.CEO'/>" +
200
201
  "</query>"
@@ -209,7 +210,7 @@ class TestQuerySugar < Test::Unit::TestCase
209
210
  where("department.employees" => manager).
210
211
  where("department.employees" => {:sub_class => "CEO"})
211
212
 
212
- expected = "<query model='testmodel' sortOrder='Employee.name ASC' view='Employee.name Employee.end Employee.id Employee.fullTime Employee.age'>" +
213
+ expected = "<query model='testmodel' sortOrder='Employee.age ASC' view='Employee.age Employee.end Employee.fullTime Employee.id Employee.name'>" +
213
214
  "<constraint type='Manager' path='Employee.department.employees'/>" +
214
215
  "<constraint type='CEO' path='Employee.department.employees'/>" +
215
216
  "</query>"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: intermine
3
3
  version: !ruby/object:Gem::Version
4
- hash: 405
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 99
9
- - 3
10
- version: 0.99.03
9
+ - 0
10
+ version: 1.00.00
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex Kalderimis
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-18 00:00:00 Z
18
+ date: 2012-10-08 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: json
@@ -133,6 +133,8 @@ files:
133
133
  - test/data/resultrow.json
134
134
  - test/data/resultset.json
135
135
  - test/data/testmodel_model.xml
136
+ - test/live_results.rb
137
+ - test/live_summary_test.rb
136
138
  - test/live_test.rb
137
139
  - test/test.rb
138
140
  - test/test_helper.rb
@@ -148,7 +150,6 @@ files:
148
150
  - LICENCE
149
151
  - Rakefile
150
152
  - README.rdoc
151
- - TODO
152
153
  - Gemfile
153
154
  - contact_header.rdoc
154
155
  homepage: http://www.intermine.org
@@ -184,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
185
  requirements: []
185
186
 
186
187
  rubyforge_project: intermine
187
- rubygems_version: 1.7.2
188
+ rubygems_version: 1.8.15
188
189
  signing_key:
189
190
  specification_version: 3
190
191
  summary: Webservice Client Library for InterMine Data-Warehouses
data/TODO DELETED
@@ -1,3 +0,0 @@
1
- json formats (and benchmarks)
2
- test for CD.find
3
-