rcap 1.3.1 → 2.0.0

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 (88) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/README.md +78 -151
  3. data/Rakefile +1 -1
  4. data/lib/rcap/alert.rb +2 -2
  5. data/lib/rcap/base/alert.rb +446 -0
  6. data/lib/rcap/base/area.rb +228 -0
  7. data/lib/rcap/base/circle.rb +121 -0
  8. data/lib/rcap/base/event_code.rb +6 -0
  9. data/lib/rcap/base/geocode.rb +6 -0
  10. data/lib/rcap/base/info.rb +498 -0
  11. data/lib/rcap/base/parameter.rb +88 -0
  12. data/lib/rcap/base/point.rb +87 -0
  13. data/lib/rcap/base/polygon.rb +120 -0
  14. data/lib/rcap/base/resource.rb +168 -0
  15. data/lib/rcap/cap_1_0/alert.rb +59 -342
  16. data/lib/rcap/cap_1_0/area.rb +13 -188
  17. data/lib/rcap/cap_1_0/circle.rb +2 -100
  18. data/lib/rcap/cap_1_0/event_code.rb +8 -3
  19. data/lib/rcap/cap_1_0/geocode.rb +8 -3
  20. data/lib/rcap/cap_1_0/info.rb +16 -468
  21. data/lib/rcap/cap_1_0/parameter.rb +9 -67
  22. data/lib/rcap/cap_1_0/point.rb +2 -61
  23. data/lib/rcap/cap_1_0/polygon.rb +5 -95
  24. data/lib/rcap/cap_1_0/resource.rb +4 -144
  25. data/lib/rcap/cap_1_1/alert.rb +7 -412
  26. data/lib/rcap/cap_1_1/area.rb +13 -188
  27. data/lib/rcap/cap_1_1/circle.rb +2 -100
  28. data/lib/rcap/cap_1_1/event_code.rb +8 -3
  29. data/lib/rcap/cap_1_1/geocode.rb +7 -3
  30. data/lib/rcap/cap_1_1/info.rb +127 -386
  31. data/lib/rcap/cap_1_1/parameter.rb +4 -76
  32. data/lib/rcap/cap_1_1/point.rb +2 -61
  33. data/lib/rcap/cap_1_1/polygon.rb +5 -95
  34. data/lib/rcap/cap_1_1/resource.rb +37 -143
  35. data/lib/rcap/cap_1_2/alert.rb +8 -413
  36. data/lib/rcap/cap_1_2/area.rb +13 -188
  37. data/lib/rcap/cap_1_2/circle.rb +2 -100
  38. data/lib/rcap/cap_1_2/event_code.rb +8 -3
  39. data/lib/rcap/cap_1_2/geocode.rb +8 -3
  40. data/lib/rcap/cap_1_2/info.rb +132 -419
  41. data/lib/rcap/cap_1_2/parameter.rb +4 -76
  42. data/lib/rcap/cap_1_2/point.rb +2 -61
  43. data/lib/rcap/cap_1_2/polygon.rb +5 -92
  44. data/lib/rcap/cap_1_2/resource.rb +31 -134
  45. data/lib/rcap/config.rb +3 -0
  46. data/lib/{extensions → rcap/extensions}/array.rb +1 -1
  47. data/lib/rcap/extensions/date.rb +11 -0
  48. data/lib/{extensions → rcap/extensions}/date_time.rb +2 -5
  49. data/lib/{extensions → rcap/extensions}/string.rb +1 -1
  50. data/lib/{extensions → rcap/extensions}/time.rb +2 -4
  51. data/lib/rcap/utilities.rb +11 -11
  52. data/lib/rcap/validations.rb +7 -2
  53. data/lib/rcap/version.rb +1 -1
  54. data/lib/rcap.rb +21 -4
  55. data/spec/alert_spec.rb +69 -37
  56. data/spec/cap_1_0/alert_spec.rb +46 -61
  57. data/spec/cap_1_0/area_spec.rb +77 -37
  58. data/spec/cap_1_0/circle_spec.rb +26 -6
  59. data/spec/cap_1_0/event_code_spec.rb +10 -3
  60. data/spec/cap_1_0/geocode_spec.rb +11 -4
  61. data/spec/cap_1_0/info_spec.rb +74 -77
  62. data/spec/cap_1_0/parameter_spec.rb +18 -5
  63. data/spec/cap_1_0/point_spec.rb +9 -2
  64. data/spec/cap_1_0/polygon_spec.rb +52 -9
  65. data/spec/cap_1_0/resource_spec.rb +28 -21
  66. data/spec/cap_1_1/alert_spec.rb +47 -60
  67. data/spec/cap_1_1/area_spec.rb +66 -43
  68. data/spec/cap_1_1/circle_spec.rb +29 -6
  69. data/spec/cap_1_1/event_code_spec.rb +11 -3
  70. data/spec/cap_1_1/geocode_spec.rb +11 -3
  71. data/spec/cap_1_1/info_spec.rb +262 -118
  72. data/spec/cap_1_1/parameter_spec.rb +12 -3
  73. data/spec/cap_1_1/point_spec.rb +8 -2
  74. data/spec/cap_1_1/polygon_spec.rb +57 -18
  75. data/spec/cap_1_1/resource_spec.rb +70 -20
  76. data/spec/cap_1_2/alert_spec.rb +97 -110
  77. data/spec/cap_1_2/area_spec.rb +59 -41
  78. data/spec/cap_1_2/circle_spec.rb +15 -8
  79. data/spec/cap_1_2/event_code_spec.rb +11 -3
  80. data/spec/cap_1_2/geocode_spec.rb +11 -3
  81. data/spec/cap_1_2/info_spec.rb +266 -119
  82. data/spec/cap_1_2/parameter_spec.rb +11 -3
  83. data/spec/cap_1_2/point_spec.rb +10 -3
  84. data/spec/cap_1_2/polygon_spec.rb +25 -10
  85. data/spec/cap_1_2/resource_spec.rb +33 -28
  86. data/spec/{utilities_spec.rb → extensions_spec.rb} +0 -0
  87. data/spec/validations_spec.rb +18 -2
  88. metadata +20 -46
