carto_json 0.0.6
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.
- data/.gitignore +18 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README +0 -0
- data/README.md +29 -0
- data/Rakefile +13 -0
- data/carto_json.gemspec +23 -0
- data/lib/carto_json/circle.rb +33 -0
- data/lib/carto_json/errors.rb +8 -0
- data/lib/carto_json/line_string.rb +39 -0
- data/lib/carto_json/parser.rb +55 -0
- data/lib/carto_json/point.rb +45 -0
- data/lib/carto_json/polygon.rb +13 -0
- data/lib/carto_json/shape.rb +52 -0
- data/lib/carto_json/utils.rb +19 -0
- data/lib/carto_json/version.rb +3 -0
- data/lib/carto_json/wkt_parser.rb +39 -0
- data/lib/carto_json.rb +31 -0
- data/spec/carto_json_spec.rb +18 -0
- data/spec/circle_spec.rb +52 -0
- data/spec/env.rb +8 -0
- data/spec/line_string_spec.rb +32 -0
- data/spec/parser_spec.rb +62 -0
- data/spec/point_spec.rb +49 -0
- data/spec/polygon_spec.rb +33 -0
- data/spec/wkt_parser_spec.rb +28 -0
- metadata +135 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Geoloqi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# CartoJson
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'carto_json'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install carto_json
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require "rake/testtask"
|
5
|
+
|
6
|
+
desc "Run all tests"
|
7
|
+
Rake::TestTask.new do |t|
|
8
|
+
t.libs << "spec"
|
9
|
+
t.test_files = FileList['spec/*_spec.rb','spec/shapes/*_spec.rb']
|
10
|
+
t.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :test
|
data/carto_json.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
3
|
+
require File.expand_path('../lib/carto_json/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.authors = ["Kyle Drake"]
|
7
|
+
gem.email = ["kyledrake@gmail.com"]
|
8
|
+
gem.description = %q{Helpers for the CartoJSON specification}
|
9
|
+
gem.summary = %q{Helpers for the CartoJSON spec}
|
10
|
+
gem.homepage = ""
|
11
|
+
|
12
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
14
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
gem.name = "carto_json"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = CartoJson::VERSION
|
18
|
+
gem.add_dependency 'multi_json'
|
19
|
+
gem.add_development_dependency 'rake'
|
20
|
+
gem.add_development_dependency 'pry'
|
21
|
+
gem.add_development_dependency 'minitest'
|
22
|
+
gem.add_development_dependency 'json'
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module CartoJson
|
2
|
+
class Circle < Point
|
3
|
+
type :circle
|
4
|
+
|
5
|
+
attr_accessor :radius
|
6
|
+
|
7
|
+
def radius=(r)
|
8
|
+
raise InvalidRadiusError, 'radius cannot be negative' if r < 0
|
9
|
+
raise InvalidRadiusError, 'radius cannot be blank' if r.nil?
|
10
|
+
raise InvalidRadiusError, 'radius must be a number' unless (r.is_a?(Integer) || r.is_a?(Float))
|
11
|
+
raise InvalidRadiusError, 'radius cannot be zero' if r == 0
|
12
|
+
@radius = r
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_wkt
|
16
|
+
raise NotImplementedError, 'WKT does not support circles directly, conversion to polygon is required'
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_point
|
20
|
+
Point.new LAT => send(LAT), LNG => send(LNG)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_hash
|
24
|
+
{:type => self.class.type,
|
25
|
+
:center => {
|
26
|
+
LAT => send(LAT),
|
27
|
+
LNG => send(LNG)
|
28
|
+
},
|
29
|
+
:radius => radius
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module CartoJson
|
2
|
+
class LineString
|
3
|
+
include Shape
|
4
|
+
type :linestring
|
5
|
+
|
6
|
+
attr_accessor :points
|
7
|
+
|
8
|
+
def initialize(input)
|
9
|
+
super
|
10
|
+
@points = []
|
11
|
+
input[:points].each do |p|
|
12
|
+
if p.is_a?(Point)
|
13
|
+
@points << p
|
14
|
+
else
|
15
|
+
@points << Point.new(LAT => p[LAT], LNG => p[LNG])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
validate
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
{:type => self.class.type,
|
24
|
+
:points => points.collect {|p| p.to_hash_for_array}}
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_wkt
|
28
|
+
"#{type.to_s.upcase} ((#{@points.dup.push(@points.first).collect {|p| "#{p.send(LNG)} #{p.send(LAT)}"}.join(', ')}))"
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def validate
|
34
|
+
if @points.length < 2
|
35
|
+
raise InsufficientPointsError, "a minimum of 2 points is required to make a linestring, you provided #{@points.length}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module CartoJson
|
2
|
+
class Parser
|
3
|
+
def self.parse(input)
|
4
|
+
p = new input
|
5
|
+
p.parse
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(input)
|
9
|
+
@input = input
|
10
|
+
@parsed = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(input=@input)
|
14
|
+
return nil if input.nil?
|
15
|
+
|
16
|
+
case input
|
17
|
+
when Array
|
18
|
+
@parsed = []
|
19
|
+
input.each {|element| @parsed << parse_element(element) }
|
20
|
+
|
21
|
+
when Hash
|
22
|
+
input = Utils.symbolize_keys(input)
|
23
|
+
@parsed = parse_element input
|
24
|
+
|
25
|
+
when String
|
26
|
+
begin
|
27
|
+
decoded = MultiJson.decode(input, :symbolize_keys => true)
|
28
|
+
rescue MultiJson::DecodeError => e
|
29
|
+
raise InputError, "unable to decode JSON: \"#{e.message}\""
|
30
|
+
end
|
31
|
+
@parsed = parse decoded
|
32
|
+
else
|
33
|
+
raise InputError, "expected Array, Hash or String, you provided #{input.class}"
|
34
|
+
end
|
35
|
+
|
36
|
+
@parsed
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_element(element)
|
40
|
+
if element[:type].nil?
|
41
|
+
if element[LAT] && element[LNG]
|
42
|
+
element[:type] = 'point'
|
43
|
+
else
|
44
|
+
raise InputError, "cannot determine type for the provided element (type is missing or #{LAT}/#{LNG} are not present)"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
unless TYPES.include? element[:type].to_sym
|
49
|
+
raise InvalidTypeError, "unsupported type: \"#{element[:type]}\", supported types: #{TYPES.join(', ')}"
|
50
|
+
end
|
51
|
+
|
52
|
+
CartoJson.const_get(element[:type].capitalize).parse element
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module CartoJson
|
2
|
+
class Point
|
3
|
+
include Shape
|
4
|
+
|
5
|
+
type :point
|
6
|
+
|
7
|
+
attr_accessor LAT, LNG
|
8
|
+
|
9
|
+
def initialize(input)
|
10
|
+
raise InputError, 'cannot create a shape with an array' if input.is_a?(Array)
|
11
|
+
|
12
|
+
if input[LAT].nil? || input[LNG].nil?
|
13
|
+
raise InputError, "#{LAT} and #{LNG} are required to instantiate a point"
|
14
|
+
end
|
15
|
+
|
16
|
+
input[LAT] = input[LAT].to_f
|
17
|
+
input[LNG] = input[LNG].to_f
|
18
|
+
|
19
|
+
super input
|
20
|
+
|
21
|
+
unless (-90..90).include? input[LAT]
|
22
|
+
raise InputError, "latitude must be between -90 and 90, \"#{input[LAT]}\" was provided"
|
23
|
+
end
|
24
|
+
|
25
|
+
unless (-180..180).include? input[LNG]
|
26
|
+
raise InputError, "longitude must be between -180 and 180, \"#{input[LNG]}\" was provided"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_hash
|
31
|
+
{:type => self.class.type,
|
32
|
+
LAT => send(LAT),
|
33
|
+
LNG => send(LNG)}
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hash_for_array
|
37
|
+
{LAT => send(LAT),
|
38
|
+
LNG => send(LNG)}
|
39
|
+
end
|
40
|
+
|
41
|
+
def ==(point)
|
42
|
+
send(LAT) == point.send(LAT) && send(LNG) == point.send(LNG)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CartoJson
|
2
|
+
class Polygon < LineString
|
3
|
+
type :polygon
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
def validate
|
8
|
+
if @points.length < 3
|
9
|
+
raise InsufficientPointsError, "a minimum of 3 points is required to make a polygon, you provided #{@points.length}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module CartoJson
|
2
|
+
|
3
|
+
module Shape
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
attr_accessor :type
|
10
|
+
|
11
|
+
def type(val=nil)
|
12
|
+
@type = val unless val.nil?
|
13
|
+
@type
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse(input)
|
17
|
+
new input
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(input=nil)
|
22
|
+
raise InputError, 'cannot create a shape with an array' if input.is_a?(Array)
|
23
|
+
|
24
|
+
if input.respond_to?(:each)
|
25
|
+
input.each do |k,v|
|
26
|
+
next if k == :type
|
27
|
+
send "#{k}=".to_sym, v
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_hash
|
33
|
+
raise NotImplementedError, 'you need to provide the to_hash method'
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_json
|
37
|
+
MultiJson.encode to_hash
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_pretty_json
|
41
|
+
MultiJson.encode to_hash, :pretty => true
|
42
|
+
end
|
43
|
+
|
44
|
+
def type
|
45
|
+
self.class.type
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_wkt
|
49
|
+
"#{self.class.name.split('::').last.upcase} (#{send(LNG)} #{send(LAT)})"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CartoJson
|
2
|
+
module Utils
|
3
|
+
def self.symbolize_keys(arg)
|
4
|
+
case arg
|
5
|
+
when Array
|
6
|
+
arg.map { |elem| symbolize_keys elem }
|
7
|
+
when Hash
|
8
|
+
Hash[
|
9
|
+
arg.map { |key, value|
|
10
|
+
k = key.is_a?(String) ? key.to_sym : key
|
11
|
+
v = symbolize_keys value
|
12
|
+
[k,v]
|
13
|
+
}]
|
14
|
+
else
|
15
|
+
arg
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# TODO: Write in a real parsing library like Parslet, finish multi type support
|
2
|
+
module CartoJson
|
3
|
+
class WKTParser
|
4
|
+
def self.parse(input)
|
5
|
+
new(input).parse
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(input)
|
9
|
+
@input = input
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse
|
13
|
+
type = @input.match /(\w+) \(/i
|
14
|
+
|
15
|
+
raise InputError, "invalid WKT input" if type.nil?
|
16
|
+
|
17
|
+
type = type.captures.first
|
18
|
+
|
19
|
+
case type.downcase.to_sym
|
20
|
+
when :polygon
|
21
|
+
points = xy_to_points(@input.match(/polygon \(\((.+)\)\)/i).captures.first)
|
22
|
+
Polygon.new :points => points[0...points.length-1]
|
23
|
+
when :linestring
|
24
|
+
LineString.new :points => xy_to_points(@input.match(/linestring \((.+)\)/i).captures.first)
|
25
|
+
when :point
|
26
|
+
Point.new xy_to_points(@input.match(/point \((.+)\)/i).captures.first).first
|
27
|
+
else
|
28
|
+
raise NotImplementedError, 'multi types are not implemented yet' if MULTI_TYPES.include? type.downcase
|
29
|
+
raise Input Error, "invalid type: #{type}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def xy_to_points(capture)
|
36
|
+
capture.split(',').collect { |coordinates| coordinates.split(' ') }.collect {|c| {LAT => c.last, LNG => c.first}}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/carto_json.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module CartoJson
|
2
|
+
PRIMITIVE_TYPES = [:point, :linestring, :polygon, :rectangle]
|
3
|
+
MULTI_TYPES = [:multipoint, :multilinestring, :multipolygon]
|
4
|
+
TYPES = PRIMITIVE_TYPES+MULTI_TYPES
|
5
|
+
|
6
|
+
# These might change, so I've made it easier to switch.
|
7
|
+
LAT = :lat.freeze
|
8
|
+
LNG = :lng.freeze
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def parse(input)
|
12
|
+
Parser.parse input
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_wkt(input)
|
16
|
+
WKTParser.parse input
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'carto_json/errors'
|
22
|
+
require 'carto_json/utils'
|
23
|
+
require 'carto_json/parser'
|
24
|
+
require 'carto_json/shape'
|
25
|
+
require 'carto_json/point'
|
26
|
+
require 'carto_json/circle'
|
27
|
+
require 'carto_json/line_string'
|
28
|
+
require 'carto_json/polygon'
|
29
|
+
require 'carto_json/wkt_parser'
|
30
|
+
require 'carto_json/version'
|
31
|
+
require 'multi_json'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'env.rb'
|
2
|
+
|
3
|
+
describe CartoJson do
|
4
|
+
describe 'the parse module function' do
|
5
|
+
it 'should load point' do
|
6
|
+
point = CartoJson.parse MultiJson.encode({
|
7
|
+
:type => 'point',
|
8
|
+
LAT => 45.52,
|
9
|
+
LNG => -122.681944
|
10
|
+
})
|
11
|
+
|
12
|
+
point.class.must_equal CartoJson::Point
|
13
|
+
point.type.must_equal :point
|
14
|
+
point.send(LAT).must_equal 45.52
|
15
|
+
point.send(LNG).must_equal -122.681944
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/circle_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'env.rb'
|
2
|
+
|
3
|
+
include CartoJson
|
4
|
+
|
5
|
+
describe CartoJson::Circle do
|
6
|
+
before do
|
7
|
+
@args = {LAT => 45.52, LNG => -122.681944, :radius => 500}
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should create a circle with valid data' do
|
11
|
+
|
12
|
+
circle = Circle.new @args
|
13
|
+
circle.is_a?(Circle).must_equal true
|
14
|
+
circle.type.must_equal :circle
|
15
|
+
circle.class.type.must_equal :circle
|
16
|
+
|
17
|
+
hash = MultiJson.decode(circle.to_json, :symbolize_keys => true)
|
18
|
+
|
19
|
+
hash[:center][LAT].must_equal @args[LAT]
|
20
|
+
hash[:center][LNG].must_equal @args[LNG]
|
21
|
+
hash[:radius].must_equal @args[:radius]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should fail with negative radius' do
|
25
|
+
lambda {
|
26
|
+
Circle.new @args.merge(:radius => -40)
|
27
|
+
}.must_raise CartoJson::InvalidRadiusError
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should fail with crazy lat and lng' do
|
31
|
+
lambda {
|
32
|
+
Circle.new @args.merge(LAT => -31337)
|
33
|
+
}.must_raise CartoJson::InputError
|
34
|
+
|
35
|
+
lambda {
|
36
|
+
Circle.new @args.merge(LNG => -31337)
|
37
|
+
}.must_raise CartoJson::InputError
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'fails for wkt' do
|
41
|
+
lambda { Circle.new(@args).to_wkt }.must_raise CartoJson::NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'converts to point' do
|
45
|
+
p = Circle.new(@args).to_point
|
46
|
+
@args.delete :radius
|
47
|
+
|
48
|
+
np = Point.new(@args)
|
49
|
+
p.send(LAT).must_equal np.send(LAT)
|
50
|
+
p.send(LNG).must_equal np.send(LNG)
|
51
|
+
end
|
52
|
+
end
|
data/spec/env.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'env.rb'
|
2
|
+
|
3
|
+
include CartoJson
|
4
|
+
|
5
|
+
describe LineString do
|
6
|
+
before do
|
7
|
+
@args = {:points => [
|
8
|
+
{LAT => 45.52, LNG => -122.681944},
|
9
|
+
{LAT => 45.53, LNG => -122.681945},
|
10
|
+
{LAT => 45.54, LNG => -122.681946}]}
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should create a linestring with valid data' do
|
14
|
+
ls = LineString.new @args
|
15
|
+
ls.type.must_equal :linestring
|
16
|
+
ls.class.type.must_equal :linestring
|
17
|
+
ls.points.first.class.must_equal Point
|
18
|
+
|
19
|
+
hash = MultiJson.decode(ls.to_json, :symbolize_keys => true)
|
20
|
+
hash[:points].length.must_equal 3
|
21
|
+
hash[:points].first[LAT].must_equal @args[:points].first[LAT]
|
22
|
+
hash[:points].first[LNG].must_equal @args[:points].first[LNG]
|
23
|
+
|
24
|
+
ls.to_wkt.must_equal "LINESTRING ((#{ls.points.dup.push(ls.points.first).collect {|p| "#{p.send(LNG)} #{p.send(LAT)}"}.join(', ')}))"
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should fail if less than three points' do
|
28
|
+
@args[:points].pop
|
29
|
+
@args[:points].pop
|
30
|
+
lambda { LineString.new @args }.must_raise InsufficientPointsError
|
31
|
+
end
|
32
|
+
end
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'env.rb'
|
2
|
+
|
3
|
+
describe CartoJson::Parser do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@json_point_one = MultiJson.encode({
|
7
|
+
:type => 'point',
|
8
|
+
LAT => 45.52,
|
9
|
+
LNG => -122.681944
|
10
|
+
})
|
11
|
+
|
12
|
+
@json_point_two = MultiJson.encode({
|
13
|
+
:type => 'point',
|
14
|
+
LAT => 45.53,
|
15
|
+
LNG => -122.681945
|
16
|
+
})
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'the parse class method' do
|
20
|
+
it 'should fail when provided with crap data' do
|
21
|
+
lambda { CartoJson::Parser.parse MultiJson.encode({}) }.must_raise CartoJson::InputError
|
22
|
+
lambda { CartoJson::Parser.parse MultiJson.encode({:junk => 'ok'}) }.must_raise CartoJson::InputError
|
23
|
+
CartoJson::Parser.parse(nil).must_equal nil
|
24
|
+
lambda { CartoJson::Parser.parse 'CATS ARE FUN' }.must_raise CartoJson::InputError
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should load point from JSON string' do
|
28
|
+
point = CartoJson::Parser.parse @json_point_one
|
29
|
+
|
30
|
+
point.class.must_equal CartoJson::Point
|
31
|
+
point.type.must_equal :point
|
32
|
+
point.send(LAT).must_equal 45.52
|
33
|
+
point.send(LNG).must_equal -122.681944
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should load point from hash' do
|
37
|
+
point = CartoJson::Parser.parse MultiJson.decode(@json_point_one, :symbolize_keys => true)
|
38
|
+
|
39
|
+
point.class.must_equal CartoJson::Point
|
40
|
+
point.type.must_equal :point
|
41
|
+
point.send(LAT).must_equal 45.52
|
42
|
+
point.send(LNG).must_equal -122.681944
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should load point from hash with string keys' do
|
46
|
+
point = CartoJson::Parser.parse MultiJson.decode(@json_point_one, :symbolize_keys => false)
|
47
|
+
|
48
|
+
point.class.must_equal CartoJson::Point
|
49
|
+
point.type.must_equal :point
|
50
|
+
point.send(LAT).must_equal 45.52
|
51
|
+
point.send(LNG).must_equal -122.681944
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should parse objects with multiple points' do
|
55
|
+
points = CartoJson.parse "[#{@json_point_one}, #{@json_point_two}]"
|
56
|
+
|
57
|
+
points.length.must_equal 2
|
58
|
+
points.first.send(LAT).must_equal 45.52
|
59
|
+
points.last.send(LNG).must_equal -122.681945
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/point_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'env.rb'
|
2
|
+
|
3
|
+
include CartoJson
|
4
|
+
|
5
|
+
describe CartoJson::Point do
|
6
|
+
before do
|
7
|
+
@args = {LAT => 45.52, LNG => -122.681944}
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should create a point with valid data' do
|
11
|
+
point = Point.new @args
|
12
|
+
point.type.must_equal :point
|
13
|
+
point.class.type.must_equal :point
|
14
|
+
|
15
|
+
hash = MultiJson.decode(point.to_json, :symbolize_keys => true)
|
16
|
+
hash[LAT].must_equal @args[LAT]
|
17
|
+
hash[LNG].must_equal @args[LNG]
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should fail with crazy lat and lng' do
|
21
|
+
lambda {
|
22
|
+
Point.new @args.merge(LAT => -31337)
|
23
|
+
}.must_raise CartoJson::InputError
|
24
|
+
|
25
|
+
lambda {
|
26
|
+
Point.new @args.merge(LNG => -31337)
|
27
|
+
}.must_raise CartoJson::InputError
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should fail with an array' do
|
31
|
+
lambda {
|
32
|
+
Point.new [1,2,3]
|
33
|
+
}.must_raise CartoJson::InputError
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'works with string keys' do
|
37
|
+
p = Point.new Hash[@args.map {|k,v| [k.to_sym, v]}]
|
38
|
+
p.send(LAT).class.must_equal Float
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'converts latitude and longitude to float' do
|
42
|
+
p = Point.new Hash[@args.map {|k,v| [k.to_sym, v.to_s]}]
|
43
|
+
p.send(LAT).class.must_equal Float
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns wkt' do
|
47
|
+
Point.new(@args).to_wkt.must_equal "POINT (#{@args[LNG]} #{@args[LAT]})"
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'env.rb'
|
2
|
+
|
3
|
+
include CartoJson
|
4
|
+
|
5
|
+
describe CartoJson::Polygon do
|
6
|
+
before do
|
7
|
+
@args = {:points => [
|
8
|
+
{LAT => 45.52, LNG => -122.681944},
|
9
|
+
{LAT => 45.53, LNG => -122.681945},
|
10
|
+
{LAT => 45.54, LNG => -122.681946}]}
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should create a polygon with valid data' do
|
14
|
+
p = Polygon.new @args
|
15
|
+
p.type.must_equal :polygon
|
16
|
+
p.class.type.must_equal :polygon
|
17
|
+
|
18
|
+
p.points.first.class.must_equal Point
|
19
|
+
|
20
|
+
hash = MultiJson.decode(p.to_json, :symbolize_keys => true)
|
21
|
+
|
22
|
+
hash[:points].length.must_equal 3
|
23
|
+
hash[:points].first[LAT].must_equal @args[:points].first[LAT]
|
24
|
+
hash[:points].first[LNG].must_equal @args[:points].first[LNG]
|
25
|
+
|
26
|
+
p.to_wkt.must_equal "POLYGON ((#{p.points.dup.push(p.points.first).collect {|p| "#{p.send(LNG)} #{p.send(LAT)}"}.join(', ')}))"
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should fail if less than three points' do
|
30
|
+
@args[:points].pop
|
31
|
+
lambda { Polygon.new @args }.must_raise InsufficientPointsError
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'env.rb'
|
2
|
+
|
3
|
+
include CartoJson
|
4
|
+
|
5
|
+
describe CartoJson::WKTParser do
|
6
|
+
it 'works with point' do
|
7
|
+
point = WKTParser.parse "POINT (2 1)"
|
8
|
+
point.class.must_equal Point
|
9
|
+
point.send(LAT).must_equal 1
|
10
|
+
point.send(LNG).must_equal 2
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'works with polygon' do
|
14
|
+
polygon = WKTParser.parse "POLYGON ((2 1, 4 3, 6 5, 2 1))"
|
15
|
+
polygon.class.must_equal Polygon
|
16
|
+
polygon.points.length.must_equal 3
|
17
|
+
polygon.points.first.must_equal Point.new(LAT => 1, LNG => 2)
|
18
|
+
polygon.points.last.must_equal Point.new(LAT => 5, LNG => 6)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'works with linestring' do
|
22
|
+
ls = WKTParser.parse "LINESTRING (2 1, 4 3)"
|
23
|
+
ls.class.must_equal LineString
|
24
|
+
ls.type.must_equal :linestring
|
25
|
+
ls.points.first.must_equal Point.new(LAT => 1, LNG => 2)
|
26
|
+
ls.points.last.must_equal Point.new(LAT => 3, LNG => 4)
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carto_json
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kyle Drake
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: multi_json
|
16
|
+
requirement: &70336033905880 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70336033905880
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70336033905460 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70336033905460
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: pry
|
38
|
+
requirement: &70336033905040 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70336033905040
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: minitest
|
49
|
+
requirement: &70336033904620 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70336033904620
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: json
|
60
|
+
requirement: &70336033904200 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70336033904200
|
69
|
+
description: Helpers for the CartoJSON specification
|
70
|
+
email:
|
71
|
+
- kyledrake@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE
|
79
|
+
- README
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- carto_json.gemspec
|
83
|
+
- lib/carto_json.rb
|
84
|
+
- lib/carto_json/circle.rb
|
85
|
+
- lib/carto_json/errors.rb
|
86
|
+
- lib/carto_json/line_string.rb
|
87
|
+
- lib/carto_json/parser.rb
|
88
|
+
- lib/carto_json/point.rb
|
89
|
+
- lib/carto_json/polygon.rb
|
90
|
+
- lib/carto_json/shape.rb
|
91
|
+
- lib/carto_json/utils.rb
|
92
|
+
- lib/carto_json/version.rb
|
93
|
+
- lib/carto_json/wkt_parser.rb
|
94
|
+
- spec/carto_json_spec.rb
|
95
|
+
- spec/circle_spec.rb
|
96
|
+
- spec/env.rb
|
97
|
+
- spec/line_string_spec.rb
|
98
|
+
- spec/parser_spec.rb
|
99
|
+
- spec/point_spec.rb
|
100
|
+
- spec/polygon_spec.rb
|
101
|
+
- spec/wkt_parser_spec.rb
|
102
|
+
homepage: ''
|
103
|
+
licenses: []
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 1.8.17
|
123
|
+
signing_key:
|
124
|
+
specification_version: 3
|
125
|
+
summary: Helpers for the CartoJSON spec
|
126
|
+
test_files:
|
127
|
+
- spec/carto_json_spec.rb
|
128
|
+
- spec/circle_spec.rb
|
129
|
+
- spec/env.rb
|
130
|
+
- spec/line_string_spec.rb
|
131
|
+
- spec/parser_spec.rb
|
132
|
+
- spec/point_spec.rb
|
133
|
+
- spec/polygon_spec.rb
|
134
|
+
- spec/wkt_parser_spec.rb
|
135
|
+
has_rdoc:
|