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
@@ -0,0 +1,88 @@
1
+ module RCAP
2
+ module Base
3
+ class Parameter
4
+ include Validation
5
+
6
+ validates_presence_of( :name, :value )
7
+
8
+ # @return [String]
9
+ attr_accessor( :name )
10
+ # @return [String]
11
+ attr_accessor( :value )
12
+
13
+ XML_ELEMENT_NAME = "parameter"
14
+ NAME_ELEMENT_NAME = "valueName"
15
+ VALUE_ELEMENT_NAME = "value"
16
+
17
+ XPATH = "cap:#{ XML_ELEMENT_NAME }"
18
+ NAME_XPATH = "cap:#{ NAME_ELEMENT_NAME }"
19
+ VALUE_XPATH = "cap:#{ VALUE_ELEMENT_NAME }"
20
+
21
+ # @param [Hash] attributes
22
+ # @option attributes [Symbol] :name Parameter name
23
+ # @option attributes [Symbol] :value Parameter value
24
+ def initialize
25
+ yield( self ) if block_given?
26
+ end
27
+
28
+ # @return [REXML::Element]
29
+ def to_xml_element
30
+ xml_element = REXML::Element.new( self.class::XML_ELEMENT_NAME )
31
+ xml_element.add_element( self.class::NAME_ELEMENT_NAME ).add_text( @name )
32
+ xml_element.add_element( self.class::VALUE_ELEMENT_NAME ).add_text( @value )
33
+ xml_element
34
+ end
35
+
36
+ # @return [String]
37
+ def to_xml
38
+ self.to_xml_element.to_s
39
+ end
40
+
41
+ # @return [String]
42
+ def inspect
43
+ "#{ @name }: #{ @value }"
44
+ end
45
+
46
+ # Returns a string representation of the parameter of the form
47
+ # name: value
48
+ #
49
+ # @return [String]
50
+ def to_s
51
+ self.inspect
52
+ end
53
+
54
+ # Two parameters are equivalent if they have the same name and value.
55
+ #
56
+ # @param [Parameter] other
57
+ # @return [true, false]
58
+ def ==( other )
59
+ [ @name, @value ] == [ other.name, other.value ]
60
+ end
61
+
62
+ # @param [REXML::Element] parameter_xml_element
63
+ # @return [Parameter]
64
+ def self.from_xml_element( parameter_xml_element )
65
+ self.new do |parameter|
66
+ parameter.name = RCAP.xpath_text( parameter_xml_element, self::NAME_XPATH, parameter.xmlns )
67
+ parameter.value = RCAP.xpath_text( parameter_xml_element, self::VALUE_XPATH, parameter.xmlns )
68
+ end
69
+ end
70
+
71
+ # @return [Hash]
72
+ def to_h
73
+ RCAP.attribute_values_to_hash( [ @name, @value ])
74
+ end
75
+
76
+ # @param [Hash] hash
77
+ # @return [Parameter]
78
+ def self.from_h( hash )
79
+ key = hash.keys.first
80
+ self.new do |parameter|
81
+ parameter.name = key
82
+ parameter.value = hash[ key ]
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
@@ -0,0 +1,87 @@
1
+ module RCAP
2
+ module Base
3
+ class Point
4
+ include Validation
5
+
6
+ MAX_LONGITUDE = 180
7
+ MIN_LONGITUDE = -180
8
+ MAX_LATTITUDE = 90
9
+ MIN_LATTITUDE= -90
10
+
11
+ # @return [Numeric]
12
+ attr_accessor( :lattitude )
13
+ # @return [Numeric]
14
+ attr_accessor( :longitude )
15
+
16
+ validates_numericality_of( :lattitude, :longitude )
17
+ validates_inclusion_of( :lattitude, :in => MIN_LATTITUDE..MAX_LATTITUDE )
18
+ validates_inclusion_of( :longitude, :in => MIN_LONGITUDE..MAX_LONGITUDE)
19
+
20
+ # @param [Hash] attributes
21
+ # @option attributes [Numeric] :lattitude
22
+ # @option attributes [Numeric] :longitude
23
+ def initialize
24
+ yield( self ) if block_given?
25
+ end
26
+
27
+ # Returns a string representation of the point of the form
28
+ # lattitude,longitude
29
+ #
30
+ # @return [String]
31
+ def to_s
32
+ "#{ self.lattitude },#{ self.longitude }"
33
+ end
34
+
35
+ # @return [String]
36
+ def inspect
37
+ '('+self.to_s+')'
38
+ end
39
+
40
+ # Two points are equivalent if they have the same lattitude and longitude
41
+ #
42
+ # @param [Point] other
43
+ # @return [true, false]
44
+ def ==( other )
45
+ [ self.lattitude, self.longitude ] == [ other.lattitude, other.longitude ]
46
+ end
47
+
48
+ LATTITUDE_KEY = 'lattitude'
49
+ LONGITUDE_KEY = 'longitude'
50
+
51
+ # @return [Hash]
52
+ def to_h
53
+ RCAP.attribute_values_to_hash( [ LATTITUDE_KEY, self.lattitude ],
54
+ [ LONGITUDE_KEY, self.longitude ])
55
+ end
56
+
57
+ # @param [Hash] point_hash
58
+ # @return [Point]
59
+ def self.from_h( point_hash )
60
+ self.new do |point|
61
+ point.lattitude = point_hash[ LATTITUDE_KEY ]
62
+ point.longitude = point_hash[ LONGITUDE_KEY ]
63
+ end
64
+ end
65
+
66
+ LATTITUDE_INDEX = 0
67
+ LONGITUDE_INDEX = 1
68
+
69
+ # @return [Array(Numeric, Numeric)]
70
+ def to_a
71
+ Array.new.tap do |array|
72
+ array[ LATTITUDE_INDEX ] = self.lattitude
73
+ array[ LONGITUDE_INDEX ] = self.longitude
74
+ end
75
+ end
76
+
77
+ # @param [Array(Numeric, Numeric)] point_array
78
+ # @return [Point]
79
+ def self.from_a( point_array )
80
+ self.new do |point|
81
+ point.lattitude = point_array[ LATTITUDE_INDEX ]
82
+ point.longitude = point_array[ LONGITUDE_INDEX ]
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,120 @@
1
+ module RCAP
2
+ module Base
3
+ class Polygon
4
+ include Validation
5
+
6
+ # @return [Array<Point>] Collection of {Point} objects
7
+ attr_reader( :points )
8
+
9
+ validates_collection_of( :points )
10
+ validates_length_of( :points, :minimum => 3 )
11
+ validates_equality_of_first_and_last( :points )
12
+
13
+ XML_ELEMENT_NAME = 'polygon'
14
+ XPATH = "cap:#{ XML_ELEMENT_NAME }"
15
+
16
+ # @param [Hash] attributes
17
+ # @option attributes [Array<Point>] :points Collection of {Point} objects
18
+ def initialize
19
+ @points = []
20
+ yield( self ) if block_given?
21
+ end
22
+
23
+ def add_point
24
+ point = self.point_class.new
25
+ yield( point ) if block_given?
26
+ self.points << point
27
+ point
28
+ end
29
+
30
+ # Returns a string representation of the polygon of the form
31
+ # points[0] points[1] points[2] ...
32
+ # where each point is formatted with Point#to_s
33
+ def to_s
34
+ @points.join( ' ' )
35
+ end
36
+
37
+ # @return [String]
38
+ def inspect
39
+ "(#{ @points.map{|point| point.inspect}.join(', ')})"
40
+ end
41
+
42
+ # @return [REXML::Element]
43
+ def to_xml_element
44
+ xml_element = REXML::Element.new( XML_ELEMENT_NAME )
45
+ xml_element.add_text( self.to_s )
46
+ xml_element
47
+ end
48
+
49
+ # @return [Polygon]
50
+ def self.from_xml_element( polygon_xml_element )
51
+ if !polygon_xml_element.text.nil? && !polygon_xml_element.text.empty?
52
+ coordinates = self.parse_polygon_string( polygon_xml_element.text )
53
+ self.new do |polygon|
54
+ coordinates.each do |lattitude, longitude|
55
+ polygon.add_point do |point|
56
+ point.lattitude = lattitude
57
+ point.longitude = longitude
58
+ end
59
+ end
60
+ end
61
+ else
62
+ self.new
63
+ end
64
+ end
65
+
66
+ # @return [String]
67
+ def to_xml
68
+ self.to_xml_element.to_s
69
+ end
70
+
71
+ # Two polygons are equivalent if their collection of points is equivalent.
72
+ #
73
+ # @return [true,false]
74
+ def ==( other )
75
+ @points == other.points
76
+ end
77
+
78
+ # @return [Array<Array(Numeric,Numeric)>]
79
+ def self.parse_polygon_string( polygon_string )
80
+ polygon_string.split( ' ' ).map{ |coordinate_string| coordinate_string.split( ',' ).map{|coordinate| coordinate.to_f }}
81
+ end
82
+
83
+ # @return [Polygon]
84
+ def self.from_yaml_data( polygon_yaml_data )
85
+ self.new do |polygon|
86
+ Array( polygon_yaml_data ).each do |lattitude, longitude|
87
+ polygon.add_point do |point|
88
+ point.lattitude = lattitude
89
+ point.longitude = longitude
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # @return [String]
96
+ def to_yaml( options = {} )
97
+ @points.map{ |point| [ point.lattitude, point.longitude ]}.to_yaml( options )
98
+ end
99
+
100
+ POINTS_KEY = 'points'
101
+
102
+ # @return [Polygon]
103
+ def self.from_h( polygon_hash )
104
+ self.new do |polygon|
105
+ Array( polygon_hash[ POINTS_KEY ]).each do |point_array|
106
+ polygon.add_point do |point|
107
+ point.lattitude = point_array[ Point::LATTITUDE_INDEX ]
108
+ point.longitude = point_array[ Point::LONGITUDE_INDEX ]
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ # @return [Hash]
115
+ def to_h
116
+ { POINTS_KEY => @points.map{ |point| point.to_a }}
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,168 @@
1
+ module RCAP
2
+ module Base
3
+ class Resource
4
+ include Validation
5
+
6
+ # @return [String] Resource Description
7
+ attr_accessor( :resource_desc )
8
+ # @return [String]
9
+ attr_accessor( :mime_type )
10
+ # @return [Integer] Expressed in bytes
11
+ attr_accessor( :size )
12
+ # @return [String] Resource location
13
+ attr_accessor( :uri )
14
+ # @return [String] SHA-1 hash of contents of resource
15
+ attr_accessor( :digest )
16
+
17
+ validates_presence_of( :resource_desc )
18
+
19
+ XML_ELEMENT_NAME = 'resource'
20
+ MIME_TYPE_ELEMENT_NAME = 'mimeType'
21
+ SIZE_ELEMENT_NAME = 'size'
22
+ URI_ELEMENT_NAME = 'uri'
23
+ DIGEST_ELEMENT_NAME = 'digest'
24
+ RESOURCE_DESC_ELEMENT_NAME = 'resourceDesc'
25
+
26
+ XPATH = "cap:#{ XML_ELEMENT_NAME }"
27
+ MIME_TYPE_XPATH = "cap:#{ MIME_TYPE_ELEMENT_NAME }"
28
+ SIZE_XPATH = "cap:#{ SIZE_ELEMENT_NAME }"
29
+ URI_XPATH = "cap:#{ URI_ELEMENT_NAME }"
30
+ DIGEST_XPATH = "cap:#{ DIGEST_ELEMENT_NAME }"
31
+ RESOURCE_DESC_XPATH = "cap:#{ RESOURCE_DESC_ELEMENT_NAME }"
32
+
33
+ # @param [Hash{Symbol => Object}] attributes
34
+ # @option attributes [String] :mime_type
35
+ # @option attributes [Numeric] :size Size in bytes
36
+ # @option attributes [String] :uri
37
+ # @option attributes [String] :digest
38
+ # @option attributes [String] :resource_desc
39
+ def initialize
40
+ yield( self ) if block_given?
41
+ end
42
+
43
+ # @return [REXML::Element]
44
+ def to_xml_element
45
+ xml_element = REXML::Element.new( XML_ELEMENT_NAME )
46
+ xml_element.add_element( RESOURCE_DESC_ELEMENT_NAME ).add_text( @resource_desc )
47
+ xml_element.add_element( MIME_TYPE_ELEMENT_NAME ).add_text( @mime_type ) if @mime_type
48
+ xml_element.add_element( SIZE_ELEMENT_NAME ).add_text( @size.to_s ) if @size
49
+ xml_element.add_element( URI_ELEMENT_NAME ).add_text( @uri ) if @uri
50
+ xml_element.add_element( DIGEST_ELEMENT_NAME ).add_text( @digest ) if @digest
51
+ xml_element
52
+ end
53
+
54
+ # @param [REXML::Element] resource_xml_element
55
+ # @return [Resource]
56
+ def self.from_xml_element( resource_xml_element )
57
+ resource = self.new do |resource|
58
+ resource.resource_desc = RCAP.xpath_text( resource_xml_element, RESOURCE_DESC_XPATH, resource.xmlns )
59
+ resource.uri = RCAP.xpath_text( resource_xml_element, URI_XPATH, resource.xmlns )
60
+ resource.mime_type = RCAP.xpath_text( resource_xml_element, MIME_TYPE_XPATH, resource.xmlns )
61
+ resource.size = RCAP.xpath_text( resource_xml_element, SIZE_XPATH, resource.xmlns ).to_i
62
+ resource.digest = RCAP.xpath_text( resource_xml_element, DIGEST_XPATH, resource.xmlns )
63
+ end
64
+ end
65
+
66
+ # Calculates the SHA-1 hash and size of the contents of {#deref_uri}.
67
+ # Returns an array containing the size (in bytes) and SHA-1 hash if
68
+ # {#deref_uri} is present otherwise returns nil.
69
+ #
70
+ # @return [nil,Array(Integer,String)]
71
+ def calculate_hash_and_size
72
+ if @deref_uri
73
+ @digest = Digest::SHA1.hexdigest( @deref_uri )
74
+ @size = @deref_uri.bytesize
75
+ [ @size, @digest ]
76
+ end
77
+ end
78
+
79
+ # The decoded contents of {#deref_uri} if present otherwise nil.
80
+ #
81
+ # @return [nil,String]
82
+ def decoded_deref_uri
83
+ Base64.decode64( @deref_uri ) if @deref_uri
84
+ end
85
+
86
+ # If size is defined returns the size in kilobytes
87
+ # @return [Float]
88
+ def size_in_kb
89
+ if @size
90
+ @size.to_f/1024
91
+ end
92
+ end
93
+
94
+ # @return [String]
95
+ def to_xml
96
+ self.to_xml_element.to_s
97
+ end
98
+
99
+ # @return [String]
100
+ def inspect
101
+ [ @resource_desc, @uri, @mime_type, @size ? format( "%.1fKB", @size_in_kb ) : nil ].compact.join(' - ')
102
+ end
103
+
104
+ # Returns a string representation of the resource of the form
105
+ # resource_desc
106
+ #
107
+ # @return [String]
108
+ def to_s
109
+ @resource_desc
110
+ end
111
+
112
+ RESOURCE_DESC_YAML = "Resource Description"
113
+ URI_YAML = "URI"
114
+ MIME_TYPE_YAML = "Mime Type"
115
+ SIZE_YAML = "Size"
116
+ DIGEST_YAML = "Digest"
117
+
118
+ # @param [Hash] options
119
+ # @return [String]
120
+ def to_yaml( options = {} )
121
+ RCAP.attribute_values_to_hash( [ RESOURCE_DESC_YAML, @resource_desc ],
122
+ [ URI_YAML, @uri ],
123
+ [ MIME_TYPE_YAML, @mime_type ],
124
+ [ SIZE_YAML, @size ],
125
+ [ DIGEST_YAML, @digest ]).to_yaml( options )
126
+ end
127
+
128
+ # @param [Hash] resource_yaml_data
129
+ # @return [Resource]
130
+ def self.from_yaml_data( resource_yaml_data )
131
+ self.new do |resource|
132
+ resource.resource_desc = resource_yaml_data[ RESOURCE_DESC_YAML ]
133
+ resource.uri = resource_yaml_data[ URI_YAML ]
134
+ resource.mime_type = resource_yaml_data[ MIME_TYPE_YAML ]
135
+ resource.size = resource_yaml_data[ SIZE_YAML ]
136
+ resource.digest = resource_yaml_data[ DIGEST_YAML ]
137
+ end
138
+ end
139
+
140
+ RESOURCE_DESC_KEY = 'resource_desc'
141
+ URI_KEY = 'uri'
142
+ MIME_TYPE_KEY = 'mime_type'
143
+ SIZE_KEY = 'size'
144
+ DIGEST_KEY = 'digest'
145
+
146
+ # @return [Hash]
147
+ def to_h
148
+ RCAP.attribute_values_to_hash( [ RESOURCE_DESC_KEY, @resource_desc ],
149
+ [ URI_KEY, @uri],
150
+ [ MIME_TYPE_KEY, @mime_type],
151
+ [ SIZE_KEY, @size ],
152
+ [ DIGEST_KEY, @digest ])
153
+ end
154
+
155
+ # @param [Hash] resource_hash
156
+ # @return [Resource]
157
+ def self.from_h( resource_hash )
158
+ self.new do |resource|
159
+ resource.resource_desc = resource_hash[ RESOURCE_DESC_KEY ]
160
+ resource.uri = resource_hash[ URI_KEY ]
161
+ resource.mime_type = resource_hash[ MIME_TYPE_KEY ]
162
+ resource.size = resource_hash[ SIZE_KEY ]
163
+ resource.digest = resource_hash[ DIGEST_KEY ]
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end