rcap-rails-generators 1.3

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 (32) hide show
  1. data/CHANGELOG.rdoc +25 -0
  2. data/README.rdoc +248 -0
  3. data/lib/generators/rcap/migrations/migrations_generator.rb +38 -0
  4. data/lib/generators/rcap/migrations/templates/alerts_migration.rb +27 -0
  5. data/lib/generators/rcap/migrations/templates/areas_migration.rb +14 -0
  6. data/lib/generators/rcap/migrations/templates/infos_migration.rb +33 -0
  7. data/lib/generators/rcap/migrations/templates/resources_migration.rb +14 -0
  8. data/lib/generators/rcap/models/models_generator.rb +33 -0
  9. data/lib/generators/rcap/models/templates/models/alert.rb +365 -0
  10. data/lib/generators/rcap/models/templates/models/area.rb +156 -0
  11. data/lib/generators/rcap/models/templates/models/circle.rb +76 -0
  12. data/lib/generators/rcap/models/templates/models/event_code.rb +20 -0
  13. data/lib/generators/rcap/models/templates/models/geocode.rb +20 -0
  14. data/lib/generators/rcap/models/templates/models/info.rb +452 -0
  15. data/lib/generators/rcap/models/templates/models/parameter.rb +64 -0
  16. data/lib/generators/rcap/models/templates/models/point.rb +51 -0
  17. data/lib/generators/rcap/models/templates/models/polygon.rb +75 -0
  18. data/lib/generators/rcap/models/templates/models/resource.rb +143 -0
  19. data/lib/generators/rcap/models/templates/modules/rcap.rb +5 -0
  20. data/lib/generators/rcap/models/templates/modules/validations.rb +116 -0
  21. data/spec/alert_spec.rb +195 -0
  22. data/spec/area_spec.rb +179 -0
  23. data/spec/circle_spec.rb +88 -0
  24. data/spec/geocode_spec.rb +38 -0
  25. data/spec/info_spec.rb +270 -0
  26. data/spec/point_spec.rb +46 -0
  27. data/spec/polygon_spec.rb +68 -0
  28. data/spec/resource_spec.rb +156 -0
  29. data/spec/spec_helper.rb +8 -0
  30. data/spec/utilities_spec.rb +57 -0
  31. data/spec/validations_spec.rb +95 -0
  32. metadata +155 -0
