rcap 1.3.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 (88) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/README.md +78 -151
  3. data/Rakefile +1 -1
  4. data/lib/rcap/alert.rb +2 -2
  5. data/lib/rcap/base/alert.rb +446 -0
  6. data/lib/rcap/base/area.rb +228 -0
  7. data/lib/rcap/base/circle.rb +121 -0
  8. data/lib/rcap/base/event_code.rb +6 -0
  9. data/lib/rcap/base/geocode.rb +6 -0
  10. data/lib/rcap/base/info.rb +498 -0
  11. data/lib/rcap/base/parameter.rb +88 -0
  12. data/lib/rcap/base/point.rb +87 -0
  13. data/lib/rcap/base/polygon.rb +120 -0
  14. data/lib/rcap/base/resource.rb +168 -0
  15. data/lib/rcap/cap_1_0/alert.rb +59 -342
  16. data/lib/rcap/cap_1_0/area.rb +13 -188
  17. data/lib/rcap/cap_1_0/circle.rb +2 -100
  18. data/lib/rcap/cap_1_0/event_code.rb +8 -3
  19. data/lib/rcap/cap_1_0/geocode.rb +8 -3
  20. data/lib/rcap/cap_1_0/info.rb +16 -468
  21. data/lib/rcap/cap_1_0/parameter.rb +9 -67
  22. data/lib/rcap/cap_1_0/point.rb +2 -61
  23. data/lib/rcap/cap_1_0/polygon.rb +5 -95
  24. data/lib/rcap/cap_1_0/resource.rb +4 -144
  25. data/lib/rcap/cap_1_1/alert.rb +7 -412
  26. data/lib/rcap/cap_1_1/area.rb +13 -188
  27. data/lib/rcap/cap_1_1/circle.rb +2 -100
  28. data/lib/rcap/cap_1_1/event_code.rb +8 -3
  29. data/lib/rcap/cap_1_1/geocode.rb +7 -3
  30. data/lib/rcap/cap_1_1/info.rb +127 -386
  31. data/lib/rcap/cap_1_1/parameter.rb +4 -76
  32. data/lib/rcap/cap_1_1/point.rb +2 -61
  33. data/lib/rcap/cap_1_1/polygon.rb +5 -95
  34. data/lib/rcap/cap_1_1/resource.rb +37 -143
  35. data/lib/rcap/cap_1_2/alert.rb +8 -413
  36. data/lib/rcap/cap_1_2/area.rb +13 -188
  37. data/lib/rcap/cap_1_2/circle.rb +2 -100
  38. data/lib/rcap/cap_1_2/event_code.rb +8 -3
  39. data/lib/rcap/cap_1_2/geocode.rb +8 -3
  40. data/lib/rcap/cap_1_2/info.rb +132 -419
  41. data/lib/rcap/cap_1_2/parameter.rb +4 -76
  42. data/lib/rcap/cap_1_2/point.rb +2 -61
  43. data/lib/rcap/cap_1_2/polygon.rb +5 -92
  44. data/lib/rcap/cap_1_2/resource.rb +31 -134
  45. data/lib/rcap/config.rb +3 -0
  46. data/lib/{extensions → rcap/extensions}/array.rb +1 -1
  47. data/lib/rcap/extensions/date.rb +11 -0
  48. data/lib/{extensions → rcap/extensions}/date_time.rb +2 -5
  49. data/lib/{extensions → rcap/extensions}/string.rb +1 -1
  50. data/lib/{extensions → rcap/extensions}/time.rb +2 -4
  51. data/lib/rcap/utilities.rb +11 -11
  52. data/lib/rcap/validations.rb +7 -2
  53. data/lib/rcap/version.rb +1 -1
  54. data/lib/rcap.rb +21 -4
  55. data/spec/alert_spec.rb +69 -37
  56. data/spec/cap_1_0/alert_spec.rb +46 -61
  57. data/spec/cap_1_0/area_spec.rb +77 -37
  58. data/spec/cap_1_0/circle_spec.rb +26 -6
  59. data/spec/cap_1_0/event_code_spec.rb +10 -3
  60. data/spec/cap_1_0/geocode_spec.rb +11 -4
  61. data/spec/cap_1_0/info_spec.rb +74 -77
  62. data/spec/cap_1_0/parameter_spec.rb +18 -5
  63. data/spec/cap_1_0/point_spec.rb +9 -2
  64. data/spec/cap_1_0/polygon_spec.rb +52 -9
  65. data/spec/cap_1_0/resource_spec.rb +28 -21
  66. data/spec/cap_1_1/alert_spec.rb +47 -60
  67. data/spec/cap_1_1/area_spec.rb +66 -43
  68. data/spec/cap_1_1/circle_spec.rb +29 -6
  69. data/spec/cap_1_1/event_code_spec.rb +11 -3
  70. data/spec/cap_1_1/geocode_spec.rb +11 -3
  71. data/spec/cap_1_1/info_spec.rb +262 -118
  72. data/spec/cap_1_1/parameter_spec.rb +12 -3
  73. data/spec/cap_1_1/point_spec.rb +8 -2
  74. data/spec/cap_1_1/polygon_spec.rb +57 -18
  75. data/spec/cap_1_1/resource_spec.rb +70 -20
  76. data/spec/cap_1_2/alert_spec.rb +97 -110
  77. data/spec/cap_1_2/area_spec.rb +59 -41
  78. data/spec/cap_1_2/circle_spec.rb +15 -8
  79. data/spec/cap_1_2/event_code_spec.rb +11 -3
  80. data/spec/cap_1_2/geocode_spec.rb +11 -3
  81. data/spec/cap_1_2/info_spec.rb +266 -119
  82. data/spec/cap_1_2/parameter_spec.rb +11 -3
  83. data/spec/cap_1_2/point_spec.rb +10 -3
  84. data/spec/cap_1_2/polygon_spec.rb +25 -10
  85. data/spec/cap_1_2/resource_spec.rb +33 -28
  86. data/spec/{utilities_spec.rb → extensions_spec.rb} +0 -0
  87. data/spec/validations_spec.rb +18 -2
  88. metadata +20 -46
