rcap 1.2.0 → 1.2.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.
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ tags
5
5
  *.gem
6
6
  .bundle
7
7
  Gemfile.lock
8
+ .yardoc
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,13 @@
1
1
  = Change Log
2
2
 
3
+ == 1.2.1 - 27 October 2011
4
+
5
+ * Fixed bug initialising 'audience' attribute in Info class
6
+ * Added CAP/Atom files from Google CAP Library project into specs
7
+ * Organised extension code into separate file
8
+ * Modifed RCAP::Alert.from_xml to auto-detect the XML namespace and CAP version. Will default to CAP 1.2 if no
9
+ namespace is found.
10
+
3
11
  == 1.2.0 - 17 July 2011
4
12
 
5
13
  * CAP 1.1 and CAP 1.2 - Resource#dereference_uri! fetches data from Resource#uri and sets Resource#deref_uri
data/Rakefile CHANGED
@@ -1,10 +1,12 @@
1
+ require 'rubygems'
1
2
  require 'bundler'
2
- require 'hanna/rdoctask'
3
+
4
+ require 'rdoc/task'
3
5
  require 'rspec/core/rake_task'
4
6
 
5
7
  Bundler::GemHelper.install_tasks
6
8
 
7
- Rake::RDocTask.new do |rdoc|
9
+ RDoc::Task.new do |rdoc|
8
10
  rdoc.main = 'README.rdoc'
9
11
  rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'lib/**/*.rb')
10
12
  rdoc.rdoc_dir = 'doc'
@@ -0,0 +1,5 @@
1
+ class Array # :nodoc:
2
+ def to_s_for_cap
3
+ self.map{ |element| element.to_s.for_cap_list }.join( ' ' )
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ class DateTime # :nodoc:
2
+ RCAP_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
3
+ RCAP_ZONE_FORMAT = "%+03i:00"
4
+
5
+ alias inspect to_s
6
+
7
+ def to_s_for_cap
8
+ t = self.strftime( RCAP_TIME_FORMAT ) + format( RCAP_ZONE_FORMAT , utc_hours_offset )
9
+ t.sub(/\+(00:\d\d)$/, '-\1')
10
+ end
11
+
12
+ private
13
+ def utc_hours_offset
14
+ self.offset * 24
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ class String # :nodoc:
2
+ CAP_LIST_REGEX = Regexp.new( '"([\w\s]+)"|(\S+)' )
3
+ WHITESPACE_REGEX = Regexp.new('^\s+$')
4
+
5
+ def for_cap_list
6
+ if self =~ /\s/
7
+ '"'+self+'"'
8
+ else
9
+ self
10
+ end
11
+ end
12
+
13
+ def unpack_cap_list
14
+ self.split( CAP_LIST_REGEX ).reject{ |match| match == "" || match =~ WHITESPACE_REGEX }
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ class Time # :nodoc:
2
+ RCAP_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
3
+ RCAP_ZONE_FORMAT = "%+03i:00"
4
+
5
+ def to_s_for_cap
6
+ t = self.strftime( RCAP_TIME_FORMAT ) + format( RCAP_ZONE_FORMAT , utc_hours_offset )
7
+ t.sub(/\+(00:\d\d)$/, '-\1')
8
+ end
9
+
10
+ private
11
+ def utc_hours_offset
12
+ self.utc_offset/3600
13
+ end
14
+ end
data/lib/rcap.rb CHANGED
@@ -9,11 +9,15 @@ require 'rexml/formatters/pretty'
9
9
  require 'open-uri'
10
10
  require 'base64'
11
11
  require 'digest/sha1'
12
+ # Extensions
13
+ require 'extensions/array'
14
+ require 'extensions/string'
15
+ require 'extensions/date_time'
16
+ require 'extensions/time'
12
17
  # RCAP
13
18
  require 'rcap/version'
14
19
  require 'rcap/utilities'
15
20
  require 'rcap/validations'
