rcap-rails-generators 1.3

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