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