rcap 0.4 → 1.0.0.rc.1

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