class InterMine::Lists::ListManager
Synopsis ¶ ↑
An internal class for managing lists throughout the lifetime of a program. The main Service
object delegates list functionality to this class.
# Creation list = service.create_list("path/to/some/file.txt", "Gene", "my-favourite-genes") # Retrieval other_list = service.list("my-previously-saved-list") # Combination intersection = service.intersection_of([list, other_list]) # Deletion service.delete_lists(list, other_list)
Description ¶ ↑
This class contains logic for reading and updating the lists available to a given user at a webservice. This class in particular is responsible for parsing list responses, and performing the operations that combine lists into new result sets (intersection, union, symmetric difference, subtraction).
- author
-
Alex Kalderimis dev@intermine.org
- homepage
- Licence
-
Copyright (C) 2002-2011 FlyMine
This code may be freely distributed and modified under the terms of the GNU Lesser General Public Licence. This should be distributed with the code. See the LICENSE file for more information or www.gnu.org/copyleft/lesser.html.
Constants
- DEFAULT_DESCRIPTION
The description given by default to all new lists for which you do not provide a description explicitly. The purpose of this is to help you identify automatically created lists in you profile.
- DEFAULT_LIST_NAME
The name given by default to all lists you do not explicitly name
l = service.create_list("genes.txt", "Gene") puts l.name => "my_list_1"
Attributes
The service this manager belongs to
The temporary lists created in this session. These will be deleted at program exit.
Public Class Methods
Construct a new ListManager
.
You will never need to call this constructor yourself.
# File lib/intermine/lists.rb 492 def initialize(service) 493 @service = service 494 @lists = {} 495 @temporary_lists = [] 496 @uri = URI.parse(@service.root) 497 @http = Net::HTTP.new(@uri.host, @uri.port) 498 if @uri.scheme == 'https' 499 @http.use_ssl = true 500 end 501 do_at_exit(self) 502 end
Public Instance Methods
Create a new List
with the given content.¶ ↑
Creates a new List
and stores it on the appropriate webservice:
Arguments:
content
-
Can be a string with delimited identifiers, an
Array
of identifiers, a File object containing identifiers, or a name of an unopened readable file containing identifiers. It can also be anotherList
(in which case the list is cloned) or a query that describes a result set. type
-
Required when identifiers are being given (but not when the content is a
PathQuery::Query
or aList
. This should be the kind of object to look for (such as “Gene”). tags
-
An
Array
of tags to apply to the new list. If a list is supplied as the content, these tags will be added to the existing tags. name
-
The name of the new list. One will be generated if none is provided.
Lists
created with generated names are considered temporary and will be deleted upon program exit. description
-
An informative description of the list
# With Array of Ids list = service.create_list(%{eve bib zen}) # From a file list = service.create_list("path/to/some/file.txt", "Gene", [], "my-stored-genes") # With a query list = service.create_list(service.query("Gene").select(:id).where(:length => {"<" => 500}))
# File lib/intermine/lists.rb 577 def create_list(content, type=nil, tags=[], name=nil, description=nil) 578 name ||= get_unused_list_name 579 description ||= DEFAULT_DESCRIPTION 580 581 if content.is_a?(List) 582 tags += content.tags 583 response = create_list_from_query(content.list_query, tags, name, description) 584 elsif content.respond_to?(:list_upload_uri) 585 response = create_list_from_query(content, tags, name, description) 586 else 587 response = create_list_from_ids(content, type, tags, name, description) 588 end 589 590 return process_list_creation_response(response) 591 end
Deletes the given lists from the webservice. The lists can be supplied as List
objects, or as their names as Strings.
Raises errors if problems occur with the deletion of these lists, including if the lists do not exist.
# File lib/intermine/lists.rb 599 def delete_lists(*lists) 600 lists.map {|x| x.is_a?(List) ? x.name : x.to_s}.uniq.each do |name| 601 uri = URI.parse(@service.root + Service::LISTS_PATH) 602 params = {"name" => name} 603 req = Net::HTTP::Delete.new(uri.path + "?" + params_to_query_string(params)) 604 res = @http.start do |http| 605 http.request(req) 606 end 607 check_response_for_error(res) 608 end 609 refresh_lists 610 end
Create a new list in the webservice from the intersection of two or more lists, and return a List
object that represents it.
See ListManager#create_list
for an explanation of tags, name and description
# File lib/intermine/lists.rb 632 def intersection_of(lists=[], tags=[], name=nil, description=nil) 633 do_commutative_list_operation(Service::LIST_INTERSECTION_PATH, "Intersection", lists, tags, name, description) 634 end
Get a list by name. Returns nil if the list does not exist.
# File lib/intermine/lists.rb 518 def list(name) 519 refresh_lists 520 return @lists[name] 521 end
Get the names of the lists currently available in the webservice
# File lib/intermine/lists.rb 512 def list_names 513 refresh_lists 514 return @lists.keys.sort 515 end
Get the lists currently available in the webservice.
# File lib/intermine/lists.rb 506 def lists 507 refresh_lists 508 return @lists.values 509 end
only handles single value keys!
# File lib/intermine/lists.rb 716 def params_to_query_string(p) 717 return @service.params.merge(p).map { |k,v| "#{k}=#{CGI::escape(v.to_s)}" }.join('&') 718 end
Common code to all list requests for interpreting the response from the webservice.
# File lib/intermine/lists.rb 657 def process_list_creation_response(response) 658 check_response_for_error(response) 659 new_list = JSON.parse(response.body) 660 new_name = new_list["listName"] 661 failed_matches = new_list["unmatchedIdentifiers"] || [] 662 refresh_lists 663 ret = list(new_name) 664 ret.unmatched_identifiers.replace(failed_matches) 665 return ret 666 end
Update the stored record of lists. This method is called before all list retrieval methods.
# File lib/intermine/lists.rb 537 def refresh_lists 538 lists = JSON.parse(@service.get_list_data) 539 @lists = {} 540 lists["lists"].each {|hash| 541 l = List.new(hash, self) 542 @lists[l.name] = l 543 } 544 end
Create a new list in the webservice by subtracting all the elements in the 'delenda' lists from all the elements in the 'reference' lists, and return a List
object that represents it.
See ListManager#create_list
for an explanation of tags, name and description
# File lib/intermine/lists.rb 641 def subtract(references=[], delenda=[], tags=[], name=nil, description=nil) 642 ref_names = make_list_names(references) 643 del_names = make_list_names(delenda) 644 name ||= get_unused_list_name 645 description ||= "Subtraction of #{del_names[0 .. -2].join(", ")} and #{del_names.last} from #{ref_names[0 .. -2].join(", ")} and #{ref_names.last}" 646 uri = URI.parse(@service.root + Service::LIST_SUBTRACTION_PATH) 647 params = @service.params.merge("name" => name, "description" => description, "references" => ref_names.join(';'), 648 "subtract" => del_names.join(';'), "tags" => tags.join(';')) 649 res = @http.start() do |http| 650 Net::HTTP.post_form(uri, params) 651 end 652 return process_list_creation_response(res) 653 end
Create a new list in the webservice from the symmetric difference of two or more lists, and return a List
object that represents it.
See ListManager#create_list
for an explanation of tags, name and description
# File lib/intermine/lists.rb 616 def symmetric_difference_of(lists=[], tags=[], name=nil, description=nil) 617 do_commutative_list_operation(Service::LIST_DIFFERENCE_PATH, "Symmetric difference", lists, tags, name, description) 618 end
Create a new list in the webservice from the union of two or more lists, and return a List
object that represents it.
See ListManager#create_list
for an explanation of tags, name and description
# File lib/intermine/lists.rb 624 def union_of(lists=[], tags=[], name=nil, description=nil) 625 do_commutative_list_operation(Service::LIST_UNION_PATH, "Union", lists, tags, name, description) 626 end
Private Instance Methods
Error checking routine.
# File lib/intermine/lists.rb 777 def check_response_for_error(response) 778 case response 779 when Net::HTTPSuccess 780 # Ok 781 else 782 begin 783 container = JSON.parse(response.body) 784 raise ServiceError, container["error"] 785 rescue 786 response.error! 787 end 788 end 789 end
Routine for creating a List
in a webservice from a list of Ids.
# File lib/intermine/lists.rb 807 def create_list_from_ids(ids, type, tags=[], name=nil, description=nil) 808 if @service.model.get_cd(type).nil? 809 raise ArgumentError, "Invalid type (#{type.inspect})" 810 end 811 uri = URI.parse(@service.root + Service::LISTS_PATH) 812 list_params = { 813 "name" => name, 814 "description" => description, 815 "tags" => tags.join(";"), 816 "type" => type 817 } 818 if ids.is_a?(File) 819 f = ids 820 elsif ids.is_a?(Array) 821 f = StringIO.new(ids.map {|x| '"' + x.gsub(/"/, '\"') + '"'}.join(" ")) 822 elsif File.readable?(ids.to_s) 823 f = File.open(ids, "r") 824 else 825 f = StringIO.new(ids.to_s) 826 end 827 req = Net::HTTP::Post.new(uri.path + "?" + params_to_query_string(list_params)) 828 req.body_stream = f 829 req.content_type = "text/plain" 830 req.content_length = f.size 831 832 res = @http.start() do |http| 833 http.request(req) 834 end 835 f.close 836 return res 837 end
Routine for creating a list from a PathQuery::Query
# File lib/intermine/lists.rb 792 def create_list_from_query(query, tags=[], name=nil, description=nil) 793 uri = query.list_upload_uri 794 list_params = { 795 "listName" => name, 796 "description" => description, 797 "tags" => tags.join(";") 798 } 799 service_params = @service.params 800 params = query.params.merge(list_params).merge(service_params) 801 @http.start() do |http| 802 return Net::HTTP.post_form(URI.parse(uri), params) 803 end 804 end
Clean up after itself by deleting any temporary lists left lying about
# File lib/intermine/lists.rb 724 def do_at_exit(this) 725 at_exit do 726 unless this.temporary_lists.empty? 727 this.lists.each do |x| 728 begin 729 x.delete if this.temporary_lists.include?(x.name) 730 rescue 731 # Ignore errors here. 732 end 733 end 734 end 735 end 736 end
Common code behind the operation of union, intersection and symmetric difference operations.
# File lib/intermine/lists.rb 760 def do_commutative_list_operation(path, operation, lists, tags=[], name=nil, description=nil) 761 list_names = make_list_names(lists) 762 name ||= get_unused_list_name 763 description ||= "#{operation} of #{list_names[0 .. -2].join(", ")} and #{list_names.last}" 764 765 uri = URI.parse(@service.root + path) 766 params = @service.params.merge( 767 "name" => name, "lists" => list_names.join(";"), 768 "description" => description, "tags" => tags.join(';') 769 ) 770 res = @http.start() do |http| 771 Net::HTTP::post_form(uri, params) 772 end 773 return process_list_creation_response(res) 774 end
Helper to get an unused default name
# File lib/intermine/lists.rb 840 def get_unused_list_name(no=1) 841 name = DEFAULT_LIST_NAME + "_" + no.to_s 842 names = list_names 843 while names.include?(name) 844 no += 1 845 name = DEFAULT_LIST_NAME + "_" + no.to_s 846 end 847 @temporary_lists.push(name) 848 return name 849 end
Transform a collection of objects containing Lists
, Queries and Strings into a collection of Strings with list names.
Raises errors if an object cannot be resolved to an accessible list.
# File lib/intermine/lists.rb 743 def make_list_names(objs) 744 current_names = list_names 745 return objs.map do |x| 746 case x 747 when List 748 x.name 749 when x.respond_to?(:list_upload_uri) 750 create_list(x).name 751 when current_names.include?(x.to_s) 752 x.to_s 753 else 754 raise ArgumentError, "#{x} is not a list you can access" 755 end 756 end 757 end