rcap 1.2.0 → 1.2.1

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