mapwkt 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,140 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Map
4
+ def center
5
+ return @center if @center
6
+ return if self.overlays.empty?
7
+
8
+ n, s, e, w = nil
9
+
10
+ self.overlays.each do |o|
11
+ n = o.center.y if !n || o.center.y > n
12
+ s = o.center.y if !s || o.center.y < s
13
+ e = o.center.x if !e || o.center.x > e
14
+ w = o.center.x if !w || o.center.x < w
15
+ end
16
+
17
+ x = (e + w) / 2
18
+ y = (n + s) / 2
19
+
20
+ @center = MapWKT::Geometry::Point.new(y, x)
21
+ end
22
+
23
+ def center= (center)
24
+ return unless MapWKT::Geometry::Point === center
25
+ @center = center
26
+ end
27
+
28
+ def id
29
+ @id
30
+ end
31
+
32
+ def id= (id)
33
+ return unless id
34
+ raise(ArgumentError, "invalid HTML id: #{id.to_json}") unless id =~ /^[a-zA-Z][\w\d.:-]*$/
35
+ @id = id
36
+ end
37
+
38
+ def initialize (arg = {})
39
+ @overlays = []
40
+
41
+ self.options = case arg
42
+ when String then { id: arg }
43
+ when Hash then arg
44
+ else {}
45
+ end
46
+ end
47
+
48
+ def js_initialize
49
+ "mapwkt_#{self.object_id}_initialize()"
50
+ end
51
+
52
+ def js_output (arg = {})
53
+ self.options = case arg
54
+ when String then { id: arg }
55
+ when Hash then arg
56
+ else {}
57
+ end
58
+
59
+ raise(ArgumentError, "HMTL id is required") unless self.id
60
+
61
+ <<-JAVASCRIPT.gsub('new google.maps.LatLng','new p')
62
+ function mapwkt_#{self.object_id}_initialize ()
63
+ {
64
+ var p = google.maps.LatLng
65
+ var element = document.getElementById('#{self.id}')
66
+ var options = { center: new google.maps.LatLng(#{self.center.latitude_f},#{self.center.longitude_f}), mapTypeId: google.maps.MapTypeId.#{self.map_type_id}, zoom: #{self.zoom} }
67
+ var map = new google.maps.Map(element, options)
68
+ #{self.overlays.map {|obj| obj.js_output('map') }.join("\n ")}
69
+ }
70
+ JAVASCRIPT
71
+ end
72
+
73
+ def map_type_id
74
+ @map_type_id ||= 'ROADMAP'
75
+ end
76
+
77
+ def map_type_id= (map_type_id)
78
+ return unless map_type_id
79
+ @map_type_id = ([map_type_id.to_s.upcase] & %w:HYBRID ROADMAP SATELLITE TERRAIN:).first || 'ROADMAP'
80
+ end
81
+
82
+ def options
83
+ {
84
+ center: self.center,
85
+ id: self.id,
86
+ map_type_id: self.map_type_id,
87
+ zoom: self.zoom
88
+ }
89
+ end
90
+
91
+ def options= (options)
92
+ options.symbolize_keys!
93
+ self.center = options[:center] || self.center
94
+ self.id = options[:id] || self.id
95
+ self.map_type_id = options[:map_type_id] || options[:mapTypeId] || self.map_type_id
96
+ self.zoom = options[:zoom] || self.zoom || 10
97
+ end
98
+
99
+ def overlays
100
+ self.refresh!
101
+ @overlays
102
+ end
103
+
104
+ def refresh!
105
+ return self if @refreshed
106
+ @refreshed = true
107
+
108
+ self.overlays.select! {|p| MapWKT::Overlay === p }
109
+ self
110
+ end
111
+
112
+ def zoom
113
+ @zoom ||= 10
114
+ end
115
+
116
+ def zoom= (zoom)
117
+ return unless zoom
118
+ @zoom = [0,[zoom.to_i, 25].min].max
119
+ end
120
+
121
+ def << (obj)
122
+ overlays = case obj
123
+ when MapWKT::Geometry then [MapWKT::Overlay.new(obj)]
124
+ when MapWKT::Overlay then [obj]
125
+ else
126
+ raise(TypeError, "method `wkt' is not defined for #{obj.inspect}") unless obj.respond_to?(:wkt)
127
+
128
+ MapWKT::Geometry.parse_wkt(obj.wkt).map do |g|
129
+ {
130
+ MapWKT::Geometry::Point => MapWKT::Overlay::Marker,
131
+ MapWKT::Geometry::LineString => MapWKT::Overlay::Polyline,
132
+ MapWKT::Geometry::Polygon => MapWKT::Overlay::Polygon
133
+ }[g.class].new(g, obj)
134
+ end
135
+ end
136
+
137
+ self.overlays.push(*overlays)
138
+ self
139
+ end
140
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Overlay::Marker < MapWKT::Overlay
4
+ def js_output (map_name = nil)
5
+ "new google.maps.Marker({#{" map: #{map_name}," if map_name} position: new google.maps.LatLng(#{self.geometry.latitude_f},#{self.geometry.longitude_f}) })"
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Overlay
4
+ def center
5
+ self.geometry.center
6
+ end
7
+
8
+ def geometry
9
+ @geometry
10
+ end
11
+
12
+ def initialize (geometry, source)
13
+ @geometry = geometry
14
+ @source = source
15
+ end
16
+
17
+ def source
18
+ @source
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Overlay::Polygon < MapWKT::Overlay
4
+ def js_output (map_name = nil)
5
+ paths = [self.geometry.perimeter, *self.geometry.lacunae].map do |g|
6
+ points = [*g.points, g.points.first]
7
+ "[#{points.map {|p| "new google.maps.LatLng(#{p.latitude_f},#{p.longitude_f})" }.join(?,)}]"
8
+ end.join(?,)
9
+
10
+ "new google.maps.Polygon({#{" map: #{map_name}," if map_name} paths: [#{paths}] })"
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Overlay::Polyline < MapWKT::Overlay
4
+ def js_output (map_name = nil)
5
+ points = self.geometry.open? ? self.geometry.points : [*self.geometry.points, self.geometry.points.first]
6
+ path = "[#{points.map {|p| "new google.maps.LatLng(#{p.latitude_f},#{p.longitude_f})" }.join(?,)}]"
7
+
8
+ "new google.maps.Polyline({#{" map: #{map_name}," if map_name} path: #{path} })"
9
+ end
10
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Geometry
4
+ def self.parse_wkt (wkt_string)
5
+ # Remove extraneous whitespace.
6
+ s = wkt_string.to_s.upcase.strip.gsub(/\s*([),(])\s*/,'\1').gsub(/\s+/,' ')
7
+
8
+ case s
9
+ when /^POINT\(([\d\s.-]*?)\)$/
10
+ x, y = self.parse_x_y $1
11
+ [MapWKT::Geometry::Point.new(y,x)]
12
+
13
+ when /^LINESTRING\(([\d\s,.-]*?)\)$/
14
+ points = self.parse_points $1
15
+ [MapWKT::Geometry::LineString.new(*points)]
16
+
17
+ when /^POLYGON\((\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*)\)$/
18
+ perimeter, lacunae = self.parse_linestrings $1
19
+ [MapWKT::Geometry::Polygon.new(perimeter, *lacunae)]
20
+
21
+ when /^MULTIPOINT\(([\d\s,.-]*?)\)$/
22
+ self.parse_points $1
23
+
24
+ when /^MULTIPOINT\((\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*)\)$/
25
+ points_string = $1.gsub(/[()]/,'')
26
+ self.parse_points(points_string)
27
+
28
+ when /^MULTILINESTRING\((\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*)\)$/
29
+ self.parse_linestrings $1
30
+
31
+ when /^MULTIPOLYGON\((\(\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*\)(?:,\(\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*\))*)\)$/
32
+ self.parse_polygons $1
33
+
34
+ when /^GEOMETRYCOLLECTION\((.*?)\)$/
35
+ wkt_strings = $1.scan(/([A-Z]+\(.*?\))(?=,[A-Z]|$)/).flatten
36
+ wkt_strings.map {|wkt_string| self.parse_wkt(wkt_string) }.flatten
37
+
38
+ else
39
+ raise SyntaxError
40
+ end
41
+
42
+ rescue SyntaxError
43
+ raise SyntaxError, "not a valid WKT string: #{wkt_string.inspect}"
44
+ end
45
+
46
+ def self.parse_polygons (polygons_string)
47
+ # Create Polygons from each "((x y, …), (x y, …))" in the polygons string.
48
+ polygons_string.scan(/\((\(.*?\))\)/).flatten.map do |linestrings_string|
49
+ perimeter, lacunae = self.parse_linestrings(linestrings_string)
50
+ MapWKT::Geometry::Polygon.new(perimeter, *lacunae)
51
+ end
52
+ end
53
+
54
+ def self.parse_linestrings (linestrings_string)
55
+ # Create LineStrings from each "(x y, …)" in the linestrings string.
56
+ linestrings_string.scan(/\((.*?)\)/).flatten.map do |points_string|
57
+ points = self.parse_points(points_string)
58
+ MapWKT::Geometry::LineString.new(*points)
59
+ end
60
+ end
61
+
62
+ def self.parse_points (points_string)
63
+ # Create Points from each "x y" in the points string.
64
+ points_string.split(?,).map do |x_y_string|
65
+ x, y = self.parse_x_y(x_y_string)
66
+ MapWKT::Geometry::Point.new(y,x)
67
+ end
68
+ end
69
+
70
+ def self.parse_x_y (x_y_string)
71
+ # Check the string.
72
+ raise SyntaxError unless x_y_string =~ /^(-?\d+(?:\.\d+)?)\s(-?\d+(?:\.\d+)?)$/
73
+
74
+ # Return the x and y values.
75
+ [$1, $2].map(&:to_f)
76
+ end
77
+ end
@@ -0,0 +1,97 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Geometry::LineString < MapWKT::Geometry
4
+ # Returns a Point midway between the N/S- & E/W-most Points in the LineString.
5
+ def center
6
+ return if self.points.empty?
7
+ n, s, e, w = nil
8
+
9
+ self.points.each do |p|
10
+ n = p.y if !n || p.y > n
11
+ s = p.y if !s || p.y < s
12
+ e = p.x if !e || p.x > e
13
+ w = p.x if !w || p.x < w
14
+ end
15
+
16
+ x = (e + w) / 2
17
+ y = (n + s) / 2
18
+
19
+ Point.new(y, x)
20
+ end
21
+
22
+ # Returns this LineString after closing its endpoints.
23
+ def close!
24
+ self.refresh! unless @refreshed
25
+ @closed = true
26
+ self
27
+ end
28
+
29
+ # Returns true if this LineString is closed, false otherwise.
30
+ def closed?
31
+ self.refresh!
32
+ @closed ||= false
33
+ end
34
+
35
+ # Returns a new LineString with the same geographic Points as this LineString.
36
+ def dup
37
+ points = self.points.map(&:dup)
38
+ LineString(*points).tap {|ls| ls.close! if self.closed? }
39
+ end
40
+
41
+ # Returns a new LineString containing the given Points.
42
+ def initialize (*points)
43
+ @points = points
44
+ self.refresh!
45
+ end
46
+
47
+ # Returns false if this LineString is closed, true otherwise.
48
+ def open?
49
+ !self.closed?
50
+ end
51
+
52
+ # Returns this LineString after opening its endpoints.
53
+ def open!
54
+ self.refresh!
55
+ @closed = false
56
+ self
57
+ end
58
+
59
+ # Returns the array of Points in this LineString.
60
+ def points
61
+ self.refresh!
62
+ @points
63
+ end
64
+
65
+ # Removes any non-Point objects from this LineString's #points array. If the
66
+ # first Point has been added to the end of the #points array, closes the
67
+ # LineString and removes the Point. Returns this LineString.
68
+ def refresh!
69
+ return self if @refreshed
70
+ @refreshed = true
71
+
72
+ self.points.select! {|p| MapWKT::Geometry::Point === p }
73
+
74
+ while (self.points.many?) && (self.points.last == self.points.first)
75
+ self.points.pop
76
+ @closed = true
77
+ end
78
+
79
+ self
80
+ end
81
+
82
+ # Returns a string representation of this LineString. ⤿ indicates an open
83
+ # LineString, while ⟲ indicates a closed LineString.
84
+ def to_s
85
+ points = self.points.join(", ")
86
+ marker = self.closed? ? ?⟲ : ?⤿
87
+
88
+ "#{marker} #{points} #{marker} "
89
+ end
90
+
91
+ # Returns this LineString's WKT representation, with latitudes and longitudes
92
+ # rounded to 7 decimal places.
93
+ def wkt
94
+ points = self.open? ? self.points : [*self.points, self.points.first]
95
+ "LINESTRING(#{points.map {|p| "#{p.longitude_f} #{p.latitude_f}" }.join(", ")})"
96
+ end
97
+ end
@@ -0,0 +1,123 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Geometry::Point < MapWKT::Geometry
4
+ # Returns a new Point with the same latitude and longitude as this Point.
5
+ def center
6
+ self.dup
7
+ end
8
+
9
+ # Returns true if this Point lies in the eastern hemisphere, false otherwise.
10
+ def east?
11
+ self.longitude > 0
12
+ end
13
+
14
+ # Returns true if this Point lies on the equator, false otherwise.
15
+ def equator?
16
+ self.latitude == 0
17
+ end
18
+
19
+ # Returns a new MapWKT::Geometry::Point with latitude and longitude normalized
20
+ # to fit within the range [-90,90] for latitude and (-180,180] for longitude.
21
+ def initialize (φ, λ)
22
+ # Check arguments.
23
+ if [φ, λ].all? {|arg| arg.respond_to?(:to_f) }
24
+ φ = φ.to_f
25
+ λ = λ.to_f
26
+ else
27
+ raise ArgumentError, "expected (latitude, longitude), got (#{φ.inspect}, #{λ.inspect})"
28
+ end
29
+
30
+ # Normalize latitude (-90..90) and longitude (-179..180).
31
+ λ += 180 * (((φ / 90 + 1).floor / 2) % 2)
32
+ @y = 90 - (((90 + φ) % 360) - 180).abs
33
+ @x = self.pole? ? 0 : (λ - 180) % -360 + 180
34
+ end
35
+
36
+ # Returns this Point's latitude as a float, rounded to 7 decimal places.
37
+ def latitude
38
+ self.y.round(7)
39
+ end
40
+
41
+ # Returns this Point's latitude as a string, rounded to 7 decimal places.
42
+ def latitude_f
43
+ sprintf("%.7f", self.latitude).gsub(/\.?0*$/,'')
44
+ end
45
+
46
+ # Returns this Point's latitude in degrees N/S, rounded to 7 decimal places.
47
+ def latitude_°
48
+ φ = self.latitude
49
+ direction = (φ == 0) ? "" : (φ > 0) ? "N" : "S"
50
+
51
+ sprintf("%.7f°%s", φ.abs, direction).gsub(/\.?0*(?=°)/,'')
52
+ end
53
+
54
+ # Returns this Point's longitude as a float, rounded to 7 decimal places.
55
+ def longitude
56
+ self.x.round(7)
57
+ end
58
+
59
+ # Returns this Point's longitude as a string, rounded to 7 decimal places.
60
+ def longitude_f
61
+ sprintf("%.7f", self.longitude).gsub(/\.?0*$/,'')
62
+ end
63
+
64
+ # Returns this Point's longitude in degrees E/W, rounded to 7 decimal places.
65
+ def longitude_°
66
+ λ = self.longitude
67
+ direction = [0, 180].include?(λ) ? "" : (λ > 0) ? "E" : "W"
68
+
69
+ sprintf("%.7f°%s", λ.abs, direction).gsub(/\.?0*(?=°)/,'')
70
+ end
71
+
72
+ # Returns 1 if this Point is the north pole, -1 if it is the south pole, or nil
73
+ # if it is neither.
74
+ def pole?
75
+ return 1 if self.north_pole?
76
+ return -1 if self.south_pole?
77
+ end
78
+
79
+ # Returns true if this Point is the north pole.
80
+ def north_pole?
81
+ self.latitude == 90
82
+ end
83
+
84
+ # Returns true if this Point is the south pole.
85
+ def south_pole?
86
+ self.latitude == -90
87
+ end
88
+
89
+ # Returns a string representation of this Point.
90
+ def to_s
91
+ "#{self.latitude_°} #{self.longitude_°}"
92
+ end
93
+
94
+ # Returns true if this Point lies in the western hemisphere, false otherwise.
95
+ def west?
96
+ self.longitude < 0
97
+ end
98
+
99
+ # Returns this Point's WKT representation, rounded to 7 decimal places.
100
+ def wkt
101
+ "POINT(#{self.longitude_f} #{self.latitude_f})"
102
+ end
103
+
104
+ # Returns this Point's longitude as a float.
105
+ def x
106
+ @x
107
+ end
108
+
109
+ # Returns this Point's latitude as a float.
110
+ def y
111
+ @y
112
+ end
113
+
114
+ # Returns true if this Point matches the other Point, within 7 decimal places.
115
+ def == (other)
116
+ [self.latitude, self.longitude] == [other.latitude, other.longitude]
117
+ end
118
+
119
+ # Returns true if this Point matches the other Point exactly.
120
+ def === (other)
121
+ [self.x, self.y] == [other.x, other.y]
122
+ end
123
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: UTF-8
2
+
3
+ class MapWKT::Geometry::Polygon < MapWKT::Geometry
4
+ # Returns a Point midway between the N/S- & E/W-most Points in the perimeter.
5
+ def center
6
+ self.perimeter.center
7
+ end
8
+
9
+ # Returns a new MapWKT::Geometry::Polygon with the given outer perimeter and
10
+ # internal lacunae. If the given LineStrings were unclosed, closes them for
11
+ # use in the Polygon, but leaves the original LineStrings unchanged.
12
+ def initialize (perimeter, *lacunae)
13
+ @perimeter = perimeter.dup.close!
14
+ @lacunae = lacunae.map {|lacuna| lacuna.dup.close! }
15
+ end
16
+
17
+ # Returns an array of LineStrings representing the geographical areas treated
18
+ # as lacunae in this Polygon's enclosed area. Does not return the objects
19
+ # themselves, nor the actual array containing them.
20
+ def lacunae
21
+ @lacunae.map(&:dup)
22
+ end
23
+
24
+ # Returns a LineString representing the geographical area treated as the
25
+ # outer perimeter of this Polygon's enclosed area. Does not return the actual
26
+ # LineString object used in this Polygon.
27
+ def perimeter
28
+ @perimeter.dup
29
+ end
30
+
31
+ # Returns a string representation of this Polygon. ⭓ indicates the perimeter
32
+ # LineString, while ⬠ indicates a lacuna LineString.
33
+ def to_s
34
+ "⭓ #{@perimeter.points.join(", ")} ⭓#{@lacunae.map {|lacuna| " | ⬠ #{lacuna.points.join(", ")} ⬠" }.join} "
35
+ end
36
+
37
+ # Returns this Polygon's WKT representation, with latitudes and longitudes
38
+ # rounded to 7 decimal places.
39
+ def wkt
40
+ "POLYGON((#{[*@perimeter.points, @perimeter.points.first].map {|p| "#{p.longitude_f} #{p.latitude_f}" }.join(", ")})#{@lacunae.map {|lacuna| ", (#{[*lacuna.points, lacuna.points.first].map {|p| "#{p.longitude_f} #{p.latitude_f}" }.join(", ")})" }.join })"
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+
3
+ module MapWKT
4
+ require 'bundler/setup'
5
+ require 'active_support/all'
6
+
7
+ require_relative 'mapwkt/gmap/overlay'
8
+ require_relative 'mapwkt/gmap/map'
9
+ require_relative 'mapwkt/gmap/marker'
10
+ require_relative 'mapwkt/gmap/polygon'
11
+ require_relative 'mapwkt/gmap/polyline'
12
+
13
+ require_relative 'mapwkt/wkt/geometry'
14
+ require_relative 'mapwkt/wkt/line_string'
15
+ require_relative 'mapwkt/wkt/point'
16
+ require_relative 'mapwkt/wkt/polygon'
17
+ end
data/lib/mapwkt.rb ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+
3
+ Geometry = Class.new
4
+ Map = Class.new
5
+ Overlay = Class.new
6
+
7
+ LineString = Class.new(Geometry)
8
+ Point = Class.new(Geometry)
9
+ Polygon = Class.new(Geometry)
10
+
11
+ Marker = Class.new(Overlay)
12
+ PolygonOverlay = Class.new(Overlay)
13
+ Polyline = Class.new(Overlay)
14
+
15
+ # Register the class names in the top-level namespace.
16
+ [
17
+ Geometry, LineString, Map, Marker, Overlay,
18
+ Point, Polygon, PolygonOverlay, Polyline
19
+ ].map(&:name)
20
+
21
+ # Create the namespaced constants pointing to the classes.
22
+ module MapWKT
23
+ Geometry = ::Geometry
24
+ Map = ::Map
25
+ Overlay = ::Overlay
26
+
27
+ class Geometry
28
+ LineString = ::LineString
29
+ Point = ::Point
30
+ Polygon = ::Polygon
31
+ end
32
+
33
+ class Overlay
34
+ Marker = ::Marker
35
+ Polygon = ::PolygonOverlay
36
+ Polyline = ::Polyline
37
+ end
38
+
39
+ require_relative 'mapwkt-safe'
40
+ end
41
+
42
+ def Point (*args) Point.new(*args) end
43
+ def LineString (*args) LineString.new(*args) end
44
+ def Polygon (*args) Polygon.new(*args) end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mapwkt
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jesse Sielaff
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-11 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: .
15
+ email: jesse.sielaff@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ./lib/mapwkt/gmap/map.rb
21
+ - ./lib/mapwkt/gmap/marker.rb
22
+ - ./lib/mapwkt/gmap/overlay.rb
23
+ - ./lib/mapwkt/gmap/polygon.rb
24
+ - ./lib/mapwkt/gmap/polyline.rb
25
+ - ./lib/mapwkt/wkt/geometry.rb
26
+ - ./lib/mapwkt/wkt/line_string.rb
27
+ - ./lib/mapwkt/wkt/point.rb
28
+ - ./lib/mapwkt/wkt/polygon.rb
29
+ - ./lib/mapwkt-safe.rb
30
+ - ./lib/mapwkt.rb
31
+ homepage:
32
+ licenses: []
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.23
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: An object library for converting Ruby objects with WKT to JavaScript for
55
+ Google Maps.
56
+ test_files: []