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,2 @@
1
+ require 'rexml/document'
2
+ require 'voruby/misc'
@@ -0,0 +1,173 @@
1
+ require 'soap/rpc/driver'
2
+ require 'ostruct'
3
+
4
+ module VORuby
5
+ # Unified Content Descriptors[http://www.ivoa.net/Documents/latest/UCD.html] or UCDs constitute a controlled vocabulary
6
+ # used throughout the VO. This class provides some useful methods for dealing with them.
7
+ class UCD
8
+ attr_accessor :check_availability
9
+
10
+ # Create a new UCD resolver.
11
+ # <tt>options</tt> is a hash with the following keys:
12
+ #
13
+ # [<tt>:end_point</tt>] the UCD SOAP endpoint to use (default: http://cdsws.u-strasbg.fr/axis/services/UCD)
14
+ # [<tt>:check_availability</tt>] whether to try to determine if the sesame service is available or not before each name resolution (default: false)
15
+ #
16
+ # ucd = UCD.new(
17
+ # :end_point => 'ttp://vizier.hia.nrc.ca:8080/axis/services/UCD' # maybe we're in Canada...
18
+ # :check_availability => true # and we want to always check the availability of the service
19
+ # )
20
+ def initialize(options={})
21
+ self.end_point = options[:end_point] || 'http://cdsws.u-strasbg.fr/axis/services/UCD'
22
+ self.check_availability = options[:check_availability] || false
23
+ end
24
+
25
+ # The "end-point" or location of the UCD resolver's webservice.
26
+ def end_point
27
+ @end_point
28
+ end
29
+
30
+ # Set the end-point or location of the UCD resolver's webservice.
31
+ # ucd.end_point = 'http://vizier.hia.nrc.ca:8080/axis/services/UCD'
32
+ def end_point=(epoint)
33
+ @end_point = epoint
34
+
35
+ @resolver = SOAP::RPC::Driver.new(@end_point)
36
+ @resolver.add_rpc_method('translate', 'ucd')
37
+ @resolver.add_rpc_method('assign', 'descr')
38
+ @resolver.add_rpc_method('explain', 'ucd')
39
+ @resolver.add_rpc_method('resolveUCD', 'ucd')
40
+ @resolver.add_rpc_method('validate', 'ucd')
41
+ @resolver.add_rpc_method('upgrade','ucd')
42
+ @resolver.add_rpc_method('getAvailability')
43
+ end
44
+
45
+ # Translate an old-style UCD1 into it's newer UCD1+ form.
46
+ # Returns <tt>nil</tt> if the UCD is untranslatable.
47
+ #
48
+ # ucd.translate('POS_EQ_RA_MAIN') # => 'pos.eq.ra;meta.main'
49
+ def translate(ucd)
50
+ raise "UCD resolver at #{self.end_point} is not currently available" if self.check_availability and !self.available?
51
+
52
+ ucd_plus = @resolver.translate(ucd).strip
53
+ ucd_plus.match('Could not translate') ? nil : ucd_plus
54
+ end
55
+
56
+ # Convenience class method for #translate.
57
+ def self.translate(ucd, options={})
58
+ self.new(options).translate(ucd)
59
+ end
60
+
61
+ # Given a text description of a parameter (i.e. V magnitude), find
62
+ # a likely corresponding UCD1+. Returns <tt>nil</tt> if no UCD is found.
63
+ #
64
+ # ucd.assign('V magnitude') # => 'phot.mag;em.opt.V'
65
+ def assign(descr)
66
+ raise "UCD resolver at #{self.end_point} is not currently available" if self.check_availability and !self.available?
67
+
68
+ ucd_plus = @resolver.assign(descr).strip
69
+ ucd_plus.match('Could not find') ? nil : ucd_plus
70
+ end
71
+
72
+ # Convenience class method for #assign.
73
+ def self.assign(descr, options={})
74
+ self.new(options).assign(descr)
75
+ end
76
+
77
+ # Given a UCD, discover a human-readable description.
78
+ # <tt>version</tt> may be '1+' (the default) for a UCD1+ or
79
+ # '1' for an old-style UCD.
80
+ # Returns <tt>nil</tt> if the UCD is not recognized.
81
+ #
82
+ # ucd.explain('ivoa:phot.mag;em.opt.B') # => 'Photometric magnitude / Optical band between 400 and 500 nm'
83
+ # ucd.explain('PHOT_JHN_V', '1') # => 'Johnson magnitude V (JHN)'
84
+ def explain(ucd, version='1+')
85
+ version ||= '1+'
86
+ raise "UCD resolver at #{self.end_point} is not currently available" if self.check_availability and !self.available?
87
+
88
+ descr = case version
89
+ when '1'
90
+ @resolver.resolveUCD(ucd)
91
+ else
92
+ @resolver.explain(ucd)
93
+ end
94
+
95
+ (descr.match('Non-standard UCD') or descr.match('Invalid UCD')) ? nil : descr.strip
96
+ end
97
+
98
+ # Convenience class method for #explain.
99
+ def self.explain(ucd, version='1+', options={})
100
+ self.new(options).explain(ucd, version)
101
+ end
102
+
103
+ # Validate a specifed UCD1+. Returns an object that responds
104
+ # to a #code method and a human-readable list of of error strings.
105
+ # A <tt>code</tt> of 0 implies the UCD is valid. Possible combinations
106
+ # arise from bitwise-OR'ing the following:
107
+ #
108
+ # * 1: warning indicating use of non-standard namespace (not ivoa:)
109
+ # * 2: use of deprecated word
110
+ # * 4: use of non-existing word
111
+ # * 8: syntax error (extra space or unallowed character)
112
+ #
113
+ # result = ucd.validate('ivob:phot.mag;em.opt.Z')
114
+ # puts result.code # => 5
115
+ # puts result.errors => ["use of non-standard namespace 'ivob'", "invalid UCD word 'em.opt.Z'"]
116
+ def validate(ucd)
117
+ raise "UCD resolver at #{self.end_point} is not currently available" if self.check_availability and !self.available?
118
+
119
+ error = @resolver.validate(ucd).strip
120
+ parts = error.split(/\s*\*\*\*\*\s*/)
121
+
122
+ OpenStruct.new(
123
+ :code => parts.first.to_i,
124
+ :errors => parts[1..-1]
125
+ )
126
+ end
127
+
128
+ # Convenience class method for #validate.
129
+ def self.validate(ucd, options={})
130
+ self.new(options).validate(ucd)
131
+ end
132
+
133
+ # Returns true or false depending on whether a UCD1+ is
134
+ # valid. This is the same checking the <tt>code</tt> on the object
135
+ # that #validate returns.
136
+ #
137
+ # ucd.valid?('ivob:phot.mag;em.opt.Z') # => false
138
+ # ucd.valid?('ivoa:phot.mag;em.opt.B') # => true
139
+ def valid?(ucd)
140
+ self.validate(ucd).code == 0 ? true : false
141
+ end
142
+
143
+ # Convenience class method for #valid?.
144
+ def self.valid?(ucd, options={})
145
+ self.new(options).valid?(ucd)
146
+ end
147
+
148
+ # Find a valid UCD1+ corresponding to a deprecated word.
149
+ #
150
+ # ucd.upgrade('pos.gal.lat') # => 'pos.galactic.lat'
151
+ def upgrade(ucd)
152
+ raise "UCD resolver at #{self.end_point} is not currently available" if self.check_availability and !self.available?
153
+ @resolver.upgrade(ucd).strip
154
+ end
155
+
156
+ # Convenience class method for #upgrade.
157
+ def self.upgrade(ucd, options={})
158
+ self.new(options).upgrade(ucd)
159
+ end
160
+
161
+ # Checks to see whether the UCD resolver is available.
162
+ # At this point it's assumed the service is present at
163
+ # the location specified by #end_point. This just checks
164
+ # to see whether sesame reports itself as available or not.
165
+ def available?
166
+ # We don't use an XML parser here because (as of 2007-01-04)
167
+ # the validTo tag isn't closed properly, rendering the XML
168
+ # malformed.
169
+ result = @resolver.getAvailability
170
+ result.match(/<available>\s*(.*)\s*<\/available>/)[1] == 'true'
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,1124 @@
1
+ require 'voruby/voevent/support'
2
+ require 'voruby/stc/1.30/stc'
3
+ include VORuby::STC::V1_30
4
+
5
+ module VORuby
6
+ module VOEvent
7
+ module V1_1
8
+ include XMLUtilities
9
+
10
+ class Base
11
+ include SerializableToXml
12
+ end
13
+
14
+ # External content.
15
+ class Reference < Base
16
+ attr_accessor :type, :name
17
+ attr_reader :uri
18
+
19
+ def initialize(uri, type='url', name=nil)
20
+ self.uri = uri
21
+ self.type = type || 'url'
22
+ self.name = name
23
+ end
24
+
25
+ def uri=(u)
26
+ raise_argument_required_error('URI') if !u
27
+ @uri = u.is_a?(URI) ? u : URI.parse(u.to_s)
28
+ end
29
+
30
+ def ==(r)
31
+ self.uri == r.uri and
32
+ self.type == r.type and
33
+ self.name == r.name
34
+ end
35
+
36
+ def to_xml(name=nil)
37
+ el = element(name)
38
+
39
+ el.attributes["#{obj_ns.prefix}:uri"] = self.uri.to_s
40
+ el.attributes["#{obj_ns.prefix}:name"] = self.name.to_s if self.name
41
+ el.attributes["#{obj_ns.prefix}:type"] = self.type.to_s if self.type
42
+
43
+ el
44
+ end
45
+
46
+ def self.from_xml(xml)
47
+ root = element_from(xml)
48
+
49
+ name = root.attributes.get_attribute_ns(obj_ns.uri, 'name')
50
+ type = root.attributes.get_attribute_ns(obj_ns.uri, 'type')
51
+
52
+ self.new(
53
+ URI.parse(root.attributes.get_attribute_ns(obj_ns.uri, 'uri').value),
54
+ type ? type.value : nil,
55
+ name ? name.value : nil
56
+ )
57
+ end
58
+ end
59
+
60
+ # Human readable text.
61
+ class Description < Base
62
+ attr_accessor :format
63
+ attr_reader :value
64
+
65
+ def initialize(value, format='text/plain')
66
+ self.value = value
67
+ self.format = format || 'text/plain'
68
+ end
69
+
70
+ def value=(v)
71
+ raise_argument_required_error('description value') if !v
72
+ @value = v.to_s
73
+ end
74
+
75
+ def ==(d)
76
+ self.value == d.value and
77
+ self.format == d.format
78
+ end
79
+
80
+ def to_xml(name=nil)
81
+ el = element(name)
82
+
83
+ el.text = self.value.to_s
84
+ el.attributes["#{obj_ns.prefix}:format"] = self.format.to_s if self.format
85
+
86
+ el
87
+ end
88
+
89
+ def self.from_xml(xml)
90
+ root = element_from(xml)
91
+
92
+ format = root.attributes.get_attribute_ns(obj_ns.uri, 'format')
93
+
94
+ self.new(
95
+ root.texts.join('').strip,
96
+ format ? format.value : nil
97
+ )
98
+ end
99
+ end
100
+
101
+ class Cite < Enumeration
102
+ def self.choices; ['followup', 'supersedes', 'retraction'] end
103
+ end
104
+
105
+ class EventIVORN < Base
106
+ attr_reader :uri, :cite
107
+
108
+ def initialize(uri, cite)
109
+ self.uri = uri
110
+ self.cite = cite
111
+ end
112
+
113
+ def uri=(u)
114
+ raise_argument_required_error('URI') if !u
115
+ @uri = u.is_a?(URI) ? u : URI.parse(u.to_s)
116
+ end
117
+
118
+ def cite=(c)
119
+ raise_argument_required_error('cite') if !c
120
+
121
+ c = Cite.new(c) if c.is_a?(String)
122
+ raise_type_mismatch_error(c, Cite)
123
+
124
+ @cite = c
125
+ end
126
+
127
+ def ==(i)
128
+ self.uri == i.uri and
129
+ self.cite == i.cite
130
+ end
131
+
132
+ def to_xml(name=nil)
133
+ el = element(name)
134
+
135
+ el.text = self.uri.to_s
136
+ el.attributes["#{obj_ns.prefix}:cite"] = self.cite.to_s
137
+
138
+ el
139
+ end
140
+
141
+ def self.from_xml(xml)
142
+ root = element_from(xml)
143
+
144
+ self.new(
145
+ root.text,
146
+ Cite.new(root.attributes.get_attribute_ns(obj_ns.uri, 'cite').value)
147
+ )
148
+ end
149
+ end
150
+
151
+ class DescriptionList < TypedArray
152
+ def self.restricted_to; [Description] end
153
+ end
154
+
155
+ class ReferenceList < TypedArray
156
+ def self.restricted_to; [Reference] end
157
+ end
158
+
159
+ class Described < Base
160
+ attr_reader :descriptions, :references
161
+
162
+ def initialize(descriptions=nil, references=nil)
163
+ self.descriptions = descriptions
164
+ self.references = references
165
+ end
166
+
167
+ def descriptions=(ds)
168
+ if ds
169
+ ds = DescriptionList.new(ds) if ds.class == Array
170
+ raise_type_mismatch_error(ds, DescriptionList)
171
+ end
172
+
173
+ @descriptions = ds
174
+ end
175
+
176
+ def references=(rs)
177
+ if rs
178
+ rs = ReferenceList.new(rs) if rs.class == Array
179
+ raise_type_mismatch_error(rs, ReferenceList)
180
+ end
181
+
182
+ @references = rs
183
+ end
184
+
185
+ def ==(h)
186
+ self.descriptions == h.descriptions and
187
+ self.references == h.references
188
+ end
189
+
190
+ def to_xml(name=nil)
191
+ el = element(name)
192
+
193
+ self.descriptions.each{ |d| el.add_element(d.to_xml('Description')) } if self.descriptions
194
+ self.references.each{ |r| el.add_element(r.to_xml('Reference')) } if self.references
195
+
196
+ collapse_namespaces(el)
197
+ el
198
+ end
199
+
200
+ def self.described_from_xml(root)
201
+ descrs = REXML::XPath.match(root, 'x:Description', {'x' => obj_ns.uri})
202
+ descrs = nil if descrs.size == 0
203
+
204
+ refs = REXML::XPath.match(root, 'x:Reference', {'x' => obj_ns.uri})
205
+ refs = nil if refs.size == 0
206
+
207
+ [
208
+ descrs ? DescriptionList.new(descrs.collect{ |d| Description.from_xml(d) }) : nil,
209
+ refs ? ReferenceList.new(refs.collect{ |r| Reference.from_xml(r) }) : nil
210
+ ]
211
+ end
212
+
213
+ def self.from_xml(xml)
214
+ root = element_from(xml)
215
+ self.new(*described_from_xml(root))
216
+ end
217
+ end
218
+
219
+ # Follow-up Observations.
220
+ class Citations < Described
221
+ class EventIVORNList < TypedArray
222
+ def self.restricted_to; [EventIVORN] end
223
+ def self.minimum_length; 1 end
224
+ end
225
+
226
+ attr_reader :event_ivorns
227
+
228
+ def initialize(ivorns, descriptions=nil, references=nil)
229
+ super(descriptions, references)
230
+ self.event_ivorns = ivorns
231
+ end
232
+
233
+ def event_ivorns=(eis)
234
+ raise_argument_required_error('event IVORNs') if !eis
235
+
236
+ eis = EventIVORNList.new(eis) if eis.class == Array
237
+ raise_type_mismatch_error(eis, EventIVORNList)
238
+
239
+ @event_ivorns = eis
240
+ end
241
+
242
+ def ==(c)
243
+ super(c) and
244
+ self.event_ivorns == c.event_ivorns
245
+ end
246
+
247
+ def to_xml(name=nil)
248
+ el = super(name)
249
+
250
+ self.event_ivorns.each{ |i| el.add_element(i.to_xml('EventIVORN')) }
251
+
252
+ collapse_namespaces(el)
253
+ el
254
+ end
255
+
256
+ def self.from_xml(xml)
257
+ root = element_from(xml)
258
+
259
+ ivorns = REXML::XPath.match(root, 'x:EventIVORN', {'x' => obj_ns.uri})
260
+ ivorns = nil if ivorns.size == 0
261
+
262
+ self.new(
263
+ ivorns ? EventIVORNList.new(ivorns.collect{ |e| EventIVORN.from_xml(e) }) : nil,
264
+ *Described.described_from_xml(root)
265
+ )
266
+ end
267
+ end
268
+
269
+ class NameList < TypedArray
270
+ def self.restricted_to; [String] end
271
+ end
272
+
273
+ class ConceptList < TypedArray
274
+ def self.restricted_to; [String] end
275
+ end
276
+
277
+ class Inference < Described
278
+ attr_reader :names, :concepts, :probability, :relation
279
+
280
+ def initialize(names, concepts, probability=nil, relation=nil, descriptions=nil, references=nil)
281
+ super(descriptions, references)
282
+ self.names = names
283
+ self.concepts = concepts
284
+ self.probability = probability
285
+ self.relation = relation
286
+ end
287
+
288
+ def names=(ns)
289
+ if ns
290
+ ns = NameList.new(ns) if ns.class == Array
291
+ raise_type_mismatch_error(ns, NameList)
292
+ end
293
+
294
+ @names = ns
295
+ end
296
+
297
+ def concepts=(cs)
298
+ if cs
299
+ cs = ConceptList.new(cs) if cs.class == Array
300
+ raise_type_mismatch_error(cs, ConceptList)
301
+ end
302
+
303
+ @concepts = cs
304
+ end
305
+
306
+ def probability=(p)
307
+ if p
308
+ p = Float(p)
309
+ raise 'float must be between 0.0 and 1.0' if p < 0.0 or p > 1.0
310
+ end
311
+
312
+ @probability = p
313
+ end
314
+
315
+ def relation=(r)
316
+ @relation = r ? r.to_s : nil
317
+ end
318
+
319
+ def ==(i)
320
+ super(i) and
321
+ self.names == i.names and
322
+ self.concepts == i.concepts and
323
+ self.probability == i.probability and
324
+ self.relation == i.relation
325
+ end
326
+
327
+ def to_xml(name=nil)
328
+ el = super(name)
329
+
330
+ self.names.each{ |n|
331
+ name_el = REXML::Element.new("#{obj_ns.prefix}:Name")
332
+ name_el.text = n
333
+ el.add_element(name_el)
334
+ } if self.names
335
+
336
+ self.concepts.each{ |c|
337
+ concept_el = REXML::Element.new("#{obj_ns.prefix}:Concept")
338
+ concept_el.text = c
339
+ el.add_element(concept_el)
340
+ } if self.concepts
341
+
342
+ el.attributes["#{obj_ns.prefix}:probability"] = self.probability.to_s if self.probability
343
+ el.attributes["#{obj_ns.prefix}:relation"] = self.relation if self.relation
344
+
345
+ el
346
+ end
347
+
348
+ def self.from_xml(xml)
349
+ root = element_from(xml)
350
+
351
+ names = REXML::XPath.match(root, 'x:Name', {'x' => obj_ns.uri})
352
+ names = nil if names.size == 0
353
+
354
+ concepts = REXML::XPath.match(root, 'x:Concept', {'x' => obj_ns.uri})
355
+ concepts = nil if concepts.size == 0
356
+
357
+ probability = root.attributes.get_attribute_ns(obj_ns.uri, 'probability')
358
+ relation = root.attributes.get_attribute_ns(obj_ns.uri, 'relation')
359
+
360
+ self.new(
361
+ names ? NameList.new(names.collect{ |name| name.text }) : nil,
362
+ concepts ? ConceptList.new(concepts.collect{ |concept| concept.text }) : nil,
363
+ probability ? Float(probability.value) : nil,
364
+ relation ? relation.value : nil,
365
+ *Described.described_from_xml(root)
366
+ )
367
+ end
368
+ end
369
+
370
+ class InferenceList < TypedArray
371
+ def self.restricted_to; [Inference] end
372
+ end
373
+
374
+ # Initial scientific assessment.
375
+ class Why < Described
376
+ attr_reader :inferences, :importance, :expires, :names, :concepts
377
+
378
+ def initialize(inferences, importance=nil, expires=nil, names=nil, concepts=nil, descriptions=nil, references=nil)
379
+ super(descriptions, references)
380
+ self.inferences = inferences
381
+ self.importance = importance
382
+ self.expires = expires
383
+ self.names = names
384
+ self.concepts = concepts
385
+ end
386
+
387
+ def inferences=(is)
388
+ if is
389
+ is = InferenceList.new(is) if is.class == Array
390
+ raise_type_mismatch_error(is, InferenceList)
391
+ end
392
+
393
+ @inferences = is
394
+ end
395
+
396
+ def importance=(i)
397
+ i = Float(i) if i
398
+ @importance = i
399
+ end
400
+
401
+ def expires=(e)
402
+ if e
403
+ e = DateTime.parse(e) if e.is_a?(String)
404
+ raise_type_mismatch_error(e, DateTime)
405
+ end
406
+
407
+ @expires = e
408
+ end
409
+
410
+ def names=(ns)
411
+ if ns
412
+ ns = NameList.new(ns) if ns.class == Array
413
+ raise_type_mismatch_error(ns, NameList)
414
+ end
415
+
416
+ @names = ns
417
+ end
418
+
419
+ def concepts=(cs)
420
+ if cs
421
+ cs = ConceptList.new(cs) if cs.class == Array
422
+ raise_type_mismatch_error(cs, ConceptList)
423
+ end
424
+
425
+ @concepts = cs
426
+ end
427
+
428
+ def ==(w)
429
+ super(w) and
430
+ self.inferences == w.inferences and
431
+ self.importance == w.importance and
432
+ self.expires == w.expires and
433
+ self.names == w.names and
434
+ self.concepts == w.concepts
435
+ end
436
+
437
+ def to_xml(name=nil)
438
+ el = super(name)
439
+
440
+ self.inferences.each{ |i| el.add_element(i.to_xml('Inference')) } if self.inferences
441
+
442
+ el.attributes["#{obj_ns.prefix}:importance"] = self.importance.to_s if self.importance
443
+ el.attributes["#{obj_ns.prefix}:expires"] = self.expires.strftime('%Y-%m-%dT%H:%M:%S') if self.expires
444
+
445
+ self.names.each{ |n|
446
+ name_el = REXML::Element.new("#{obj_ns.prefix}:Name")
447
+ name_el.text = n
448
+ el.add_element(name_el)
449
+ } if self.names
450
+
451
+ self.concepts.each{ |c|
452
+ concept_el = REXML::Element.new("#{obj_ns.prefix}:Concept")
453
+ concept_el.text = c
454
+ el.add_element(concept_el)
455
+ } if self.concepts
456
+
457
+ collapse_namespaces(el)
458
+ el
459
+ end
460
+
461
+ def self.from_xml(xml)
462
+ root = element_from(xml)
463
+
464
+ inferences = REXML::XPath.match(root, 'x:Inference', {'x' => obj_ns.uri})
465
+ inferences = nil if inferences.size == 0
466
+
467
+ names = REXML::XPath.match(root, 'x:Name', {'x' => obj_ns.uri})
468
+ names = nil if names.size == 0
469
+
470
+ concepts = REXML::XPath.match(root, 'x:Concept', {'x' => obj_ns.uri})
471
+ concepts = nil if concepts.size == 0
472
+
473
+ importance = root.attributes.get_attribute_ns(obj_ns.uri, 'importance')
474
+ expires = root.attributes.get_attribute_ns(obj_ns.uri, 'expires')
475
+
476
+ self.new(
477
+ inferences ? InferenceList.new(inferences.collect{ |i| Inference.from_xml(i) }) : nil,
478
+ importance ? Float(importance.value) : nil,
479
+ expires ? DateTime.parse(expires.value) : nil,
480
+ names ? NameList.new(names.collect{ |n| n.text }) : nil,
481
+ concepts ? ConceptList.new(concepts.collect{ |c| c.text }) : nil,
482
+ *Described.described_from_xml(root)
483
+ )
484
+ end
485
+ end
486
+
487
+ # Instrument Configuration, references to RTML documents.
488
+ class How < Described; end
489
+
490
+ # Space-Time Coordinates, uses the VO STC schema.
491
+ class WhereWhen < Described
492
+ class ObsDataLocationList < TypedArray
493
+ def self.restricted_to; [ObsDataLocation] end
494
+ end
495
+
496
+ attr_reader :obs_data_locations
497
+
498
+ def initialize(obs_data_locations=nil, descriptions=nil, references=nil)
499
+ super(descriptions, references)
500
+ self.obs_data_locations = obs_data_locations
501
+ end
502
+
503
+ def obs_data_locations=(odls)
504
+ if odls
505
+ odls = ObsDataLocationList.new(odls) if odls.class == Array
506
+ raise_type_mismatch_error(odls, ObsDataLocationList)
507
+ end
508
+
509
+ @obs_data_locations = odls
510
+ end
511
+
512
+ def ==(w)
513
+ super(w) and
514
+ self.obs_data_locations == w.obs_data_locations
515
+ end
516
+
517
+ def to_xml(name=nil)
518
+ el = super(name)
519
+
520
+ self.obs_data_locations.each{ |l| el.add_element(l.to_xml) } if self.obs_data_locations
521
+
522
+ collapse_namespaces(el)
523
+ el
524
+ end
525
+
526
+ def self.from_xml(xml)
527
+ root = element_from(xml)
528
+
529
+ locs = REXML::XPath.match(root, 'x:ObsDataLocation', {'x' => obj_ns('VORuby::STC::V1_30').uri})
530
+ locs = nil if locs.size == 0
531
+
532
+ self.new(
533
+ locs ? ObsDataLocationList.new(locs.collect{ |l| ObsDataLocation.from_xml(l) }) : nil,
534
+ *Described.described_from_xml(root)
535
+ )
536
+ end
537
+ end
538
+
539
+ class Param < Base
540
+ attr_reader :name, :ucd, :value, :unit
541
+
542
+ def initialize(name, value, ucd=nil, unit=nil)
543
+ self.name = name
544
+ self.value = value
545
+ self.ucd = ucd
546
+ self.unit = unit
547
+ end
548
+
549
+ def name=(n)
550
+ @name = n ? n.to_s : nil
551
+ end
552
+
553
+ def value=(v)
554
+ @value = v ? v.to_s : nil
555
+ end
556
+
557
+ def ucd=(u)
558
+ @ucd = u ? u.to_s : nil
559
+ end
560
+
561
+ def unit=(u)
562
+ @unit = u ? u.to_s : nil
563
+ end
564
+
565
+ def ==(p)
566
+ self.name == p.name and
567
+ self.value == p.value and
568
+ self.ucd == p.ucd and
569
+ self.unit == p.unit
570
+ end
571
+
572
+ def to_xml(name=nil)
573
+ el = element(name)
574
+
575
+ el.attributes["#{obj_ns.prefix}:name"] = self.name if self.name
576
+ el.attributes["#{obj_ns.prefix}:value"] = self.value if self.value
577
+ el.attributes["#{obj_ns.prefix}:ucd"] = self.ucd if self.ucd
578
+ el.attributes["#{obj_ns.prefix}:unit"] = self.unit if self.unit
579
+
580
+ el
581
+ end
582
+
583
+ def self.from_xml(xml)
584
+ root = element_from(xml)
585
+
586
+ name = root.attributes.get_attribute_ns(obj_ns.uri, 'name')
587
+ value = root.attributes.get_attribute_ns(obj_ns.uri, 'value')
588
+ ucd = root.attributes.get_attribute_ns(obj_ns.uri, 'ucd')
589
+ unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
590
+
591
+ self.new(
592
+ name ? name.value : nil,
593
+ value ? value.value : nil,
594
+ ucd ? ucd.value : nil,
595
+ unit ? unit.value : nil
596
+ )
597
+ end
598
+ end
599
+
600
+ class ParamList < TypedArray
601
+ def self.restriced_to; [Param] end
602
+ end
603
+
604
+ class Group < Described
605
+ attr_reader :params, :name, :type
606
+
607
+ def initialize(params, name=nil, type=nil, descriptions=nil, references=nil)
608
+ super(descriptions, references)
609
+ self.params = params
610
+ self.name = name
611
+ self.type = type
612
+ end
613
+
614
+ def params=(ps)
615
+ if ps
616
+ ps = ParamList.new(ps) if ps.class == Array
617
+ raise_type_mismatch_error(ps, ParamList)
618
+ end
619
+
620
+ @params = ps
621
+ end
622
+
623
+ def name=(n)
624
+ @name = n ? n.to_s : nil
625
+ end
626
+
627
+ def type=(t)
628
+ @type = t ? t.to_s : nil
629
+ end
630
+
631
+ def ==(g)
632
+ super(g) and
633
+ self.params == g.params and
634
+ self.name == g.name and
635
+ self.type == g.type
636
+ end
637
+
638
+ def to_xml(name=nil)
639
+ el = super(name)
640
+
641
+ el.attributes["#{obj_ns.prefix}:name"] = self.name if self.name
642
+ el.attributes["#{obj_ns.prefix}:type"] = self.type if self.type
643
+
644
+ self.params.each{ |p| el.add_element(p.to_xml('Param')) } if self.params
645
+
646
+ el
647
+ end
648
+
649
+ def self.from_xml(xml)
650
+ root = element_from(xml)
651
+
652
+ params = REXML::XPath.match(root, 'x:Param', {'x' => obj_ns.uri})
653
+ params = nil if params.size == 0
654
+
655
+ name = root.attributes.get_attribute_ns(obj_ns.uri, 'name')
656
+ type = root.attributes.get_attribute_ns(obj_ns.uri, 'type')
657
+
658
+ self.new(
659
+ params ? ParamList.new(params.collect{ |p| Param.from_xml(p) }) : nil,
660
+ name ? name.value : nil,
661
+ type ? type.value : nil,
662
+ *Described.described_from_xml(root)
663
+ )
664
+ end
665
+ end
666
+
667
+ class GroupList < TypedArray
668
+ def self.restricted_to; [Group] end
669
+ end
670
+
671
+ # Event characterization.
672
+ class What < Described
673
+ attr_reader :params, :groups
674
+
675
+ def initialize(groups, params=nil, descriptions=nil, references=nil)
676
+ super(descriptions, references)
677
+ self.groups = groups
678
+ self.params = params
679
+ end
680
+
681
+ def groups=(gs)
682
+ if gs
683
+ gs = GroupList.new(gs) if gs.class == Array
684
+ raise_type_mismatch_error(gs, GroupList)
685
+ end
686
+
687
+ @groups = gs
688
+ end
689
+
690
+ def params=(ps)
691
+ if ps
692
+ ps = ParamList.new(ps) if ps.class == Array
693
+ raise_type_mismatch_error(ps, ParamList)
694
+ end
695
+
696
+ @params = ps
697
+ end
698
+
699
+ def ==(w)
700
+ super(w) and
701
+ self.groups == w.groups and
702
+ self.params == w.params
703
+ end
704
+
705
+ def to_xml(name=nil)
706
+ el = super(name)
707
+
708
+ self.groups.each{ |g| el.add_element(g.to_xml('Group')) } if self.groups
709
+ self.params.each{ |p| el.add_element(p.to_xml('Param')) } if self.params
710
+
711
+ collapse_namespaces(el)
712
+ el
713
+ end
714
+
715
+ def self.from_xml(xml)
716
+ root = element_from(xml)
717
+
718
+ groups = REXML::XPath.match(root, 'x:Group', {'x' => obj_ns.uri})
719
+ groups = nil if groups.size == 0
720
+
721
+ params = REXML::XPath.match(root, 'x:Param', {'x' => obj_ns.uri})
722
+ params = nil if params.size == 0
723
+
724
+ self.new(
725
+ groups ? GroupList.new(groups.collect{ |g| Group.from_xml(g) }) : nil,
726
+ params ? ParamList.new(params.collect{ |p| Param.from_xml(p) }) : nil,
727
+ *Described.described_from_xml(root)
728
+ )
729
+ end
730
+ end
731
+
732
+ class Author < Base
733
+ class StringList < TypedArray
734
+ def self.restriced_to; [String] end
735
+ end
736
+
737
+ attr_reader :titles, :short_names, :logo_urls, :contact_names,
738
+ :contact_emails, :contact_phones, :contributors
739
+
740
+ def initialize(options={})
741
+ options.each{ |key, value| send("#{key}=", value) }
742
+ end
743
+
744
+ def titles=(ts)
745
+ if ts
746
+ ts = StringList.new(ts) if ts.class == Array
747
+ raise_type_mismatch_error(ts, StringList)
748
+ end
749
+
750
+ @titles = ts
751
+ end
752
+
753
+ def short_names=(sns)
754
+ if sns
755
+ sns = StringList.new(sns) if sns.class == Array
756
+ raise_type_mismatch_error(sns, StringList)
757
+ end
758
+
759
+ @short_names = sns
760
+ end
761
+
762
+ def logo_urls=(lus)
763
+ if lus
764
+ lus = StringList.new(lus) if lus.class == Array
765
+ raise_type_mismatch_error(lus, StringList)
766
+ end
767
+
768
+ @logo_urls = lus
769
+ end
770
+
771
+ def contact_names=(cns)
772
+ if cns
773
+ cns = StringList.new(cns) if cns.class == Array
774
+ raise_type_mismatch_error(cns, StringList)
775
+ end
776
+
777
+ @contact_names = cns
778
+ end
779
+
780
+ def contact_emails=(ces)
781
+ if ces
782
+ ces = StringList.new(ces) if ces.class == Array
783
+ raise_type_mismatch_error(ces, StringList)
784
+ end
785
+
786
+ @contact_emails = ces
787
+ end
788
+
789
+ def contact_phones=(cps)
790
+ if cps
791
+ cps = StringList.new(cps) if cps.class == Array
792
+ raise_type_mismatch_error(cps, StringList)
793
+ end
794
+
795
+ @contact_phones = cps
796
+ end
797
+
798
+ def contributors=(cs)
799
+ if cs
800
+ cs = StringList.new(cs) if cs.class == Array
801
+ raise_type_mismatch_error(cs, StringList)
802
+ end
803
+
804
+ @contributors = cs
805
+ end
806
+
807
+ def ==(a)
808
+ self.titles == a.titles and
809
+ self.short_names == a.short_names and
810
+ self.logo_urls == a.logo_urls and
811
+ self.contact_names == a.contact_names and
812
+ self.contact_emails == a.contact_emails and
813
+ self.contact_phones == a.contact_phones and
814
+ self.contributors == a.contributors
815
+ end
816
+
817
+ def to_xml(name=nil)
818
+ el = element(name)
819
+
820
+ self.titles.each { |t|
821
+ e = REXML::Element.new("#{obj_ns.prefix}:title")
822
+ e.text = t
823
+ el.add_element(e)
824
+ } if self.titles
825
+
826
+ self.short_names.each{ |n|
827
+ e = REXML::Element.new("#{obj_ns.prefix}:shortName")
828
+ e.text = n
829
+ el.add_element(e)
830
+ } if self.short_names
831
+
832
+ self.logo_urls.each{ |u|
833
+ e = REXML::Element.new("#{obj_ns.prefix}:logoURL")
834
+ e.text = u
835
+ el.add_element(e)
836
+ } if self.logo_urls
837
+
838
+ self.contact_names.each{ |n|
839
+ e = REXML::Element.new("#{obj_ns.prefix}:contactName")
840
+ e.text = n
841
+ el.add_element(e)
842
+ } if self.contact_names
843
+
844
+ self.contact_emails.each{ |m|
845
+ e = REXML::Element.new("#{obj_ns.prefix}:contactEmail")
846
+ e.text = m
847
+ el.add_element(e)
848
+ } if self.contact_emails
849
+
850
+ self.contact_phones.each{ |p|
851
+ e = REXML::Element.new("#{obj_ns.prefix}:contactPhone")
852
+ e.text = p
853
+ el.add_element(e)
854
+ } if self.contact_phones
855
+
856
+ self.contributors.each{ |c|
857
+ e = REXML::Element.new("#{obj_ns.prefix}:contributor")
858
+ e.text = c
859
+ el.add_element(e)
860
+ } if self.contributors
861
+
862
+ el
863
+ end
864
+
865
+ def self.from_xml(xml)
866
+ root = element_from(xml)
867
+
868
+ titles = REXML::XPath.match(root, 'x:title', {'x' => obj_ns.uri})
869
+ titles = nil if titles.size == 0
870
+
871
+ short_names = REXML::XPath.match(root, 'x:shortName', {'x' => obj_ns.uri})
872
+ short_names = nil if short_names.size == 0
873
+
874
+ logo_urls = REXML::XPath.match(root, 'x:logoURL', {'x' => obj_ns.uri})
875
+ logo_urls = nil if logo_urls.size == 0
876
+
877
+ contact_names = REXML::XPath.match(root, 'x:contactName', {'x' => obj_ns.uri})
878
+ contact_names = nil if contact_names.size == 0
879
+
880
+ contact_emails = REXML::XPath.match(root, 'x:contactEmail', {'x' => obj_ns.uri})
881
+ contact_emails = nil if contact_emails.size == 0
882
+
883
+ contact_phones = REXML::XPath.match(root, 'x:contactPhone', {'x' => obj_ns.uri})
884
+ contact_phones = nil if contact_phones.size == 0
885
+
886
+ contributors = REXML::XPath.match(root, 'x:contributor', {'x' => obj_ns.uri})
887
+ contributors = nil if contributors.size == 0
888
+
889
+ self.new(
890
+ :titles => titles ? StringList.new(titles.collect{ |t| t.text }) : nil,
891
+ :short_names => short_names ? StringList.new(short_names.collect{ |n| n.text }) : nil,
892
+ :logo_urls => logo_urls ? StringList.new(logo_urls.collect{ |u| u.text }) : nil,
893
+ :contact_names => contact_names ? StringList.new(contact_names.collect{ |n| n.text }) : nil,
894
+ :contact_emails => contact_emails ? StringList.new(contact_emails.collect{ |e| e.text }) : nil,
895
+ :contact_phones => contact_phones ? StringList.new(contact_phones.collect{ |p| p.text }) : nil,
896
+ :contributors => contributors ? StringList.new(contributors.collect{ |c| c.text }) : nil
897
+ )
898
+ end
899
+ end
900
+
901
+ class Who < Described
902
+ class IVORNList < TypedArray
903
+ def self.restricted_to; [URI] end
904
+ end
905
+
906
+ class DateTimeList < TypedArray
907
+ def self.restricted_to; [DateTime] end
908
+ end
909
+
910
+ class AuthorList < TypedArray
911
+ def self.restricted_to; [Author] end
912
+ end
913
+
914
+ attr_reader :author_ivorns, :dates, :authors
915
+
916
+ def initialize(author_ivorns, dates, authors=nil, descriptions=nil, references=nil)
917
+ super(descriptions, references)
918
+ self.author_ivorns = author_ivorns
919
+ self.dates = dates
920
+ self.authors = authors
921
+ end
922
+
923
+ def author_ivorns=(ais)
924
+ if ais
925
+ ais = IVORNList.new(ais) if ais.class == Array
926
+ raise_type_mismatch_error(ais, IVORNList)
927
+ end
928
+
929
+ @author_ivorns = ais
930
+ end
931
+
932
+ def dates=(ds)
933
+ if ds
934
+ ds = DateTimeList.new(ds) if ds.class == Array
935
+ raise_type_mismatch_error(ds, DateTimeList)
936
+ end
937
+
938
+ @dates = ds
939
+ end
940
+
941
+ def authors=(as)
942
+ if as
943
+ as = AuthorList.new(as) if as.class == Array
944
+ raise_type_mismatch_error(as, AuthorList)
945
+ end
946
+
947
+ @authors = as
948
+ end
949
+
950
+ def ==(w)
951
+ super(w) and
952
+ self.author_ivorns == w.author_ivorns and
953
+ self.dates == w.dates and
954
+ self.authors == w.authors
955
+ end
956
+
957
+ def to_xml(name=nil)
958
+ el = super(name)
959
+
960
+ self.author_ivorns.each{ |i|
961
+ e = REXML::Element.new("#{obj_ns.prefix}:AuthorIVORN")
962
+ e.text = i.to_s
963
+ el.add_element(e)
964
+ } if self.author_ivorns
965
+
966
+ self.dates.each{ |d|
967
+ e = REXML::Element.new("#{obj_ns.prefix}:Date")
968
+ e.text = d.to_s
969
+ el.add_element(e)
970
+ } if self.dates
971
+
972
+ self.authors.each{ |a| el.add_element(a.to_xml('Author')) } if self.authors
973
+
974
+ collapse_namespaces(el)
975
+ el
976
+ end
977
+
978
+ def self.from_xml(xml)
979
+ root = element_from(xml)
980
+
981
+ author_ivorns = REXML::XPath.match(root, 'x:AuthorIVORN', {'x' => obj_ns.uri})
982
+ author_ivorns = nil if author_ivorns.size == 0
983
+
984
+ dates = REXML::XPath.match(root, 'x:Date', {'x' => obj_ns.uri})
985
+ dates = nil if dates.size == 0
986
+
987
+ authors = REXML::XPath.match(root, 'x:Author', {'x' => obj_ns.uri})
988
+ authors = nil if authors.size == 0
989
+
990
+ self.new(
991
+ author_ivorns ? IVORNList.new(author_ivorns.collect{ |i| URI.parse(i.text) }) : nil,
992
+ dates ? DateTimeList.new(dates.collect{ |d| DateTime.parse(d.text) }) : nil,
993
+ authors ? AuthorList.new(authors.collect{ |a| Author.from_xml(a) }) : nil,
994
+ *Described.described_from_xml(root)
995
+ )
996
+ end
997
+ end
998
+
999
+ class VOEvent < Described
1000
+ attr_reader :who, :what, :where_when, :how, :why, :citations,
1001
+ :version, :ivorn, :role
1002
+
1003
+ def initialize(ivorn, who, what, where_when, how, why, version='1.1', role='observation', citations=nil, descriptions=nil, references=nil)
1004
+ super(descriptions, references)
1005
+ self.ivorn = ivorn
1006
+ self.who = who
1007
+ self.what = what
1008
+ self.where_when = where_when
1009
+ self.how = how
1010
+ self.why = why
1011
+ self.version = version || '1.1'
1012
+ self.role = role || 'observation'
1013
+ self.citations = citations
1014
+ end
1015
+
1016
+ def ivorn=(i)
1017
+ raise_argument_required_error('IVORN') if !i
1018
+
1019
+ i = URI.parse(i) if i.is_a?(String)
1020
+ raise_type_mismatch_error(i, URI)
1021
+
1022
+ @ivorn = i
1023
+ end
1024
+
1025
+ def who=(w)
1026
+ raise_type_mismatch_error(w, Who) if w
1027
+ @who = w
1028
+ end
1029
+
1030
+ def what=(w)
1031
+ raise_type_mismatch_error(w, What) if w
1032
+ @what = w
1033
+ end
1034
+
1035
+ def where_when=(ww)
1036
+ raise_type_mismatch_error(ww, WhereWhen) if ww
1037
+ @where_when = ww
1038
+ end
1039
+
1040
+ def how=(h)
1041
+ raise_type_mismatch_error(h, How) if h
1042
+ @how = h
1043
+ end
1044
+
1045
+ def why=(w)
1046
+ raise_type_mismatch_error(w, Why) if w
1047
+ @why = w
1048
+ end
1049
+
1050
+ def version=(v)
1051
+ raise_argument_required_error('version') if !v
1052
+ @version = v.to_s
1053
+ end
1054
+
1055
+ def role=(r)
1056
+ @role = r ? r.to_s : nil
1057
+ end
1058
+
1059
+ def citations=(c)
1060
+ raise_type_mismatch_error(c, Citations) if c
1061
+ @citations = c
1062
+ end
1063
+
1064
+ def ==(e)
1065
+ super(e) and
1066
+ self.who == e.who and
1067
+ self.what == e.what and
1068
+ self.where_when == e.where_when and
1069
+ self.how == e.how and
1070
+ self.why == e.why and
1071
+ self.citations == e.citations and
1072
+ self.version == e.version and
1073
+ self.ivorn == e.ivorn and
1074
+ self.role == e.role
1075
+ end
1076
+
1077
+ def to_xml(name='VOEvent')
1078
+ el = super(name)
1079
+
1080
+ el.attributes["#{obj_ns.prefix}:version"] = self.version
1081
+ el.attributes["#{obj_ns.prefix}:ivorn"] = self.ivorn.to_s
1082
+ el.attributes["#{obj_ns.prefix}:role"] = self.role if self.role
1083
+
1084
+ el.add_element(self.who.to_xml('Who')) if self.who
1085
+ el.add_element(self.what.to_xml('What')) if self.what
1086
+ el.add_element(self.where_when.to_xml('WhereWhen')) if self.where_when
1087
+ el.add_element(self.how.to_xml('How')) if self.how
1088
+ el.add_element(self.why.to_xml('Why')) if self.why
1089
+ el.add_element(self.citations.to_xml('Citations')) if self.citations
1090
+
1091
+ collapse_namespaces(el)
1092
+ el
1093
+ end
1094
+
1095
+ def self.from_xml(xml)
1096
+ root = element_from(xml)
1097
+
1098
+ role = root.attributes.get_attribute_ns(obj_ns.uri, 'role')
1099
+
1100
+ who = REXML::XPath.first(root, 'x:Who', {'x' => obj_ns.uri})
1101
+ what = REXML::XPath.first(root, 'x:What', {'x' => obj_ns.uri})
1102
+ where_when = REXML::XPath.first(root, 'x:WhereWhen', {'x' => obj_ns.uri})
1103
+ how = REXML::XPath.first(root, 'x:How', {'x' => obj_ns.uri})
1104
+ why = REXML::XPath.first(root, 'x:Why', {'x' => obj_ns.uri})
1105
+ citations = REXML::XPath.first(root, 'x:Citations', {'x' => obj_ns.uri})
1106
+
1107
+ self.new(
1108
+ URI.parse(root.attributes.get_attribute_ns(obj_ns.uri, 'ivorn').value),
1109
+ who ? Who.from_xml(who) : nil,
1110
+ what ? What.from_xml(what) : nil,
1111
+ where_when ? WhereWhen.from_xml(where_when) : nil,
1112
+ how ? How.from_xml(how) : nil,
1113
+ why ? Why.from_xml(why) : nil,
1114
+ root.attributes.get_attribute_ns(obj_ns.uri, 'version').value,
1115
+ role ? role.value : nil,
1116
+ citations ? Citations.from_xml(citations) : nil,
1117
+ *Described.described_from_xml(root)
1118
+ )
1119
+ end
1120
+ end
1121
+
1122
+ end
1123
+ end
1124
+ end