@@ -1,207 +1,32 @@
1
1
  module RCAP
2
2
  module CAP_1_0
3
+
3
4
  # An Area object is valid if
4
5
  # * it has an area description
5
6
  # * all Circle objects contained in circles are valid
6
7
  # * all Geocode objects contained in geocodes are valid
7
8
  # * all Polygon objects contained in polygons are valid
8
9
  # * altitude has a value if ceiling is set
9
- class Area
10
- include Validation
11
-
12
- # @return [String] Textual description of area.
13
- attr_accessor( :area_desc )
14
- # @return [Numeric] Expressed in feet above sea level
15
- attr_accessor( :altitude )
16
- # @return [Numeric] Expressed in feet above sea level.
17
- attr_accessor( :ceiling )
18
- # @return [Array<Circle>]
19
- attr_reader( :circles )
20
- # @return [Array<Geocode>]
21
- attr_reader( :geocodes )
22
- # @return [Array<Polygon>]
23
- attr_reader( :polygons )
24
-
25
- validates_presence_of( :area_desc )
26
- validates_collection_of( :circles, :geocodes, :polygons, allow_empty: true )
27
- validates_dependency_of( :ceiling, on: :altitude )
28
-
29
- XML_ELEMENT_NAME = 'area'
30
- AREA_DESC_ELEMENT_NAME = 'areaDesc'
31
- ALTITUDE_ELEMENT_NAME = 'altitude'
32
- CEILING_ELEMENT_NAME = 'ceiling'
33
-
34
- XPATH = "cap:#{ XML_ELEMENT_NAME }"
35
- AREA_DESC_XPATH = "cap:#{ AREA_DESC_ELEMENT_NAME }"
36
- ALTITUDE_XPATH = "cap:#{ ALTITUDE_ELEMENT_NAME }"
37
- CEILING_XPATH = "cap:#{ CEILING_ELEMENT_NAME }"
38
-
39
- # @example
40
- # Area.new( area_desc: 'Cape Town CBD' )
41
- # @param [Hash] attributes Area attributes
42
- # @option attributes [String] :area_desc Area description
43
- # @option attributes [Numeric] :altitude Altitude above sea level (in feet)
44
- # @option attributes [Numeric] :ceiling Ceiling above sea level (in feet)
45
- # @option attributes [Array<Circle>] :circles Collection of {Circle}
46
- # @option attributes [Array<Geocode>] :geocodes Collection of {Geocode}
47
- # @option attributes [Array<Polygon>] :polygons Collection of {Polygon}
48
- def initialize( attributes = {})
49
- @area_desc = attributes[ :area_desc ]
50
- @altitude = attributes[ :altitude ]
51
- @ceiling = attributes[ :ceiling ]
52
- @circles = Array( attributes[ :circles ])
53
- @geocodes = Array( attributes[ :geocodes ])
54
- @polygons = Array( attributes[ :polygons ])
55
- end
56
-
57
- # Creates a new {Polygon} object and adds it to the {#polygons} array.
58
- #
59
- # @see Polygon#initialize
60
- # @param [Hash] polygon_attributes see {Polygon#initialize}
61
- # @return [Polygon]
62
- def add_polygon( polygon_attributes = {})
63
- polygon = Polygon.new( polygon_attributes )
64
- @polygons << polygon
65
- polygon
66
- end
67
-
68
- # Creates a new {Circle} object and adds it to the {#circles} array.
69
- #
70
- # @see Circle#initialize
71
- # @param [Hash] circle_attributes see {Circle#initialize}
72
- # @return [Circle]
73
- def add_circle( circle_attributes = {})
74
- circle = Circle.new( circle_attributes )
75
- @circles << circle
76
- circle
77
- end
78
-
79
- # Creates a new {Geocode} object and adds it to the {#geocodes} array.
80
- #
81
- # @see Geocode#initialize
82
- # @param [Hash] geocode_attributes see {Geocode#initialize}
83
- # @return [Geocode]
84
- def add_geocode( geocode_attributes = {})
85
- geocode = Geocode.new( geocode_attributes )
86
- @geocodes << geocode
87
- geocode
88
- end
89
-
90
- # @return [REXML::Element]
91
- def to_xml_element
92
- xml_element = REXML::Element.new( XML_ELEMENT_NAME )
93
- xml_element.add_element( AREA_DESC_ELEMENT_NAME ).add_text( @area_desc.to_s )
94
- add_to_xml_element = lambda do |element, object|
95
- element.add_element( object.to_xml_element )
96
- element
97
- end
98
- @polygons.inject( xml_element, &add_to_xml_element )
99
- @circles.inject( xml_element, &add_to_xml_element )
100
- @geocodes.inject( xml_element, &add_to_xml_element )
101
- xml_element.add_element( ALTITUDE_ELEMENT_NAME ).add_text( @altitude.to_s ) unless @altitude.blank?
102
- xml_element.add_element( CEILING_ELEMENT_NAME ).add_text( @ceiling.to_s ) unless @altitude.blank?
103
- xml_element
104
- end
105
-
106
- # @return [String] XML representation of the Area
107
- def to_xml
108
- self.to_xml_element.to_s
109
- end
110
-
111
- # Implements an equality operator for the Area object. Two Area objects are equal if all their attributes are equal.
112
- #
113
- # @param [Area] other Area object to compare
114
- # @return [true,false]
115
- def ==( other )
116
- comparison_attributes = lambda{ |area| [ area.area_desc, area.altitude, area.ceiling, area.circles, area.geocodes, area.polygons ]}
117
- comparison_attributes.call( self ) == comparison_attributes.call( other )
118
- end
119
-
120
- # @return [String]
121
- def inspect
122
- area_inspect = "Area Description: #{ @area_desc }\n"+
123
- "Polygons:\n"+
124
- @polygons.map{ |polygon| " " + polygon.inspect }.join("\n" )+"\n"+
125
- "Circles: #{ @circles.inspect }\n"+
126
- "Geocodes: #{ @geocodes.inspect }\n"
127
- RCAP.format_lines_for_inspect( 'AREA', area_inspect )
128
- end
10
+ class Area < RCAP::Base::Area
129
11
 