16
- require 'rcap/alert'
17
21
  require 'rcap/cap_1_0/alert'
18
22
  require 'rcap/cap_1_0/parameter'
19
23
  require 'rcap/cap_1_0/event_code'
@@ -44,5 +48,6 @@ require 'rcap/cap_1_2/circle'
44
48
  require 'rcap/cap_1_2/polygon'
45
49
  require 'rcap/cap_1_2/geocode'
46
50
  require 'rcap/cap_1_2/area'
51
+ require 'rcap/alert'
47
52
  # Configuration
48
53
  require 'config'
data/lib/rcap/alert.rb CHANGED
@@ -5,13 +5,20 @@ module RCAP
5
5
  YAML_CAP_VERSION_KEY = "CAP Version"
6
6
  JSON_CAP_VERSION_KEY = "cap_version"
7
7
 
8
+ CAP_NAMESPACES = [ RCAP::CAP_1_0::Alert::XMLNS, RCAP::CAP_1_1::Alert::XMLNS, RCAP::CAP_1_2::Alert::XMLNS ]
9
+
8
10
  # Initialise a RCAP Alert from a XML document. The namespace of the
9
11
  # document is inspected and a CAP_1_0::Alert, CAP_1_1::Alert
10
12
  # or CAP_1_2::Alert is instantiated.
11
- def self.from_xml( xml, namespace_key = XMLNS_KEY )
13
+ #
14
+ # The namespace key ('cap' if the CAP document is stored under 'xmlns:cap')
15
+ # can be specified explicitly by passing it in as a second parameter.
16
+ def self.from_xml( xml, namespace_key = nil )
12
17
  xml_document = REXML::Document.new( xml )
18
+ document_namespaces = xml_document.root.namespaces.invert
19
+ namespace = namespace_key || CAP_NAMESPACES.find{ |namepsace| document_namespaces[ namepsace ]}
13
20
 
14
- case xml_document.root.namespaces[ namespace_key ]
21
+ case namespace
15
22
  when CAP_1_0::Alert::XMLNS
16
23
  CAP_1_0::Alert.from_xml_document( xml_document )
17
24
  when CAP_1_1::Alert::XMLNS
@@ -19,7 +26,6 @@ module RCAP
19
26
  else
20
27
  CAP_1_2::Alert.from_xml_document( xml_document )
21
28
  end
22
-
23
29
  end
24
30
 
25
31
  # Initialise a RCAP Alert from a YAML document produced by
@@ -126,14 +126,11 @@ module RCAP
126
126
  POLYGONS_YAML = 'Polygons' # :nodoc:
127
127
 
128
128
  def to_yaml( options = {} ) # :nodoc:
129
- circles_yaml = self.circles.map{ |circle| [ circle.lattitude, circle.longitude, circle.radius ]}
130
- def circles_yaml.to_yaml_style; :inline; end
131
-
132
129
  RCAP.attribute_values_to_hash(
133
130
  [ AREA_DESC_YAML, self.area_desc ],
134
131
  [ ALTITUDE_YAML, self.altitude ],
135
132
  [ CEILING_YAML, self.ceiling ],
136
- [ CIRCLES_YAML, circles_yaml ],
133
+ [ CIRCLES_YAML, self.circles.map{ |circle| [ circle.lattitude, circle.longitude, circle.radius ]} ],
137
134
  [ GEOCODES_YAML, self.geocodes.inject({}){|h,geocode| h.merge( geocode.name => geocode.value )}],
138
135
  [ POLYGONS_YAML, self.polygons ]
139
136
  ).to_yaml( options )
@@ -139,6 +139,7 @@ module RCAP
139
139
  def initialize( attributes = {} )
140
140
  @language = attributes[ :language ] || DEFAULT_LANGUAGE
141
141
  @categories = Array( attributes[ :categories ])
142
+ @audience = attributes [ :audience ]
142
143
  @event = attributes [ :event ]
