rcap 0.4 → 1.0.0.rc.1

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 (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