130
- # Returns the area description
131
- #
132
12
  # @return [String]
133
- def to_s
134
- @area_desc
135
- end
136
-
137
- # @param [REXML::Element] area_xml_element
138
- # @return [Area]
139
- def self.from_xml_element( area_xml_element )
140
- self.new( :area_desc => RCAP.xpath_text( area_xml_element, AREA_DESC_XPATH, Alert::XMLNS ),
141
- :altitude => (( alt = RCAP.xpath_text( area_xml_element, ALTITUDE_XPATH, Alert::XMLNS )) ? alt.to_f : nil ),
142
- :ceiling => (( ceil = RCAP.xpath_text( area_xml_element, CEILING_XPATH, Alert::XMLNS )) ? ceil.to_f : nil ),
143
- :circles => RCAP.xpath_match( area_xml_element, Circle::XPATH, Alert::XMLNS ).map{ |circle_element| Circle.from_xml_element( circle_element )},
144
- :geocodes => RCAP.xpath_match( area_xml_element, Geocode::XPATH, Alert::XMLNS ).map{ |geocode_element| Geocode.from_xml_element( geocode_element )},
145
- :polygons => RCAP.xpath_match( area_xml_element, Polygon::XPATH, Alert::XMLNS ).map{ |polygon_element| Polygon.from_xml_element( polygon_element )})
13
+ def xmlns
14
+ Alert::XMLNS
146
15
  end
