rcap 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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