rcap 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,11 @@
1
1
  = Change Log
2
2
 
3
+ == 0.4 - 6th March 2011
4
+
5
+ * Implemented Hash generation and parsing
6
+ * Implemented JSON generation and parsing
7
+ * Circle is now a subclass of Point
8
+
3
9
  == 0.3 - 26th November 2009
4
10
 
5
11
  * Bugfix release
data/README.rdoc CHANGED
@@ -8,7 +8,7 @@ RCAP currently supports only CAP Version 1.1.
8
8
 
9
9
  == Version
10
10
 
11
- 0.3
11
+ 0.4
12
12
 
13
13
  == Dependencies
14
14
 
@@ -16,13 +16,14 @@ RCAP depends on the following gems
16
16
 
17
17
  * {Assistance}[http://assistance.rubyforge.org]
18
18
  * {UUIDTools}[http://uuidtools.rubyforge.org]
19
+ * {JSON}[http://json.rubyforge.org]
19
20
 
20
21
  RCAP uses the REXML API, included in Ruby, to parse and generate XML.
21
22
 
22
23
  == Installation
23
24
 
24
25
  RCAP is distributed as a Ruby gem and is available from {Gemcutter}[http://gemcutter.org]. If you have Gemcutter set as a source of your gems then RCAP can be installed from the command line
25
-
26
+
26
27
  gem install rcap
27
28
 
28
29
  The gem is also available for download and manual installtion at http://www.aimred.com/gems .
@@ -31,8 +32,8 @@ The gem is also available for download and manual installtion at http://www.aimr
31
32
 
32
33
  * The RCAP project page can be found at http://www.aimred.com/projects/rcap
33
34
  * The RCAP API docs can be fount at http://www.aimred.com/projects/rcap/api
34
- * A public git repository can be found at http:///www.aimred.com/git/rcap.git
35
-
35
+ * A public git repository can be found at git://github.com/farrel/RCAP.git
36
+
36
37
  == Usage
37
38
 
38
39
  To include RCAP into your application add the following require
@@ -136,6 +137,32 @@ will produce the following YAML document
136
137
 
137
138
  Note: If you use Ruby 1.8 the order of the attributes is jumbled due to hashes being unorderd (Ruby 1.9 implements ordered hashes). This does not affect the ability to parse documents generated from RCAP::Alert#to_yaml, it just makes things the output slightly messy.
138
139
 
140
+ === To JSON
141
+
142
+ JSON(JavaScript Object Notation) is a text serialization format that can be easily loaded in a JavaScript environment.
143
+
144
+ alert.to_json
145
+
146
+ will produce the following JSON string
147
+
148
+ {"identifier":"0eb97e40-195b-437b-9a01-55fe89691def",
149
+ "sender":"cape_town_disaster_relief@capetown.municipal.za",
150
+ "sent":"2011-03-04T15:58:01+02:00",
151
+ "status":"Actual",
152
+ "msg_type":"Alert",
153
+ "scope":"Public",
154
+ "infos":[
155
+ {"language":"en-ZA",
156
+ "categories":["Transport","Fire"],
157
+ "event":"Liquid Petroleoum Tanker Fire",
158
+ "urgency":"Immediate",
159
+ "severity":"Severe",
160
+ "certainty":"Observed",
161
+ "headline":"LIQUID PETROLEOUM TANKER FIRE ON N2 INCOMING FREEWAY",
162
+ "description":"A liquid petroleoum tanker has caught fire on the N2 incoming freeway 1km
163
+ after the R300 interchange. Municipal fire fighting crews have been dispatched.
164
+ Traffic control officers are on the scene and have diverted traffic onto \nalternate routes."}]}
165
+
139
166
  === Parsing an Alert From An External Source
140
167
 
141
168
  ==== From XML
@@ -152,6 +179,12 @@ Alert messgaes can be read in from text files containing data formatted in YAML
152
179
 
153
180
  alert = RCAP::Alert.from_yaml( yaml_string )
154
181
 
182
+ ==== From JSON
183
+
184
+ An Alert can also be initialised from a JSON string produced by Alert#to_json
185
+
186
+ alert = RCAP::Alert.from_json( json_string )
187
+
155
188
  === Validating an alert
156
189
 
157
190
  The RCAP API aims to codify as many of the rules of the CAP XML format into validation rules that can be checked using the Assistance API. The following Info object has two attributes ('severity' and 'certainty') set to incorrect values.
@@ -162,18 +195,19 @@ The RCAP API aims to codify as many of the rules of the CAP XML format into vali
162
195
  :urgency => Info::URGENCY_IMMEDIATE,
163
196
  :severity => nil, # Severity is not assigned
164
197
  :certainty => 'Unknown Certainty' ) # Certainty is assigned in incorrect value
165
- puts info.valid?
166
- puts info.errors.full_messages
198
+
199
+ puts "Is info valid: #{ info.valid? }"
200
+ info.errors.full_messages.each{ |message| puts "Error: #{ message }" }
167
201
 
168
202
  Will produce the folling output:
169
203
 
170
- false
171
- severity is not present
172
- certainty can only be assigned the following values: Observed, Likely, Possible, Unlikely, Unknown
204
+ Is info valid: false
205
+ Error: severity is not present
206
+ Error: certainty can only be assigned the following values: Observed, Likely, Possible, Unlikely, Unknown
173
207
 
174
208
  All RCAP classes include the Validation module.
175
209
 
176
- A full spec suite using {RSpec}[http://www.rspec.info] was used to test the validations and currently numbers over 150 tests.
210
+ A full spec suite using {RSpec}[http://www.rspec.info] was used to test the validations and currently numbers over 250 tests.
177
211
 
178
212
  === DateTime and Time
179
213
 
data/lib/rcap.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'date'
2
2
  require 'assistance'
3
3
  require 'uuidtools'
4
+ require 'yaml'
5
+ require 'json'
4
6
  require 'rexml/document'
5
7
  require 'rcap/utilities'
6
8
  require 'rcap/validations'
@@ -17,5 +19,5 @@ require 'rcap/area'
17
19
 
18
20
  module RCAP
19
21
  XMLNS = "urn:oasis:names:tc:emergency:cap:1.1"
20
- VERSION = "0.3"
22
+ VERSION = "0.4"
21
23
  end
data/lib/rcap/alert.rb CHANGED
@@ -7,30 +7,30 @@ module RCAP
7
7
  # * it has a valid messge type value
8
8
  # * it has a valid scope value
9
9
  # * all Info objects contained in infos are valid
10
- class Alert
11
- include Validation
10
+ class Alert
11
+ include Validation
12
12
 
13
- STATUS_ACTUAL = "Actual" # :nodoc:
14
- STATUS_EXERCISE = "Exercise" # :nodoc:
15
- STATUS_SYSTEM = "System" # :nodoc:
16
- STATUS_TEST = "Test" # :nodoc:
17
- STATUS_DRAFT = "Draft" # :nodoc:
13
+ STATUS_ACTUAL = "Actual"
14
+ STATUS_EXERCISE = "Exercise"
15
+ STATUS_SYSTEM = "System"
16
+ STATUS_TEST = "Test"
17
+ STATUS_DRAFT = "Draft"
18
18
  # Valid values for status
19
- VALID_STATUSES = [ STATUS_ACTUAL, STATUS_EXERCISE, STATUS_SYSTEM, STATUS_TEST, STATUS_DRAFT ]
19
+ VALID_STATUSES = [ STATUS_ACTUAL, STATUS_EXERCISE, STATUS_SYSTEM, STATUS_TEST, STATUS_DRAFT ]
20
20
 
21
- MSG_TYPE_ALERT = "Alert" # :nodoc:
22
- MSG_TYPE_UPDATE = "Update" # :nodoc:
23
- MSG_TYPE_CANCEL = "Cancel" # :nodoc:
24
- MSG_TYPE_ACK = "Ack" # :nodoc:
25
- MSG_TYPE_ERROR = "Error" # :nodoc:
21
+ MSG_TYPE_ALERT = "Alert"
22
+ MSG_TYPE_UPDATE = "Update"
23
+ MSG_TYPE_CANCEL = "Cancel"
24
+ MSG_TYPE_ACK = "Ack"
25
+ MSG_TYPE_ERROR = "Error"
26
26
  # Valid values for msg_type
27
- VALID_MSG_TYPES = [ MSG_TYPE_ALERT, MSG_TYPE_UPDATE, MSG_TYPE_CANCEL, MSG_TYPE_ACK, MSG_TYPE_ERROR ]
27
+ VALID_MSG_TYPES = [ MSG_TYPE_ALERT, MSG_TYPE_UPDATE, MSG_TYPE_CANCEL, MSG_TYPE_ACK, MSG_TYPE_ERROR ]
28
28
 
29
- SCOPE_PUBLIC = "Public" # :nodoc:
30
- SCOPE_RESTRICTED = "Restricted" # :nodoc:
31
- SCOPE_PRIVATE = "Private" # :nodoc:
29
+ SCOPE_PUBLIC = "Public"
30
+ SCOPE_RESTRICTED = "Restricted"
31
+ SCOPE_PRIVATE = "Private"
32
32
  # Valid values for scope
33
- VALID_SCOPES = [ SCOPE_PUBLIC, SCOPE_PRIVATE, SCOPE_RESTRICTED ]
33
+ VALID_SCOPES = [ SCOPE_PUBLIC, SCOPE_PRIVATE, SCOPE_RESTRICTED ]
34
34
 
35
35
  XML_ELEMENT_NAME = 'alert' # :nodoc:
36
36
  IDENTIFIER_ELEMENT_NAME = 'identifier' # :nodoc:
@@ -63,7 +63,7 @@ module RCAP
63
63
  INCIDENTS_XPATH = "cap:#{ INCIDENTS_ELEMENT_NAME }" # :nodoc:
64
64
 
65
65
  # If not set a UUID will be set by default
66
- attr_accessor( :identifier)
66
+ attr_accessor( :identifier)
67
67
  attr_accessor( :sender )
68
68
  # Sent Time - If not set will value will be time of creation.
69
69
  attr_accessor( :sent )
@@ -80,7 +80,7 @@ module RCAP
80
80
  attr_accessor( :note )
81
81
 
82
82
  # Collection of address strings. Depends on scope being SCOPE_PRIVATE.
83
- attr_reader( :addresses )
83
+ attr_reader( :addresses )
84
84
  # Collection of reference strings - see Alert#to_reference
85
85
  attr_reader( :references)
86
86
  # Collection of incident strings
@@ -88,7 +88,7 @@ module RCAP
88
88
  # Collection of Info objects
89
89
  attr_reader( :infos )
90
90
 
91
- validates_presence_of( :identifier, :sender, :sent, :status, :msg_type, :scope )
91
+ validates_presence_of( :identifier, :sender, :sent, :status, :msg_type, :scope )
92
92
 
93
93
  validates_inclusion_of( :status, :in => VALID_STATUSES )
94
94
  validates_inclusion_of( :msg_type, :in => VALID_MSG_TYPES )
@@ -102,20 +102,20 @@ module RCAP
102
102
 
103
103
  validates_collection_of( :infos )
104
104
 
105
- def initialize( attributes = {})
106
- @identifier = attributes[ :identifier ] || UUIDTools::UUID.random_create.to_s
107
- @sender = attributes[ :sender ]
108
- @sent = attributes[ :sent ] || DateTime.now
109
- @status = attributes[ :status ]
110
- @msg_type = attributes[ :msg_type ]
111
- @scope = attributes[ :scope ]
112
- @source = attributes[ :source ]
113
- @restriction = attributes[ :restriction ]
114
- @addresses = Array( attributes[ :addresses ])
115
- @references = Array( attributes[ :references ])
116
- @incidents = Array( attributes[ :incidents ])
117
- @infos = Array( attributes[ :infos ])
118
- end
105
+ def initialize( attributes = {})
106
+ @identifier = attributes[ :identifier ] || UUIDTools::UUID.random_create.to_s
107
+ @sender = attributes[ :sender ]
108
+ @sent = attributes[ :sent ] || DateTime.now
109
+ @status = attributes[ :status ]
110
+ @msg_type = attributes[ :msg_type ]
111
+ @scope = attributes[ :scope ]
112
+ @source = attributes[ :source ]
113
+ @restriction = attributes[ :restriction ]
114
+ @addresses = Array( attributes[ :addresses ])
115
+ @references = Array( attributes[ :references ])
116
+ @incidents = Array( attributes[ :incidents ])
117
+ @infos = Array( attributes[ :infos ])
118
+ end
119
119
 
120
120
  def to_xml_element #:nodoc:
121
121
  xml_element = REXML::Element.new( XML_ELEMENT_NAME )
@@ -181,7 +181,7 @@ Incidents: #{ self.incidents.join( ' ')}
181
181
  Information:
182
182
  #{ self.infos.map{ |info| " " + info.to_s }.join( "\n" )}
183
183
  EOF
184
- RCAP.format_lines_for_inspect( 'ALERT', alert_inspect )
184
+ RCAP.format_lines_for_inspect( 'ALERT', alert_inspect )
185
185
  end
186
186
 
187
187
  # Returns a string representation of the alert of the form
@@ -192,20 +192,20 @@ EOF
192
192
  end
193
193
 
194
194
  def self.from_xml_element( alert_xml_element ) # :nodoc:
195
- RCAP::Alert.new( :identifier => RCAP.xpath_text( alert_xml_element, RCAP::Alert::IDENTIFIER_XPATH ),
196
- :sender => RCAP.xpath_text( alert_xml_element, SENDER_XPATH ),
197
- :sent => (( sent = RCAP.xpath_first( alert_xml_element, SENT_XPATH )) ? DateTime.parse( sent.text ) : nil ),
198
- :status => RCAP.xpath_text( alert_xml_element, STATUS_XPATH ),
199
- :msg_type => RCAP.xpath_text( alert_xml_element, MSG_TYPE_XPATH ),
200
- :source => RCAP.xpath_text( alert_xml_element, SOURCE_XPATH ),
201
- :scope => RCAP.xpath_text( alert_xml_element, SCOPE_XPATH ),
202
- :restriction => RCAP.xpath_text( alert_xml_element, RESTRICTION_XPATH ),
203
- :addresses => (( address = RCAP.xpath_text( alert_xml_element, ADDRESSES_XPATH )) ? address.unpack_cap_list : nil ),
204
- :code => RCAP.xpath_text( alert_xml_element, CODE_XPATH ),
205
- :note => RCAP.xpath_text( alert_xml_element, NOTE_XPATH ),
206
- :references => (( references = RCAP.xpath_text( alert_xml_element, REFERENCES_XPATH )) ? references.split( ' ' ) : nil ),
207
- :incidents => (( incidents = RCAP.xpath_text( alert_xml_element, INCIDENTS_XPATH )) ? incidents.split( ' ' ) : nil ),
208
- :infos => RCAP.xpath_match( alert_xml_element, RCAP::Info::XPATH ).map{ |element| RCAP::Info.from_xml_element( element )})
195
+ self.new( :identifier => RCAP.xpath_text( alert_xml_element, RCAP::Alert::IDENTIFIER_XPATH ),
196
+ :sender => RCAP.xpath_text( alert_xml_element, SENDER_XPATH ),
197
+ :sent => (( sent = RCAP.xpath_first( alert_xml_element, SENT_XPATH )) ? DateTime.parse( sent.text ) : nil ),
198
+ :status => RCAP.xpath_text( alert_xml_element, STATUS_XPATH ),
199
+ :msg_type => RCAP.xpath_text( alert_xml_element, MSG_TYPE_XPATH ),
200
+ :source => RCAP.xpath_text( alert_xml_element, SOURCE_XPATH ),
201
+ :scope => RCAP.xpath_text( alert_xml_element, SCOPE_XPATH ),
202
+ :restriction => RCAP.xpath_text( alert_xml_element, RESTRICTION_XPATH ),
203
+ :addresses => (( address = RCAP.xpath_text( alert_xml_element, ADDRESSES_XPATH )) ? address.unpack_cap_list : nil ),
204
+ :code => RCAP.xpath_text( alert_xml_element, CODE_XPATH ),
205
+ :note => RCAP.xpath_text( alert_xml_element, NOTE_XPATH ),
206
+ :references => (( references = RCAP.xpath_text( alert_xml_element, REFERENCES_XPATH )) ? references.split( ' ' ) : nil ),
207
+ :incidents => (( incidents = RCAP.xpath_text( alert_xml_element, INCIDENTS_XPATH )) ? incidents.split( ' ' ) : nil ),
208
+ :infos => RCAP.xpath_match( alert_xml_element, RCAP::Info::XPATH ).map{ |element| RCAP::Info.from_xml_element( element )})
209
209
  end
210
210
 
211
211
  def self.from_xml_document( xml_document ) # :nodoc:
@@ -217,63 +217,125 @@ EOF
217
217
  self.from_xml_document( REXML::Document.new( xml ))
218
218
  end
219
219
 
220
- IDENTIFIER_YAML = "Identifier" # :nodoc:
221
- SENDER_YAML = "Sender" # :nodoc:
222
- SENT_YAML = "Sent" # :nodoc:
223
- STATUS_YAML = "Status" # :nodoc:
224
- MSG_TYPE_YAML = "Message Type" # :nodoc:
225
- SOURCE_YAML = "Source" # :nodoc:
226
- SCOPE_YAML = "Scope" # :nodoc:
227
- RESTRICTION_YAML = "Restriction" # :nodoc:
228
- ADDRESSES_YAML = "Addresses" # :nodoc:
229
- CODE_YAML = "Code" # :nodoc:
230
- NOTE_YAML = "Note" # :nodoc:
231
- REFERENCES_YAML = "References" # :nodoc:
232
- INCIDENTS_YAML = "Incidents" # :nodoc:
233
- INFOS_YAML = "Information" # :nodoc:
220
+ IDENTIFIER_YAML = "Identifier" # :nodoc:
221
+ SENDER_YAML = "Sender" # :nodoc:
222
+ SENT_YAML = "Sent" # :nodoc:
223
+ STATUS_YAML = "Status" # :nodoc:
224
+ MSG_TYPE_YAML = "Message Type" # :nodoc:
225
+ SOURCE_YAML = "Source" # :nodoc:
226
+ SCOPE_YAML = "Scope" # :nodoc:
227
+ RESTRICTION_YAML = "Restriction" # :nodoc:
228
+ ADDRESSES_YAML = "Addresses" # :nodoc:
229
+ CODE_YAML = "Code" # :nodoc:
230
+ NOTE_YAML = "Note" # :nodoc:
231
+ REFERENCES_YAML = "References" # :nodoc:
232
+ INCIDENTS_YAML = "Incidents" # :nodoc:
233
+ INFOS_YAML = "Information" # :nodoc:
234
234
 
235
235
  # Returns a string containing the YAML representation of the alert.
236
- def to_yaml( options = {} )
237
- RCAP.attribute_values_to_yaml_hash(
238
- [ IDENTIFIER_YAML, self.identifier ],
239
- [ SENDER_YAML, self.sender ],
240
- [ SENT_YAML, self.sent ],
241
- [ STATUS_YAML, self.status ],
242
- [ MSG_TYPE_YAML, self.msg_type ],
243
- [ SOURCE_YAML, self.source ],
244
- [ SCOPE_YAML, self.scope ],
245
- [ RESTRICTION_YAML, self.restriction ],
246
- [ ADDRESSES_YAML, self.addresses ],
247
- [ CODE_YAML, self.code ],
248
- [ NOTE_YAML, self.note ],
249
- [ REFERENCES_YAML, self.references ],
250
- [ INCIDENTS_YAML, self.incidents ],
251
- [ INFOS_YAML, self.infos ]
252
- ).to_yaml( options )
253
- end
236
+ def to_yaml( options = {} )
237
+ RCAP.attribute_values_to_hash(
238
+ [ IDENTIFIER_YAML, self.identifier ],
239
+ [ SENDER_YAML, self.sender ],
240
+ [ SENT_YAML, self.sent ],
241
+ [ STATUS_YAML, self.status ],
242
+ [ MSG_TYPE_YAML, self.msg_type ],
243
+ [ SOURCE_YAML, self.source ],
244
+ [ SCOPE_YAML, self.scope ],
245
+ [ RESTRICTION_YAML, self.restriction ],
246
+ [ ADDRESSES_YAML, self.addresses ],
247
+ [ CODE_YAML, self.code ],
248
+ [ NOTE_YAML, self.note ],
249
+ [ REFERENCES_YAML, self.references ],
250
+ [ INCIDENTS_YAML, self.incidents ],
251
+ [ INFOS_YAML, self.infos ]
252
+ ).to_yaml( options )
253
+ end
254
254
 
255
255
  # Initialise an Alert object from a YAML string. Any object that is a subclass of IO (e.g. File) can be passed in.
256
- def self.from_yaml( yaml )
257
- self.from_yaml_data( YAML.load( yaml ))
258
- end
256
+ def self.from_yaml( yaml )
257
+ self.from_yaml_data( YAML.load( yaml ))
258
+ end
259
259
 
260
- def self.from_yaml_data( alert_yaml_data ) # :nodoc:
261
- Alert.new(
262
- :identifier => alert_yaml_data[ IDENTIFIER_YAML ],
263
- :sender => alert_yaml_data[ SENDER_YAML ],
264
- :sent => ( sent = alert_yaml_data[ SENT_YAML ]).blank? ? nil : DateTime.parse( sent.to_s ),
265
- :status => alert_yaml_data[ STATUS_YAML ],
266
- :msg_type => alert_yaml_data[ MSG_TYPE_YAML ],
267
- :source => alert_yaml_data[ SOURCE_YAML ],
268
- :scope => alert_yaml_data[ SCOPE_YAML ],
269
- :restriction => alert_yaml_data[ RESTRICTION_YAML ],
270
- :addresses => alert_yaml_data[ ADDRESSES_YAML ],
271
- :code => alert_yaml_data[ CODE_YAML ],
272
- :note => alert_yaml_data[ NOTE_YAML ],
273
- :references => alert_yaml_data[ REFERENCES_YAML ],
274
- :incidents => alert_yaml_data[ INCIDENTS_YAML ],
275
- :infos => Array( alert_yaml_data[ INFOS_YAML ]).map{ |info_yaml_data| RCAP::Info.from_yaml_data( info_yaml_data )}
276
- )
277
- end
260
+ def self.from_yaml_data( alert_yaml_data ) # :nodoc:
261
+ Alert.new(
262
+ :identifier => alert_yaml_data[ IDENTIFIER_YAML ],
263
+ :sender => alert_yaml_data[ SENDER_YAML ],
264
+ :sent => ( sent = alert_yaml_data[ SENT_YAML ]).blank? ? nil : DateTime.parse( sent.to_s ),
265
+ :status => alert_yaml_data[ STATUS_YAML ],
266
+ :msg_type => alert_yaml_data[ MSG_TYPE_YAML ],
267
+ :source => alert_yaml_data[ SOURCE_YAML ],
268
+ :scope => alert_yaml_data[ SCOPE_YAML ],
269
+ :restriction => alert_yaml_data[ RESTRICTION_YAML ],
270
+ :addresses => alert_yaml_data[ ADDRESSES_YAML ],
271
+ :code => alert_yaml_data[ CODE_YAML ],
272
+ :note => alert_yaml_data[ NOTE_YAML ],
273
+ :references => alert_yaml_data[ REFERENCES_YAML ],
274
+ :incidents => alert_yaml_data[ INCIDENTS_YAML ],
275
+ :infos => Array( alert_yaml_data[ INFOS_YAML ]).map{ |info_yaml_data| RCAP::Info.from_yaml_data( info_yaml_data )}
276
+ )
277
+ end
278
+
279
+ IDENTIFIER_KEY = 'identifier' # :nodoc:
280
+ SENDER_KEY = 'sender' # :nodoc:
281
+ SENT_KEY = 'sent' # :nodoc:
282
+ STATUS_KEY = 'status' # :nodoc:
283
+ MSG_TYPE_KEY = 'msg_type' # :nodoc:
284
+ SOURCE_KEY = 'source' # :nodoc:
285
+ SCOPE_KEY = 'scope' # :nodoc:
286
+ RESTRICTION_KEY = 'restriction' # :nodoc:
287
+ ADDRESSES_KEY = 'addresses' # :nodoc:
288
+ CODE_KEY = 'code' # :nodoc:
289
+ NOTE_KEY = 'note' # :nodoc:
290
+ REFERENCES_KEY = 'references' # :nodoc:
291
+ INCIDENTS_KEY = 'incidents' # :nodoc:
292
+ INFOS_KEY = 'infos' # :nodoc:
293
+
294
+ # Returns a Hash representation of an Alert object
295
+ def to_h
296
+ RCAP.attribute_values_to_hash([ IDENTIFIER_KEY, self.identifier ],
297
+ [ SENDER_KEY, self.sender ],
298
+ [ SENT_KEY, RCAP.to_s_for_cap( self.sent )],
299
+ [ STATUS_KEY, self.status ],
300
+ [ MSG_TYPE_KEY, self.msg_type ],
301
+ [ SOURCE_KEY, self.source ],
302
+ [ SCOPE_KEY, self.scope ],
303
+ [ RESTRICTION_KEY, self.restriction ],
304
+ [ ADDRESSES_KEY, self.addresses ],
305
+ [ CODE_KEY, self.code ],
306
+ [ NOTE_KEY, self.note ],
307
+ [ REFERENCES_KEY, self.references ],
308
+ [ INCIDENTS_KEY, self.incidents ],
309
+ [ INFOS_KEY, self.infos.map{ |info| info.to_h }])
310
+ end
311
+
312
+ # Initialises an Alert object from a Hash produced by Alert#to_h
313
+ def self.from_h( alert_hash )
314
+ self.new(
315
+ :identifier => alert_hash[ IDENTIFIER_KEY ],
316
+ :sender => alert_hash[ SENDER_KEY ],
317
+ :sent => RCAP.parse_datetime( alert_hash[ SENT_KEY ]),
318
+ :status => alert_hash[ STATUS_KEY ],
319
+ :msg_type => alert_hash[ MSG_TYPE_KEY ],
320
+ :source => alert_hash[ SOURCE_KEY ],
321
+ :scope => alert_hash[ SCOPE_KEY ],
322
+ :restriction => alert_hash[ RESTRICTION_KEY ],
323
+ :addresses => alert_hash[ ADDRESSES_KEY ],
324
+ :code => alert_hash[ CODE_KEY ],
325
+ :note => alert_hash[ NOTE_KEY ],
326
+ :references => alert_hash[ REFERENCES_KEY ],
327
+ :incidents => alert_hash[ INCIDENTS_KEY ],
328
+ :infos => Array( alert_hash[ INFOS_KEY ]).map{ |info_hash| RCAP::Info.from_h( info_hash )})
329
+ end
330
+
331
+ # Returns a JSON string representation of an Alert object
332
+ def to_json
333
+ self.to_h.to_json
334
+ end
335
+
336
+ # Initiialises an Alert object from a JSON string produced by Alert#to_json
337
+ def self.from_json( json_string )
338
+ self.from_h( JSON.parse( json_string ))
339
+ end
278
340
  end
279
341
  end