@@ -0,0 +1,64 @@
1
+ # A Parameter object is valid if
2
+ # * it has a name
3
+ # * it has a value
4
+ class Parameter < ActiveRecord::Base
5
+ include Validation
6
+
7
+ validates_presence_of( :name, :value )
8
+
9
+ attr_accessor( :name, :value )
10
+
11
+ XML_ELEMENT_NAME = "parameter" # :nodoc:
12
+ NAME_ELEMENT_NAME = "valueName" # :nodoc:
13
+ VALUE_ELEMENT_NAME = "value" # :nodoc:
14
+
15
+ XPATH = "cap:#{ XML_ELEMENT_NAME }" # :nodoc:
16
+ NAME_XPATH = "cap:#{ NAME_ELEMENT_NAME }" # :nodoc:
17
+ VALUE_XPATH = "cap:#{ VALUE_ELEMENT_NAME }" # :nodoc:
18
+
19
+ def initialize( attributes = {} )
20
+ @name = attributes[ :name ]
21
+ @value = attributes[ :value ]
22
+ end
23
+
24
+ def to_xml_element # :nodoc:
25
+ xml_element = REXML::Element.new( XML_ELEMENT_NAME )
26
+ xml_element.add_element( NAME_ELEMENT_NAME ).add_text( self.name )
27
+ xml_element.add_element( VALUE_ELEMENT_NAME ).add_text( self.value )
28
+ xml_element
29
+ end
30
+
31
+ def to_xml # :nodoc:
32
+ self.to_xml_element.to_s
33
+ end
34
+
35
+ def inspect # :nodoc:
36
+ "#{ self.name }: #{ self.value }"
37
+ end
38
+
39
+ # Returns a string representation of the parameter of the form
40
+ # name: value
41
+ def to_s
42
+ self.inspect
43
+ end
44
+
45
+ def self.from_xml_element( parameter_xml_element ) # :nodoc:
46
+ Parameter.new( :name => RCAP.xpath_text( parameter_xml_element, NAME_XPATH ),
47
+ :value => RCAP.xpath_text( parameter_xml_element, VALUE_XPATH ))
48
+ end
49
+
50
+ # Two parameters are equivalent if they have the same name and value.
51
+ def ==( other )
52
+ [ self.name, self.value ] == [ other.name, other.value ]
53
+ end
54
+
55
+ def to_h # :nodoc:
56
+ RCAP.attribute_values_to_hash(
57
+ [ @name, @value ])
58
+ end
59
+
60
+ def self.from_h( hash ) # :nodoc:
61
+ key = hash.keys.first
62
+ self.new( :name => key, :value => hash[ key ])
63
+ end
64
+ end
@@ -0,0 +1,51 @@
1
+ # A Point object is valid if
2
+ # * it has a latitude within the minimum and maximum latitude values
3
+ # * it has a longitude within the minimum and maximum longitude values
4
+ class Point < ActiveRecord::Base
5
+ include Validation
6
+
7
+ MAX_LONGITUDE = 180
8
+ MIN_LONGITUDE = -180
9
+ MAX_LATITUDE = 90
10
+ MIN_LATITUDE= -90
11
+
12
+ attr_accessor( :latitude )
13
+ attr_accessor( :longitude )
14
+
15
+ validates_numericality_of( :latitude, :longitude )
16
+ validates_inclusion_of( :latitude, :in => MIN_LATITUDE..MAX_LATITUDE )
17
+ validates_inclusion_of( :longitude, :in => MIN_LONGITUDE..MAX_LONGITUDE)
18
+
19
+ def initialize( attributes = {} )
20
+ @latitude = attributes[ :latitude ]
21
+ @longitude = attributes[ :longitude ]
22
+ end
23
+
24
+ # Returns a string representation of the point of the form
25
+ # latitude,longitude
26
+ def to_s
27
+ "#{ self.latitude },#{ self.longitude }"
28
+ end
29
+
30
+ def inspect # :nodoc:
31
+ '('+self.to_s+')'
32
+ end
33
+
34
+ # Two points are equivalent if they have the same latitude and longitude
35
+ def ==( other )
36
+ [ self.latitude, self.longitude ] == [ other.latitude, other.longitude ]
37
+ end
38
+
39
+ LATITUDE_KEY = 'latitude_hash' # :nodoc:
40
+ LONGITUDE_KEY = 'longitude_hash' # :nodoc:
41
+
42
+ def to_h # :nodoc:
43
+ RCAP.attribute_values_to_hash(
44
+ [ LATITUDE_KEY, self.latitude ],
45
+ [ LONGITUDE_KEY, self.longitude ])
46
+ end
47
+
48
+ def self.from_h( point_hash ) # :nodoc:
49
+ self.new( :latitude => point_hash[ LATITUDE_KEY ], :longitude => point_hash[ LONGITUDE_KEY ])
50
+ end
51
+ end
@@ -0,0 +1,75 @@
1
+ # A Polygon object is valid if
2
+ # * it has a minimum of three points
3
+ # * each Point object in the points collection is valid
4
+ class Polygon < ActiveRecord::Base
5
+ include Validation
6
+
7
+ # Collection of Point objects.
8
+ attr_reader( :points )
9
+
10
+ validates_length_of( :points, :minimum => 3 )
11
+ validates_collection_of( :points )
12
+
13
+ XML_ELEMENT_NAME = 'polygon' # :nodoc:
14
+ XPATH = "cap:#{ XML_ELEMENT_NAME }" # :nodoc:
15
+
16
+ def initialize( attributes = {})
17
+ @points = Array( attributes[ :points ])
18
+ end
19
+
20
+ # Returns a string representation of the polygon of the form
21
+ # points[0] points[1] points[2] ... points[n-1] points[0]
22
+ # where each point is formatted with RCAP::Point#to_s
23
+ def to_s
24
+ (@points + [ @points.first ]).join( ' ' )
25
+ end
26
+
27
+ def inspect # :nodoc:
28
+ "(#{ @points.map{|point| point.inspect}.join(', ')})"
29
+ end
30
+
31
+ def to_xml_element # :nodoc:
32
+ xml_element = REXML::Element.new( XML_ELEMENT_NAME )
33
+ xml_element.add_text( self.to_s )
34
+ xml_element
35
+ end
36
+
37
+ # Two polygons are equivalent if their collection of points is equivalent.
38
+ def ==( other )
39
+ self.points == other.points
40
+ end
41
+
42
+ def self.parse_polygon_string( polygon_string ) # :nodoc:
43
+ polygon_string.split( ' ' ).map{ |coordinate_string| coordinate_string.split( ',' ).map{|coordinate| coordinate.to_f }}
44
+ end
45
+
46
+ def self.from_xml_element( polygon_xml_element ) # :nodoc:
47
+ coordinates = self.parse_polygon_string( polygon_xml_element.text )
48
+ points = coordinates.map{ |lattitude, longitude| RCAP::Point.new( :lattitude => lattitude, :longitude => longitude )}[0..-2]
49
+ polygon = self.new( :points => points )
50
+ end
51
+
52
+
53
+ def to_yaml( options = {} ) # :nodoc:
54
+ yaml_points = self.points.map{ |point| [ point.lattitude, point.longitude ]}
55
+ def yaml_points.to_yaml_style; :inline; end
56
+
57
+ yaml_points.to_yaml( options )
58
+ end
59
+
60
+ def self.from_yaml_data( polygon_yaml_data ) # :nodoc:
61
+ self.new(
62
+ :points => Array( polygon_yaml_data ).map{ |lattitude, longitude| Point.new( :lattitude => lattitude, :longitude => longitude )}
63
+ )
64
+ end
65
+
66
+ POINTS_KEY = 'points' # :nodoc:
67
+
68
+ def to_h # :nodoc:
69
+ { POINTS_KEY => self.points.map{ |point| point.to_h }}
70
+ end
71
+
72
+ def self.from_h( polygon_hash ) # :nodoc:
73
+ self.new( :points => polygon_hash[ POINTS_KEY ].map{ |point_hash| Point.from_h( point_hash )})
74
+ end
75
+ end
@@ -0,0 +1,143 @@
1
+ # A Resourse object is valid if
2
+ # * it has a resource description
3
+ class Resource < ActiveRecord::Base
4
+ include Validation
5
+
6
+ belongs_to :item
7
+
8
+ # Resource Description
9
+ attr_accessor( :resource_desc )
10
+ attr_accessor( :mime_type )
11
+ # Expressed in bytes
12
+ attr_accessor( :size )
13
+ # Resource location
14
+ attr_accessor( :uri )
15
+ # Dereferenced URI - contents of URI Base64 encoded
16
+ attr_accessor( :deref_uri )
17
+ # SHA-1 hash of contents of resource
18
+ attr_accessor( :digest )
19
+
20
+ validates_presence_of( :resource_desc )
21
+
22
+ XML_ELEMENT_NAME = 'resource' # :nodoc:
23
+ MIME_TYPE_ELEMENT_NAME = 'mimeType' # :nodoc:
24
+ SIZE_ELEMENT_NAME = 'size' # :nodoc:
25
+ URI_ELEMENT_NAME = 'uri' # :nodoc:
26
+ DEREF_URI_ELEMENT_NAME = 'derefUri' # :nodoc:
27
+ DIGEST_ELEMENT_NAME = 'digest' # :nodoc:
28
+ RESOURCE_DESC_ELEMENT_NAME = 'resourceDesc' # :nodoc:
29
+
30
+ XPATH = "cap:#{ XML_ELEMENT_NAME }" # :nodoc:
31
+ MIME_TYPE_XPATH = "cap:#{ MIME_TYPE_ELEMENT_NAME }" # :nodoc:
32
+ SIZE_XPATH = "cap:#{ SIZE_ELEMENT_NAME }" # :nodoc:
33
+ URI_XPATH = "cap:#{ URI_ELEMENT_NAME }" # :nodoc:
34
+ DEREF_URI_XPATH = "cap:#{ DEREF_URI_ELEMENT_NAME }" # :nodoc:
35
+ DIGEST_XPATH = "cap:#{ DIGEST_ELEMENT_NAME }" # :nodoc:
36
+ RESOURCE_DESC_XPATH = "cap:#{ RESOURCE_DESC_ELEMENT_NAME }" # :nodoc:
37
+
38
+ def initialize( attributes = {} )
39
+ @mime_type = attributes[ :mime_type ]
40
+ @size = attributes[ :size ]
41
+ @uri = attributes[ :uri ]
42
+ @deref_uri = attributes[ :deref_uri ]
43
+ @digest = attributes[ :digest ]
44
+ @resource_desc = attributes[ :resource_desc ]
45
+ end
46
+
47
+ def to_xml_element # :nodoc:
48
+ xml_element = REXML::Element.new( XML_ELEMENT_NAME )
49
+ xml_element.add_element( RESOURCE_DESC_ELEMENT_NAME ).add_text( self.resource_desc )
50
+ xml_element.add_element( MIME_TYPE_ELEMENT_NAME ).add_text( self.mime_type ) if self.mime_type
51
+ xml_element.add_element( SIZE_ELEMENT_NAME ).add_text( self.size ) if self.size
52
+ xml_element.add_element( URI_ELEMENT_NAME ).add_text( self.uri ) if self.uri
53
+ xml_element.add_element( DEREF_URI_ELEMENT_NAME ).add_text( self.deref_uri ) if self.deref_uri
54
+ xml_element.add_element( DIGEST_ELEMENT_NAME ).add_text( self.digest ) if self.digest
55
+ xml_element
56
+ end
57
+
58
+ # If size is defined returns the size in kilobytes
59
+ def size_in_kb
60
+ if self.size
61
+ self.size.to_f/1024
62
+ end
63
+ end
64
+
65
+ def to_xml # :nodoc:
66
+ self.to_xml_element.to_s
67
+ end
68
+
69
+ def inspect # :nodoc:
70
+ [ self.resource_desc, self.uri, self.mime_type, self.size ? format( "%.1fKB", self.size_in_kb ) : nil ].compact.join(' - ')
71
+ end
72
+
73
+ # Returns a string representation of the resource of the form
74
+ # resource_desc
75
+ def to_s
76
+ self.resource_desc
77
+ end
78
+
79
+ def self.from_xml_element( resource_xml_element ) # :nodoc:
80
+ resource = self.new( :resource_desc => RCAP.xpath_text( resource_xml_element, RESOURCE_DESC_XPATH ),
81
+ :uri => RCAP.xpath_text( resource_xml_element, URI_XPATH ),
82
+ :mime_type => RCAP.xpath_text( resource_xml_element, MIME_TYPE_XPATH ),
83
+ :deref_uri => RCAP.xpath_text( resource_xml_element, DEREF_URI_XPATH ),
84
+ :size => RCAP.xpath_text( resource_xml_element, SIZE_XPATH ),
85
+ :digest => RCAP.xpath_text( resource_xml_element, DIGEST_XPATH ))
86
+ end
87
+
88
+ RESOURCE_DESC_YAML = "Resource Description" # :nodoc:
89
+ URI_YAML = "URI" # :nodoc:
90
+ MIME_TYPE_YAML = "Mime Type" # :nodoc:
91
+ DEREF_URI_YAML = "Derefrenced URI Data" # :nodoc:
92
+ SIZE_YAML = "Size" # :nodoc:
93
+ DIGEST_YAML = "Digest" # :nodoc:
94
+
95
+ def to_yaml( options ) # :nodoc:
96
+ RCAP.attribute_values_to_hash(
97
+ [ RESOURCE_DESC_YAML, self.resource_desc ],
98
+ [ URI_YAML, self.uri ],
99
+ [ MIME_TYPE_YAML, self.mime_type ],
100
+ [ DEREF_URI_YAML, self.deref_uri ],
101
+ [ SIZE_YAML, self.size ],
102
+ [ DIGEST_YAML, self.digest ]
103
+ ).to_yaml( options )
104
+ end
105
+
106
+ def self.from_yaml_data( resource_yaml_data ) # :nodoc:
107
+ self.new(
108
+ :resource_desc => reource_yaml_data[ RESOURCE_DESC_YAML ],
109
+ :uri => reource_yaml_data[ URI_YAML ],
110
+ :mime_type => reource_yaml_data[ MIME_TYPE_YAML ],
111
+ :deref_uri => reource_yaml_data[ DEREF_URI_YAML ],
112
+ :size => reource_yaml_data[ SIZE_YAML ],
113
+ :digest => reource_yaml_data[ DIGEST_YAML ]
114
+ )
115
+ end
116
+
117
+ RESOURCE_DESC_KEY = 'resource_desc' # :nodoc:
118
+ URI_KEY = 'uri' # :nodoc:
119
+ MIME_TYPE_KEY = 'mime_type' # :nodoc:
120
+ DEREF_URI_KEY = 'deref_uri' # :nodoc:
121
+ SIZE_KEY = 'size' # :nodoc:
122
+ DIGEST_KEY = 'digest' # :nodoc:
123
+
124
+ def to_h # :nodoc:
125
+ RCAP.attribute_values_to_hash(
126
+ [ RESOURCE_DESC_KEY, self.resource_desc ],
127
+ [ URI_KEY, self.uri],
128
+ [ MIME_TYPE_KEY, self.mime_type],
129
+ [ DEREF_URI_KEY, self.deref_uri],
130
+ [ SIZE_KEY, self.size ],
131
+ [ DIGEST_KEY, self.digest ])
132
+ end
133
+
134
+ def self.from_h( resource_hash ) # :nodoc:
135
+ self.new(
136
+ :resource_desc => resource_hash[ RESOURCE_DESC_KEY ],
137
+ :uri => resource_hash[ URI_KEY ],
138
+ :mime_type => resource_hash[ MIME_TYPE_KEY ],
139
+ :deref_uri => resource_hash[ DEREF_URI_KEY ],
140
+ :size => resource_hash[ SIZE_KEY ],
141
+ :digest => resource_hash[ DIGEST_KEY ])
142
+ end
143
+ end
@@ -0,0 +1,5 @@
1
+ module RCAP
2
+ XMLNS = "urn:oasis:names:tc:emergency:cap:1.1"
3
+ CAP_VERSION = "1.1"
4
+ VERSION = "0.4"
5
+ end
@@ -0,0 +1,116 @@
1
+ module Validation # :nodoc:
2
+ module ClassMethods # :nodoc:
3
+
4
+ CAP_NUMBER_REGEX = Regexp.new( '^-{0,1}\d*\.{0,1}\d+$' )
5
+ CAP_INTEGER_REGEX = Regexp.new( '\-{0,1}A[+-]?\d+\Z' )
6
+
7
+ def validates_inclusion_of( *attributes )
8
+ options = {
9
+ :message => 'is not in the required range'
10
+ }.merge!( attributes.extract_options! )
11
+
12
+ validates_each( *attributes ) do |object, attribute, value|
13
+ next if ( value.nil? && options[ :allow_nil ]) || ( value.blank? && options[ :allow_blank ])
14
+ unless options[ :in ].include?( value )
15
+ object.errors[ attribute ] << options[ :message ]
16
+ end
17
+ end
18
+ end
19
+
20
+ def validates_inclusion_of_members_of( *attributes )
21
+ options = {
22
+ :message => 'contains members that are not valid'
23
+ }.merge!( attributes.extract_options! )
24
+
25
+ validates_each( *attributes ) do |object, attribute, collection|
26
+ next if ( collection.nil? && options[ :allow_nil ]) || (collection.blank? && options[ :allow_blank ])
27
+ unless collection.all?{ |member| options[ :in ].include?( member )}
28
+ object.errors[ attribute ] << options[ :message ]
29
+ end
30
+ end
31
+ end
32
+
33
+ def validates_length_of_members_of( *attributes )
34
+ options = {
35
+ :message => 'contains members with incorrect length'
36
+ }.merge!( attributes.extract_options! )
37
+
38
+ validates_each( *attributes ) do |object, attribute, collection|
39
+ next if ( collection.nil? && options[ :allow_nil ]) || (collection.blank? && options[ :allow_blank ])
40
+ unless options[ :minimum ] && collection.length >= options[ :minimum ]
41
+ object.errors[ attribute ] << options[ :message ]
42
+ end
43
+ end
44
+ end
45
+
46
+ def validates_validity_of( *attributes )
47
+ options = {
48
+ :message => 'is not valid'
49
+ }.merge!( attributes.extract_options! )
50
+
51
+ validates_each( *attributes ) do |object, attribute, value|
52
+ next if ( value.nil? && options[ :allow_nil ]) || ( value.blank? && options[ :allow_blank ])
53
+ unless value && value.valid?
54
+ object.errors[ attribute ] << options[ :message ]
55
+ end
56
+ end
57
+ end
58
+
59
+ def validates_collection_of( *attributes )
60
+ options = {
61
+ :message => 'contains an invalid element'
62
+ }.merge!( attributes.extract_options! )
63
+
64
+ validates_each( *attributes ) do |object, attribute, collection|
65
+ next if ( collection.nil? && options[ :allow_nil ]) || ( collection.blank? && options[ :allow_blank ])
66
+ unless collection.all?{ |element| element.valid? }
67
+ object.errors[ attribute ] << options[ :message ]
68
+ end
69
+ end
70
+ end
71
+
72
+ def validates_dependency_of( *attributes )
73
+ options = {
74
+ :message => 'is dependent on :attribute being defined'
75
+ }.merge!( attributes.extract_options! )
76
+
77
+ validates_each( *attributes ) do |object, attribute, value|
78
+ contingent_on_value = object.send( options[ :on ])
79
+ next if ( value.nil? && options[ :allow_nil ]) || ( value.blank? && options[ :allow_blank ])
80
+ unless value.blank? || !value.blank? && !contingent_on_value.blank? && ( options[ :with_value ].nil? || contingent_on_value == options[ :with_value ])
81
+ object.errors[ attribute ] << options[ :message ].gsub( /:attribute/, options[ :on ].to_s )
82
+ end
83
+ end
84
+ end
85
+
86
+ def validates_numericality_of( *attributes )
87
+ options = {
88
+ :message => 'is not a number',
89
+ }.merge!(attributes.extract_options!)
90
+
91
+ re = options[:only_integer] ? CAP_INTEGER_REGEX : CAP_NUMBER_REGEX
92
+
93
+ validates_each( *attributes ) do |object, attribute, value|
94
+ next if (value.nil? && options[ :allow_nil ]) || (value.blank? && options[ :allow_blank ])
95
+ unless ( value.to_s =~ re ) &&
96
+ ( options[ :greater_than ].nil? || value && value > options[ :greater_than ])
97
+ object.errors[ attribute ] << options[ :message ]
98
+ end
99
+ end
100
+ end
101
+
102
+
103
+ def validates_responsiveness_of( *attributes )
104
+ options = {
105
+ :message => 'does not respond to the given method'
106
+ }.merge!( attributes.extract_options! )
107
+
108
+ validates_each( *attributes ) do |object, attribute, value|
109
+ next if ( collection.nil? && options[ :allow_nil ]) || ( collection.blank? && options[ :allow_blank ])
110
+ unless options[ :to ].all?{ |method_name| object.respond_to?( method_name )}
111
+ object.errors[ attribute ] << options [ :message ]
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end