geoq 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9190180a02062cf1119badc7fd43d908bd1e5ba
4
+ data.tar.gz: ad237a21af279b4fd18e1dd0950f81e7986919da
5
+ SHA512:
6
+ metadata.gz: b3a19251027bf22b2696c5286cd797fa3c4e36725969259619be913a06012469a431df93e6d6dc9af4fa94051ba9b2510d9f14689b51753dd33b6b25547d9345
7
+ data.tar.gz: 38c00b909152f112bc6e7de00fd971e553e9dc44f33b9ae965b7201b4a6f72b1af7aa8bf22cbb55e3ddef53a226aa55b762cb92741923ae66132faa5fc960143
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,85 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ geoq (0.0.1)
5
+ gli (~> 2.17)
6
+ pr_geohash (~> 1.0)
7
+ rgeo (~> 1.0)
8
+ rgeo-geojson (~> 2.0)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ ansi (1.5.0)
14
+ aruba (0.14.5)
15
+ childprocess (>= 0.6.3, < 0.10.0)
16
+ contracts (~> 0.9)
17
+ cucumber (>= 1.3.19)
18
+ ffi (~> 1.9.10)
19
+ rspec-expectations (>= 2.99)
20
+ thor (~> 0.19)
21
+ backports (3.11.3)
22
+ builder (3.2.3)
23
+ childprocess (0.9.0)
24
+ ffi (~> 1.0, >= 1.0.11)
25
+ coderay (1.1.2)
26
+ contracts (0.16.0)
27
+ cucumber (3.1.0)
28
+ builder (>= 2.1.2)
29
+ cucumber-core (~> 3.1.0)
30
+ cucumber-expressions (~> 5.0.4)
31
+ cucumber-wire (~> 0.0.1)
32
+ diff-lcs (~> 1.3)
33
+ gherkin (~> 5.0)
34
+ multi_json (>= 1.7.5, < 2.0)
35
+ multi_test (>= 0.1.2)
36
+ cucumber-core (3.1.0)
37
+ backports (>= 3.8.0)
38
+ cucumber-tag_expressions (~> 1.1.0)
39
+ gherkin (>= 5.0.0)
40
+ cucumber-expressions (5.0.17)
41
+ cucumber-tag_expressions (1.1.1)
42
+ cucumber-wire (0.0.1)
43
+ diff-lcs (1.3)
44
+ ffi (1.9.23)
45
+ gherkin (5.0.0)
46
+ gli (2.17.1)
47
+ method_source (0.9.0)
48
+ minitest (5.11.3)
49
+ minitest-reporters (1.2.0)
50
+ ansi
51
+ builder
52
+ minitest (>= 5.0)
53
+ ruby-progressbar
54
+ multi_json (1.13.1)
55
+ multi_test (0.1.2)
56
+ pr_geohash (1.0.0)
57
+ pry (0.11.3)
58
+ coderay (~> 1.1.0)
59
+ method_source (~> 0.9.0)
60
+ rake (12.3.1)
61
+ rdoc (6.0.4)
62
+ rgeo (1.0.0)
63
+ rgeo-geojson (2.0.0)
64
+ rgeo (~> 1.0)
65
+ rspec-expectations (3.7.0)
66
+ diff-lcs (>= 1.2.0, < 2.0)
67
+ rspec-support (~> 3.7.0)
68
+ rspec-support (3.7.1)
69
+ ruby-progressbar (1.9.0)
70
+ thor (0.20.0)
71
+
72
+ PLATFORMS
73
+ ruby
74
+
75
+ DEPENDENCIES
76
+ aruba (~> 0.14)
77
+ geoq!
78
+ minitest (~> 5.11)
79
+ minitest-reporters (~> 1.2)
80
+ pry (~> 0.11)
81
+ rake (~> 12.3)
82
+ rdoc (~> 6.0)
83
+
84
+ BUNDLED WITH
85
+ 1.16.2
@@ -0,0 +1,55 @@
1
+ # geoq
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/geoq.svg)](https://badge.fury.io/rb/geoq)
4
+
5
+ [![Build Status](https://travis-ci.org/worace/geoq.svg?branch=master)](https://travis-ci.org/worace/geoq)
6
+
7
+ Geospatial Utility Belt.
8
+
9
+ ## Install
10
+
11
+ ```
12
+ gem install geoq
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ **[View the Usage Doc](https://github.com/worace/geoq/blob/master/usage.md)** for detailed usage examples.
18
+
19
+ To view the included help just run the base command:
20
+
21
+ ```
22
+ geoq
23
+ # or
24
+ geoq --help
25
+ ```
26
+
27
+ Or view help for a specific command:
28
+
29
+ ```
30
+ geoq wkt --help
31
+ ```
32
+
33
+ ## Feature Wishlist
34
+
35
+ * [X] Read WKT
36
+ * [X] Read GeoJSON
37
+ * [X] Read Geohash
38
+ * [X] Read Lat,Lon
39
+ * [X] Output GeoJSON geom
40
+ * [X] Output GeoJSON feature
41
+ * [X] Output GeoJSON featurecollection
42
+ * [X] Output geohash (point)
43
+ * [ ] Output geohashes (geometry -- covering geohashes)
44
+ * [ ] Output Geom Centroid
45
+ * [ ] Output Geom area
46
+ * [ ] Output Geom perimeter
47
+ * [X] Output Geohash Children
48
+ * [X] Output Geohash Neighbors
49
+ * [ ] Output results to gist (geojson only)
50
+ * [X] Literate-style Usage doc with checked examples
51
+
52
+ ## Releasing
53
+
54
+ ```
55
+ ```
@@ -0,0 +1,6 @@
1
+ = geoq
2
+
3
+ Describe your project here
4
+
5
+ :include:geoq.rdoc
6
+
@@ -0,0 +1,45 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ require 'cucumber'
6
+ require 'cucumber/rake/task'
7
+ Rake::RDocTask.new do |rd|
8
+ rd.main = "README.rdoc"
9
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
10
+ rd.title = 'Your application title'
11
+ end
12
+
13
+ spec = eval(File.read('geoq.gemspec'))
14
+
15
+ Gem::PackageTask.new(spec) do |pkg|
16
+ end
17
+ CUKE_RESULTS = 'results.html'
18
+ CLEAN << CUKE_RESULTS
19
+ desc 'Run features'
20
+ Cucumber::Rake::Task.new(:features) do |t|
21
+ opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
22
+ opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
23
+ t.cucumber_opts = opts
24
+ t.fork = false
25
+ end
26
+
27
+ desc 'Run features tagged as work-in-progress (@wip)'
28
+ Cucumber::Rake::Task.new('features:wip') do |t|
29
+ tag_opts = ' --tags ~@pending'
30
+ tag_opts = ' --tags @wip'
31
+ t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
32
+ t.fork = false
33
+ end
34
+
35
+ task :cucumber => :features
36
+ task 'cucumber:wip' => 'features:wip'
37
+ task :wip => 'features:wip'
38
+ require 'rake/testtask'
39
+ Rake::TestTask.new(:test) do |t|
40
+ t.libs << "test"
41
+ t.libs << "lib"
42
+ t.test_files = FileList["test/**/*_test.rb"]
43
+ end
44
+
45
+ task :default => [:test]
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ begin # XXX: Remove this begin/rescue before distributing your app
4
+ require 'geoq'
5
+ rescue LoadError
6
+ STDERR.puts "In development, you need to use `bundle exec bin/geoq` to run your app"
7
+ STDERR.puts "At install-time, RubyGems will make sure lib, etc. are in the load path"
8
+ STDERR.puts "Feel free to remove this message from bin/geoq now"
9
+ exit 64
10
+ end
11
+
12
+ include GLI::App
13
+
14
+ program_desc <<-desc
15
+ Geospatial utility belt
16
+
17
+ geoq is a command-line tool for converting between various
18
+ GIS serialization formats. For example:
19
+
20
+ echo 9q5 | geoq gj geometry
21
+
22
+ Will output the geohash 9q5 as a geojson geometry.
23
+
24
+ Most commands will accept a Lat/Lon (comma-separated), a Geohash
25
+ (base 32 encoded), a WKT, or a GeoJSON input.
26
+
27
+ The tool should recognize the input type based on its format.
28
+
29
+ Commands expect one geo entity per line.
30
+
31
+ See COMMANDS for more possible commands.
32
+
33
+ See geoq <COMMAND> --help for more info on a given command.
34
+ desc
35
+
36
+ version Geoq::VERSION
37
+
38
+ subcommand_option_handling :normal
39
+ arguments :strict
40
+
41
+
42
+ desc 'Convert to and manipulate GeoJSON.'
43
+ # desc 'Treat all lines of input as a single collection'
44
+ # switch [:s,:slurp]
45
+ command :gj do |c|
46
+ c.desc "Output entity as a geojson geometry"
47
+ c.command :geometry do |c|
48
+ c.action do |global_options,options,args|
49
+ Geoq::GeomReader.new(STDIN).each do |entity|
50
+ puts entity.to_geojson
51
+ end
52
+ end
53
+ end
54
+
55
+ c.desc "Output entity as a geojson feature"
56
+ c.command :feature do |c|
57
+ c.action do |global_options,options,args|
58
+ Geoq::GeomReader.new(STDIN).each do |entity|
59
+ puts entity.to_geojson(true)
60
+ end
61
+ end
62
+ end
63
+
64
+ c.desc "Combine entities into a geojson feature collection"
65
+ c.command :fc do |c|
66
+ c.action do |global_options,options,args|
67
+ entities = Geoq::GeomReader.new(STDIN)
68
+ puts Geoq::Commands::GeoJson::FeatureCollection.new(entities).output
69
+ end
70
+ end
71
+ end
72
+
73
+ desc "Output entity as WKT"
74
+ command :wkt do |c|
75
+ c.action do |global_options,options,args|
76
+ Geoq::GeomReader.new(STDIN).each do |geom|
77
+ puts geom.to_wkt
78
+ end
79
+ end
80
+ end
81
+
82
+ desc "Encode and manipulate geometries as GeoHashes"
83
+ command :gh do |c|
84
+ c.desc "Encode supplied point as a GeoHash at the specified level. Only supports lat,lon points."
85
+ c.arg "level", required: true
86
+ c.command :point do |c|
87
+ c.action do |global_options,options,args|
88
+ reader = Geoq::GeomReader.new(STDIN)
89
+ Geoq::Commands::GeoHash::Point.new(reader, global_options, options, args).output.each do |gh|
90
+ puts gh
91
+ end
92
+ end
93
+ end
94
+
95
+ c.desc "Output the 32 children of the supplied Geohash."
96
+ c.command :children do |c|
97
+ c.action do |global_options,options,args|
98
+ reader = Geoq::GeomReader.new(STDIN)
99
+ Geoq::Commands::GeoHash::Children.new(reader, global_options, options, args).output.each do |gh|
100
+ puts gh
101
+ end
102
+ end
103
+ end
104
+
105
+ c.desc "Output the 8 neighbors of the supplied Geohash."
106
+ c.command :neighbors do |c|
107
+ c.switch :i, "inclusive",
108
+ desc: "Include the supplied geohash in the output, giving a 3x3 grid centered on the geohash. Default: False",
109
+ negatable: false
110
+ c.action do |global_options,options,args|
111
+ reader = Geoq::GeomReader.new(STDIN)
112
+ Geoq::Commands::GeoHash::Neighbors.new(reader, global_options, options, args).output.each do |gh|
113
+ puts gh
114
+ end
115
+ end
116
+ end
117
+
118
+ end
119
+
120
+ pre do |global,command,options,args|
121
+ # Pre logic here
122
+ # Return true to proceed; false to abort and not call the
123
+ # chosen command
124
+ # Use skips_pre before a command to skip this block
125
+ # on that command only
126
+ true
127
+ end
128
+
129
+ post do |global,command,options,args|
130
+ # Post logic here
131
+ # Use skips_post before a command to skip this
132
+ # block on that command only
133
+ end
134
+
135
+ on_error do |exception|
136
+ # Error logic here
137
+ # return false to skip default error handling
138
+ true
139
+ end
140
+
141
+ exit run(ARGV)
@@ -0,0 +1,29 @@
1
+ # Ensure we require the local version and not one we might have installed already
2
+ require File.join([File.dirname(__FILE__),'lib','geoq','version.rb'])
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'geoq'
5
+ s.version = Geoq::VERSION
6
+ s.author = 'Horace Williams'
7
+ s.email = 'horace@worace.works'
8
+ s.homepage = 'https://github.com/worace/geoq'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.license = 'MIT'
11
+ s.summary = 'geoq is a command-line utility for GIS format conversion and common GIS operations'
12
+ s.files = `git ls-files`.split('
13
+ ')
14
+ s.require_paths << 'lib'
15
+ s.has_rdoc = false
16
+ s.bindir = 'bin'
17
+ s.executables << 'geoq'
18
+
19
+ s.add_development_dependency('rake', '~>12.3')
20
+ s.add_development_dependency('aruba', '~>0.14')
21
+ s.add_development_dependency('minitest', '~> 5.11')
22
+ s.add_development_dependency('minitest-reporters', '~>1.2')
23
+ s.add_development_dependency('pry', '~>0.11')
24
+
25
+ s.add_runtime_dependency('gli','~>2.17')
26
+ s.add_runtime_dependency('rgeo', '~>1.0')
27
+ s.add_runtime_dependency('rgeo-geojson', '~>2.0')
28
+ s.add_runtime_dependency('pr_geohash', '~>1.0')
29
+ end
@@ -0,0 +1,7 @@
1
+ require 'geoq/version.rb'
2
+ require 'geoq/geom_reader.rb'
3
+ require 'geoq/commands/base.rb'
4
+ require 'geoq/commands/geohash.rb'
5
+ require 'geoq/commands/geojson.rb'
6
+ require 'geoq/entity.rb'
7
+ require 'geoq/errors.rb'
@@ -0,0 +1,17 @@
1
+ module Geoq
2
+ module Commands
3
+ class Base
4
+ attr_reader :global_opts, :opts, :args, :instream
5
+ def initialize(instream, global_opts = {}, opts = {}, args = [])
6
+ @global_opts = global_opts
7
+ @opts = opts
8
+ @args = args
9
+ @instream = instream
10
+ end
11
+
12
+ def output
13
+ raise "Not implemented"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ module Geoq
2
+ module Commands
3
+ module GeoHash
4
+ class Point < Base
5
+ def level
6
+ args.first.to_i
7
+ end
8
+
9
+ def output
10
+ Enumerator.new do |e|
11
+ instream.each do |entity|
12
+ e << entity.gh_string(level)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ class Children < Base
19
+ def output
20
+ Enumerator.new do |e|
21
+ instream.each do |entity|
22
+ entity.gh_children.each do |gh|
23
+ e << gh
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ class Neighbors < Base
31
+ def output
32
+ Enumerator.new do |e|
33
+ instream.each do |entity|
34
+ entity.gh_neighbors(opts[:inclusive]).each do |gh|
35
+ e << gh
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ module Geoq
2
+ module Commands
3
+ module GeoJson
4
+ class FeatureCollection < Base
5
+ def output
6
+ Geoq::FeatureCollection.new(instream).to_geojson
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,97 @@
1
+ require "rgeo/geo_json"
2
+ require "pr_geohash"
3
+ require "rgeo"
4
+
5
+ module Geoq
6
+ class Entity
7
+ attr_reader :entity, :raw
8
+
9
+ def initialize(entity, raw)
10
+ @entity = entity
11
+ @raw = raw
12
+ end
13
+
14
+ def as_geojson(feature = false)
15
+ geom = RGeo::GeoJSON.encode(entity)
16
+ if feature
17
+ {type: "Feature",
18
+ properties: {},
19
+ geometry: geom}
20
+ else
21
+ geom
22
+ end
23
+ end
24
+
25
+ def to_geojson(feature = false)
26
+ as_geojson(feature).to_json
27
+ end
28
+
29
+ def to_wkt
30
+ entity.as_text
31
+ end
32
+
33
+ def gh_string(level)
34
+ if entity.dimension == 0
35
+ GeoHash.encode(entity.y, entity.x, level)
36
+ else
37
+ raise RepresentationError.new("GeoHash representation not supported for #{entity.to_s}")
38
+ end
39
+ end
40
+
41
+ def gh_children
42
+ raise RepresentationError.new("GeoHash children not supported for #{entity.to_s}")
43
+ end
44
+
45
+ def gh_neighbors(inclusive = false)
46
+ raise RepresentationError.new("GeoHash neighbors not supported for #{entity.to_s}")
47
+ end
48
+ end
49
+
50
+ class Geohash < Entity
51
+ def gh_children
52
+ BASE_32.chars.map { |char| raw + char }
53
+ end
54
+
55
+ def gh_neighbors(inclusive = false)
56
+ if inclusive
57
+ [raw] + GeoHash.neighbors(raw)
58
+ else
59
+ GeoHash.neighbors(raw)
60
+ end
61
+ end
62
+ end
63
+
64
+ class Wkt < Entity
65
+ end
66
+
67
+ class LatLon < Entity
68
+ end
69
+
70
+ class GeoJson < Entity
71
+ def as_geojson(feature = false)
72
+ if feature
73
+ if entity.is_a?(RGeo::GeoJSON::Feature)
74
+ RGeo::GeoJSON.encode(entity)
75
+ else
76
+ {type: "Feature",
77
+ properties: {},
78
+ geometry: RGeo::GeoJSON.encode(entity)}
79
+ end
80
+ else
81
+ RGeo::GeoJSON.encode(entity)
82
+ end
83
+ end
84
+ end
85
+
86
+ class FeatureCollection
87
+ attr_reader :entities
88
+ def initialize(entities)
89
+ @entities = entities
90
+ end
91
+
92
+ def to_geojson
93
+ {type: "FeatureCollection",
94
+ features: entities.map { |e| e.as_geojson(true) } }.to_json
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,4 @@
1
+ module Geoq
2
+ class RepresentationError < ArgumentError
3
+ end
4
+ end
@@ -0,0 +1,71 @@
1
+ require "pr_geohash"
2
+ require "rgeo"
3
+ require "rgeo/geo_json"
4
+
5
+ module Geoq
6
+ BASE_32 = %w(0 1 2 3 4 5 6 7 8 9 b c d e f g h j
7
+ k m n p q r s t u v w x y z).join("")
8
+ class GeomReader
9
+ attr_reader :wkt
10
+
11
+ GH_REGEX = Regexp.new(/\A[#{BASE_32}]+\z/)
12
+
13
+ LAT_LON_REGEX = /\A-?\d+\.?\d*,-?\d+\.?\d*\z/
14
+
15
+ include Enumerable
16
+
17
+ def initialize(instream)
18
+ @instream = instream
19
+ @wkt = RGeo::WKRep::WKTParser.new
20
+ @factory = RGeo::Cartesian.factory
21
+ end
22
+
23
+ def each(&block)
24
+ instream.each_line do |l|
25
+ block.call(decode(l))
26
+ end
27
+ end
28
+
29
+ def decode(line)
30
+ if geohash?(line)
31
+ (lat1, lon1), (lat2, lon2) = GeoHash.decode(line)
32
+ p1 = factory.point(lon1, lat1)
33
+ p2 = factory.point(lon2, lat2)
34
+ geom = RGeo::Cartesian::BoundingBox.create_from_points(p1, p2).to_geometry
35
+ Geohash.new(geom, strip_whitespace(line))
36
+ elsif geojson?(line)
37
+ GeoJson.new(RGeo::GeoJSON.decode(line), line)
38
+ elsif latlon?(line)
39
+ LatLon.new(factory.point(*strip_whitespace(line).split(",").map(&:to_f).reverse), line)
40
+ else
41
+ Wkt.new(wkt.parse(line), line)
42
+ end
43
+ end
44
+
45
+ def strip_whitespace(line)
46
+ line.gsub(/\s+/, "").downcase
47
+ end
48
+
49
+ def geohash?(line)
50
+ !!GH_REGEX.match(strip_whitespace(line))
51
+ end
52
+
53
+ def geojson?(line)
54
+ line.lstrip.start_with?("{")
55
+ end
56
+
57
+ def latlon?(line)
58
+ !!LAT_LON_REGEX.match(strip_whitespace(line))
59
+ end
60
+
61
+ private
62
+
63
+ def instream
64
+ @instream
65
+ end
66
+
67
+ def factory
68
+ @factory
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ module Geoq
2
+ VERSION = '0.0.1.pre'
3
+ end
@@ -0,0 +1,78 @@
1
+ require "test_helper"
2
+ require "json"
3
+
4
+ module Geoq
5
+ class CommandsTest < Minitest::Test
6
+ def test_feature_collection
7
+ fc = Geoq::Commands::GeoJson::FeatureCollection.new(TestData.mixed_stream)
8
+ json = JSON.parse(fc.output)
9
+ assert_equal "FeatureCollection", json["type"]
10
+ assert_equal ["type", "features"].sort, json.keys.sort
11
+ features = json["features"]
12
+ assert_equal 5, features.count
13
+
14
+ # encodes properties
15
+ assert_equal [{}, {}, {}, {"a" => "b"}, {}], features.map { |f| f["properties"] }
16
+ assert_equal Hash.new, features[0]["properties"]
17
+ assert_equal Hash.new, features[1]["properties"]
18
+ assert_equal Hash.new, features[2]["properties"]
19
+ assert_equal({"a" => "b"}, features[3]["properties"])
20
+
21
+ assert_equal ["Polygon", "Point", "Point", "Point", "Point"], features.map { |f| f["geometry"]["type"] }
22
+
23
+ gh = [[[-119.53125, 33.75], [-118.125, 33.75], [-118.125, 35.15625], [-119.53125, 35.15625], [-119.53125, 33.75]]]
24
+ assert_equal [gh, [0.0,1.0], [1.0, 2.0], [3.0, 4.0], [-118.3, 34.52]], features.map { |f| f["geometry"]["coordinates"] }
25
+ end
26
+
27
+ def test_geohash_point
28
+ input = TestData.stream(["0,0", "34, -118"])
29
+ command = Geoq::Commands::GeoHash::Point.new(input, {}, {}, ["4"])
30
+ assert_equal ["7zzz", "9qh1"], command.output.to_a
31
+ end
32
+
33
+ def test_gh_point_raises_for_geometry
34
+ input = TestData.mixed_stream.take(1)
35
+ command = Geoq::Commands::GeoHash::Point.new(input, {}, {}, ["4"])
36
+ assert_raises Geoq::RepresentationError do
37
+ command.output.to_a
38
+ end
39
+ end
40
+
41
+ def test_geohash_children
42
+ input = TestData.stream(["9q"])
43
+ command = Geoq::Commands::GeoHash::Children.new(input)
44
+ children = ["9q0", "9q1", "9q2", "9q3", "9q4", "9q5", "9q6",
45
+ "9q7", "9q8", "9q9", "9qb", "9qc", "9qd", "9qe",
46
+ "9qf", "9qg", "9qh", "9qj", "9qk", "9qm", "9qn",
47
+ "9qp", "9qq", "9qr", "9qs", "9qt", "9qu", "9qv",
48
+ "9qw", "9qx", "9qy", "9qz"]
49
+ assert_equal children, command.output.to_a
50
+ end
51
+
52
+ def test_geohash_children_raises_for_other_geoms
53
+ TestData.mixed_stream.reject do |entity|
54
+ entity.is_a?(Geohash)
55
+ end.each do |i|
56
+ s = TestData.stream([i.raw])
57
+ command = Geoq::Commands::GeoHash::Children.new(s)
58
+ assert_raises Geoq::RepresentationError do
59
+ command.output.to_a
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_geohash_neighbors
65
+ input = TestData.stream(["9q"])
66
+ command = Geoq::Commands::GeoHash::Neighbors.new(input)
67
+ neighbors = ["9r", "9x", "9w", "9t", "9m", "9j", "9n", "9p"]
68
+ assert_equal neighbors, command.output.to_a
69
+ end
70
+
71
+ def test_geohash_neighbors_inclusive
72
+ input = TestData.stream(["9q"])
73
+ command = Geoq::Commands::GeoHash::Neighbors.new(input, {}, {inclusive: true})
74
+ neighbors = ["9q", "9r", "9x", "9w", "9t", "9m", "9j", "9n", "9p"]
75
+ assert_equal neighbors, command.output.to_a
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,56 @@
1
+ require "test_helper"
2
+ require "json"
3
+
4
+ module Geoq
5
+ class GeomReaderTest < Minitest::Test
6
+ attr_reader :reader
7
+
8
+ def setup
9
+ r,w = IO.pipe
10
+ w.close
11
+ @reader = Geoq::GeomReader.new(r)
12
+ end
13
+
14
+ def test_recognizes_geohashes
15
+ assert reader.geohash?("9q5")
16
+ assert reader.geohash?("9Q5")
17
+ assert reader.geohash?(" 9Q5 ")
18
+ refute reader.geohash?(" 9aQ5 ")
19
+ assert reader.geohash?("u58seqshdz50")
20
+ end
21
+
22
+ def test_recognizes_geojson
23
+ assert reader.geojson?({type: "Point", coordinates: [0,1]}.to_json)
24
+ refute reader.geojson?("a")
25
+ end
26
+
27
+ def test_parse_objects
28
+ parsed = TestData.mixed_stream.to_a
29
+ assert parsed[0].is_a? Geoq::Geohash
30
+ assert parsed[1].is_a? Geoq::GeoJson
31
+ assert parsed[2].is_a? Geoq::Wkt
32
+ assert parsed[3].is_a? Geoq::GeoJson
33
+ assert parsed[4].is_a? Geoq::LatLon
34
+ end
35
+
36
+ def test_parsing_lat_lons
37
+ assert reader.latlon?("0,0")
38
+ assert reader.latlon?("0, 0")
39
+ assert reader.latlon?("123.456,98.2")
40
+ assert reader.latlon?(" -123.456,-98.2 ")
41
+ end
42
+
43
+ def test_correct_lat_lon_ordering
44
+ entities = TestData.stream(["1,2", "34, -118"]).to_a
45
+ assert_equal entities[0].entity.x, 2
46
+ assert_equal entities[0].entity.y, 1
47
+ assert_equal entities[1].entity.x, -118
48
+ assert_equal entities[1].entity.y, 34
49
+ end
50
+
51
+ def test_lat_lon_geohash_conversion
52
+ point = TestData.stream(["34, -118"]).first
53
+ assert_equal "9qh1", point.gh_string(4)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
+ require "geoq"
3
+
4
+ require "minitest/autorun"
5
+ require "minitest/reporters"
6
+ require "minitest/spec"
7
+
8
+ Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new
9
+
10
+ module Geoq::TestData
11
+ def self.stream(strings)
12
+ r,w = IO.pipe
13
+ strings.each do |s|
14
+ w.puts(s)
15
+ end
16
+ w.close
17
+ Geoq::GeomReader.new(r)
18
+ end
19
+
20
+ def self.mixed_stream
21
+ inputs = ["9q5",
22
+ {type: "Point", coordinates: [0,1]}.to_json,
23
+ "POINT (1.0 2.0)",
24
+ {type: "Feature", properties: {a: "b"}, geometry: {type: "Point", coordinates: [3,4]}}.to_json,
25
+ "34.52,-118.3"]
26
+ stream(inputs)
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ require "test_helper"
2
+
3
+ module Geoq
4
+ class UsageTest < Minitest::Test
5
+ def script_setup
6
+ File.read("./usage.md").match(/```setup\n(.+)\n```/)[1]
7
+ end
8
+
9
+ def examples
10
+ File.read("./usage.md").scan(/```example\n(.*?)```\n/m).to_a.flatten.map { |match| match.split("\n=> ") }
11
+ end
12
+
13
+ def setup
14
+ end
15
+
16
+ def test_reads_examples
17
+ assert_equal 15, examples.count
18
+ end
19
+
20
+ def checked_command(command)
21
+ result = `#{command}`
22
+ if $? != 0
23
+ raise RuntimeError.new("Command #{command} exited with non-zero response code.")
24
+ end
25
+ result
26
+ end
27
+
28
+ def test_run_examples
29
+ examples.each do |command, expected_output|
30
+ result = checked_command(command)
31
+ assert_equal expected_output, result, "Checked example: #{command} failed"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,150 @@
1
+ # Geoq Usage
2
+
3
+ ```setup
4
+ alias geoqqq="bundle exec geoq" &&
5
+ ```
6
+
7
+ ## GeoJSON (`geoq gj`)
8
+
9
+ Output a geo feature as a GeoJSON Geometry
10
+
11
+ ```example
12
+ echo 9q5 | bundle exec bin/geoq gj geometry
13
+ => {"type":"Polygon","coordinates":[[[-119.53125,33.75],[-118.125,33.75],[-118.125,35.15625],[-119.53125,35.15625],[-119.53125,33.75]]]}
14
+ ```
15
+
16
+ Output a geo feature as a GeoJSON Feature
17
+
18
+ ```example
19
+ echo 9q5 | bundle exec bin/geoq gj feature
20
+ => {"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-119.53125,33.75],[-118.125,33.75],[-118.125,35.15625],[-119.53125,35.15625],[-119.53125,33.75]]]}}
21
+ ```
22
+
23
+ Combine 1 or more geo features into a GeoJSON Feature Collection
24
+
25
+ ```example
26
+ printf "9q5\n9q4\n" | bundle exec bin/geoq gj fc
27
+ => {"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-119.53125,33.75],[-118.125,33.75],[-118.125,35.15625],[-119.53125,35.15625],[-119.53125,33.75]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-120.9375,33.75],[-119.53125,33.75],[-119.53125,35.15625],[-120.9375,35.15625],[-120.9375,33.75]]]}}]}
28
+ ```
29
+
30
+ Converts Geohashes, WKTs, Lat/Lons, and GeoJSON into GeoJSON
31
+
32
+ ```example
33
+ echo 9q5 | bundle exec bin/geoq gj geometry
34
+ => {"type":"Polygon","coordinates":[[[-119.53125,33.75],[-118.125,33.75],[-118.125,35.15625],[-119.53125,35.15625],[-119.53125,33.75]]]}
35
+ ```
36
+
37
+ ```example
38
+ echo "POINT (1.0 2.0)" | bundle exec bin/geoq gj geometry
39
+ => {"type":"Point","coordinates":[1.0,2.0]}
40
+ ```
41
+
42
+ ```example
43
+ echo "34.52,-118.3" | bundle exec bin/geoq gj geometry
44
+ => {"type":"Point","coordinates":[-118.3,34.52]}
45
+ ```
46
+
47
+ ```example
48
+ echo '{"type":"Point","coordinates":[-118.3,34.52]}' | bundle exec bin/geoq gj geometry
49
+ => {"type":"Point","coordinates":[-118.3,34.52]}
50
+ ```
51
+
52
+ ## Geohashes (`geoq gh`)
53
+
54
+ Convert a point to a geohash at specified level
55
+
56
+ ```example
57
+ echo "34,-118" | bundle exec bin/geoq gh point 4
58
+ => 9qh1
59
+ ```
60
+
61
+ Get children of a geohash
62
+
63
+ ```example
64
+ echo 9qh1 | bundle exec bin/geoq gh children
65
+ => 9qh10
66
+ 9qh11
67
+ 9qh12
68
+ 9qh13
69
+ 9qh14
70
+ 9qh15
71
+ 9qh16
72
+ 9qh17
73
+ 9qh18
74
+ 9qh19
75
+ 9qh1b
76
+ 9qh1c
77
+ 9qh1d
78
+ 9qh1e
79
+ 9qh1f
80
+ 9qh1g
81
+ 9qh1h
82
+ 9qh1j
83
+ 9qh1k
84
+ 9qh1m
85
+ 9qh1n
86
+ 9qh1p
87
+ 9qh1q
88
+ 9qh1r
89
+ 9qh1s
90
+ 9qh1t
91
+ 9qh1u
92
+ 9qh1v
93
+ 9qh1w
94
+ 9qh1x
95
+ 9qh1y
96
+ 9qh1z
97
+ ```
98
+
99
+ Get neighbors of a geohash
100
+
101
+ ```example
102
+ echo 9qh1 | bundle exec bin/geoq gh neighbors
103
+ => 9qh4
104
+ 9qh6
105
+ 9qh3
106
+ 9qh2
107
+ 9qh0
108
+ 9q5b
109
+ 9q5c
110
+ 9q5f
111
+ ```
112
+
113
+ Include the original geohash in the neighbors list:
114
+
115
+ ```example
116
+ echo 9qh1 | bundle exec bin/geoq gh neighbors -i
117
+ => 9qh1
118
+ 9qh4
119
+ 9qh6
120
+ 9qh3
121
+ 9qh2
122
+ 9qh0
123
+ 9q5b
124
+ 9q5c
125
+ 9q5f
126
+ ```
127
+
128
+ ## WKT (`geoq wkt`)
129
+
130
+ Converts Geohashes, WKTs, Lat/Lons, and GeoJSON into GeoJSON
131
+
132
+ ```example
133
+ echo 9q5 | bundle exec bin/geoq wkt
134
+ => POLYGON ((-119.53125 33.75, -118.125 33.75, -118.125 35.15625, -119.53125 35.15625, -119.53125 33.75))
135
+ ```
136
+
137
+ ```example
138
+ echo "POINT (1.0 2.0)" | bundle exec bin/geoq wkt
139
+ => POINT (1.0 2.0)
140
+ ```
141
+
142
+ ```example
143
+ echo "34.52,-118.3" | bundle exec bin/geoq wkt
144
+ => POINT (-118.3 34.52)
145
+ ```
146
+
147
+ ```example
148
+ echo '{"type":"Point","coordinates":[-118.3,34.52]}' | bundle exec bin/geoq wkt
149
+ => POINT (-118.3 34.52)
150
+ ```
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geoq
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre
5
+ platform: ruby
6
+ authors:
7
+ - Horace Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-05-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '12.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '12.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aruba
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.11'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.11'
83
+ - !ruby/object:Gem::Dependency
84
+ name: gli
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.17'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.17'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rgeo
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rgeo-geojson
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pr_geohash
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.0'
139
+ description:
140
+ email: horace@worace.works
141
+ executables:
142
+ - geoq
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".travis.yml"
148
+ - Gemfile
149
+ - Gemfile.lock
150
+ - README.md
151
+ - README.rdoc
152
+ - Rakefile
153
+ - bin/geoq
154
+ - geoq.gemspec
155
+ - lib/geoq.rb
156
+ - lib/geoq/commands/base.rb
157
+ - lib/geoq/commands/geohash.rb
158
+ - lib/geoq/commands/geojson.rb
159
+ - lib/geoq/entity.rb
160
+ - lib/geoq/errors.rb
161
+ - lib/geoq/geom_reader.rb
162
+ - lib/geoq/version.rb
163
+ - test/commands_test.rb
164
+ - test/geom_reader_test.rb
165
+ - test/test_helper.rb
166
+ - test/usage_test.rb
167
+ - usage.md
168
+ homepage: https://github.com/worace/geoq
169
+ licenses:
170
+ - MIT
171
+ metadata: {}
172
+ post_install_message:
173
+ rdoc_options: []
174
+ require_paths:
175
+ - lib
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">"
185
+ - !ruby/object:Gem::Version
186
+ version: 1.3.1
187
+ requirements: []
188
+ rubyforge_project:
189
+ rubygems_version: 2.6.14.1
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: geoq is a command-line utility for GIS format conversion and common GIS operations
193
+ test_files: []