143
144
  @urgency = attributes[ :urgency ]
144
145
  @severity = attributes[ :severity ]
@@ -310,13 +311,10 @@ module RCAP
310
311
  AREAS_YAML = 'Areas' # :nodoc:
311
312
 
312
313
  def to_yaml( options = {} ) # :nodoc:
313
- categories_yaml = self.categories
314
- def categories_yaml.to_yaml_style; :inline; end
315
-
316
314
  parameter_to_hash = lambda{ |hash, parameter| hash.merge( parameter.name => parameter.value )}
317
315
 
318
316
  RCAP.attribute_values_to_hash( [ LANGUAGE_YAML, self.language ],
319
- [ CATEGORIES_YAML, categories_yaml ],
317
+ [ CATEGORIES_YAML, self.categories ],
320
318
  [ EVENT_YAML, self.event ],
321
319
  [ URGENCY_YAML, self.urgency ],
322
320
  [ SEVERITY_YAML, self.severity ],
@@ -65,10 +65,7 @@ module RCAP
65
65
 
66
66
 
67
67
  def to_yaml( options = {} ) # :nodoc:
68
- yaml_points = self.points.map{ |point| [ point.lattitude, point.longitude ]}
69
- def yaml_points.to_yaml_style; :inline; end
70
-
71
- yaml_points.to_yaml( options )
68
+ self.points.map{ |point| [ point.lattitude, point.longitude ]}.to_yaml( options )
72
69
  end
73
70
 
74
71
  def self.from_yaml_data( polygon_yaml_data ) # :nodoc:
@@ -126,14 +126,11 @@ module RCAP
126
126
  POLYGONS_YAML = 'Polygons' # :nodoc:
127
127
 
128
128
  def to_yaml( options = {} ) # :nodoc:
129
- circles_yaml = self.circles.map{ |circle| [ circle.lattitude, circle.longitude, circle.radius ]}
130
- def circles_yaml.to_yaml_style; :inline; end
131
-
132
129
  RCAP.attribute_values_to_hash(
133
130
  [ AREA_DESC_YAML, self.area_desc ],
134
131
  [ ALTITUDE_YAML, self.altitude ],
135
132
  [ CEILING_YAML, self.ceiling ],
136
- [ CIRCLES_YAML, circles_yaml ],
133
+ [ CIRCLES_YAML, self.circles.map{ |circle| [ circle.lattitude, circle.longitude, circle.radius ]}],
137
134
  [ GEOCODES_YAML, self.geocodes.inject({}){|h,geocode| h.merge( geocode.name => geocode.value )}],
138
135
  [ POLYGONS_YAML, self.polygons ]
139
136
  ).to_yaml( options )
@@ -157,6 +157,7 @@ module RCAP
157
157
  def initialize( attributes = {} )
158
158
  @language = attributes[ :language ] || DEFAULT_LANGUAGE
159
159
  @categories = Array( attributes[ :categories ])
160
+ @audience = attributes [ :audience ]
160
161
  @event = attributes [ :event ]
161
162
  @response_types = Array( attributes[ :response_types ])
162
163
  @urgency = attributes[ :urgency ]
@@ -335,19 +336,13 @@ module RCAP
335
336
  AREAS_YAML = 'Areas' # :nodoc:
336
337
 
337
338
  def to_yaml( options = {} ) # :nodoc:
338
- response_types_yaml = self.response_types
339
- def response_types_yaml.to_yaml_style; :inline; end
340
-
341
- categories_yaml = self.categories
342
- def categories_yaml.to_yaml_style; :inline; end
343
-
344
339
  parameter_to_hash = lambda{ |hash, parameter| hash.merge( parameter.name => parameter.value )}
345
340
 
346
341
  RCAP.attribute_values_to_hash(
347
342
  [ LANGUAGE_YAML, self.language ],
348
- [ CATEGORIES_YAML, categories_yaml ],
343
+ [ CATEGORIES_YAML, self.categories ],
349
344
  [ EVENT_YAML, self.event ],
350
- [ RESPONSE_TYPES_YAML, response_types_yaml ],
345
+ [ RESPONSE_TYPES_YAML, self.response_types ],
351
346
  [ URGENCY_YAML, self.urgency ],
352
347
  [ SEVERITY_YAML, self.severity ],
353
348
  [ CERTAINTY_YAML, self.certainty ],
@@ -65,10 +65,7 @@ module RCAP
65
65
 
66
66
 
67
67
  def to_yaml( options = {} ) # :nodoc:
68
- yaml_points = self.points.map{ |point| [ point.lattitude, point.longitude ]}
69
- def yaml_points.to_yaml_style; :inline; end
70
-
71
- yaml_points.to_yaml( options )
68
+ self.points.map{ |point| [ point.lattitude, point.longitude ]}.to_yaml( options )
72
69
  end
73
70
 
74
71
  def self.from_yaml_data( polygon_yaml_data ) # :nodoc:
@@ -126,14 +126,11 @@ module RCAP
126
126
  POLYGONS_YAML = 'Polygons' # :nodoc:
127
127
 
128
128
  def to_yaml( options = {} ) # :nodoc:
129
- circles_yaml = self.circles.map{ |circle| [ circle.lattitude, circle.longitude, circle.radius ]}
130
- def circles_yaml.to_yaml_style; :inline; end
131
-
132
129
  RCAP.attribute_values_to_hash(
133
130
  [ AREA_DESC_YAML, self.area_desc ],
134
131
  [ ALTITUDE_YAML, self.altitude ],
135
132
  [ CEILING_YAML, self.ceiling ],
136
- [ CIRCLES_YAML, circles_yaml ],
133
+ [ CIRCLES_YAML, self.circles.map{ |circle| [ circle.lattitude, circle.longitude, circle.radius ]} ],
137
134
  [ GEOCODES_YAML, self.geocodes.inject({}){|h,geocode| h.merge( geocode.name => geocode.value )}],
138
135
  [ POLYGONS_YAML, self.polygons ]
139
136
  ).to_yaml( options )
@@ -159,6 +159,7 @@ module RCAP
159
159
  def initialize( attributes = {} )
160
160
  @language = attributes[ :language ] || DEFAULT_LANGUAGE
161
161
  @categories = Array( attributes[ :categories ])
162
+ @audience = attributes [ :audience ]
162
163
  @event = attributes [ :event ]
163
164
  @response_types = Array( attributes[ :response_types ])
164
165
  @urgency = attributes[ :urgency ]
@@ -337,18 +338,12 @@ module RCAP
337
338
  AREAS_YAML = 'Areas' # :nodoc:
338
339
 
339
340
  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
341
  parameter_to_hash = lambda{ |hash, parameter| hash.merge( parameter.name => parameter.value )}
347
342
 
348
343
  RCAP.attribute_values_to_hash( [ LANGUAGE_YAML, self.language ],
349
- [ CATEGORIES_YAML, categories_yaml ],
344
+ [ CATEGORIES_YAML, self.categories ],
350
345
  [ EVENT_YAML, self.event ],
351
- [ RESPONSE_TYPES_YAML, response_types_yaml ],
346
+ [ RESPONSE_TYPES_YAML, self.response_types ],
352
347
  [ URGENCY_YAML, self.urgency ],
353
348
  [ SEVERITY_YAML, self.severity ],
354
349
  [ CERTAINTY_YAML, self.certainty ],
@@ -66,10 +66,7 @@ module RCAP
66
66
 
67
67
 
68
68
  def to_yaml( options = {} ) # :nodoc:
69
- yaml_points = self.points.map{ |point| [ point.lattitude, point.longitude ]}
70
- def yaml_points.to_yaml_style; :inline; end
71
-
72
- yaml_points.to_yaml( options )
69
+ self.points.map{ |point| [ point.lattitude, point.longitude ]}.to_yaml( options )
73
70
  end
74
71
 
75
72
  def self.from_yaml_data( polygon_yaml_data ) # :nodoc:
@@ -1,47 +1,5 @@
1
1
  ALLOWED_CHARACTERS = /[^\s&<]+/ # :nodoc:
2
2
 
3
- class Array # :nodoc:
4
- def to_s_for_cap
5
- self.map{ |element| element.to_s.for_cap_list }.join( ' ' )
6
- end
7
- end
8
-
9
- class String # :nodoc:
10
- CAP_LIST_REGEX = Regexp.new( '"([\w\s]+)"|(\S+)' )
11
- WHITESPACE_REGEX = Regexp.new('^\s+$')
12
-
13
- def for_cap_list
14
- if self =~ /\s/
15
- '"'+self+'"'
16
- else
17
- self
18
- end
19
- end
20
-
21
- def unpack_cap_list
22
- self.split( CAP_LIST_REGEX ).reject{ |match| match == "" || match =~ WHITESPACE_REGEX }
23
- end
24
- end
25
-
26
- class DateTime # :nodoc:
27
- alias inspect to_s
28
- alias to_s_for_cap to_s
29
- end
30
-
31
- class Time # :nodoc:
32
- RCAP_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
33
- RCAP_ZONE_FORMAT = "%+03i:00"
34
-
35
- def to_s_for_cap
36
- t = self.strftime( RCAP_TIME_FORMAT ) + format( RCAP_ZONE_FORMAT , self.utc_hours_offset )
37
- t.sub(/\+(00:\d\d)$/, '-\1')
38
- end
39
-
40
- def utc_hours_offset
41
- self.utc_offset/3600
42
- end
43
- end
44
-
45
3
  module RCAP # :nodoc:
46
4
  def self.generate_identifier
47
5
  UUIDTools::UUID.random_create.to_s
data/lib/rcap/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RCAP
2
- VERSION = '1.2.0'
2
+ VERSION = '1.2.1'
3
3
  end
data/rcap.gemspec CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path('../lib', __FILE__)
2
+ $:.unshift File.expand_path('../lib', __FILE__)
3
3
  require 'rcap/version'
4
4
 
5
5
  Gem::Specification.new do |s|
@@ -25,6 +25,6 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency('uuidtools', '>= 2.1.2')
26
26
 
27
27
  s.add_development_dependency( 'rspec', '>= 2.5.0' )
28
- s.add_development_dependency( 'hanna', '>= 0.1.12' )
28
+ s.add_development_dependency( 'rdoc' )
29
29
  s.add_development_dependency( 'webmock' )
30
30
  end
data/spec/alert_spec.rb CHANGED
@@ -17,8 +17,6 @@ describe( RCAP::Alert ) do
17
17
  :infos => [ RCAP::CAP_1_0::Info.new, RCAP::CAP_1_0::Info.new ])
18
18
  end
19
19
 
20
-
21
-
22
20
  shared_examples_for( 'it has parsed a CAP 1.0 alert correctly' ) do
23
21
  it( 'should use the correct CAP Version' ){ @alert.class.should == RCAP::CAP_1_0::Alert }
24
22
  it( 'should parse identifier correctly' ) { @alert.identifier.should == @original_alert.identifier }
@@ -81,8 +79,6 @@ describe( RCAP::Alert ) do
81
79
  :infos => [ RCAP::CAP_1_1::Info.new, RCAP::CAP_1_1::Info.new ])
82
80
  end
83
81
 
84
-
85
-
86
82
  shared_examples_for( 'it has parsed a CAP 1.1 alert correctly' ) do
87
83
  it( 'should use the correct CAP Version' ){ @alert.class.should == RCAP::CAP_1_1::Alert }
88
84
  it( 'should parse identifier correctly' ) { @alert.identifier.should == @original_alert.identifier }
@@ -145,8 +141,6 @@ describe( RCAP::Alert ) do
145
141
  :infos => [ RCAP::CAP_1_2::Info.new, RCAP::CAP_1_2::Info.new ])
