voruby 1.1.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile.rb +107 -224
- data/lib/misc.rb +1 -0
- data/lib/misc/misc.rb +60 -0
- data/lib/misc/propertyfile.rb +31 -0
- data/lib/symphony.rb +1 -0
- data/lib/symphony/symphony.rb +247 -0
- data/lib/voruby.rb +186 -0
- data/lib/voruby/active_votable/active_votable.rb +468 -347
- data/lib/voruby/adql/1.0/adql.rb +2418 -0
- data/lib/voruby/adql/support.rb +2 -0
- data/lib/voruby/misc.rb +351 -0
- data/lib/voruby/misc/connection_monitor.rb +97 -0
- data/lib/voruby/misc/libxml_ext.rb +121 -0
- data/lib/voruby/misc/rexml_ext.rb +223 -0
- data/lib/voruby/resolver/resolver.rb +12 -0
- data/lib/voruby/resolver/sesame.rb +299 -0
- data/lib/voruby/sky_query/sky_query.rb +192 -0
- data/lib/voruby/stc/1.10/coords.rb +2272 -0
- data/lib/voruby/stc/1.10/region.rb +892 -0
- data/lib/voruby/stc/1.10/stc.rb +3271 -0
- data/lib/voruby/stc/1.30/stc.rb +8666 -0
- data/lib/voruby/stc/support.rb +2 -0
- data/lib/voruby/ucd/ucd.rb +173 -0
- data/lib/voruby/voevent/1.1/voevent.rb +1124 -0
- data/lib/voruby/voevent/support.rb +5 -0
- data/lib/voruby/votable/1.0/votable.rb +1807 -0
- data/lib/voruby/votable/1.1/votable.rb +2100 -0
- data/lib/voruby/votable/votable.rb +305 -0
- data/lib/voruby/wesix/wesix.rb +491 -0
- data/lib/voruby/xlink/1.2/xlink.rb +21 -0
- data/test/voruby/active_votable/complex.vot +60 -0
- data/test/voruby/active_votable/error.vot +6 -0
- data/test/voruby/active_votable/large.vot +130040 -0
- data/test/voruby/active_votable/simple1.vot +38 -0
- data/test/voruby/active_votable/simple2.vot +38 -0
- data/test/voruby/active_votable/test.rb +193 -0
- data/test/voruby/adql/1.0/adql-alias.sql +1 -0
- data/test/voruby/adql/1.0/adql-alias.xml +26 -0
- data/test/voruby/adql/1.0/adql-avg.sql +1 -0
- data/test/voruby/adql/1.0/adql-avg.xml +31 -0
- data/test/voruby/adql/1.0/adql-circle.sql +1 -0
- data/test/voruby/adql/1.0/adql-circle.xml +46 -0
- data/test/voruby/adql/1.0/adql-expr.sql +1 -0
- data/test/voruby/adql/1.0/adql-expr.xml +34 -0
- data/test/voruby/adql/1.0/adql-function.sql +1 -0
- data/test/voruby/adql/1.0/adql-function.xml +41 -0
- data/test/voruby/adql/1.0/adql-group.sql +1 -0
- data/test/voruby/adql/1.0/adql-group.xml +51 -0
- data/test/voruby/adql/1.0/adql-having.sql +1 -0
- data/test/voruby/adql/1.0/adql-having.xml +25 -0
- data/test/voruby/adql/1.0/adql-like.sql +1 -0
- data/test/voruby/adql/1.0/adql-like.xml +17 -0
- data/test/voruby/adql/1.0/adql-order.sql +1 -0
- data/test/voruby/adql/1.0/adql-order.xml +37 -0
- data/test/voruby/adql/1.0/adql-simple.sql +1 -0
- data/test/voruby/adql/1.0/adql-simple.xml +12 -0
- data/test/voruby/adql/1.0/adql-top.sql +1 -0
- data/test/voruby/adql/1.0/adql-top.xml +33 -0
- data/test/voruby/adql/1.0/test.rb +2220 -0
- data/test/voruby/misc/test.rb +32 -0
- data/test/voruby/resolver/sesame/test.rb +56 -0
- data/test/voruby/sky_query/test.rb +107 -0
- data/test/voruby/stc/1.10/coords_test.rb +3704 -0
- data/test/voruby/stc/1.10/region_test.rb +993 -0
- data/test/voruby/stc/1.10/stc-catalog-entry-location.xml +112 -0
- data/test/voruby/stc/1.10/stc-obs-data-location.xml +126 -0
- data/test/voruby/stc/1.10/stc-region-circle.xml +5 -0
- data/test/voruby/stc/1.10/stc-region-convex.xml +11 -0
- data/test/voruby/stc/1.10/stc-region-convexhull.xml +5 -0
- data/test/voruby/stc/1.10/stc-region-ellipse.xml +7 -0
- data/test/voruby/stc/1.10/stc-region-intersection.xml +25 -0
- data/test/voruby/stc/1.10/stc-region-negation.xml +7 -0
- data/test/voruby/stc/1.10/stc-region-polygon.xml +13 -0
- data/test/voruby/stc/1.10/stc-region-sector.xml +6 -0
- data/test/voruby/stc/1.10/stc-region-union.xml +25 -0
- data/test/voruby/stc/1.10/stc-resource-profile.xml +60 -0
- data/test/voruby/stc/1.10/stc-search-location.xml +54 -0
- data/test/voruby/stc/1.10/stc_test.rb +4626 -0
- data/test/voruby/stc/1.30/stc-catalog-entry-location.xml +210 -0
- data/test/voruby/stc/1.30/stc-obs-data-location-arecibo.xml +353 -0
- data/test/voruby/stc/1.30/stc-obs-data-location-fits.xml +250 -0
- data/test/voruby/stc/1.30/stc-obs-data-location-xlink.xml +63 -0
- data/test/voruby/stc/1.30/stc-obs-data-location.xml +216 -0
- data/test/voruby/stc/1.30/stc-resource-profile-unusual-ref-pos.xml +39 -0
- data/test/voruby/stc/1.30/stc-resource-profile.xml +129 -0
- data/test/voruby/stc/1.30/stc-search-location-arecibo.xml +86 -0
- data/test/voruby/stc/1.30/stc-search-location.xml +101 -0
- data/test/voruby/stc/1.30/test.rb +6274 -0
- data/test/voruby/ucd/test.rb +48 -0
- data/test/voruby/voevent/1.1/test.rb +812 -0
- data/test/{voevent/voevent_v1_1.xml → voruby/voevent/1.1/voevent.xml} +2 -2
- data/test/voruby/voregistry/0.3/test.rb +137 -0
- data/test/voruby/votable/1.0/test.rb +714 -0
- data/test/voruby/votable/1.0/votable.basic.xml +660 -0
- data/test/voruby/votable/1.0/votable.html +86 -0
- data/test/voruby/votable/1.0/votable.ns.xml +56 -0
- data/test/voruby/votable/1.1/test.rb +785 -0
- data/test/voruby/votable/1.1/votable.basic.xml +38 -0
- data/test/voruby/votable/1.1/votable.html +86 -0
- data/test/voruby/votable/1.1/votable.ns.xml +56 -0
- data/test/voruby/votable/test.rb +15 -0
- data/test/voruby/wesix/test.rb +268 -0
- data/test/voruby/wesix/testr.fits +28 -0
- metadata +234 -247
- data/REQUIREMENTS +0 -6
- data/lib/voruby/active_votable/loader.rb +0 -5
- data/lib/voruby/adql/adql.rb +0 -2787
- data/lib/voruby/adql/ext.rb +0 -14
- data/lib/voruby/adql/loader.rb +0 -6
- data/lib/voruby/adql/operations.rb +0 -54
- data/lib/voruby/adql/parser.rb +0 -160
- data/lib/voruby/adql/transforms.rb +0 -573
- data/lib/voruby/ext.rb +0 -17
- data/lib/voruby/loader.rb +0 -4
- data/lib/voruby/misc/propertyfile.rb +0 -36
- data/lib/voruby/plastic/applications.rb +0 -174
- data/lib/voruby/plastic/constants.rb +0 -30
- data/lib/voruby/plastic/loader.rb +0 -10
- data/lib/voruby/plastic/plastic.rb +0 -1
- data/lib/voruby/resources/conesearch/conesearch.rb +0 -9
- data/lib/voruby/resources/conesearch/conesearch_v0_2.rb +0 -55
- data/lib/voruby/resources/conesearch/conesearch_v0_3.rb +0 -50
- data/lib/voruby/resources/conesearch/conesearch_v1_0.rb +0 -72
- data/lib/voruby/resources/conesearch/loader.rb +0 -4
- data/lib/voruby/resources/loader.rb +0 -50
- data/lib/voruby/resources/nodes.rb +0 -190
- data/lib/voruby/resources/openskynode/loader.rb +0 -4
- data/lib/voruby/resources/openskynode/openskynode.rb +0 -9
- data/lib/voruby/resources/openskynode/openskynode_v0_1.rb +0 -54
- data/lib/voruby/resources/sia/loader.rb +0 -5
- data/lib/voruby/resources/sia/sia.rb +0 -9
- data/lib/voruby/resources/sia/sia_v0_6.rb +0 -90
- data/lib/voruby/resources/sia/sia_v0_7.rb +0 -89
- data/lib/voruby/resources/sia/sia_v1_0.rb +0 -122
- data/lib/voruby/resources/stsci.rb +0 -59
- data/lib/voruby/resources/vodataservice/coverage_v0_2.rb +0 -195
- data/lib/voruby/resources/vodataservice/coverage_v0_3.rb +0 -158
- data/lib/voruby/resources/vodataservice/loader.rb +0 -5
- data/lib/voruby/resources/vodataservice/vodataservice.rb +0 -9
- data/lib/voruby/resources/vodataservice/vodataservice_v0_4.rb +0 -189
- data/lib/voruby/resources/vodataservice/vodataservice_v0_5.rb +0 -163
- data/lib/voruby/resources/vodataservice/vodataservice_v1_0.rb +0 -221
- data/lib/voruby/resources/voregistry/loader.rb +0 -4
- data/lib/voruby/resources/voregistry/voregistry.rb +0 -9
- data/lib/voruby/resources/voregistry/voregistry_v0_2.rb +0 -40
- data/lib/voruby/resources/voregistry/voregistry_v0_3.rb +0 -30
- data/lib/voruby/resources/voregistry/voregistry_v1_0.rb +0 -86
- data/lib/voruby/resources/voresource/loader.rb +0 -17
- data/lib/voruby/resources/voresource/voresource.rb +0 -9
- data/lib/voruby/resources/voresource/voresource_v0_10.rb +0 -327
- data/lib/voruby/resources/voresource/voresource_v0_9.rb +0 -405
- data/lib/voruby/resources/voresource/voresource_v1_0.rb +0 -230
- data/lib/voruby/services/ext.rb +0 -11
- data/lib/voruby/services/gestalt/footprint.rb +0 -95
- data/lib/voruby/services/gestalt/wcs_fixer.rb +0 -105
- data/lib/voruby/services/gestalt/wesix.rb +0 -155
- data/lib/voruby/services/loader.rb +0 -7
- data/lib/voruby/services/registry/registry.rb +0 -53
- data/lib/voruby/services/resolver/resolver.rb +0 -35
- data/lib/voruby/services/schema/schema.rb +0 -644
- data/lib/voruby/sesame/loader.rb +0 -6
- data/lib/voruby/sesame/sesame_v1_0.rb +0 -64
- data/lib/voruby/simple/loader.rb +0 -6
- data/lib/voruby/simple/parameters.rb +0 -196
- data/lib/voruby/simple/sap.rb +0 -446
- data/lib/voruby/spacetime/loader.rb +0 -3
- data/lib/voruby/spacetime/spacetime.rb +0 -607
- data/lib/voruby/stc/coords_v1_20.rb +0 -900
- data/lib/voruby/stc/loader.rb +0 -55
- data/lib/voruby/stc/region_v1_20.rb +0 -274
- data/lib/voruby/stc/stc_v1_20.rb +0 -1196
- data/lib/voruby/util.rb +0 -27
- data/lib/voruby/voevent/loader.rb +0 -7
- data/lib/voruby/voevent/voevent_v1_0.rb +0 -213
- data/lib/voruby/voevent/voevent_v1_1.rb +0 -196
- data/lib/voruby/votables/chandra.rb +0 -373
- data/lib/voruby/votables/data.rb +0 -179
- data/lib/voruby/votables/galex.rb +0 -377
- data/lib/voruby/votables/int.rb +0 -354
- data/lib/voruby/votables/libxml_parser.rb +0 -411
- data/lib/voruby/votables/libxml_votable.rb +0 -67
- data/lib/voruby/votables/loader.rb +0 -10
- data/lib/voruby/votables/meta.rb +0 -763
- data/lib/voruby/votables/misc.rb +0 -51
- data/lib/voruby/votables/nsa.rb +0 -410
- data/lib/voruby/votables/rexml_parser.rb +0 -408
- data/lib/voruby/votables/rexml_votable.rb +0 -67
- data/lib/voruby/votables/sdss.rb +0 -356
- data/lib/voruby/votables/transforms.rb +0 -388
- data/lib/voruby/votables/tree.rb +0 -45
- data/lib/voruby/votables/types.rb +0 -391
- data/lib/voruby/votables/votable.rb +0 -687
- data/test/active_votable/database.yml +0 -6
- data/test/active_votable/test.vot +0 -168492
- data/test/active_votable/unittest.rb +0 -41
- data/test/adql/test1.adql +0 -49
- data/test/adql/test2.adql +0 -51
- data/test/adql/test3.adql +0 -81
- data/test/adql/test4.adql +0 -53
- data/test/adql/test5.adql +0 -55
- data/test/adql/test6.adql +0 -18
- data/test/adql/test7.adql +0 -48
- data/test/adql/unittest.rb +0 -1672
- data/test/plastic/test.rb +0 -44
- data/test/plastic/test.vot +0 -5385
- data/test/plastic/unittest.rb +0 -66
- data/test/resources/conesearch/conesearch_v0_3.xml +0 -31
- data/test/resources/conesearch/conesearch_v1_0.xml +0 -86
- data/test/resources/conesearch/unittest_v0_3.rb +0 -22
- data/test/resources/conesearch/unittest_v1_0.rb +0 -24
- data/test/resources/openskynode/open_sky_node_v0_1.xml +0 -32
- data/test/resources/openskynode/unittest_v0_1.rb +0 -31
- data/test/resources/sia/simple_image_access_v0_7.xml +0 -36
- data/test/resources/sia/simple_image_access_v1_0.xml +0 -122
- data/test/resources/sia/unittest_v0_7.rb +0 -24
- data/test/resources/sia/unittest_v1_0.rb +0 -29
- data/test/resources/stsci.xml +0 -336
- data/test/resources/unittest_stsci.rb +0 -25
- data/test/resources/vodataservice/catalog_service_resource_v1_0.xml +0 -128
- data/test/resources/vodataservice/data_collection_resource_v0_5.xml +0 -54
- data/test/resources/vodataservice/data_collection_resource_v1_0.xml +0 -117
- data/test/resources/vodataservice/data_service_resource_v1_0.xml +0 -115
- data/test/resources/vodataservice/sky_service_resource_v0_10.xml +0 -45
- data/test/resources/vodataservice/table_service_resource_v1_0.xml +0 -122
- data/test/resources/vodataservice/tabular_sky_service_resource_v0_10.xml +0 -60
- data/test/resources/vodataservice/unittest_v0_5.rb +0 -126
- data/test/resources/vodataservice/unittest_v1_0.rb +0 -151
- data/test/resources/voregistry/authority_resource_v0_3.xml +0 -20
- data/test/resources/voregistry/authority_resource_v1_0.xml +0 -82
- data/test/resources/voregistry/registry_service_v0_3.xml +0 -20
- data/test/resources/voregistry/registry_service_v1_0.xml +0 -107
- data/test/resources/voregistry/unittest_v0_3.rb +0 -31
- data/test/resources/voregistry/unittest_v1_0.rb +0 -34
- data/test/resources/voresource/organisation_resource_v1_0.xml +0 -90
- data/test/resources/voresource/resource_organisation_v0_10.xml +0 -22
- data/test/resources/voresource/resource_service_v0_10.xml +0 -19
- data/test/resources/voresource/resource_v0_10.xml +0 -19
- data/test/resources/voresource/resource_v1_0.xml +0 -79
- data/test/resources/voresource/service_resource_v1_0.xml +0 -91
- data/test/resources/voresource/unittest_v0_10.rb +0 -61
- data/test/resources/voresource/unittest_v0_9.rb +0 -4
- data/test/resources/voresource/unittest_v1_0.rb +0 -190
- data/test/services/gestalt/unittest.rb +0 -74
- data/test/services/registry/unittest.rb +0 -34
- data/test/services/resolver/unittest.rb +0 -38
- data/test/simple/unittest.rb +0 -46
- data/test/spacetime/unittest.rb +0 -39
- data/test/stc/catalog_entry_location_v1_20.xml +0 -112
- data/test/stc/obs_data_location_v1_20.xml +0 -108
- data/test/stc/search_location_v1_20.xml +0 -54
- data/test/stc/stc_resource_profile_v1_20.xml +0 -60
- data/test/stc/unittest_v1_20.rb +0 -620
- data/test/voevent/unittest_v1_0.rb +0 -79
- data/test/voevent/unittest_v1_1.rb +0 -70
- data/test/voevent/voevent_v1_0.xml +0 -96
- data/test/votables/test.vot +0 -366
- data/test/votables/unittest.rb +0 -54
@@ -0,0 +1,121 @@
|
|
1
|
+
class XML::Node
|
2
|
+
def replace_with(other)
|
3
|
+
self.next = other
|
4
|
+
remove!
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module XML
|
9
|
+
module Object
|
10
|
+
# A (essentially abstract) class that can be used in the
|
11
|
+
# creation of domain objects backed by XML documents.
|
12
|
+
class Base
|
13
|
+
# The XML::Node used to store the state of the domain object.
|
14
|
+
attr_reader :node
|
15
|
+
|
16
|
+
# Create a domain object from an XML file on disk.
|
17
|
+
# _filename_:: the name of the file to parse
|
18
|
+
#
|
19
|
+
# votable = VOTable::V1_1::VOTable.from_file('myvotable.xml')
|
20
|
+
def self.from_file(filename)
|
21
|
+
self.new(XML::Document.file(filename))
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get the name of the element when serialized
|
25
|
+
# to XML that the object in question will take on.
|
26
|
+
# By default, the name of the class.
|
27
|
+
def self.element_name
|
28
|
+
self.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create a new domain object from a number of source formats.
|
32
|
+
# _xml_ may be one of
|
33
|
+
# * a string
|
34
|
+
# * an IO object (i.e. a File object)
|
35
|
+
# * a LibXML Document (i.e. XML::Document)
|
36
|
+
# * a LibXML Node (i.e. XML::Node)
|
37
|
+
# * nothing (to create a blank object)
|
38
|
+
# * a hash where the keys of the hash represent the method to call
|
39
|
+
#
|
40
|
+
# Assuming VOTable::V1_1::VOTable is a subclass of Base...
|
41
|
+
#
|
42
|
+
# votable = VOTable::V1_1::VOTable.new('<VOTABLE version="1.1"/>')
|
43
|
+
# votable = VOTable::V1_1::VOTable.new(File.new('myvotable.xml')) # you could also use #from_file
|
44
|
+
# votable = VOTable::V1_1::VOTable.new(XML::Document.file('myvotable.xml'))
|
45
|
+
# votable = VOTable::V1_1::VOTable.new(XML::Node.new('VOTABLE'))
|
46
|
+
# votable = VOTable::V1_1::VOTable.new()
|
47
|
+
# votable = VOTable::V1_1::VOTable.new(:version => '1.1')
|
48
|
+
def initialize(xml=nil)
|
49
|
+
@node = case xml
|
50
|
+
when String
|
51
|
+
parser = XML::Parser.new
|
52
|
+
parser.string = xml
|
53
|
+
parser.parse.root
|
54
|
+
when IO
|
55
|
+
parser = XML::Parser.new
|
56
|
+
parser.io = xml
|
57
|
+
parser.parse.root
|
58
|
+
when XML::Document
|
59
|
+
xml.root
|
60
|
+
when XML::Node
|
61
|
+
xml
|
62
|
+
when NilClass
|
63
|
+
doc = XML::Document.new
|
64
|
+
doc.root = XML::Node.new(self.class.element_name)
|
65
|
+
doc.root
|
66
|
+
when Hash
|
67
|
+
doc = XML::Document.new
|
68
|
+
doc.root = XML::Node.new(self.class.element_name)
|
69
|
+
doc.root
|
70
|
+
else
|
71
|
+
raise "XML must be a XML::Document, XML::Node, String or IO object"
|
72
|
+
end
|
73
|
+
|
74
|
+
initialize_members(xml) if xml.is_a?(Hash)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Serialize the domain object to XML.
|
78
|
+
def to_s
|
79
|
+
self.node.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
# Equality among domain objects.
|
83
|
+
# Always returns false, override to get less brain-dead result.
|
84
|
+
def ==(obj)
|
85
|
+
false
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
|
90
|
+
# Retrieve the domain object that corresponds to
|
91
|
+
# the specified class.
|
92
|
+
def get_element(klass)
|
93
|
+
subnode = self.node.find_first(self.xpath_for(klass))
|
94
|
+
subnode ? klass.new(subnode) : nil
|
95
|
+
end
|
96
|
+
|
97
|
+
# Set the specified domain object that corresponds to
|
98
|
+
# the specified class.
|
99
|
+
def set_element(klass, e)
|
100
|
+
descr_node = self.node.find_first(xpath_for(klass))
|
101
|
+
descr_node ? descr_node.replace_with(e.node) : @node.child_add(e.node.copy(true))
|
102
|
+
end
|
103
|
+
|
104
|
+
# Determine the xpath corresponding to the specified class.
|
105
|
+
# By default, this is just the name of the class.
|
106
|
+
# obj.xpath_for(Field) # => 'Field'
|
107
|
+
def xpath_for(klass)
|
108
|
+
klass.to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def initialize_members(args)
|
114
|
+
args.each do |name, value|
|
115
|
+
send("#{name}=", value)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module REXML
|
4
|
+
module Object
|
5
|
+
|
6
|
+
class ReflectiveElementList
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
attr_reader :parent, :xpath
|
10
|
+
|
11
|
+
def initialize(parent, *xpath)
|
12
|
+
@parent = parent
|
13
|
+
@xpath = xpath
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](i)
|
17
|
+
path = "#{self.xpath.first}[#{i+1}]"
|
18
|
+
XPath.first(self.parent, path, self.xpath.last)
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(i, element)
|
22
|
+
el = self[i]
|
23
|
+
el ? el.replace_with(element) : self<<(element)
|
24
|
+
end
|
25
|
+
|
26
|
+
def <<(element)
|
27
|
+
path = "#{self.xpath.first}[last()]"
|
28
|
+
last = XPath.first(self.parent, path, self.xpath.last)
|
29
|
+
last ? last.next_sibling = element : self.parent << element
|
30
|
+
end
|
31
|
+
|
32
|
+
def last
|
33
|
+
path = "#{self.xpath.first}[last()]"
|
34
|
+
XPath.first(self.parent, path, self.xpath.last)
|
35
|
+
end
|
36
|
+
|
37
|
+
def first
|
38
|
+
path = "#{self.xpath.first}[1]"
|
39
|
+
XPath.first(self.parent, path, self.xpath.last)
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete_at(i)
|
43
|
+
path = "#{self.xpath.first}[#{i+1}]"
|
44
|
+
XPath.first(self.parent, path, self.xpath.last).remove
|
45
|
+
end
|
46
|
+
|
47
|
+
def size
|
48
|
+
path = "count(#{self.xpath.first})"
|
49
|
+
XPath.first(self.parent, path, self.xpath.last)
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_a
|
53
|
+
XPath.match(self.parent, *self.xpath)
|
54
|
+
end
|
55
|
+
|
56
|
+
def clear
|
57
|
+
self.each { |el| el.remove }
|
58
|
+
end
|
59
|
+
|
60
|
+
def replace(ary)
|
61
|
+
self.clear
|
62
|
+
ary.each { |el| self<<(el) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def each
|
66
|
+
XPath.each(self.parent, *self.xpath) { |el| yield el }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class ClassifiedElementList < ReflectiveElementList
|
71
|
+
attr_reader :klass
|
72
|
+
|
73
|
+
def initialize(klass, parent, *xpath)
|
74
|
+
@klass = klass
|
75
|
+
super(parent, *xpath)
|
76
|
+
end
|
77
|
+
|
78
|
+
def [](i)
|
79
|
+
self.klass.new(super(i))
|
80
|
+
end
|
81
|
+
|
82
|
+
def []=(i, obj)
|
83
|
+
el = self[i]
|
84
|
+
el ? el.node.replace_with(obj.node) : self<<(obj.node)
|
85
|
+
end
|
86
|
+
|
87
|
+
def <<(obj)
|
88
|
+
super(obj.node)
|
89
|
+
end
|
90
|
+
|
91
|
+
def last
|
92
|
+
self.klass.new(super())
|
93
|
+
end
|
94
|
+
|
95
|
+
def first
|
96
|
+
self.klass.new(super())
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_a
|
100
|
+
super().collect{ |el| self.klass.new(el) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def replace(ary)
|
104
|
+
self.clear
|
105
|
+
ary.each { |obj| self<<(obj) }
|
106
|
+
end
|
107
|
+
|
108
|
+
def each
|
109
|
+
XPath.each(self.parent, *self.xpath) { |el| yield self.klass.new(el) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def clear
|
113
|
+
self.each { |el| el.node.remove }
|
114
|
+
end
|
115
|
+
|
116
|
+
def ==(ary)
|
117
|
+
return false if self.size != ary.size
|
118
|
+
|
119
|
+
self.each_with_index do |item, i|
|
120
|
+
return false if item != ary[i]
|
121
|
+
end
|
122
|
+
|
123
|
+
return true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class Base
|
128
|
+
attr_reader :node, :xml_element_name
|
129
|
+
|
130
|
+
def self.xsi_namespace; 'http://www.w3.org/2001/XMLSchema-instance' end
|
131
|
+
def self.xsd_namespace; 'http://www.w3.org/2001/XMLSchema' end
|
132
|
+
def self.xml_type; self.class.to_s.split('::').last end
|
133
|
+
|
134
|
+
def initialize(defn=nil)
|
135
|
+
@node = case defn
|
136
|
+
when Document then defn.root
|
137
|
+
when Element then defn
|
138
|
+
when Hash then Element.new(self.xml_element_name)
|
139
|
+
when NilClass then Element.new(self.xml_element_name)
|
140
|
+
else
|
141
|
+
Document.new(defn).root
|
142
|
+
end
|
143
|
+
|
144
|
+
initialize_members(defn) if defn.is_a?(Hash)
|
145
|
+
end
|
146
|
+
|
147
|
+
def xml_element_name; self.class.to_s.split('::').last end
|
148
|
+
|
149
|
+
def find_namespace_by_href(href)
|
150
|
+
self.node.namespaces.find{ |prefix, uri| uri == href }
|
151
|
+
end
|
152
|
+
|
153
|
+
def get_attribute(name, ns=nil)
|
154
|
+
attribute = self.node.attributes.get_attribute_ns(ns, name)
|
155
|
+
attribute ? attribute.value : nil
|
156
|
+
end
|
157
|
+
|
158
|
+
def set_attribute(name, value, ns=nil)
|
159
|
+
self.node.attributes[attribute_xpath_for(name, ns)] = value.to_s
|
160
|
+
end
|
161
|
+
|
162
|
+
def get_element(name, ns=nil)
|
163
|
+
XPath.first(self.node, *element_xpath_for(name, ns))
|
164
|
+
end
|
165
|
+
|
166
|
+
def set_element(name, value, ns)
|
167
|
+
el = get_element(name, ns)
|
168
|
+
|
169
|
+
# The element doesn't exist...
|
170
|
+
if !el
|
171
|
+
el = REXML::Element.new(name)
|
172
|
+
@node << el # so insert it
|
173
|
+
end
|
174
|
+
|
175
|
+
case value
|
176
|
+
when String then el.text = value.to_s
|
177
|
+
when REXML::Element then value.name = name; el.replace_with(value)
|
178
|
+
end
|
179
|
+
|
180
|
+
el.add_namespace(ns) if !find_namespace_by_href(ns)
|
181
|
+
end
|
182
|
+
|
183
|
+
def get_elements(name, ns=nil)
|
184
|
+
ReflectiveElementList.new(self.node, *element_xpath_for(name, ns))
|
185
|
+
end
|
186
|
+
|
187
|
+
def set_elements(name, values, ns=nil)
|
188
|
+
get_elements(name, ns).replace(values)
|
189
|
+
end
|
190
|
+
|
191
|
+
def to_s
|
192
|
+
formatter = Formatters::Default.new
|
193
|
+
xml = ''
|
194
|
+
formatter.write(self.node, xml)
|
195
|
+
xml
|
196
|
+
end
|
197
|
+
|
198
|
+
protected
|
199
|
+
|
200
|
+
def attribute_xpath_for(name, ns=nil)
|
201
|
+
if ns
|
202
|
+
namespace = find_namespace_by_href(ns)
|
203
|
+
namespace ? "#{namespace.first}:#{name}" : name
|
204
|
+
else
|
205
|
+
name
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def element_xpath_for(name, ns=nil)
|
210
|
+
ns ? ["x:#{name}", {'x' => ns}] : [name]
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
|
215
|
+
def initialize_members(args)
|
216
|
+
args.each do |name, value|
|
217
|
+
send("#{name}=", value)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'soap/rpc/driver'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubygems'
|
6
|
+
rescue LoadError; end
|
7
|
+
require 'xml/libxml'
|
8
|
+
|
9
|
+
module VORuby
|
10
|
+
# Name resolvers (i.e. the CDS's sesame[http://cdsweb.u-strasbg.fr/cdsws/name_resolver.gml] service)
|
11
|
+
module Resolver; end
|
12
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
require 'voruby/resolver/resolver'
|
2
|
+
|
3
|
+
module VORuby
|
4
|
+
module Resolver
|
5
|
+
|
6
|
+
# Sesame[http://cdsweb.u-strasbg.fr/cdsws/name_resolver.gml] is the standard
|
7
|
+
# name resolution service of the virtual observatory. There are a couple of
|
8
|
+
# ways to use it, but typically one wants the RA and Dec of the target:
|
9
|
+
#
|
10
|
+
# ra, dec = Sesame.resolve_position('m51') # => the primary J2000 RA and Dec of M 51 in degrees
|
11
|
+
# sesame = Sesame.resolve('m51') # => a Sesame object with in-depth information about the name resolution
|
12
|
+
# puts sesame.jradeg, sesame.jdedeg
|
13
|
+
#
|
14
|
+
# It's also possible to change the location of the web service used (to a mirror, say) and to specify
|
15
|
+
# which resolvers sesame should aggregate over (by default Simbad is used).
|
16
|
+
class Sesame
|
17
|
+
# The result of the name resolution as an XML::Node.
|
18
|
+
# Not available until after #resolve has been called.
|
19
|
+
attr_reader :xml
|
20
|
+
|
21
|
+
# Whether to try to determine if the sesame service
|
22
|
+
# is available or not before each name resolution.
|
23
|
+
# The default is false.
|
24
|
+
attr_accessor :check_availability
|
25
|
+
|
26
|
+
# Resolve the <tt>target</tt>.
|
27
|
+
# The optional <tt>against</tt> may be one of <tt>:simbad</tt>, <tt>:ned</tt>, <tt>:vizier</tt> or <tt>:all</tt>.
|
28
|
+
# Simbad is the most reliable, so that's the default.
|
29
|
+
# <tt>options</tt> is a hash with the following keys:
|
30
|
+
#
|
31
|
+
# [<tt>:end_point</tt>] the sesame SOAP endpoint to use (default: http://cdsws.u-strasbg.fr/axis/services/Sesame)
|
32
|
+
# [<tt>:check_availability</tt>] whether to try to determine if the sesame service is available or not before each name resolution (default: false)
|
33
|
+
#
|
34
|
+
# Returns a Sesame object, and is exactly equivalent to:
|
35
|
+
#
|
36
|
+
# sesame = Sesame.new
|
37
|
+
# sesame.resolve
|
38
|
+
def self.resolve(target, against=:simbad, options={})
|
39
|
+
sesame = Sesame.new(options)
|
40
|
+
sesame.resolve(target, against)
|
41
|
+
|
42
|
+
sesame
|
43
|
+
end
|
44
|
+
|
45
|
+
# Resolve the <tt>target</tt>, but return only the primary position and no
|
46
|
+
# other information. The parameters are as for #resolve with the addition
|
47
|
+
# of <tt>as</tt> which may be <tt>:degrees</tt> (default) or <tt>:sexigesimal</tt>.
|
48
|
+
# In the former case, an array of floats (ra, dec) is returned while in the latter
|
49
|
+
# an array of strings.
|
50
|
+
#
|
51
|
+
# Sesame.resolve_position('m51') # => [202.4682083, 47.1946667]
|
52
|
+
# Sesame.resolve_position('m51', :sexigesimal) # => ['13:29:52.36', '+47:11:40.8']
|
53
|
+
def self.resolve_position(target, against=:simbad, as=:degrees, options={})
|
54
|
+
self.resolve(target, against, options).position(as)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Create a new sesame name resolver.
|
58
|
+
# <tt>options</tt> is a hash with the following keys:
|
59
|
+
#
|
60
|
+
# [<tt>:end_point</tt>] the sesame SOAP endpoint to use (default: http://cdsws.u-strasbg.fr/axis/services/Sesame)
|
61
|
+
# [<tt>:check_availability</tt>] whether to try to determine if the sesame service is available or not before each name resolution (default: false)
|
62
|
+
#
|
63
|
+
# sesame = Sesame.new(
|
64
|
+
# :end_point => 'http://vizier.nao.ac.jp:8080/axis/services/Sesame' # maybe we're in Japan...
|
65
|
+
# :check_availability => true # and we want to always check the availability of the service
|
66
|
+
# )
|
67
|
+
def initialize(options={})
|
68
|
+
self.end_point = options[:end_point] || 'http://cdsws.u-strasbg.fr/axis/services/Sesame'
|
69
|
+
self.check_availability = options[:check_availability] || false
|
70
|
+
end
|
71
|
+
|
72
|
+
# The "end-point" or location of the name resolver's webservice.
|
73
|
+
def end_point
|
74
|
+
@end_point
|
75
|
+
end
|
76
|
+
|
77
|
+
# Set the end-point or location of the name resolver's webservice.
|
78
|
+
# sesame.end_point = 'http://vizier.nao.ac.jp:8080/axis/services/Sesame'
|
79
|
+
def end_point=(epoint)
|
80
|
+
@end_point = epoint
|
81
|
+
|
82
|
+
# We don't use the WSDL for this because ruby doesn't deal well with method overloading.
|
83
|
+
@resolver = SOAP::RPC::Driver.new(@end_point)
|
84
|
+
@resolver.add_rpc_method('sesame', 'name', 'resultType', 'all', 'service')
|
85
|
+
@resolver.add_rpc_method('getAvailability')
|
86
|
+
end
|
87
|
+
|
88
|
+
# Retrieve whatever information we can about the position of the specified <tt>target</tt>.
|
89
|
+
# The optional <tt>against</tt> may be one of <tt>:simbad</tt>, <tt>:ned</tt>, <tt>:vizier</tt> or <tt>:all</tt>.
|
90
|
+
# Simbad is the most reliable, so that's the default.
|
91
|
+
#
|
92
|
+
# sesame.resolve('m51', :all) # use all the resources at sesame's disposal
|
93
|
+
#
|
94
|
+
# This method may throw an exception if:
|
95
|
+
#
|
96
|
+
# * #end_point doesn't exist
|
97
|
+
# * you have set #check_availabilty to true and the resolver has indicated it is not available
|
98
|
+
def resolve(target, against=:simbad)
|
99
|
+
raise "Sesame at #{self.end_point} is not currently available" if self.check_availability and !self.available?
|
100
|
+
|
101
|
+
parser = XML::Parser.new
|
102
|
+
parser.string =
|
103
|
+
@resolver.sesame(target.to_s, 'x', true, service_designation(against))
|
104
|
+
@xml = parser.parse.root
|
105
|
+
end
|
106
|
+
|
107
|
+
# The target you requested name resolution on.
|
108
|
+
def target
|
109
|
+
self.xml.find_first('target').content
|
110
|
+
end
|
111
|
+
|
112
|
+
# Any information that sesame sent back with your results.
|
113
|
+
def infos
|
114
|
+
self.xml.find('INFO').collect{ |i| i.content }
|
115
|
+
end
|
116
|
+
|
117
|
+
# Any errors reported by sesame sent back with your results.
|
118
|
+
def errors
|
119
|
+
self.xml.find('ERROR').collect{ |e| e.content }
|
120
|
+
end
|
121
|
+
|
122
|
+
# Sesame actually aggregates results from a number of sources.
|
123
|
+
# Returns an array of ResolvedInfo objects, one for each resource
|
124
|
+
# polled (i.e. some combination of Simbad, VizieR and Ned).
|
125
|
+
def resolvers
|
126
|
+
self.xml.find('Resolver').collect{ |r| ResolvedInfo.new(r) }
|
127
|
+
end
|
128
|
+
|
129
|
+
# A shortcut for ResolvedInfo#position.
|
130
|
+
# Assumes the first resolver is the one you're most
|
131
|
+
# interested in.
|
132
|
+
def position(as=:degrees)
|
133
|
+
self.resolvers.first.position(as)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Checks to see whether sesame is available.
|
137
|
+
# At this point it's assumed the service is present at
|
138
|
+
# the location specified by #end_point. This just checks
|
139
|
+
# to see whether sesame reports itself as available or not.
|
140
|
+
def available?
|
141
|
+
# We don't use an XML parser here because (as of 2007-01-04)
|
142
|
+
# the validTo tag isn't closed properly, rendering the XML
|
143
|
+
# malformed.
|
144
|
+
result = @resolver.getAvailability
|
145
|
+
result.match(/<available>\s*(.*)\s*<\/available>/)[1] == 'true'
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def service_designation(svc)
|
151
|
+
{
|
152
|
+
:simbad => 'S',
|
153
|
+
:ned => 'N',
|
154
|
+
:vizier => 'V',
|
155
|
+
:all => 'A'
|
156
|
+
}[svc] || svc
|
157
|
+
end
|
158
|
+
|
159
|
+
# A simple object that represents a name resolution attempt.
|
160
|
+
class ResolvedInfo
|
161
|
+
attr_reader :xml
|
162
|
+
|
163
|
+
# Create a ResolvedInfo object from an appropriate
|
164
|
+
# XML::Node (one that represents a <Resolver> XML element).
|
165
|
+
def initialize(xml)
|
166
|
+
@xml = xml
|
167
|
+
end
|
168
|
+
|
169
|
+
# The name of the resolver (i.e. Simbad).
|
170
|
+
def name
|
171
|
+
self.xml['name']
|
172
|
+
end
|
173
|
+
|
174
|
+
def code
|
175
|
+
self.xml['code']
|
176
|
+
end
|
177
|
+
|
178
|
+
# Any info accompanying the name resolution.
|
179
|
+
# Returns an array of strings.
|
180
|
+
def infos
|
181
|
+
self.xml.find('INFO').collect{ |i| i.content }
|
182
|
+
end
|
183
|
+
|
184
|
+
# Any errors accompanying the name resolution.
|
185
|
+
# Returns an array of string.
|
186
|
+
def errors
|
187
|
+
self.xml.find('ERROR').collect{ |e| e.content }
|
188
|
+
end
|
189
|
+
|
190
|
+
# The classification of the object (i.e. Seyfert_2 or QSO).
|
191
|
+
def otype
|
192
|
+
self.xml.find_first('otype').content if self.xml.find_first('otype')
|
193
|
+
end
|
194
|
+
|
195
|
+
# The J2000 coordinates of the object in sexigesimal format (i.e. '13:29:52.36 +47:11:40.8')
|
196
|
+
def jpos
|
197
|
+
self.xml.find_first('jpos').content if self.xml.find_first('jpos')
|
198
|
+
end
|
199
|
+
|
200
|
+
# The J2000 right ascension of the object in decimal degrees.
|
201
|
+
def jradeg
|
202
|
+
self.xml.find_first('jradeg').content.to_f if self.xml.find_first('jradeg')
|
203
|
+
end
|
204
|
+
|
205
|
+
# The J2000 declination of the object in decimal degrees.
|
206
|
+
def jdedeg
|
207
|
+
self.xml.find_first('jdedeg').content.to_f if self.xml.find_first('jdedeg')
|
208
|
+
end
|
209
|
+
|
210
|
+
# A bibcode that corresponds to the publication in which the position
|
211
|
+
# of the object was determined.
|
212
|
+
def ref_pos
|
213
|
+
self.xml.find_first('refPos').content if self.xml.find_first('refPos')
|
214
|
+
end
|
215
|
+
|
216
|
+
# The error of the right ascension in milliarcseconds.
|
217
|
+
def err_ra_mas
|
218
|
+
self.xml.find_first('errRAmas').content.to_f if self.xml.find_first('errRAmas')
|
219
|
+
end
|
220
|
+
|
221
|
+
# The error of the declination in milliarcseconds.
|
222
|
+
def err_de_mas
|
223
|
+
self.xml.find_first('errDEmas').content.to_f if self.xml.find_first('errDEmas')
|
224
|
+
end
|
225
|
+
|
226
|
+
# The redshift of the object.
|
227
|
+
def z
|
228
|
+
self.xml.find_first('z').content.to_f if self.xml.find_first('z')
|
229
|
+
end
|
230
|
+
|
231
|
+
# The error in the redshift of the object.
|
232
|
+
def errz
|
233
|
+
self.xml.find_first('errz').content.to_i if self.xml.find_first('errz')
|
234
|
+
end
|
235
|
+
|
236
|
+
# A bibcode that corresponds to the publication in which the redshift
|
237
|
+
# of the object was determined.
|
238
|
+
def refz
|
239
|
+
self.xml.find_first('refz').content if self.xml.find_first('refz')
|
240
|
+
end
|
241
|
+
|
242
|
+
# The velocity of the object in km/s.
|
243
|
+
def vel
|
244
|
+
self.xml.find_first('Vel').content.to_f if self.xml.find_first('Vel')
|
245
|
+
end
|
246
|
+
|
247
|
+
# The error in the velocity of the object in km/s.
|
248
|
+
def err_vel
|
249
|
+
self.xml.find_first('errVel').content.to_if if self.xml.find_first('errVel')
|
250
|
+
end
|
251
|
+
|
252
|
+
# A bibcode that corresponds to the publication in which the velocity
|
253
|
+
# of the object was determined.
|
254
|
+
def ref_vel
|
255
|
+
self.xml.find_first('refVel').content if self.xml.find_first('refVel')
|
256
|
+
end
|
257
|
+
|
258
|
+
# The morphological type of the object (i.e. Sc).
|
259
|
+
def mtype
|
260
|
+
self.xml.find_first('MType').content if self.xml.find_first('MType')
|
261
|
+
end
|
262
|
+
|
263
|
+
# The spectral type of the object (i.e. A10)
|
264
|
+
def sptype
|
265
|
+
self.xml.find_first('spType').content if self.xml.find_first('spType')
|
266
|
+
end
|
267
|
+
|
268
|
+
# The canonical name of the object.
|
269
|
+
def oname
|
270
|
+
self.xml.find_first('oname').content if self.xml.find_first('oname')
|
271
|
+
end
|
272
|
+
|
273
|
+
# The number of references to this object.
|
274
|
+
def nrefs
|
275
|
+
self.xml.find_first('nrefs').content.to_i if self.xml.find_first('nrefs')
|
276
|
+
end
|
277
|
+
|
278
|
+
# A list of aliases for the object.
|
279
|
+
# Returns a list of strings.
|
280
|
+
def aliases
|
281
|
+
self.xml.find('alias').collect{ |a| a.content }
|
282
|
+
end
|
283
|
+
|
284
|
+
# The J2000 position of the object in degrees or sexigesimal format.
|
285
|
+
# info.position(:degrees) # => [202.4682083, 47.1946667]
|
286
|
+
# info.position(:sexigesimal) # => ['13:29:52.36', '+47:11:40.8']
|
287
|
+
def position(as=:degrees)
|
288
|
+
case as
|
289
|
+
when :sexigesimal then (self.jpos || '').split(/\s+/)
|
290
|
+
else
|
291
|
+
[self.jradeg, self.jdedeg]
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
end
|