147
16
 
148
- AREA_DESC_YAML = 'Area Description'
149
- ALTITUDE_YAML = 'Altitude'
150
- CEILING_YAML = 'Ceiling'
151
- CIRCLES_YAML = 'Circles'
152
- GEOCODES_YAML = 'Geocodes'
153
- POLYGONS_YAML = 'Polygons'
154
-
155
- # @return [String] YAML representation of object
156
- def to_yaml( options = {} )
157
- RCAP.attribute_values_to_hash(
158
- [ AREA_DESC_YAML, @area_desc ],
159
- [ ALTITUDE_YAML, @altitude ],
160
- [ CEILING_YAML, @ceiling ],
161
- [ CIRCLES_YAML, @circles.map{ |circle| [ circle.lattitude, circle.longitude, circle.radius ]} ],
162
- [ GEOCODES_YAML, @geocodes.inject({}){|h,geocode| h.merge( geocode.name => geocode.value )}],
163
- [ POLYGONS_YAML, @polygons ]
164
- ).to_yaml( options )
17
+ # @return [Class]
18
+ def polygon_class
19
+ Polygon
165
20
  end
166
21
 
167
- # @param [Hash] area_yaml_data
168
- # @return [Area]
169
- def self.from_yaml_data( area_yaml_data )
170
- self.new( :area_desc => area_yaml_data[ AREA_DESC_YAML ],
171
- :altitude => area_yaml_data[ ALTITUDE_YAML ],
172
- :ceiling => area_yaml_data[ CEILING_YAML ],
173
- :circles => Array( area_yaml_data[ CIRCLES_YAML ]).map{ |circle_yaml_data| Circle.from_yaml_data( circle_yaml_data )},
174
- :geocodes => Array( area_yaml_data[ GEOCODES_YAML ]).map{ |name, value| Geocode.new( :name => name, :value => value )},
175
- :polygons => Array( area_yaml_data[ POLYGONS_YAML ]).map{ |polyon_yaml_data| Polygon.from_yaml_data( polyon_yaml_data )})
176
- end
177
-
178
- AREA_DESC_KEY = 'area_desc'
179
- ALTITUDE_KEY = 'altitude'
180
- CEILING_KEY = 'ceiling'
181
- CIRCLES_KEY = 'circles'
182
- GEOCODES_KEY = 'geocodes'
183
- POLYGONS_KEY = 'polygons'
184
-
185
- # @return [Hash]
186
- def to_h
187
- RCAP.attribute_values_to_hash( [ AREA_DESC_KEY, @area_desc ],
188
- [ ALTITUDE_KEY, @altitude ],
189
- [ CEILING_KEY, @ceiling ],
190
- [ CIRCLES_KEY, @circles.map{ |circle| circle.to_h }],
191
- [ GEOCODES_KEY, @geocodes.map{ |geocode| geocode.to_h }],
192
- [ POLYGONS_KEY, @polygons.map{ |polygon| polygon.to_h }])
22
+ # @return [Class]
23
+ def circle_class
24
+ Circle
193
25
  end
