require 'voruby/votable/votable' module VORuby module VOTable # Classes that represent the domain objects in the VOTable 1.0 specification # (http://www.ivoa.net/Documents/PR/VOTable/VOTable-20031017.html). module V1_0 # The root element of the votable. class VOTable < VORuby::VOTable::Base ELEMENT_NAME = 'VOTABLE' def self.serialization_order [ :description, :definitions, :infos, :resources, :version, :id ] end # Create a votable. # To parse an existing votable one would normally do this: # votable = VOTable.from_file('my_file.xml') # but any of the other methods described in VOTable::Base#new are also acceptable: # votable = VOTable.new( # :version => '1.0', # :id => 'votable1', # :description => Description.new(:text => 'A test votable'), # :resources => [Resource.new(...)] # ) # etc. # # or to create a blank VOTable that you'll build up later: # votable = VOTable.new() def initialize(defn=nil) super(defn) self.version = '1.0' if !self.version end # Retrieve the version. By default this is '1.0'. def version self.node['version'] end # Set the version. Normally you should leave # this as 1.0. def version=(v) @node['version'] = v.to_s end def id self.node['ID'] end def id=(i) @node['ID'] = i.to_s end # Retrieve the description (Description). def description get_element(Description) end # Set the description (Description). # votable.description = Description.new(:text => 'A fascinating votable') def description=(d) set_element(Description, d) end # Retrieve the definitions (Definitions). def definitions get_element(Definitions) end # Set the definitions (Definitions). def definitions=(d) set_element(Definitions, d) end # Retrieve the coordinate systems (Coosys). def coordinate_systems HomogeneousNodeList.new(self.node, xpath_for(Coosys), Coosys) end # Set the coordinate systems. # Takes an array of Coosys objects. # votable.coordinate_systems = [Coosys.new(), ...] def coordinate_systems=(systems) self.coordinate_systems.replace(systems) end # Retrieve the parameters (Param). # Returns a HomogeneousNodeList. def params HomogeneousNodeList.new(self.node, xpath_for(Param), Param) end # Set the parameters. # Takes an array of Param objects. # votable.params = [Param.new(), ...] def params=(parameters) self.params.replace(parameters) end # Retrieve the information list (Info). # Returns a HomogeneousNodeList. def infos HomogeneousNodeList.new(self.node, xpath_for(Info), Info) end # Set the information list. # Takes an array of Info objects. # votable.infos = [Info.new(), ...] def infos=(is) self.infos.replace(is) end # Retrieve the resources (Resource). # Returns a HomogeneousNodeList. def resources HomogeneousNodeList.new(self.node, xpath_for(Resource), Resource) end # Set the resources. # Takes an array of Resource objects. # votable.resources = [Resource.new(), ...] def resources=(res) self.resources.replace(res) end # Convert a VOTable to HTML. # Not all attributes are converted. # See test/voruby/votable/1.1/votable.html for an example of the output. def to_html builder = Builder::XmlMarkup.new(:indent => 2) votable_opts = {:class => 'votable'} votable_opts[:id] = self.id if self.id builder.div(votable_opts){ |votable| votable.div(self.description.text, :class => 'description') if self.description self.resources.each do |res| votable << res.to_html end } end protected def methods_to_test_for_equality [ :version, :id, :description, :definitions, :infos, :resources ] end end # A simple description of something. class Description < VORuby::VOTable::Base ELEMENT_NAME = 'DESCRIPTION' # Create a description. # descr = Description.new(:text => 'Hello, world!') def initialize(defn=nil) super(defn) end # Retrieve the actual text of the description. def text self.node.content end # Set the text of the description. # descr.text = 'Hello, world!' def text=(text) @node.content = text end protected def methods_to_test_for_equality; [:text] end end # Definitions of various values appropriate to the votable. class Definitions < VORuby::VOTable::Base ELEMENT_NAME = 'DEFINITIONS' # Create a set of definitions. # definitions = Definitions.new( # :coordinate_systems => [Coosys.new] # :params => [Param.new] # ) def initialize(defn=nil) super(defn) end # Retrieve the coordinate systems (Coosys). # Returns a HomogeneousNodeList. def coordinate_systems HomogeneousNodeList.new(self.node, xpath_for(Coosys), Coosys) end # Retrieve the parameters (Param). # Returns a HomogeneousNodeList. def coordinate_systems=(systems) self.coordinate_systems.replace(systems) end # Retrieve the parameters (Param). # Returns a HomogeneousNodeList. def params HomogeneousNodeList.new(self.node, xpath_for(Param), Param) end # Set the parameter list. # Takes an array of Param objects. # definitions.params = [Param.new(), ...] def params=(parameters) self.params.replace(parameters) end protected def methods_to_test_for_equality [:coordinate_systems, :params] end end # A celestial coordinate system, to which the components of a position on the celestial sphere refer. class Coosys < VORuby::VOTable::Base ELEMENT_NAME = 'COOSYS' # Create a new coordinate system. # coosys = Coosys.new( # :id => 'J2000', # :equinox => 'J2000.', # :epoch => 'J2000.', # :system => 'eq_FK5' # ) # The default system is eq_FK5. def initialize(defn=nil) super(defn) self.system = 'eq_FK5' if !self.system end def id self.node['ID'] end def id=(i) @node['ID'] = i.to_s end def equinox self.node['equinox'] end def equinox=(e) @node['equinox'] = e.to_s end def epoch self.node['epoch'] end def epoch=(e) @node['epoch'] = e.to_s end def system self.node['system'] end # Set the system. # May be one of: eq_FK4, eq_FK5, ICRS, # ecl_FK4, ecl_FK5, galactic, supergalactic, xy, # barycentric or geo_app. def system=(s) @node['system'] = s.to_s end protected def methods_to_test_for_equality [:id, :equinox, :epoch, :system] end end # A global value associated with (usually) a table. class Param < VORuby::VOTable::Base include Castable ELEMENT_NAME = 'PARAM' def self.serialization_order [ :description, :values, :links, :id, :unit, :datatype, :arraysize, :precision, :width, :ref, :name, :ucd, :value ] end # Create a new parameter. # param = Param.new( # :name => 'Telescope', # :datatype => 'float', # :ucd => 'phys.size;instr.tel', # :unit => 'm', # :value => '3.6' # ) def initialize(defn=nil) super(defn) end def id self.node['ID'] end def id=(i) @node['ID'] = i.to_s end def unit self.node['unit'] end # Set the unit. # Units should be of the form outlined by Vizier[http://vizier.u-strasbg.fr/doc/catstd-3.2.htx]. def unit=(u) @node['unit'] = u.to_s end def datatype self.node['datatype'] end # Set the datatype. # Should be one of: boolean, bit, unsignedByte, short, int, long, # char, unicodeChar, float, double, floatComplex, doubleComplex. def datatype=(d) @node['datatype'] = d.to_s end def precision self.node['precision'] end # Set the precision of the value. # Should match [EF]?[1-9][0-9]* # param.precision = '1' def precision=(p) @node['precision'] = p.to_s end def width self.node['width'].to_i end def width=(w) @node['width'] = w.to_s end def ref self.node['ref'] end def ref=(r) @node['ref'] = r.to_s end def name self.node['name'] end def name=(n) @node['name'] = n.to_s end def ucd self.node['ucd'] end # Set the unified content descriptor or UCD[http://vizier.u-strasbg.fr/doc/UCD.htx]. def ucd=(u) @node['ucd'] = u.to_s end def arraysize self.node['arraysize'] end # Set the arraysize (if applicable). # i.e. *, 8x2 def arraysize=(a) @node['arraysize'] = a.to_s end # Retrieve the value of the parameter. # If _cast_ is false (default), the value is returned as a simple string. # However, if _cast_ is true, the datatype and arraysize are used to # determine a suitable object (or list of objects) to return. # See Castable#as_obj for more details. def value(cast=false) cast ? as_obj(self.value, self.datatype, self.arraysize) : self.node['value'] end # Set the value of the parameter. # An attempt is made to convert native ruby types using the datatype and # arraysize parameters. # param.value = Complex.new(1.1, 2.2) # etc. def value=(v) @node['value'] = v.is_a?(String) ? v : as_string(v, self.datatype, self.arraysize) end # Retrieve the description (Description). def description get_element(Description) end # Set the description (Description). def description=(d) set_element(Description, d) end # Retrieve the values (Values). def values get_element(Values) end # Set the values (Values). def values=(v) set_element(Values, v) end # Retrieve the links. # Returns a HomogeneousNodeList object. def links HomogeneousNodeList.new(self.node, xpath_for(Link), Link) end # Set the links. # Takes an array of Link objects. def links=(lnks) self.links.replace(lnks) end protected def methods_to_test_for_equality [ :id, :unit, :datatype, :precision, :width, :ref, :name, :ucd, :value, :arraysize, :description, :values, :links ] end end # A name-value pair. class Info < VORuby::VOTable::Base ELEMENT_NAME = 'INFO' # Create a new name-value pair. # info = Info.new(:name => 'history', :value => 'my first observation') def initialize(defn=nil) super(defn) end def id self.node['ID'] end def id=(i) @node['ID'] = i.to_s end def name self.node['name'] end def name=(n) @node['name'] = n.to_s end def value self.node['value'] end def value=(v) @node['value'] = v end protected def methods_to_test_for_equality [:id, :name, :value] end end # A description and the data values of some logically independent data structure # within the VOTable. class Resource < VORuby::VOTable::Base ELEMENT_NAME = 'RESOURCE' def self.serialization_order [ :description, :infos, :coordinate_systems, :params, :links, :tables, :resources, :id, :name, :type ] end # Create a new resource. # res = Resource.new( # :name => 'myFavouriteGalaxies', # :type => 'meta', # :params => [Param.new()], # :links => [Link.new()], # :tables => [Table.new()] # ) def initialize(defn=nil) super(defn) end def name self.node['name'] end def name=(n) @node['name'] = n.to_s end def id self.node['ID'] end def id=(i) @node['ID'] = i.to_s end # Retrieve the type. # A type of 'meta' means that the resource is descriptive only # (does not contain any actual data in any of its sub-elements). def type self.node['type'] end # Set the type. def type=(t) @node['type'] = t.to_s end # Retrieve the description (Description). def description get_element(Description) end # Set the description (Description). # res.description = Description.new(:text => 'A fascinating resource') def description=(d) set_element(Description, d) end # Retrieve the name-value pairs (Info). # Returns a HomogeneousNodeList. def infos HomogeneousNodeList.new(self.node, xpath_for(Info), Info) end # Set any name-value pairs. # res.infos = [Info.new(), ...] def infos=(is) self.infos.replace(is) end # Retrieve the coordinate systems (Coosys). # Returns a HomogeneousNodeList. def coordinate_systems HomogeneousNodeList.new(self.node, xpath_for(Coosys), Coosys) end # Set the coordinate systems (Coosys). # res.coordinate_systems = [Coosys.new(), ...] def coordinate_systems=(systems) self.coordinate_systems.replace(systems) end # Retrieve the parameters (Param). # Returns a HomogeneousNodeList. def params HomogeneousNodeList.new(self.node, xpath_for(Param), Param) end # Set the parameters (Param). # res.params = [Param.new(), ...] def params=(parameters) self.params.clear parameters.each do |p| self.params << p end end # Retrieve the links (Link). # Returns a HomogeneousNodeList. def links HomogeneousNodeList.new(self.node, xpath_for(Link), Link) end # Set the links (Link). # res.links = [Link.new(), ...] def links=(lnks) self.links.replace(lnks) end # Retrieve the tables (Table). # Returns a HomogeneousNodeList. def tables HomogeneousNodeList.new(self.node, xpath_for(Table), Table) end # Set the tables (Table). # res.tables = [Table.new(), ....] def tables=(tbls) self.tables.replace(tbls) end # Retrieve sub-resources (Resource). # Returns a HomogeneousNodeList. def resources HomogeneousNodeList.new(self.node, xpath_for(Resource), Resource) end # Set sub-resources. # res.resources = [Resource.new(), ...] def resources=(res) self.resources.replace(res) end # Convert a resource to HTML. def to_html builder = Builder::XmlMarkup.new(:indent => 2, :margin => 1) resource_opts = {:class => 'resource'} resource_opts[:id] = self.id if self.id builder.div(resource_opts){ |resource| resource.h3(self.name) if self.name resource.div(self.description.text, :class => 'description') if self.description self.tables.each do |tbl| resource << tbl.to_html end self.resources.each do |res| resource << res.to_html end } end protected def methods_to_test_for_equality [ :name, :id, :type, :description, :infos, :coordinate_systems, :params, :links, :tables, :resources ] end end # A link or pointer to other documents or data servers on the Internet through a URI. class Link < VORuby::VOTable::Base ELEMENT_NAME = 'LINK' # Create a new link. # link = Link.new( # :href => 'http://fits.gsfc.nasa.gov/nrao_data/samples/image/swp05569slg.fits', # :content_type => 'image/fits' # ) def initialize(defn=nil) super(defn) end def id self.node['ID'] end def id=(i) @node['ID'] = i.to_s end def content_role self.node['content-role'] end # Set the content role. # May be one of: query, hints, doc or location. def content_role=(c) @node['content-role'] = c.to_s end def content_type self.node['content-type'] end # Set the content type (i.e. mimetype). def content_type=(c) @node['content-type'] = c.to_s end def title self.node['title'] end def title=(t) @node['title'] = t.to_s end def value self.node['value'] end def value=(v) @node['value'] = v.to_s end # Retrieve the URL. # Returns a URI object. def href self.node['href'] ? URI.parse(self.node['href']) : nil end # Set the URL. # link.href = 'http://www.noao.edu/' # or... # link.href = URI.parse('http://www.noao.edu/') def href=(h) @node['href'] = h.to_s end def gref self.node['gref'] end def gref=(g) @node['gref'] = g.to_s end # Retrieve the action. # Returns a URI object. def action self.node['action'] ? URI.parse(self.node['action']) : nil end # Set the action. # link.action = 'http://www.retrieve-me.com/' # or... # link.action = URI.parse('http://www.retrieve-me.com/') def action=(a) @node['action'] = a.to_s end # Retrieve the link. # Understands any URL groked by open-uri (including file://). # Returns a File object. def retrieve shref = self.href if shref shref.scheme == 'file' ? File.open(shref.path) : open(shref.to_s) else nil end end protected def methods_to_test_for_equality [ :id, :content_role, :content_type, :title, :value, :href, :gref, :action ] end end # The basic structure of a votable. Essentially, tablular data + # a description of the columns of that data. class Table < VORuby::VOTable::Base ELEMENT_NAME= 'TABLE' def self.serialization_order [ :description, :fields, :links, :data, :id, :name, :ref ] end # Create a new table. # table = Table.new( # :name => 'results', # :fields => [Field.new()], # :data => Data.new(:format => TableData.new()) # ) def initialize(defn=nil) super(defn) end def id self.node['ID'] end def id=(i) @node['ID'] = i.to_s end def name self.node['name'] end def name=(n) @node['name'] = n.to_s end def ref self.node['ref'] end def ref=(r) @node['ref'] = r.to_s end # Retrieve the description (Description). def description get_element(Description) end # Set the description (Description). def description=(d) set_element(Description, d) end # Retrieve the data (Data). def data get_element(Data) end # Set the data (Data). def data=(d) set_element(Data, d) end # Retrieve the fields (Field), a.k.a. column descriptions. # Returns a HomogeneousNodeList. def fields HomogeneousNodeList.new(self.node, xpath_for(Field), Field) end # Set the fields. # table.fields = [Field.new(), ...] def fields=(flds) self.fields.replace(flds) end # Retrieve the links (Link). # Returns a HomogeneousNodeList. def links HomogeneousNodeList.new(self.node, xpath_for(Link), Link) end # Set the links (Link). # table.links = [Link.new(), ...] def links=(lnks) self.links.replace(lnks) end # Convert the table into HTML. # Not all aspects of the votable are translated. # table = Table.new( # :id => 'table1', # :description => Description.new(:text => 'A test table'), # :fields => [ # Field.new(:name => 'RA', :id => 'col1', :ucd => 'pos.eq.ra;meta.main', # :ref => 'J2000', :datatype => 'float', :width => 6, :precision => '2', :unit => 'deg'), # Field.new(:name => 'Dec', :id => 'col2', :ucd => 'pos.eq.dec;meta.main', # :ref => 'J2000', :datatype => 'float', :width => 6, :precision => '2', :unit => 'deg'), # Field.new(:name => 'Name', :id => 'col3', :ucd => 'meta.id;meta.main', # :datatype => 'char', :arraysize => '8*') # ], # :data => Data.new( # :format => TableData.new( # :trs => [ # Tr.new(:tds => [Td.new(:text => '123'), Td.new(:text => '456'), Td.new(:text => 'my_obj1')]), # Tr.new(:tds => [Td.new(:text => '789'), Td.new(:text => '112'), Td.new(:text => 'my_obj2')]), # Tr.new(:tds => [Td.new(:text => '145'), Td.new(:text => '178'), Td.new(:text => 'my_obj3')]) # ] # ) # ) # ) # # puts table.to_html # => #
#
#
# RA
# pos.eq.ra;meta.main
# deg
# float
# |
#
#
#
# Dec
# pos.eq.dec;meta.main
# deg
# float
# |
#
#
#
# Name
# meta.id;meta.main
# char
# 8*
# |
#
---|---|---|
123 | #456 | #my_obj1 | #
789 | #112 | #my_obj2 | #
145 | #178 | #my_obj3 | #