@@ -0,0 +1,121 @@
1
+ module RCAP
2
+ module Base
3
+ class Circle < Point
4
+ include Validation
5
+
6
+ # @return [Numeric] Expresed in kilometers
7
+ attr_accessor( :radius )
8
+
9
+ validates_presence_of( :radius )
10
+ validates_numericality_of( :radius , greater_than_or_equal: 0 )
11
+
12
+ XML_ELEMENT_NAME = 'circle'
13
+
14
+ XPATH = 'cap:circle'
15
+
16
+ # @param [Hash] attributes
17
+ # @option attributes [Numeric] :lattitude
18
+ # @option attributes [Numeric] :longitude
19
+ # @option attributes [Numeric] :radius
20
+ def initialize
21
+ yield( self ) if block_given?
22
+ end
23
+
24
+ # Returns a string representation of the circle of the form
25
+ # lattitude,longitude radius
26
+ #
27
+ # @return [String]
28
+ def to_s
29
+ "#{ @lattitude },#{ @longitude } #{ @radius }"
30
+ end
31
+
32
+ # @return [String]
33
+ def inspect
34
+ "(#{ self.to_s })"
35
+ end
36
+
37
+ # @return [REXML::Element]
38
+ def to_xml_element
39
+ xml_element = REXML::Element.new( XML_ELEMENT_NAME )
40
+ xml_element.add_text( self.to_s )
41
+ xml_element
42
+ end
43
+
44
+ # @return [String]
45
+ def to_xml
46
+ self.to_xml_element.to_s
47
+ end
48
+
49
+ # Parses a circle string of the form
50
+ # lattitude,longitude radius
51
+ #
52
+ # @param [String] circle_string
53
+ # @return [Array(Float,Float,Float)]
54
+ def self.parse_circle_string( circle_string )
55
+ coordinates, radius = circle_string.split( ' ' )
56
+ lattitude, longitude = coordinates.split( ',' )
57
+ [ lattitude, longitude, radius ].map{ |e| e.to_f }
58
+ end
59
+
60
+ # @param [REXML::Element] circle_xml_element
61
+ # @return [Circle]
62
+ def self.from_xml_element( circle_xml_element )
63
+ self.from_a( self.parse_circle_string( circle_xml_element.text ))
64
+ end
65
+
66
+ # Two circles are equivalent if their lattitude, longitude and radius are equal.
67
+ #
68
+ # @param [Circle] other
69
+ # @return [true,false]
70
+ def ==( other )
71
+ self.to_a == other.to_a
72
+ end
73
+
74
+ # @param [Array(Numeric, Numeric, Numeric)] circle_yaml_data lattitude, longitude, radius
75
+ # @return [Circle]
76
+ def self.from_yaml_data( circle_yaml_data )
77
+ lattitude, longitude, radius = circle_yaml_data
78
+ self.new do |circle|
79
+ circle.lattitude = lattitude
80
+ circle.longitude = longitude
81
+ circle.radius = radius
82
+ end
83
+ end
84
+
85
+ RADIUS_KEY = 'radius'
86
+ # @return [Hash]
87
+ def to_h
88
+ RCAP.attribute_values_to_hash( [ RADIUS_KEY, @radius ],
89
+ [ LATTITUDE_KEY, @lattitude ],
90
+ [ LONGITUDE_KEY, @longitude ])
91
+ end
92
+
93
+ # @param [Hash] circle_hash
94
+ # @return [Circle]
95
+ def self.from_h( circle_hash )
96
+ self.new do |circle|
97
+ circle.radius = circle_hash[ RADIUS_KEY ]
98
+ circle.lattitude = circle_hash[ LATTITUDE_KEY ]
99
+ circle.longitude = circle_hash[ LONGITUDE_KEY ]
100
+ end
101
+ end
102
+
103
+ # @return [Array(Numeric,Numeric,Numeric)]
104
+ def to_a
105
+ [ @lattitude, @longitude, @radius ]
106
+ end
107
+
108
+ RADIUS_INDEX = 2
109
+
110
+ # @param [Array] circle_array
111
+ # @return [Circle]
112
+ def self.from_a( circle_array )
113
+ self.new do |circle|
114
+ circle.longitude = circle_array[ LONGITUDE_INDEX ]
115
+ circle.lattitude = circle_array[ LATTITUDE_INDEX ]
116
+ circle.radius = circle_array[ RADIUS_INDEX ]
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,6 @@
1
+ module RCAP
2
+ module Base
3
+ class EventCode < Parameter
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module RCAP
2
+ module Base
3
+ class Geocode < Parameter
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,498 @@
1
+ module RCAP
2
+ module Base
3
+ class Info
4
+ include Validation
5
+
6
+ CATEGORY_GEO = "Geo"
7
+ CATEGORY_MET = "Met"
8
+ CATEGORY_SAFETY = "Safety"
9
+ CATEGORY_SECURITY = "Security"
10
+ CATEGORY_RESCUE = "Rescue"
11
+ CATEGORY_FIRE = "Fire"
12
+ CATEGORY_HEALTH = "Health"
13
+ CATEGORY_ENV = "Env"
14
+ CATEGORY_TRANSPORT = "Transport"
15
+ CATEGORY_INFRA = "Infra"
16
+ CATEGORY_CBRNE = "CBRNE"
17
+ CATEGORY_OTHER = "Other"
18
+ # Valid values for categories
19
+ VALID_CATEGORIES = [ CATEGORY_GEO, CATEGORY_MET, CATEGORY_SAFETY,
20
+ CATEGORY_SECURITY, CATEGORY_RESCUE, CATEGORY_FIRE, CATEGORY_HEALTH,
21
+ CATEGORY_ENV, CATEGORY_TRANSPORT, CATEGORY_INFRA, CATEGORY_CBRNE,
22
+ CATEGORY_OTHER ]
23
+
24
+ URGENCY_IMMEDIATE = "Immediate"
25
+ URGENCY_EXPECTED = "Expected"
26
+ URGENCY_FUTURE = "Future"
27
+ URGENCY_PAST = "Past"
28
+ URGENCY_UNKNOWN = "Unknown"
29
+ # Valid values for urgency
30
+ VALID_URGENCIES = [ URGENCY_IMMEDIATE, URGENCY_EXPECTED, URGENCY_FUTURE,
31
+ URGENCY_PAST, URGENCY_UNKNOWN ]
32
+
33
+ SEVERITY_EXTREME = "Extreme"
34
+ SEVERITY_SEVERE = "Severe"
35
+ SEVERITY_MODERATE = "Moderate"
36
+ SEVERITY_MINOR = "Minor"
37
+ SEVERITY_UNKNOWN = "Unknown"
38
+ # Valid values for severity
39
+ VALID_SEVERITIES = [ SEVERITY_EXTREME, SEVERITY_SEVERE, SEVERITY_MODERATE,
40
+ SEVERITY_MINOR, SEVERITY_UNKNOWN ]
41
+
42
+ CERTAINTY_VERY_LIKELY = "Very Likely"
43
+ CERTAINTY_LIKELY = "Likely"
44
+ CERTAINTY_POSSIBLE = "Possible"
45
+ CERTAINTY_UNLIKELY = "Unlikely"
46
+ CERTAINTY_UNKNOWN = "Unknown"
47
+ # Valid valies for certainty
48
+ VALID_CERTAINTIES = [ CERTAINTY_VERY_LIKELY, CERTAINTY_LIKELY,
49
+ CERTAINTY_POSSIBLE, CERTAINTY_UNLIKELY, CERTAINTY_UNKNOWN ]
50
+
51
+ XML_ELEMENT_NAME = 'info'
52
+ LANGUAGE_ELEMENT_NAME = 'language'
53
+ CATEGORY_ELEMENT_NAME = 'category'
54
+ EVENT_ELEMENT_NAME = 'event'
55
+ URGENCY_ELEMENT_NAME = 'urgency'
56
+ SEVERITY_ELEMENT_NAME = 'severity'
57
+ CERTAINTY_ELEMENT_NAME = 'certainty'
58
+ AUDIENCE_ELEMENT_NAME = 'audience'
59
+ EVENT_CODE_ELEMENT_NAME = 'eventCode'
60
+ EFFECTIVE_ELEMENT_NAME = 'effective'
61
+ ONSET_ELEMENT_NAME = 'onset'
62
+ EXPIRES_ELEMENT_NAME = 'expires'
63
+ SENDER_NAME_ELEMENT_NAME = 'senderName'
64
+ HEADLINE_ELEMENT_NAME = 'headline'
65
+ DESCRIPTION_ELEMENT_NAME = 'description'
66
+ INSTRUCTION_ELEMENT_NAME = 'instruction'
67
+ WEB_ELEMENT_NAME = 'web'
68
+ CONTACT_ELEMENT_NAME = 'contact'
69
+
70
+ XPATH = "cap:#{ XML_ELEMENT_NAME }"
71
+ LANGUAGE_XPATH = "cap:#{ LANGUAGE_ELEMENT_NAME }"
72
+ EVENT_XPATH = "cap:#{ EVENT_ELEMENT_NAME }"
73
+ URGENCY_XPATH = "cap:#{ URGENCY_ELEMENT_NAME }"
74
+ CATEGORY_XPATH = "cap:#{ CATEGORY_ELEMENT_NAME }"
75
+ SEVERITY_XPATH = "cap:#{ SEVERITY_ELEMENT_NAME }"
76
+ CERTAINTY_XPATH = "cap:#{ CERTAINTY_ELEMENT_NAME }"
77
+ AUDIENCE_XPATH = "cap:#{ AUDIENCE_ELEMENT_NAME }"
78
+ EVENT_CODE_XPATH = "cap:#{ EVENT_CODE_ELEMENT_NAME }"
79
+ EFFECTIVE_XPATH = "cap:#{ EFFECTIVE_ELEMENT_NAME }"
80
+ ONSET_XPATH = "cap:#{ ONSET_ELEMENT_NAME }"
81
+ EXPIRES_XPATH = "cap:#{ EXPIRES_ELEMENT_NAME }"
82
+ SENDER_NAME_XPATH = "cap:#{ SENDER_NAME_ELEMENT_NAME }"
83
+ HEADLINE_XPATH = "cap:#{ HEADLINE_ELEMENT_NAME }"
84
+ DESCRIPTION_XPATH = "cap:#{ DESCRIPTION_ELEMENT_NAME }"
85
+ INSTRUCTION_XPATH = "cap:#{ INSTRUCTION_ELEMENT_NAME }"
86
+ WEB_XPATH = "cap:#{ WEB_ELEMENT_NAME }"
87
+ CONTACT_XPATH = "cap:#{ CONTACT_ELEMENT_NAME }"
88
+
89
+ DEFAULT_LANGUAGE = 'en-US'
90
+
91
+ validates_presence_of( :event )
92
+ validates_presence_of( :urgency )
93
+ validates_presence_of( :severity )
94
+ validates_presence_of( :certainty )
95
+ validates_inclusion_of( :severity, :allow_nil => true, :in => VALID_SEVERITIES, :message => "can only be assigned the following values: #{ VALID_SEVERITIES.join(', ') }" )
96
+ validates_inclusion_of( :urgency, :allow_nil => true, :in => VALID_URGENCIES, :message => "can only be assigned the following values: #{ VALID_URGENCIES.join(', ') }" )
97
+ validates_inclusion_of_members_of( :categories, :in => VALID_CATEGORIES, :allow_blank => true )
98
+ validates_collection_of( :resources, :areas, :event_codes, :parameters )
99
+
100
+ # @return [String]
101
+ attr_accessor( :event )
102
+ # @return [String] Value can only be one of {VALID_URGENCIES}
103
+ attr_accessor( :urgency )
104
+ # @return [String] Value can only be one of {VALID_SEVERITIES}
105
+ attr_accessor( :severity )
106
+ # @return [String] Value can only be one of {VALID_CERTAINTIES}
107
+ attr_accessor( :certainty )
108
+ # @return [String]
109
+ attr_accessor( :language )
110
+ # @return [String]
111
+ attr_accessor( :audience )
112
+ # @return [DateTime] Effective start time of information
113
+ attr_accessor( :effective )
114
+ # @return [DateTime] Expected start of event
115
+ attr_accessor( :onset )
116
+ # @return [DateTime] Effective expiry time of information
117
+ attr_accessor( :expires )
118
+ # @return [String]
119
+ attr_accessor( :sender_name )
120
+ # @return [String]
121
+ attr_accessor( :headline )
122
+ # @return [String]
123
+ attr_accessor( :description )
124
+ # @return [String]
125
+ attr_accessor( :instruction )
126
+ # @return [String]
127
+ attr_accessor( :web )
128
+ # @return [String]
129
+ attr_accessor( :contact )
130
+
131
+ # @return [Array<String>] Collection of textual categories; elements can be one of {VALID_CATEGORIES}
132
+ attr_reader( :categories )
133
+ # @return [Array<EventCode>] Collection of {EventCode} objects
134
+ attr_reader( :event_codes )
135
+ # @return [Array<Parameter>] Collection of {Parameter} objects
136
+ attr_reader( :parameters )
137
+ # @return [Array<Resource> Collection of {Resource} objects
138
+ attr_reader( :resources )
139
+ # @return [Array<Area>] Collection of {Area} objects
140
+ attr_reader( :areas )
141
+
142
+
143
+ # Initialises a new Info object which will be yielded to an attached block if given
144
+ #
145
+ # @return [RCAP::CAP_1_0::Info,RCAP::CAP_1_1::Info,RCAP::CAP_1_2::Info]
146
+ def initialize
147
+ @language = DEFAULT_LANGUAGE
148
+ @categories = []
149
+ @event_codes = []
150
+ @parameters = []
151
+ @resources = []
152
+ @areas = []
153
+ yield( self ) if block_given?
154
+ end
155
+
156
+ # Creates a new EventCode object and adds it to the event_codes array.
157
+ #
158
+ # @return [EventCode]
159
+ def add_event_code
160
+ event_code = self.event_code_class.new
161
+ yield( event_code ) if block_given?
162
+ @event_codes << event_code
163
+ event_code
164
+ end
165
+
166
+ # Creates a new Parameter object and adds it to the parameters array.
167
+ #
168
+ # @return [Parameter]
169
+ def add_parameter
170
+ parameter = self.parameter_class.new
171
+ yield( parameter ) if block_given?
172
+ @parameters << parameter
173
+ parameter
174
+ end
175
+
176
+ # Creates a new Resource object and adds it to the resources array.
177
+ #
178
+ # @return [Resource]
179
+ def add_resource
180
+ resource = self.resource_class.new
181
+ yield( resource ) if block_given?
182
+ @resources << resource
183
+ resource
184
+ end
185
+
186
+ # Creates a new Area object and adds it to the areas array.
187
+ #
188
+ # @return [Area]
189
+ def add_area
190
+ area = self.area_class.new
191
+ yield( area ) if block_given?
192
+ @areas << area
193
+ area
194
+ end
195
+
196
+ # @return [REXML::Element]
197
+ def to_xml_element
198
+ xml_element = REXML::Element.new( XML_ELEMENT_NAME )
199
+ xml_element.add_element( LANGUAGE_ELEMENT_NAME ).add_text( @language ) if @language
200
+ @categories.each do |category|
201
+ xml_element.add_element( CATEGORY_ELEMENT_NAME ).add_text( category )
202
+ end
203
+ xml_element.add_element( EVENT_ELEMENT_NAME ).add_text( @event )
204
+ xml_element.add_element( URGENCY_ELEMENT_NAME ).add_text( @urgency )
205
+ xml_element.add_element( SEVERITY_ELEMENT_NAME ).add_text( @severity )
206
+ xml_element.add_element( CERTAINTY_ELEMENT_NAME ).add_text( @certainty )
207
+ xml_element.add_element( AUDIENCE_ELEMENT_NAME ).add_text( @audience ) if @audience
208
+ @event_codes.each do |event_code|
209
+ xml_element.add_element( event_code.to_xml_element )
210
+ end
211
+ xml_element.add_element( EFFECTIVE_ELEMENT_NAME ).add_text( @effective.to_s_for_cap ) if @effective
212
+ xml_element.add_element( ONSET_ELEMENT_NAME ).add_text( @onset.to_s_for_cap ) if @onset
213
+ xml_element.add_element( EXPIRES_ELEMENT_NAME ).add_text( @expires.to_s_for_cap ) if @expires
214
+ xml_element.add_element( SENDER_NAME_ELEMENT_NAME ).add_text( @sender_name ) if @sender_name
215
+ xml_element.add_element( HEADLINE_ELEMENT_NAME ).add_text( @headline ) if @headline
216
+ xml_element.add_element( DESCRIPTION_ELEMENT_NAME ).add_text( @description ) if @description
217
+ xml_element.add_element( INSTRUCTION_ELEMENT_NAME ).add_text( @instruction ) if @instruction
218
+ xml_element.add_element( WEB_ELEMENT_NAME ).add_text( @web ) if @web
219
+ xml_element.add_element( CONTACT_ELEMENT_NAME ).add_text( @contact ) if @contact
220
+ @parameters.each do |parameter|
221
+ xml_element.add_element( parameter.to_xml_element )
222
+ end
223
+ @resources.each do |resource|
224
+ xml_element.add_element( resource.to_xml_element )
225
+ end
226
+ @areas.each do |area|
227
+ xml_element.add_element( area.to_xml_element )
228
+ end
229
+ xml_element
230
+ end
231
+
232
+ # @return [String]
233
+ def to_xml
234
+ self.to_xml_element.to_s
235
+ end
236
+
237
+ # @param [REXML::Element] info_xml_element
238
+ # @return [Info]
239
+ def self.from_xml_element( info_xml_element )
240
+ self.new do |info|
241
+ info.language = RCAP.xpath_text( info_xml_element, LANGUAGE_XPATH, info.xmlns ) || DEFAULT_LANGUAGE
242
+
243
+ RCAP.xpath_match( info_xml_element, CATEGORY_XPATH, info.xmlns ).each do |element|
244
+ info.categories << element.text
245
+ end
246
+
247
+ info.event = RCAP.xpath_text( info_xml_element, EVENT_XPATH, info.xmlns )
248
+ info.urgency = RCAP.xpath_text( info_xml_element, URGENCY_XPATH, info.xmlns )
249
+ info.severity = RCAP.xpath_text( info_xml_element, SEVERITY_XPATH, info.xmlns )
250
+ info.certainty = RCAP.xpath_text( info_xml_element, CERTAINTY_XPATH, info.xmlns )
251
+ info.audience = RCAP.xpath_text( info_xml_element, AUDIENCE_XPATH, info.xmlns )
252
+ info.effective = RCAP.parse_datetime( RCAP.xpath_text( info_xml_element, EFFECTIVE_XPATH, info.xmlns ))
253
+ info.onset = RCAP.parse_datetime( RCAP.xpath_text( info_xml_element, ONSET_XPATH, info.xmlns ))
254
+ info.expires = RCAP.parse_datetime( RCAP.xpath_text( info_xml_element, EXPIRES_XPATH, info.xmlns ))
255
+ info.sender_name = RCAP.xpath_text( info_xml_element, SENDER_NAME_XPATH, info.xmlns )
256
+ info.headline = RCAP.xpath_text( info_xml_element, HEADLINE_XPATH, info.xmlns )
257
+ info.description = RCAP.xpath_text( info_xml_element, DESCRIPTION_XPATH, info.xmlns )
258
+ info.instruction = RCAP.xpath_text( info_xml_element, INSTRUCTION_XPATH, info.xmlns )
259
+ info.web = RCAP.xpath_text( info_xml_element, WEB_XPATH, info.xmlns )
260
+ info.contact = RCAP.xpath_text( info_xml_element, CONTACT_XPATH, info.xmlns )
261
+
262
+ RCAP.xpath_match( info_xml_element, info.event_code_class::XPATH, info.xmlns ).each do |element|
263
+ info.event_codes << info.event_code_class.from_xml_element( element )
264
+ end
265
+
266
+ RCAP.xpath_match( info_xml_element, info.parameter_class::XPATH, info.xmlns ).each do |element|
267
+ info.parameters << info.parameter_class.from_xml_element( element )
268
+ end
269
+
270
+ RCAP.xpath_match( info_xml_element, info.resource_class::XPATH, info.xmlns ).each do |element|
271
+ info.resources << info.resource_class.from_xml_element( element )
272
+ end
273
+
274
+ RCAP.xpath_match( info_xml_element, info.area_class::XPATH, info.xmlns ).each do |element|
275
+ info.areas << info.area_class.from_xml_element( element )
276
+ end
277
+ end
278
+ end
279
+
280
+ # @return [String]
281
+ def inspect
282
+ info_inspect = "Language: #{ @language }\n"+
283
+ "Categories: #{ @categories.to_s_for_cap }\n"+
284
+ "Event: #{ @event }\n"+
285
+ "Urgency: #{ @urgency }\n"+
286
+ "Severity: #{ @severity }\n"+
287
+ "Certainty: #{ @certainty }\n"+
288
+ "Audience: #{ @audience }\n"+
289
+ "Event Codes: #{ @event_codes.inspect }\n"+
290
+ "Effective: #{ @effective }\n"+
291
+ "Onset: #{ @onset }\n"+
292
+ "Expires: #{ @expires }\n"+
293
+ "Sender Name: #{ @sender_name }\n"+
294
+ "Headline: #{ @headline }\n"+
295
+ "Description:\n"+
296
+ @description.to_s.lines.map{ |line| " " + line }.join( "\n")+"\n"+
297
+ "Instruction: #{ @instruction }\n"+
298
+ "Web: #{ @web }\n"+
299
+ "Contact: #{ @contact }\n"+
300
+ "Parameters:\n"+
301
+ @parameters.map{ |parameter| " " + parameter.inspect }.join( "\n" )+"\n"+
302
+ "Resources:\n"+
303
+ @resources.map{ |resource| " " + resource.inspect }.join( "\n" )+"\n"+
304
+ "Area:\n"+
305
+ @areas.map{ |area| " #{ area }" }.join( "\n" )+"\n"
306
+ RCAP.format_lines_for_inspect( 'INFO', info_inspect )
307
+ end
308
+
309
+ # Returns a string representation of the event of the form
310
+ # event(urgency/severity/certainty)
311
+ #
312
+ # @return [String]
313
+ def to_s
314
+ "#{ @event }(#{ @urgency }/#{ @severity }/#{ @certainty })"
315
+ end
316
+
317
+ LANGUAGE_YAML = 'Language'
318
+ CATEGORIES_YAML = 'Categories'
319
+ EVENT_YAML = 'Event'
320
+ URGENCY_YAML = 'Urgency'
321
+ SEVERITY_YAML = 'Severity'
322
+ CERTAINTY_YAML = 'Certainty'
323
+ AUDIENCE_YAML = 'Audience'
324
+ EFFECTIVE_YAML = 'Effective'
325
+ ONSET_YAML = 'Onset'
326
+ EXPIRES_YAML = 'Expires'
327
+ SENDER_NAME_YAML = 'Sender Name'
328
+ HEADLINE_YAML = 'Headline'
329
+ DESCRIPTION_YAML = 'Description'
330
+ INSTRUCTION_YAML = 'Instruction'
331
+ WEB_YAML = 'Web'
332
+ CONTACT_YAML = 'Contact'
333
+ EVENT_CODES_YAML = 'Event Codes'
334
+ PARAMETERS_YAML = 'Parameters'
335
+ RESOURCES_YAML = 'Resources'
336
+ AREAS_YAML = 'Areas'
337
+
338
+ # @return [String]
339
+ def to_yaml( options = {} )
340
+ parameter_to_hash = lambda{ |hash, parameter| hash.merge( parameter.name => parameter.value )}
341
+
342
+ RCAP.attribute_values_to_hash( [ LANGUAGE_YAML, @language ],
343
+ [ CATEGORIES_YAML, @categories ],
344
+ [ EVENT_YAML, @event ],
345
+ [ URGENCY_YAML, @urgency ],
346
+ [ SEVERITY_YAML, @severity ],
347
+ [ CERTAINTY_YAML, @certainty ],
348
+ [ AUDIENCE_YAML, @audience ],
349
+ [ EFFECTIVE_YAML, @effective ],
350
+ [ ONSET_YAML, @onset ],
351
+ [ EXPIRES_YAML, @expires ],
352
+ [ SENDER_NAME_YAML, @sender_name ],
353
+ [ HEADLINE_YAML, @headline ],
354
+ [ DESCRIPTION_YAML, @description ],
355
+ [ INSTRUCTION_YAML, @instruction ],
356
+ [ WEB_YAML, @web ],
357
+ [ CONTACT_YAML, @contact ],
358
+ [ EVENT_CODES_YAML, @event_codes.inject({}, &parameter_to_hash )],
359
+ [ PARAMETERS_YAML, @parameters.inject({}, &parameter_to_hash )],
360
+ [ RESOURCES_YAML, @resources ],
361
+ [ AREAS_YAML, @areas ]).to_yaml( options )
362
+ end
363
+
364
+ # @param [Hash] info_yaml_data
365
+ # @return [Info]
366
+ def self.from_yaml_data( info_yaml_data )
367
+ self.new do |info|
368
+ info.language = info_yaml_data [ LANGUAGE_YAML ]
369
+ Array( info_yaml_data [ CATEGORIES_YAML ]).each do |category|
370
+ info.categories << category
371
+ end
372
+ info.event = info_yaml_data [ EVENT_YAML ]
373
+ info.urgency = info_yaml_data [ URGENCY_YAML ]
374
+ info.severity = info_yaml_data [ SEVERITY_YAML ]
375
+ info.certainty = info_yaml_data [ CERTAINTY_YAML ]
376
+ info.audience = info_yaml_data [ AUDIENCE_YAML ]
377
+ info.effective = RCAP.parse_datetime( info_yaml_data[ EFFECTIVE_YAML ])
378
+ info.onset = RCAP.parse_datetime( info_yaml_data[ ONSET_YAML ])
379
+ info.expires = RCAP.parse_datetime( info_yaml_data[ EXPIRES_YAML ])
380
+ info.sender_name = info_yaml_data [ SENDER_NAME_YAML ]
381
+ info.headline = info_yaml_data [ HEADLINE_YAML ]
382
+ info.description = info_yaml_data [ DESCRIPTION_YAML ]
383
+ info.instruction = info_yaml_data [ INSTRUCTION_YAML ]
384
+ info.web = info_yaml_data [ WEB_YAML ]
385
+ info.contact = info_yaml_data [ CONTACT_YAML ]
386
+
387
+ Array( info_yaml_data [ EVENT_CODES_YAML ]).each do |name,value|
388
+ info.add_event_code do |event_code|
389
+ event_code.name = name
390
+ event_code.value = value
391
+ end
392
+ end
393
+
394
+ Array( info_yaml_data [ PARAMETERS_YAML ]).each do |name,value|
395
+ info.add_parameter do |parameter|
396
+ parameter.name = name
397
+ parameter.value = value
398
+ end
399
+ end
400
+
401
+ Array( info_yaml_data [ RESOURCES_YAML ]).each do |resource_yaml_data|
402
+ info.resources << info.resource_class.from_yaml_data( resource_yaml_data )
403
+ end
404
+
405
+ Array( info_yaml_data [ AREAS_YAML ]).each do |area_yaml_data|
406
+ info.areas << info.area_class.from_yaml_data( area_yaml_data )
407
+ end
408
+ end
409
+ end
410
+
411
+ LANGUAGE_KEY = 'language'
412
+ CATEGORIES_KEY = 'categories'
413
+ EVENT_KEY = 'event'
414
+ URGENCY_KEY = 'urgency'
415
+ SEVERITY_KEY = 'severity'
416
+ CERTAINTY_KEY = 'certainty'
417
+ AUDIENCE_KEY = 'audience'
418
+ EFFECTIVE_KEY = 'effective'
419
+ ONSET_KEY = 'onset'
420
+ EXPIRES_KEY = 'expires'
421
+ SENDER_NAME_KEY = 'sender_name'
422
+ HEADLINE_KEY = 'headline'
423
+ DESCRIPTION_KEY = 'description'
424
+ INSTRUCTION_KEY = 'instruction'
425
+ WEB_KEY = 'web'
426
+ CONTACT_KEY = 'contact'
427
+ RESOURCES_KEY = 'resources'
428
+ EVENT_CODES_KEY = 'event_codes'
429
+ PARAMETERS_KEY = 'parameters'
430
+ AREAS_KEY = 'areas'
431
+
432
+ # @return [Hash]
433
+ def to_h
434
+ RCAP.attribute_values_to_hash( [ LANGUAGE_KEY, @language ],
435
+ [ CATEGORIES_KEY, @categories ],
436
+ [ EVENT_KEY, @event ],
437
+ [ URGENCY_KEY, @urgency ],
438
+ [ SEVERITY_KEY, @severity ],
439
+ [ CERTAINTY_KEY, @certainty ],
440
+ [ AUDIENCE_KEY, @audience ],
441
+ [ EFFECTIVE_KEY, RCAP.to_s_for_cap( @effective )],
442
+ [ ONSET_KEY, RCAP.to_s_for_cap( @onset )],
443
+ [ EXPIRES_KEY, RCAP.to_s_for_cap( @expires )],
444
+ [ SENDER_NAME_KEY, @sender_name ],
445
+ [ HEADLINE_KEY, @headline ],
446
+ [ DESCRIPTION_KEY, @description ],
447
+ [ INSTRUCTION_KEY, @instruction ],
448
+ [ WEB_KEY, @web ],
449
+ [ CONTACT_KEY, @contact ],
450
+ [ RESOURCES_KEY, @resources.map{ |resource| resource.to_h } ],
451
+ [ EVENT_CODES_KEY, @event_codes.map{ |event_code| event_code.to_h } ],
452
+ [ PARAMETERS_KEY, @parameters.map{ |parameter| parameter.to_h } ],
453
+ [ AREAS_KEY, @areas.map{ |area| area.to_h }])
454
+ end
455
+
456
+ # @param [Hash] info_hash
457
+ # @return [Info]
458
+ def self.from_h( info_hash )
459
+ self.new do |info|
460
+ info.language = info_hash[ LANGUAGE_KEY ]
461
+ Array( info_hash[ CATEGORIES_KEY ]).each do |category|
462
+ info.categories << category
463
+ end
464
+ info.event = info_hash[ EVENT_KEY ]
465
+ info.urgency = info_hash[ URGENCY_KEY ]
466
+ info.severity = info_hash[ SEVERITY_KEY ]
467
+ info.certainty = info_hash[ CERTAINTY_KEY ]
468
+ info.audience = info_hash[ AUDIENCE_KEY ]
469
+ info.effective = RCAP.parse_datetime( info_hash[ EFFECTIVE_KEY ])
470
+ info.onset = RCAP.parse_datetime( info_hash[ ONSET_KEY ])
471
+ info.expires = RCAP.parse_datetime( info_hash[ EXPIRES_KEY ])
472
+ info.sender_name = info_hash[ SENDER_NAME_KEY ]
473
+ info.headline = info_hash[ HEADLINE_KEY ]
474
+ info.description = info_hash[ DESCRIPTION_KEY ]
475
+ info.instruction = info_hash[ INSTRUCTION_KEY ]
476
+ info.web = info_hash[ WEB_KEY ]
477
+ info.contact = info_hash[ CONTACT_KEY ]
478
+
479
+ Array( info_hash[ RESOURCES_KEY ]).each do |resource_hash|
480
+ info.resources << info.resource_class.from_h( resource_hash )
481
+ end
482
+
483
+ Array( info_hash[ EVENT_CODES_KEY ]).each do |event_code_hash|
484
+ info.event_codes << info.event_code_class.from_h( event_code_hash )
485
+ end
486
+
487
+ Array( info_hash[ PARAMETERS_KEY ]).each do |parameter_hash|
488
+ info.parameters << info.parameter_class.from_h( parameter_hash )
489
+ end
490
+
491
+ Array( info_hash[ AREAS_KEY ]).each do |area_hash|
492
+ info.areas << info.area_class.from_h( area_hash )
493
+ end
494
+ end
495
+ end
496
+ end
497
+ end
498
+ end