194
26
 
195
- # @param [Hash] area_hash
196
- # @return [Area]
197
- def self.from_h( area_hash )
198
- self.new(
199
- :area_desc => area_hash[ AREA_DESC_KEY ],
200
- :altitude => area_hash[ ALTITUDE_KEY ],
201
- :ceiling => area_hash[ CEILING_KEY ],
202
- :circles => Array( area_hash[ CIRCLES_KEY ]).map{ |circle_hash| Circle.from_h( circle_hash )},
203
- :geocodes => Array( area_hash[ GEOCODES_KEY ]).map{ |geocode_hash| Geocode.from_h( geocode_hash )},
204
- :polygons => Array( area_hash[ POLYGONS_KEY ]).map{ |polygon_hash| Polygon.from_h( polygon_hash )})
27
+ # @return [Class]
28
+ def geocode_class
29
+ Geocode
205
30
  end
206
31
  end
207
32
  end
@@ -1,108 +1,10 @@
1
1
  module RCAP
2
2
  module CAP_1_0
3
+
3
4
  # A Circle object is valid if
4
5
  # * it has a valid lattitude and longitude
5
6
  # * it has a radius with a value greater than zero
6
- class Circle < Point
7
- include Validation
8
-
9
- # @return [Numeric] Expresed in kilometers
10
- attr_accessor( :radius )
11
-
12
- validates_presence_of( :radius )
13
- validates_numericality_of( :radius , greater_than_or_equal: 0 )
14
-
15
- XML_ELEMENT_NAME = 'circle'
16
-
17
- XPATH = 'cap:circle'
18
-
19
- # @param [Hash] attributes
20
- # @option attributes [Numeric] :lattitude
21
- # @option attributes [Numeric] :longitude
22
- # @option attributes [Numeric] :radius
23
- def initialize( attributes = {} )
24
- super( attributes )
25
- @radius = attributes[ :radius ]
26
- end
27
-
28
- # Returns a string representation of the circle of the form
29
- # lattitude,longitude radius
30
- #
31
- # @return [String]
32
- def to_s
33
- "#{ @lattitude },#{ @longitude } #{ @radius }"
34
- end
35
-
36
- # @return [String]
37
- def inspect
38
- "(#{ self.to_s })"
39
- end
40
-
41
- # @return [REXML::Element]
42
- def to_xml_element
43
- xml_element = REXML::Element.new( XML_ELEMENT_NAME )
44
- xml_element.add_text( self.to_s )
45
- xml_element
46
- end
47
-
48
- # @return [String]
49
- def to_xml
50
- self.to_xml_element.to_s
51
- end
52
-
53
- # Parses a circle string of the form
54
- # lattitude,longitude radius
55
- #
56
- # @param [String] circle_string
57
- # @return [Array(Float,Float,Float)]
58
- def self.parse_circle_string( circle_string )
59
- coordinates, radius = circle_string.split( ' ' )
60
- lattitude, longitude = coordinates.split( ',' )
61
- [ lattitude, longitude, radius ].map{ |e| e.to_f }
62
- end
63
-
64
- # @param [REXML::Element] circle_xml_element
65
- # @return [Circle]
66
- def self.from_xml_element( circle_xml_element )
67
- lattitude, longitude, radius = self.parse_circle_string( circle_xml_element.text )
68
- circle = self.new( :lattitude => lattitude,
69
- :longitude => longitude,
70
- :radius => radius )
71
- end
72
-
73
- # Two circles are equivalent if their lattitude, longitude and radius are equal.
74
- #
75
- # @param [Circle] other
76
- # @return [true,false]
77
- def ==( other )
78
- [ @lattitude, @longitude, @radius ] == [ other.lattitude, other.longitude, other.radius ]
79
- end
80
-
81
- # @param [Array(Numeric, Numeric, Numeric)] circle_yaml_data lattitude, longitude, radius
82
- # @return [Circle]
83
- def self.from_yaml_data( circle_yaml_data )
84
- lattitude, longitude, radius = circle_yaml_data
85
- self.new( :lattitude => lattitude, :longitude => longitude, :radius => radius )
86
- end
87
-
88
- RADIUS_KEY = 'radius'
89
- LATTITUDE_KEY = 'lattitude'
90
- LONGITUDE_KEY = 'longitude'
91
-
92
- # @return [Hash]
93
- def to_h
94
- RCAP.attribute_values_to_hash( [ RADIUS_KEY, @radius ],
95
- [ LATTITUDE_KEY, @lattitude ],
96
- [ LONGITUDE_KEY, @longitude ])
97
- end
98
-
99
- # @param [Hash]
100
- # @return [Circle]
101
- def self.from_h( circle_hash )
102
- self.new( :radius => circle_hash[ RADIUS_KEY ],
103
- :lattitude => circle_hash[ LATTITUDE_KEY ],
104
- :longitude => circle_hash[ LONGITUDE_KEY ])
105
- end
7
+ class Circle < RCAP::Base::Circle
106
8
  end
