rcap 1.3.1 → 2.0.0

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