146
142
  end
147
143
 
148
-
149
-
150
144
  shared_examples_for( 'it has parsed a CAP 1.2 alert correctly' ) do
151
145
  it( 'should use the correct CAP Version' ){ @alert.class.should == RCAP::CAP_1_2::Alert }
152
146
  it( 'should parse identifier correctly' ) { @alert.identifier.should == @original_alert.identifier }
@@ -193,4 +187,77 @@ describe( RCAP::Alert ) do
193
187
  end
194
188
  end
195
189
  end
190
+
191
+ describe( 'external file' ) do
192
+ def load_file( file_name )
193
+ File.open( File.join( File.dirname( __FILE__ ), 'assets', file_name )){|f| f.read }
194
+ end
195
+
196
+ describe( "'invalid.cap'" ) do
197
+ before( :each ) do
198
+ @alert = RCAP::Alert.from_xml( load_file( 'invalid.cap' ))
199
+ end
200
+
201
+ it( 'should not be valid' ) do
202
+ @alert.should_not( be_valid )
203
+ end
204
+
205
+ it( 'should be invalid because scope is missing' ) do
206
+ @alert.valid?
207
+ @alert.errors.on( :scope ).should_not( be_empty )
208
+ end
209
+ end
210
+
211
+ describe( "'earthquake.cap'" ) do
212
+ before( :each ) do
213
+ @alert = RCAP::Alert.from_xml( load_file( 'earthquake.cap' ))
214
+ end
215
+
216
+ it( 'should be valid' ) do
217
+ @alert.should( be_valid )
218
+ end
219
+
220
+ it( 'should parse the alert correctly' ) do
221
+ @alert.class.should == RCAP::CAP_1_1::Alert
222
+ @alert.status.should == RCAP::CAP_1_1::Alert::STATUS_ACTUAL
223
+ @alert.msg_type.should == RCAP::CAP_1_1::Alert::MSG_TYPE_ALERT
224
+ @alert.scope.should == RCAP::CAP_1_1::Alert::SCOPE_PUBLIC
225
+
226
+ @alert.infos.size.should == 2
227
+ info = @alert.infos.first
228
+ info.categories.include?( RCAP::CAP_1_1::Info::CATEGORY_GEO ).should( be_true )
229
+
230
+ info.areas.size.should == 1
231
+ area = info.areas.first
232
+
233
+ area.circles.size.should == 1
234
+ circle = area.circles.first
235
+ circle.lattitude.should == -16.053
236
+ circle.longitude.should == -173.274
237
+ circle.radius.should == 0
238
+ end
239
+ end
240
+
241
+ describe( "'canada.cap'" ) do
242
+ before( :each ) do
243
+ @alert = RCAP::Alert.from_xml( load_file( 'canada.cap' ))
244
+ end
245
+
246
+ it( 'should be valid' ) do
247
+ @alert.should( be_valid )
248
+ end
249
+
250
+ it( 'should parse the alert correctly' ) do
251
+ @alert.class.should == RCAP::CAP_1_1::Alert
252
+ @alert.status.should == RCAP::CAP_1_1::Alert::STATUS_ACTUAL
253
+ @alert.msg_type.should == RCAP::CAP_1_1::Alert::MSG_TYPE_UPDATE
254
+ @alert.scope.should == RCAP::CAP_1_1::Alert::SCOPE_PUBLIC
255
+ @alert.identifier.should == "CA-EC-CWTO-2011-138776"
256
+
257
+ @alert.infos.size.should == 2
258
+ info = @alert.infos.first
259
+ info.event_codes.first.value = 'storm'
260
+ end
261
+ end
262
+ end
196
263
  end