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.
Files changed (257) hide show
  1. data/Rakefile.rb +107 -224
  2. data/lib/misc.rb +1 -0
  3. data/lib/misc/misc.rb +60 -0
  4. data/lib/misc/propertyfile.rb +31 -0
  5. data/lib/symphony.rb +1 -0
  6. data/lib/symphony/symphony.rb +247 -0
  7. data/lib/voruby.rb +186 -0
  8. data/lib/voruby/active_votable/active_votable.rb +468 -347
  9. data/lib/voruby/adql/1.0/adql.rb +2418 -0
  10. data/lib/voruby/adql/support.rb +2 -0
  11. data/lib/voruby/misc.rb +351 -0
  12. data/lib/voruby/misc/connection_monitor.rb +97 -0
  13. data/lib/voruby/misc/libxml_ext.rb +121 -0
  14. data/lib/voruby/misc/rexml_ext.rb +223 -0
  15. data/lib/voruby/resolver/resolver.rb +12 -0
  16. data/lib/voruby/resolver/sesame.rb +299 -0
  17. data/lib/voruby/sky_query/sky_query.rb +192 -0
  18. data/lib/voruby/stc/1.10/coords.rb +2272 -0
  19. data/lib/voruby/stc/1.10/region.rb +892 -0
  20. data/lib/voruby/stc/1.10/stc.rb +3271 -0
  21. data/lib/voruby/stc/1.30/stc.rb +8666 -0
  22. data/lib/voruby/stc/support.rb +2 -0
  23. data/lib/voruby/ucd/ucd.rb +173 -0
  24. data/lib/voruby/voevent/1.1/voevent.rb +1124 -0
  25. data/lib/voruby/voevent/support.rb +5 -0
  26. data/lib/voruby/votable/1.0/votable.rb +1807 -0
  27. data/lib/voruby/votable/1.1/votable.rb +2100 -0
  28. data/lib/voruby/votable/votable.rb +305 -0
  29. data/lib/voruby/wesix/wesix.rb +491 -0
  30. data/lib/voruby/xlink/1.2/xlink.rb +21 -0
  31. data/test/voruby/active_votable/complex.vot +60 -0
  32. data/test/voruby/active_votable/error.vot +6 -0
  33. data/test/voruby/active_votable/large.vot +130040 -0
  34. data/test/voruby/active_votable/simple1.vot +38 -0
  35. data/test/voruby/active_votable/simple2.vot +38 -0
  36. data/test/voruby/active_votable/test.rb +193 -0
  37. data/test/voruby/adql/1.0/adql-alias.sql +1 -0
  38. data/test/voruby/adql/1.0/adql-alias.xml +26 -0
  39. data/test/voruby/adql/1.0/adql-avg.sql +1 -0
  40. data/test/voruby/adql/1.0/adql-avg.xml +31 -0
  41. data/test/voruby/adql/1.0/adql-circle.sql +1 -0
  42. data/test/voruby/adql/1.0/adql-circle.xml +46 -0
  43. data/test/voruby/adql/1.0/adql-expr.sql +1 -0
  44. data/test/voruby/adql/1.0/adql-expr.xml +34 -0
  45. data/test/voruby/adql/1.0/adql-function.sql +1 -0
  46. data/test/voruby/adql/1.0/adql-function.xml +41 -0
  47. data/test/voruby/adql/1.0/adql-group.sql +1 -0
  48. data/test/voruby/adql/1.0/adql-group.xml +51 -0
  49. data/test/voruby/adql/1.0/adql-having.sql +1 -0
  50. data/test/voruby/adql/1.0/adql-having.xml +25 -0
  51. data/test/voruby/adql/1.0/adql-like.sql +1 -0
  52. data/test/voruby/adql/1.0/adql-like.xml +17 -0
  53. data/test/voruby/adql/1.0/adql-order.sql +1 -0
  54. data/test/voruby/adql/1.0/adql-order.xml +37 -0
  55. data/test/voruby/adql/1.0/adql-simple.sql +1 -0
  56. data/test/voruby/adql/1.0/adql-simple.xml +12 -0
  57. data/test/voruby/adql/1.0/adql-top.sql +1 -0
  58. data/test/voruby/adql/1.0/adql-top.xml +33 -0
  59. data/test/voruby/adql/1.0/test.rb +2220 -0
  60. data/test/voruby/misc/test.rb +32 -0
  61. data/test/voruby/resolver/sesame/test.rb +56 -0
  62. data/test/voruby/sky_query/test.rb +107 -0
  63. data/test/voruby/stc/1.10/coords_test.rb +3704 -0
  64. data/test/voruby/stc/1.10/region_test.rb +993 -0
  65. data/test/voruby/stc/1.10/stc-catalog-entry-location.xml +112 -0
  66. data/test/voruby/stc/1.10/stc-obs-data-location.xml +126 -0
  67. data/test/voruby/stc/1.10/stc-region-circle.xml +5 -0
  68. data/test/voruby/stc/1.10/stc-region-convex.xml +11 -0
  69. data/test/voruby/stc/1.10/stc-region-convexhull.xml +5 -0
  70. data/test/voruby/stc/1.10/stc-region-ellipse.xml +7 -0
  71. data/test/voruby/stc/1.10/stc-region-intersection.xml +25 -0
  72. data/test/voruby/stc/1.10/stc-region-negation.xml +7 -0
  73. data/test/voruby/stc/1.10/stc-region-polygon.xml +13 -0
  74. data/test/voruby/stc/1.10/stc-region-sector.xml +6 -0
  75. data/test/voruby/stc/1.10/stc-region-union.xml +25 -0
  76. data/test/voruby/stc/1.10/stc-resource-profile.xml +60 -0
  77. data/test/voruby/stc/1.10/stc-search-location.xml +54 -0
  78. data/test/voruby/stc/1.10/stc_test.rb +4626 -0
  79. data/test/voruby/stc/1.30/stc-catalog-entry-location.xml +210 -0
  80. data/test/voruby/stc/1.30/stc-obs-data-location-arecibo.xml +353 -0
  81. data/test/voruby/stc/1.30/stc-obs-data-location-fits.xml +250 -0
  82. data/test/voruby/stc/1.30/stc-obs-data-location-xlink.xml +63 -0
  83. data/test/voruby/stc/1.30/stc-obs-data-location.xml +216 -0
  84. data/test/voruby/stc/1.30/stc-resource-profile-unusual-ref-pos.xml +39 -0
  85. data/test/voruby/stc/1.30/stc-resource-profile.xml +129 -0
  86. data/test/voruby/stc/1.30/stc-search-location-arecibo.xml +86 -0
  87. data/test/voruby/stc/1.30/stc-search-location.xml +101 -0
  88. data/test/voruby/stc/1.30/test.rb +6274 -0
  89. data/test/voruby/ucd/test.rb +48 -0
  90. data/test/voruby/voevent/1.1/test.rb +812 -0
  91. data/test/{voevent/voevent_v1_1.xml → voruby/voevent/1.1/voevent.xml} +2 -2
  92. data/test/voruby/voregistry/0.3/test.rb +137 -0
  93. data/test/voruby/votable/1.0/test.rb +714 -0
  94. data/test/voruby/votable/1.0/votable.basic.xml +660 -0
  95. data/test/voruby/votable/1.0/votable.html +86 -0
  96. data/test/voruby/votable/1.0/votable.ns.xml +56 -0
  97. data/test/voruby/votable/1.1/test.rb +785 -0
  98. data/test/voruby/votable/1.1/votable.basic.xml +38 -0
  99. data/test/voruby/votable/1.1/votable.html +86 -0
  100. data/test/voruby/votable/1.1/votable.ns.xml +56 -0
  101. data/test/voruby/votable/test.rb +15 -0
  102. data/test/voruby/wesix/test.rb +268 -0
  103. data/test/voruby/wesix/testr.fits +28 -0
  104. metadata +234 -247
  105. data/REQUIREMENTS +0 -6
  106. data/lib/voruby/active_votable/loader.rb +0 -5
  107. data/lib/voruby/adql/adql.rb +0 -2787
  108. data/lib/voruby/adql/ext.rb +0 -14
  109. data/lib/voruby/adql/loader.rb +0 -6
  110. data/lib/voruby/adql/operations.rb +0 -54
  111. data/lib/voruby/adql/parser.rb +0 -160
  112. data/lib/voruby/adql/transforms.rb +0 -573
  113. data/lib/voruby/ext.rb +0 -17
  114. data/lib/voruby/loader.rb +0 -4
  115. data/lib/voruby/misc/propertyfile.rb +0 -36
  116. data/lib/voruby/plastic/applications.rb +0 -174
  117. data/lib/voruby/plastic/constants.rb +0 -30
  118. data/lib/voruby/plastic/loader.rb +0 -10
  119. data/lib/voruby/plastic/plastic.rb +0 -1
  120. data/lib/voruby/resources/conesearch/conesearch.rb +0 -9
  121. data/lib/voruby/resources/conesearch/conesearch_v0_2.rb +0 -55
  122. data/lib/voruby/resources/conesearch/conesearch_v0_3.rb +0 -50
  123. data/lib/voruby/resources/conesearch/conesearch_v1_0.rb +0 -72
  124. data/lib/voruby/resources/conesearch/loader.rb +0 -4
  125. data/lib/voruby/resources/loader.rb +0 -50
  126. data/lib/voruby/resources/nodes.rb +0 -190
  127. data/lib/voruby/resources/openskynode/loader.rb +0 -4
  128. data/lib/voruby/resources/openskynode/openskynode.rb +0 -9
  129. data/lib/voruby/resources/openskynode/openskynode_v0_1.rb +0 -54
  130. data/lib/voruby/resources/sia/loader.rb +0 -5
  131. data/lib/voruby/resources/sia/sia.rb +0 -9
  132. data/lib/voruby/resources/sia/sia_v0_6.rb +0 -90
  133. data/lib/voruby/resources/sia/sia_v0_7.rb +0 -89
  134. data/lib/voruby/resources/sia/sia_v1_0.rb +0 -122
  135. data/lib/voruby/resources/stsci.rb +0 -59
  136. data/lib/voruby/resources/vodataservice/coverage_v0_2.rb +0 -195
  137. data/lib/voruby/resources/vodataservice/coverage_v0_3.rb +0 -158
  138. data/lib/voruby/resources/vodataservice/loader.rb +0 -5
  139. data/lib/voruby/resources/vodataservice/vodataservice.rb +0 -9
  140. data/lib/voruby/resources/vodataservice/vodataservice_v0_4.rb +0 -189
  141. data/lib/voruby/resources/vodataservice/vodataservice_v0_5.rb +0 -163
  142. data/lib/voruby/resources/vodataservice/vodataservice_v1_0.rb +0 -221
  143. data/lib/voruby/resources/voregistry/loader.rb +0 -4
  144. data/lib/voruby/resources/voregistry/voregistry.rb +0 -9
  145. data/lib/voruby/resources/voregistry/voregistry_v0_2.rb +0 -40
  146. data/lib/voruby/resources/voregistry/voregistry_v0_3.rb +0 -30
  147. data/lib/voruby/resources/voregistry/voregistry_v1_0.rb +0 -86
  148. data/lib/voruby/resources/voresource/loader.rb +0 -17
  149. data/lib/voruby/resources/voresource/voresource.rb +0 -9
  150. data/lib/voruby/resources/voresource/voresource_v0_10.rb +0 -327
  151. data/lib/voruby/resources/voresource/voresource_v0_9.rb +0 -405
  152. data/lib/voruby/resources/voresource/voresource_v1_0.rb +0 -230
  153. data/lib/voruby/services/ext.rb +0 -11
  154. data/lib/voruby/services/gestalt/footprint.rb +0 -95
  155. data/lib/voruby/services/gestalt/wcs_fixer.rb +0 -105
  156. data/lib/voruby/services/gestalt/wesix.rb +0 -155
  157. data/lib/voruby/services/loader.rb +0 -7
  158. data/lib/voruby/services/registry/registry.rb +0 -53
  159. data/lib/voruby/services/resolver/resolver.rb +0 -35
  160. data/lib/voruby/services/schema/schema.rb +0 -644
  161. data/lib/voruby/sesame/loader.rb +0 -6
  162. data/lib/voruby/sesame/sesame_v1_0.rb +0 -64
  163. data/lib/voruby/simple/loader.rb +0 -6
  164. data/lib/voruby/simple/parameters.rb +0 -196
  165. data/lib/voruby/simple/sap.rb +0 -446
  166. data/lib/voruby/spacetime/loader.rb +0 -3
  167. data/lib/voruby/spacetime/spacetime.rb +0 -607
  168. data/lib/voruby/stc/coords_v1_20.rb +0 -900
  169. data/lib/voruby/stc/loader.rb +0 -55
  170. data/lib/voruby/stc/region_v1_20.rb +0 -274
  171. data/lib/voruby/stc/stc_v1_20.rb +0 -1196
  172. data/lib/voruby/util.rb +0 -27
  173. data/lib/voruby/voevent/loader.rb +0 -7
  174. data/lib/voruby/voevent/voevent_v1_0.rb +0 -213
  175. data/lib/voruby/voevent/voevent_v1_1.rb +0 -196
  176. data/lib/voruby/votables/chandra.rb +0 -373
  177. data/lib/voruby/votables/data.rb +0 -179
  178. data/lib/voruby/votables/galex.rb +0 -377
  179. data/lib/voruby/votables/int.rb +0 -354
  180. data/lib/voruby/votables/libxml_parser.rb +0 -411
  181. data/lib/voruby/votables/libxml_votable.rb +0 -67
  182. data/lib/voruby/votables/loader.rb +0 -10
  183. data/lib/voruby/votables/meta.rb +0 -763
  184. data/lib/voruby/votables/misc.rb +0 -51
  185. data/lib/voruby/votables/nsa.rb +0 -410
  186. data/lib/voruby/votables/rexml_parser.rb +0 -408
  187. data/lib/voruby/votables/rexml_votable.rb +0 -67
  188. data/lib/voruby/votables/sdss.rb +0 -356
  189. data/lib/voruby/votables/transforms.rb +0 -388
  190. data/lib/voruby/votables/tree.rb +0 -45
  191. data/lib/voruby/votables/types.rb +0 -391
  192. data/lib/voruby/votables/votable.rb +0 -687
  193. data/test/active_votable/database.yml +0 -6
  194. data/test/active_votable/test.vot +0 -168492
  195. data/test/active_votable/unittest.rb +0 -41
  196. data/test/adql/test1.adql +0 -49
  197. data/test/adql/test2.adql +0 -51
  198. data/test/adql/test3.adql +0 -81
  199. data/test/adql/test4.adql +0 -53
  200. data/test/adql/test5.adql +0 -55
  201. data/test/adql/test6.adql +0 -18
  202. data/test/adql/test7.adql +0 -48
  203. data/test/adql/unittest.rb +0 -1672
  204. data/test/plastic/test.rb +0 -44
  205. data/test/plastic/test.vot +0 -5385
  206. data/test/plastic/unittest.rb +0 -66
  207. data/test/resources/conesearch/conesearch_v0_3.xml +0 -31
  208. data/test/resources/conesearch/conesearch_v1_0.xml +0 -86
  209. data/test/resources/conesearch/unittest_v0_3.rb +0 -22
  210. data/test/resources/conesearch/unittest_v1_0.rb +0 -24
  211. data/test/resources/openskynode/open_sky_node_v0_1.xml +0 -32
  212. data/test/resources/openskynode/unittest_v0_1.rb +0 -31
  213. data/test/resources/sia/simple_image_access_v0_7.xml +0 -36
  214. data/test/resources/sia/simple_image_access_v1_0.xml +0 -122
  215. data/test/resources/sia/unittest_v0_7.rb +0 -24
  216. data/test/resources/sia/unittest_v1_0.rb +0 -29
  217. data/test/resources/stsci.xml +0 -336
  218. data/test/resources/unittest_stsci.rb +0 -25
  219. data/test/resources/vodataservice/catalog_service_resource_v1_0.xml +0 -128
  220. data/test/resources/vodataservice/data_collection_resource_v0_5.xml +0 -54
  221. data/test/resources/vodataservice/data_collection_resource_v1_0.xml +0 -117
  222. data/test/resources/vodataservice/data_service_resource_v1_0.xml +0 -115
  223. data/test/resources/vodataservice/sky_service_resource_v0_10.xml +0 -45
  224. data/test/resources/vodataservice/table_service_resource_v1_0.xml +0 -122
  225. data/test/resources/vodataservice/tabular_sky_service_resource_v0_10.xml +0 -60
  226. data/test/resources/vodataservice/unittest_v0_5.rb +0 -126
  227. data/test/resources/vodataservice/unittest_v1_0.rb +0 -151
  228. data/test/resources/voregistry/authority_resource_v0_3.xml +0 -20
  229. data/test/resources/voregistry/authority_resource_v1_0.xml +0 -82
  230. data/test/resources/voregistry/registry_service_v0_3.xml +0 -20
  231. data/test/resources/voregistry/registry_service_v1_0.xml +0 -107
  232. data/test/resources/voregistry/unittest_v0_3.rb +0 -31
  233. data/test/resources/voregistry/unittest_v1_0.rb +0 -34
  234. data/test/resources/voresource/organisation_resource_v1_0.xml +0 -90
  235. data/test/resources/voresource/resource_organisation_v0_10.xml +0 -22
  236. data/test/resources/voresource/resource_service_v0_10.xml +0 -19
  237. data/test/resources/voresource/resource_v0_10.xml +0 -19
  238. data/test/resources/voresource/resource_v1_0.xml +0 -79
  239. data/test/resources/voresource/service_resource_v1_0.xml +0 -91
  240. data/test/resources/voresource/unittest_v0_10.rb +0 -61
  241. data/test/resources/voresource/unittest_v0_9.rb +0 -4
  242. data/test/resources/voresource/unittest_v1_0.rb +0 -190
  243. data/test/services/gestalt/unittest.rb +0 -74
  244. data/test/services/registry/unittest.rb +0 -34
  245. data/test/services/resolver/unittest.rb +0 -38
  246. data/test/simple/unittest.rb +0 -46
  247. data/test/spacetime/unittest.rb +0 -39
  248. data/test/stc/catalog_entry_location_v1_20.xml +0 -112
  249. data/test/stc/obs_data_location_v1_20.xml +0 -108
  250. data/test/stc/search_location_v1_20.xml +0 -54
  251. data/test/stc/stc_resource_profile_v1_20.xml +0 -60
  252. data/test/stc/unittest_v1_20.rb +0 -620
  253. data/test/voevent/unittest_v1_0.rb +0 -79
  254. data/test/voevent/unittest_v1_1.rb +0 -70
  255. data/test/voevent/voevent_v1_0.xml +0 -96
  256. data/test/votables/test.vot +0 -366
  257. 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