107
9
  end
108
10
  end
@@ -1,9 +1,14 @@
1
1
  module RCAP
2
2
  module CAP_1_0
3
3
  # Subclass of {Parameter}
4
- class EventCode < Parameter
5
- XML_ELEMENT_NAME = 'eventCode'
6
- XPATH = "cap:#{ XML_ELEMENT_NAME }"
4
+ class EventCode < RCAP::Base::EventCode
5
+ XML_ELEMENT_NAME = 'eventCode'
6
+ XPATH = "cap:#{ XML_ELEMENT_NAME }"
7
+
8
+ # @return [String]
9
+ def xmlns
10
+ Alert::XMLNS
11
+ end
7
12
  end
8
13
  end
9
14
  end
@@ -1,9 +1,14 @@
1
1
  module RCAP
2
2
  module CAP_1_0
3
3
  # Subclass of {Parameter}
4
- class Geocode < Parameter
5
- XML_ELEMENT_NAME = 'geocode'
6
- XPATH = "cap:#{ XML_ELEMENT_NAME }"
4
+ class Geocode < RCAP::Base::Geocode
5
+ XML_ELEMENT_NAME = 'geocode'
6
+ XPATH = "cap:#{ XML_ELEMENT_NAME }"
7
+
8
+ # @return [String]
9
+ def xmlns
10
+ Alert::XMLNS
11
+ end
7
12
  end
8
13
  end
9
14
  end