geohash36 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.project.yaml +8 -0
- data/FAQ.md +11 -0
- data/Gemfile +3 -0
- data/README.md +69 -8
- data/{lib → examples}/demo.rb +0 -0
- data/geohash36.gemspec +5 -17
- data/lib/geohash36.rb +124 -81
- data/lib/geohash36/interface/rake/rspec.rb +26 -3
- data/lib/geohash36/interface/thor/info.thor +0 -1
- data/lib/geohash36/library/interval.rb +117 -75
- data/spec/spec_helper.rb +1 -1
- metadata +6 -116
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e9125eee74fa553d17038f5a61e83545bd978a5
|
4
|
+
data.tar.gz: 9dba53c12cc8097ae6cf76de5c618232c7ad1a92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7549cccdb826d55ae820d5d87d592040ba71822b54b160be3cf23f50fcac5569068e48f00299e123b51380bfe10b4d55a3ef52ab6ec549a0b2dd1f992ddd1a39
|
7
|
+
data.tar.gz: c0edded79c561df5d92b89f0104d5d399b0ba3aad04c86880f241f79646e60e243ee518a42bc96b4f6729282ce5e605346e2361c05ca1872b119fbc693735cbb
|
data/.project.yaml
ADDED
data/FAQ.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
Q: Why do you have a Gemfile and a gemspec if this is a gem?
|
3
|
+
A: For local development its quite convenient to have a Gemfile and Gemfile.lock, but once done for
|
4
|
+
publishing etc. you just need the gemspec. This kind of hybrid approach is a bit unorthodox but
|
5
|
+
useful. Once the software is mature its ok to remove gemfile, lock file, and other pinnings since
|
6
|
+
your gem is supposed to run everywhere.
|
7
|
+
|
8
|
+
Q: How is this different from Geohash 32?
|
9
|
+
A: Geohash 36 utilizes radix 36 format, which allows a slightly better precision then geohash 32
|
10
|
+
radix format. Also, the entire purpose is for machine readability in urls not human readability.
|
11
|
+
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
# Geohash36
|
2
|
-
Version 0.3.
|
2
|
+
Version 0.3.1-18-g41749f0
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/geohash36.svg)](http://badge.fury.io/rb/geohash36)
|
5
|
+
[![License](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://img.shields.io/badge/license-MIT-brightgreen.svg)
|
6
|
+
|
7
|
+
Geohash36 is a complete solution for geohashing coordinates. What is a geohash? For example, the
|
8
|
+
coordinate pair 40.689167, -74.044444 (NY City) produces a slightly shorter hash 9LVB4BH89g, which
|
9
|
+
can be used in the URL http://geo36.org/9LVB4BH89g
|
6
10
|
|
7
11
|
The main usages of Geohashes are
|
8
|
-
|
9
|
-
*
|
12
|
+
|
13
|
+
* as a unique identifier
|
14
|
+
* represent point data e.g. in databases
|
15
|
+
|
10
16
|
|
11
17
|
## More about geohashing
|
12
18
|
|
@@ -37,9 +43,11 @@ typefaces.
|
|
37
43
|
Alphabet conversion table [2]
|
38
44
|
|
39
45
|
Decimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
46
|
+
|
40
47
|
Geohash-36 2 3 4 5 6 7 8 9 b B C d D F g G h H
|
41
48
|
|
42
49
|
Decimal 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
50
|
+
|
43
51
|
Geohash-36 j J K l L M n N P q Q r R t T V W X
|
44
52
|
|
45
53
|
Each character represents a further subdivision in a 6 by 6 grid - starting at the North-West
|
@@ -49,9 +57,13 @@ The Statue of Liberty, at coordinates 40.689167, -74.044444, is encoded as 9LVB4
|
|
49
57
|
decoding equates to 40.689168,-74.044445.
|
50
58
|
|
51
59
|
[1] http://geohash.org/
|
60
|
+
|
52
61
|
[2] http://en.wikipedia.org/wiki/Geohash
|
62
|
+
|
53
63
|
[2] http://en.wikipedia.org/wiki/Geohash-36
|
64
|
+
|
54
65
|
[3] http://geo36.org/
|
66
|
+
|
55
67
|
[4] http://www.pubnub.com/blog/wp-content/uploads/2014/05/ProximityChat1.jpg
|
56
68
|
|
57
69
|
|
@@ -71,8 +83,57 @@ gem 'geohash36', git: 'https://github.com/clothesnetwork/geohash36'
|
|
71
83
|
|
72
84
|
## Usage
|
73
85
|
|
74
|
-
|
86
|
+
As library
|
87
|
+
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
2.1.2 :001 > require 'geohash36'
|
91
|
+
=> true
|
92
|
+
2.1.2 :002 > coordinates = { latitude: 40.689167, longitude: -74.044444 }
|
93
|
+
=> {:latitude=>40.689167, :longitude=>-74.044444}
|
94
|
+
2.1.2 :004 > hash = Geohash36.to_geohash( coordinates )
|
95
|
+
=> "9LVB4BH89g"
|
96
|
+
2.1.2 :005 > resolved = Geohash36.to_coords( hash )
|
97
|
+
=> {:latitude=>40.689168, :longitude=>-74.044445}
|
98
|
+
```
|
99
|
+
|
100
|
+
or from the command line
|
101
|
+
|
102
|
+
```sh
|
103
|
+
~# geohash36
|
104
|
+
|
105
|
+
Commands:
|
106
|
+
geohash36 coords GEOHASH [ACCURACY] # Get coordinates for geohash with specified accuracy
|
107
|
+
geohash36 hash LATITUDE LONGITUDE # Get geohash36 from coordinates
|
108
|
+
geohash36 help [COMMAND] # Describe available commands or one specific command
|
109
|
+
```
|
110
|
+
|
111
|
+
```sh
|
112
|
+
~# geohash36 hash 40.689167 -74.044445
|
113
|
+
|
114
|
+
9LVB4BH89g
|
115
|
+
```
|
116
|
+
```sh
|
117
|
+
~# geohash36 coords 9LVB4BH89g
|
118
|
+
|
119
|
+
Latitude: 40.689
|
120
|
+
Longitude: -74.044
|
121
|
+
```
|
122
|
+
|
123
|
+
## Contributing
|
124
|
+
|
125
|
+
1. Fork it ( https://github.com/clothesnetwork/geohash36/fork )
|
126
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
127
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
128
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
129
|
+
5. Create a new Pull Request
|
130
|
+
|
131
|
+
|
132
|
+
## Authors
|
133
|
+
|
134
|
+
* [Oleg Orlov](https://github.com/OrelSokolov)
|
135
|
+
* [Bjoern Rennhak](https://github.com/rennhak)
|
75
136
|
|
76
|
-
## Copyright
|
137
|
+
## Copyright & License
|
77
138
|
|
78
|
-
Please refer to the
|
139
|
+
Please refer to the COPYING.md and LICENSE.md file.
|
data/{lib → examples}/demo.rb
RENAMED
File without changes
|
data/geohash36.gemspec
CHANGED
@@ -43,9 +43,11 @@ Gem::Specification.new do |spec|
|
|
43
43
|
COPYING.md
|
44
44
|
LICENSE.md
|
45
45
|
MAINTAINERS.md
|
46
|
+
FAQ.md
|
46
47
|
Gemfile
|
47
48
|
README.md
|
48
49
|
Rakefile
|
50
|
+
.project.yaml
|
49
51
|
geohash36.gemspec
|
50
52
|
]
|
51
53
|
|
@@ -79,31 +81,17 @@ Gem::Specification.new do |spec|
|
|
79
81
|
spec.add_runtime_dependency 'thor'
|
80
82
|
spec.add_runtime_dependency 'ruby-try', '~> 1.1.1'
|
81
83
|
|
82
|
-
# Package building
|
83
|
-
spec.add_runtime_dependency 'fpm'
|
84
|
-
|
85
84
|
# Shell
|
86
85
|
spec.add_runtime_dependency 'ptools'
|
87
86
|
spec.add_runtime_dependency 'os'
|
88
87
|
|
89
|
-
# Data RPCs and Messaging
|
90
|
-
spec.add_runtime_dependency 'msgpack'
|
91
|
-
# spec.add_runtime_dependency 'xmpp4r'
|
92
|
-
# spec.add_runtime_dependency 'xmpp4r-simple' # , :git => 'git://github.com/blaine/xmpp4r-simple.git'
|
93
|
-
spec.add_runtime_dependency 'amqp'
|
94
|
-
|
95
|
-
spec.add_runtime_dependency 'mime-types'
|
96
|
-
|
97
|
-
# l10n
|
98
|
-
spec.add_runtime_dependency 'gettext'
|
99
|
-
|
100
88
|
# Monadic/Functional
|
101
89
|
spec.add_runtime_dependency 'andand'
|
102
|
-
spec.add_runtime_dependency 'ick'
|
90
|
+
# spec.add_runtime_dependency 'ick'
|
103
91
|
|
104
92
|
# Misc System
|
105
|
-
spec.add_runtime_dependency 'awesome_print'
|
106
|
-
spec.add_runtime_dependency 'uuid'
|
93
|
+
# spec.add_runtime_dependency 'awesome_print'
|
94
|
+
# spec.add_runtime_dependency 'uuid'
|
107
95
|
|
108
96
|
## System libraries needed (info for the user)
|
109
97
|
# spec.requirements 'iconv zlib libmagic'
|
data/lib/geohash36.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
3
|
# Standard includes
|
5
4
|
require 'bundler'
|
6
5
|
require 'thor'
|
7
6
|
require 'rake'
|
8
7
|
require 'ruby-try'
|
9
8
|
|
10
|
-
|
9
|
+
|
10
|
+
# @class Geohash36
|
11
|
+
# @brief Provides complete solution for geohashing
|
11
12
|
class Geohash36
|
12
13
|
|
13
14
|
# Geocode-36 matrix for map
|
@@ -19,85 +20,101 @@ class Geohash36
|
|
19
20
|
['n', 'N', 'P', 'q', 'Q', 'r'],
|
20
21
|
['R', 't', 'T', 'V', 'W', 'X']
|
21
22
|
]
|
23
|
+
|
22
24
|
# Needed for inversion direction of latitude
|
23
25
|
GEOMATRIX_MAX_INDEX = 5
|
26
|
+
|
24
27
|
# Standart length of geocode
|
25
|
-
GEOCODE_LENGTH
|
28
|
+
GEOCODE_LENGTH = 10
|
29
|
+
|
26
30
|
# Accuracy for coordinates when converting from geohash
|
27
|
-
DEFAULT_ACCURACY
|
31
|
+
DEFAULT_ACCURACY = 6
|
28
32
|
|
29
|
-
attr_reader :
|
30
|
-
attr_reader :hash
|
33
|
+
attr_reader :coords, :hash
|
31
34
|
attr_accessor :accuracy
|
32
35
|
|
33
|
-
#
|
36
|
+
# @fn def initialize obj = { latitude: 0, longitude: 0 } {{{
|
37
|
+
# @brief Create new Geohash object from geohash or coordinates.
|
34
38
|
#
|
35
|
-
# @param object
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
|
39
|
+
# @param [Hash or String] object Either Hash {latitude: value, longitude: value} or "geohash string"
|
40
|
+
#
|
41
|
+
# @example Pass geohash
|
42
|
+
# Geohash36.new "l222222222222"
|
43
|
+
# @example Pass coordinates
|
44
|
+
# Geohash36.new latitude: 80, longitude: 20
|
45
|
+
#
|
46
|
+
def initialize obj = { latitude: 0, longitude: 0 }
|
41
47
|
@accuracy = DEFAULT_ACCURACY
|
48
|
+
|
42
49
|
if obj.kind_of? Hash
|
43
|
-
Geohash36.validate_coords(obj)
|
44
|
-
@hash
|
50
|
+
Geohash36.validate_coords( obj )
|
51
|
+
@hash = Geohash36.to_geohash( obj )
|
45
52
|
@coords = obj
|
46
53
|
elsif obj.kind_of? String
|
47
|
-
Geohash36.validate_geohash(obj)
|
48
|
-
@hash
|
49
|
-
@coords = Geohash36.to_coords(obj, @accuracy)
|
54
|
+
Geohash36.validate_geohash( obj )
|
55
|
+
@hash = obj
|
56
|
+
@coords = Geohash36.to_coords( obj, @accuracy )
|
50
57
|
else
|
51
58
|
raise ArgumentError, "Argument type should be hash or string"
|
52
59
|
end
|
53
|
-
end
|
60
|
+
end # of def initialize }}}
|
54
61
|
|
62
|
+
# @fn def hash=(geohash) {{{
|
55
63
|
# Update geohash value. Coordinates will update automatically
|
56
64
|
def hash=(geohash)
|
57
|
-
raise ArgumenError unless geohash.kind_of? String
|
58
|
-
@hash
|
59
|
-
@coords = Geohash36.to_coords(geohash, @accuracy)
|
60
|
-
end
|
65
|
+
raise ArgumenError unless( geohash.kind_of?( String ) )
|
66
|
+
@hash = geohash
|
67
|
+
@coords = Geohash36.to_coords( geohash, @accuracy )
|
68
|
+
end # of def hash= }}}
|
61
69
|
|
62
|
-
#
|
70
|
+
# @fn def coords=(coords) {{{
|
71
|
+
# @brief Update coordinates values. Geohash will update automatically
|
72
|
+
#
|
73
|
+
# @param [Hash] coords Hash containing keys longitude, latitude with corresponding values.
|
74
|
+
#
|
63
75
|
def coords=(coords)
|
64
|
-
raise ArgumenError unless coords.kind_of? Hash
|
65
|
-
@hash = Geohash36.to_geohash(coords)
|
76
|
+
raise ArgumenError unless( coords.kind_of?( Hash ) )
|
77
|
+
@hash = Geohash36.to_geohash( coords )
|
66
78
|
@coords.merge! coords
|
67
|
-
end
|
68
|
-
|
79
|
+
end # }}}
|
69
80
|
|
70
|
-
#
|
81
|
+
# @fn def self.to_geohash coords {{{
|
82
|
+
# @brief Convert coordinates pair to geohash without creating an object
|
83
|
+
#
|
84
|
+
# @param [Hash] coords Coordinates to convert
|
71
85
|
#
|
72
|
-
# @
|
73
|
-
#
|
74
|
-
# @example
|
75
|
-
#
|
76
|
-
|
77
|
-
def self.to_geohash(coords)
|
86
|
+
# @return [String] Returns a geohash from given coordinates
|
87
|
+
#
|
88
|
+
# @example Geohash36.to_geohash(latitude: 0, longitude: 0)
|
89
|
+
# # => "l222222222"
|
90
|
+
def self.to_geohash coords
|
78
91
|
Geohash36.validate_coords(coords)
|
79
92
|
lon_interval = Geohash36.basic_lon_interval
|
80
93
|
lat_interval = Geohash36.basic_lat_interval
|
81
94
|
|
82
95
|
(0...GEOCODE_LENGTH).map{Geohash36.geohash_symbol!(lon_interval, lat_interval, coords)}.join
|
83
|
-
end
|
84
|
-
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
# @param
|
89
|
-
# @
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
# @example
|
94
|
-
#
|
95
|
-
#
|
96
|
-
|
96
|
+
end # }}}
|
97
|
+
|
98
|
+
# @fn def self.to_coords(geohash, accuracy = DEFAULT_ACCURACY) {{{
|
99
|
+
# @brief Convert geohash to coords without creating an object.
|
100
|
+
#
|
101
|
+
# @param [String] geohash Given geohash string
|
102
|
+
# @param [Fixnum] accuracy Accuracy for coordinates values
|
103
|
+
#
|
104
|
+
# @return [Hash] Returns coordinates from given hash
|
105
|
+
#
|
106
|
+
# @example With default accuracy
|
107
|
+
# Geohash36.to_coords("l222222222")
|
108
|
+
# => {:latitude=>-1.0e-06, :longitude=>3.0e-06}
|
109
|
+
# @example With accuracy 3
|
110
|
+
# Geohash36.to_coords("l222222222", 3)
|
111
|
+
# => {:latitude=>0.0, :longitude=>0.0}
|
112
|
+
#
|
113
|
+
def self.to_coords geohash, accuracy = DEFAULT_ACCURACY
|
97
114
|
Geohash36.validate_geohash(geohash)
|
98
115
|
|
99
|
-
lon_interval
|
100
|
-
lat_interval
|
116
|
+
lon_interval = Geohash36.basic_lon_interval
|
117
|
+
lat_interval = Geohash36.basic_lat_interval
|
101
118
|
|
102
119
|
geohash.each_char do |c|
|
103
120
|
lon_intervals = Geohash36::Interval.convert_array(lon_interval.split)
|
@@ -106,7 +123,7 @@ class Geohash36
|
|
106
123
|
lat_index, lon_index = 0, 0
|
107
124
|
|
108
125
|
GEOCODE_MATRIX.each_with_index do |row, row_index|
|
109
|
-
if row.include? c
|
126
|
+
if row.include?( c )
|
110
127
|
lat_index = GEOMATRIX_MAX_INDEX-row_index
|
111
128
|
lon_index = row.index(c)
|
112
129
|
break
|
@@ -119,46 +136,72 @@ class Geohash36
|
|
119
136
|
|
120
137
|
{ latitude: lat_interval.middle.round(accuracy) ,
|
121
138
|
longitude: lon_interval.middle.round(accuracy) }
|
122
|
-
end
|
139
|
+
end # }}}
|
123
140
|
|
124
|
-
private
|
125
|
-
def self.basic_lon_interval
|
126
|
-
Geohash36::Interval.new [-180, 180]
|
127
|
-
end
|
128
141
|
|
129
|
-
|
130
|
-
Geohash36::Interval.new [-90, 90]
|
131
|
-
end
|
142
|
+
private
|
132
143
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
144
|
+
# @fn def self.basic_lon_interval {{{
|
145
|
+
# @brief Returns basic Longitude interval allowed
|
146
|
+
#
|
147
|
+
# @return [Interval] Returns correctly initialized Interval class for Longitude
|
148
|
+
def self.basic_lon_interval
|
149
|
+
Geohash36::Interval.new [-180, 180]
|
150
|
+
end # }}}
|
138
151
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
152
|
+
# @fn def self.basic_lat_interval {{{
|
153
|
+
# @brief Returns basic Latitude interval allowed
|
154
|
+
#
|
155
|
+
# @return [Interval] Returns correctly initialized Interval class for Latitude
|
156
|
+
def self.basic_lat_interval
|
157
|
+
Geohash36::Interval.new [-90, 90]
|
158
|
+
end # }}}
|
159
|
+
|
160
|
+
# @fn def self.validate_geohash geohash {{{
|
161
|
+
# @brief Validate given geohash36 against ranges and alphabet
|
162
|
+
def self.validate_geohash geohash
|
163
|
+
unless geohash =~ /\A[23456789bBCdDFgGhHjJKlLMnNPqQrRtTVWX]+{1,10}\z/
|
164
|
+
raise ArgumentError, "Sorry, it doesn't seem to be Geohash-36"
|
145
165
|
end
|
166
|
+
end # }}}
|
146
167
|
|
147
|
-
|
148
|
-
|
149
|
-
|
168
|
+
# @fn def self.validate_coords coords # {{{
|
169
|
+
# @brief Validate given latitude, longitude coordinates against valid ranges
|
170
|
+
#
|
171
|
+
# @param [Hash] coords Geospartial coordinates hash (latitude, longitude)
|
172
|
+
#
|
173
|
+
def self.validate_coords coords
|
174
|
+
keys = coords.keys
|
175
|
+
raise ArgumentError, "Invalid hash" unless keys.length == 2 && keys.include?(:latitude) && keys.include?(:longitude)
|
176
|
+
lat_inclusion = Geohash36.basic_lat_interval.include? coords[:latitude]
|
177
|
+
lon_inclusion = Geohash36.basic_lon_interval.include? coords[:longitude]
|
178
|
+
raise ArgumentError, "Invalid hash values" unless lat_inclusion && lon_inclusion
|
179
|
+
end # }}}
|
180
|
+
|
181
|
+
# @fn def self.geohash_symbol! lon_interval, lat_interval, coords {{{
|
182
|
+
# @brief FIXME
|
183
|
+
#
|
184
|
+
# @param [FIXME] lon_interval FIXME
|
185
|
+
# @param [FIXME] lat_interval FIXME
|
186
|
+
# @param [Hash] coords Geospartial coordinate hash containing latitude, longitude
|
187
|
+
#
|
188
|
+
def self.geohash_symbol! lon_interval, lat_interval, coords
|
189
|
+
lon_intervals = Geohash36::Interval.convert_array(lon_interval.split, include_right: false)
|
190
|
+
lat_intervals = Geohash36::Interval.convert_array(lat_interval.split, include_left: false)
|
150
191
|
|
151
|
-
|
152
|
-
|
192
|
+
lon_index = lon_intervals.index {|interval| interval.include? coords[:longitude] }
|
193
|
+
lat_index = lat_intervals.index {|interval| interval.include? coords[:latitude] }
|
153
194
|
|
154
|
-
|
155
|
-
|
195
|
+
lon_interval.update lon_intervals[lon_index]
|
196
|
+
lat_interval.update lat_intervals[lat_index]
|
156
197
|
|
157
|
-
|
158
|
-
|
198
|
+
GEOCODE_MATRIX[GEOMATRIX_MAX_INDEX-lat_index][lon_index]
|
199
|
+
end # }}}
|
159
200
|
|
160
201
|
end # of module Geohash36
|
161
202
|
|
162
|
-
|
203
|
+
# Load other library files
|
204
|
+
Dir[ File.dirname(__FILE__) + '/geohash36/library/*.rb' ].each { |file| require file }
|
205
|
+
|
163
206
|
|
164
207
|
# vim:ts=2:tw=100:wm=100:syntax=ruby
|
@@ -1,8 +1,31 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'rspec/core/rake_task'
|
4
3
|
|
5
|
-
|
6
|
-
|
4
|
+
## Handle RSpec 1.x and 2.x branches # {{{
|
5
|
+
#
|
6
|
+
# dm-redis-adapter and others maybe need 1.x while we want 2.x is possible.
|
7
|
+
begin
|
7
8
|
|
9
|
+
require 'rspec/core/rake_task'
|
8
10
|
|
11
|
+
desc "RSpec Core Tasks" # {{{
|
12
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
13
|
+
t.rspec_opts = '--format NyanCatWideFormatter --color --fail-fast --order random'
|
14
|
+
end # }}}
|
15
|
+
|
16
|
+
rescue LoadError
|
17
|
+
|
18
|
+
puts "(WW) Could not load RSpec 2.x branch, falling back to 1.x."
|
19
|
+
|
20
|
+
require 'spec/rake/spectask'
|
21
|
+
|
22
|
+
desc "Run specs" # {{{
|
23
|
+
Spec::Rake::SpecTask.new do |t|
|
24
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
t.spec_opts = %w(-fs --color)
|
26
|
+
end # }}}
|
27
|
+
|
28
|
+
end # }}}
|
29
|
+
|
30
|
+
|
31
|
+
# vim:ts=2:tw=100:wm=100:syntax=ruby
|
@@ -1,128 +1,170 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# @class class Geohash36::Interval < Array
|
4
|
+
# @brief Designed to provide additional functionality for arrays to handle geographical intervals.
|
3
5
|
class Geohash36::Interval < Array
|
4
6
|
|
5
|
-
# @
|
6
|
-
# @
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
7
|
+
# @fn def initialize array = [0, 0], options = {} {{{
|
8
|
+
# @brief Default constructor for Interval class
|
9
|
+
#
|
10
|
+
# @param [Array<Fixnum, Float>] array Array with length 2.
|
11
|
+
# @param [Hash] options Hash containing default opts
|
12
|
+
#
|
13
|
+
# @info Options affects borders in interval. By default, all borders are included.
|
14
|
+
# If you want to exclude left border, pass: `include_left: false`
|
15
|
+
# If you want to exclude right border, pass: `include_right: false`
|
16
|
+
#
|
17
|
+
# @example With default args
|
18
|
+
# Geohash36::Interval.new
|
19
|
+
# @example With array and options
|
20
|
+
# Geohash36::Interval.new([0, 6], include_right: false)
|
21
|
+
#
|
14
22
|
def initialize array = [0, 0], options = {}
|
15
|
-
array.try(:compact!)
|
16
|
-
validate_array(array)
|
17
|
-
array.each{|element| self.push element}
|
18
|
-
defaults
|
19
|
-
@opts
|
20
|
-
end
|
21
|
-
|
22
|
-
#
|
23
|
+
array.try( :compact! )
|
24
|
+
validate_array( array )
|
25
|
+
array.each{ |element| self.push element }
|
26
|
+
defaults = { include_right: true, include_left: true }
|
27
|
+
@opts = defaults.merge options
|
28
|
+
end # of def initialize }}}
|
29
|
+
|
30
|
+
# @fn def configure options = {} {{{
|
31
|
+
# @brief Replace old interval options with new one
|
23
32
|
#
|
24
|
-
# @param
|
33
|
+
# @param [Hash] options New options for interval
|
25
34
|
def configure options = {}
|
26
35
|
@opts.merge! options
|
27
|
-
end
|
36
|
+
end # of def configure }}}
|
28
37
|
|
29
|
-
#
|
38
|
+
# @fn def include? number {{{
|
39
|
+
# @brief Check if `number` between left and right border
|
30
40
|
#
|
31
|
-
# @param
|
41
|
+
# @param [Numeric] number Number to check
|
32
42
|
def include? number
|
33
43
|
for_left_border = (@opts[:include_left] == true) ? first <= number : first < number
|
34
44
|
for_right_number = (@opts[:include_right] == true) ? number <= last : number < last
|
35
45
|
for_left_border && for_right_number
|
36
|
-
end
|
46
|
+
end # }}}
|
37
47
|
|
38
|
-
#
|
39
|
-
# @
|
48
|
+
# @fn def split {{{
|
49
|
+
# @brief Split interval into 6 parts
|
50
|
+
#
|
51
|
+
# @return [Array] Array of 6 intervals
|
40
52
|
def split
|
41
53
|
split3.each_with_object([]){|interval, result| result.concat interval.split2}
|
42
|
-
end
|
54
|
+
end # }}}
|
43
55
|
|
44
|
-
#
|
45
|
-
# @
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
56
|
+
# @fn def update array {{{
|
57
|
+
# @brief Change values of interval
|
58
|
+
#
|
59
|
+
# @param [Array] array FIXME
|
60
|
+
#
|
61
|
+
# @example my_interval = Geohash36::Interval.new([0, 1])
|
62
|
+
# my_interval.update [0,6]
|
63
|
+
# my_interval # => [0, 6]
|
49
64
|
def update array
|
50
65
|
array.try(:compact!)
|
51
66
|
validate_array(array)
|
52
67
|
self.clear
|
53
68
|
array.each{|element| self.push element}
|
54
|
-
end
|
69
|
+
end # }}}
|
55
70
|
|
56
|
-
# @
|
71
|
+
# @fn def inspect {{{
|
72
|
+
# @brief Returns string for easy inspection of self on print
|
73
|
+
#
|
74
|
+
# @return [String] String representation of object
|
57
75
|
def inspect
|
58
76
|
left_br = @opts[:include_left] ? "[" : "("
|
59
77
|
right_br = @opts[:include_right] ? "]" : ")"
|
78
|
+
|
60
79
|
"#{left_br}#{first}, #{last}#{right_br}"
|
61
|
-
end
|
80
|
+
end # }}}
|
62
81
|
|
63
|
-
# @
|
82
|
+
# @fn def to_s {{{
|
83
|
+
# @brief Returns string representation of self for print
|
84
|
+
#
|
85
|
+
# @return [String] String representation of object
|
64
86
|
def to_s
|
65
87
|
inspect
|
66
|
-
end
|
88
|
+
end # }}}
|
67
89
|
|
68
|
-
# @
|
69
|
-
# @
|
70
|
-
#
|
71
|
-
#
|
90
|
+
# @fn def middle {{{
|
91
|
+
# @brief Average of given interval (middle)
|
92
|
+
#
|
93
|
+
# @return [Numeric] Returns average of the given interval
|
94
|
+
#
|
95
|
+
# @example Geohash36::Interval.new([0, 6]).middle
|
96
|
+
# => 3.0
|
72
97
|
def middle
|
73
98
|
(first + last)/2.0
|
74
|
-
end
|
99
|
+
end # }}}
|
75
100
|
|
76
|
-
# @
|
77
|
-
# @
|
78
|
-
#
|
79
|
-
#
|
101
|
+
# @fn def third {{{
|
102
|
+
# @brief Computes third part of given interval and returns absolute result
|
103
|
+
#
|
104
|
+
# @return [Numeric] Third part of interval (absolute, returns only positive values)
|
105
|
+
#
|
106
|
+
# @example Geohash36::Interval.new([-2, 4]).third
|
107
|
+
# => 2.0
|
108
|
+
#
|
80
109
|
def third
|
81
110
|
((last - first)/3.0).abs
|
82
|
-
end
|
111
|
+
end # }}}
|
83
112
|
|
84
|
-
#
|
85
|
-
# @
|
113
|
+
# @fn def split2 {{{
|
114
|
+
# @brief Split interval into 2 parts
|
115
|
+
#
|
116
|
+
# @return [Array] Array of 2 intervals
|
86
117
|
def split2
|
87
118
|
[[first, middle], [middle, last]].map{|interval| Geohash36::Interval.new interval}
|
88
|
-
end
|
119
|
+
end # }}}
|
89
120
|
|
90
|
-
#
|
91
|
-
# @
|
121
|
+
# @fn def split3 {{{
|
122
|
+
# @brief Split interval into 3 parts
|
123
|
+
#
|
124
|
+
# @return [Array] Returns array of 3 intervals
|
92
125
|
def split3
|
93
126
|
result = [[self.first, self.first+third], [self.first+third, self.first+2*third], [self.first+2*third, self.last]]
|
94
127
|
result.map{|array| Geohash36::Interval.new array}
|
95
|
-
end
|
96
|
-
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
# @param
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
128
|
+
end # }}}
|
129
|
+
|
130
|
+
# @fn def self.convert_array array, options = {} {{{
|
131
|
+
# @brief Convert array of arrays to array of `Geohash36::Interval`s
|
132
|
+
#
|
133
|
+
# @param [Array] array Array to convert
|
134
|
+
# @param [Hash] options Options for `Geohash36::Interval` object
|
135
|
+
#
|
136
|
+
# @info It works a little different. It is not affect first\last elements in array.
|
137
|
+
# For example, if we do not want to include left border, only first element
|
138
|
+
# will include left border because this class designed to handle geographical coordinates.
|
139
|
+
# It is not designed for abstract intervals.
|
140
|
+
#
|
141
|
+
# @example e.g. We don't want to include left border of interval,
|
142
|
+
# so we will have array like `[[0, 0], [0, 0], [0, 0]] ->> [[0, 0], (0, 0], (0, 0]]`
|
143
|
+
#
|
144
|
+
# my_array = [[0, 2], [2, 6], [6, 10]]
|
145
|
+
# Geohash36.convert_array(my_array, include_left: false)
|
146
|
+
# => [[0, 2], (2, 6], (6, 10]]
|
147
|
+
#
|
112
148
|
def self.convert_array array, options = {}
|
113
149
|
intervals = array.map{|interval| Geohash36::Interval.new interval, options }
|
114
150
|
intervals.first.configure(include_left: true) unless options[:include_left]
|
115
151
|
intervals.last.configure(include_right: true) unless options[:include_right]
|
116
152
|
intervals
|
117
|
-
end
|
153
|
+
end # }}}
|
154
|
+
|
118
155
|
|
119
156
|
private
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
157
|
+
|
158
|
+
# @fn def validate_array array # {{{
|
159
|
+
# @brief Check if array has valid values
|
160
|
+
#
|
161
|
+
# @param [Array] array FIXME
|
162
|
+
def validate_array array
|
163
|
+
unless array.length == 2 && ( array.try(:first) <= array.try(:last) )
|
164
|
+
raise ArgumentError, "Not valid array for geohash interval"
|
125
165
|
end
|
166
|
+
end # }}}
|
167
|
+
|
126
168
|
|
127
169
|
end # of class Geohash36::Interval
|
128
170
|
|
data/spec/spec_helper.rb
CHANGED
@@ -23,7 +23,7 @@ RSpec.configure do |config|
|
|
23
23
|
config.tty = true
|
24
24
|
|
25
25
|
# Use the specified formatter
|
26
|
-
config.formatter = :documentation # :progress, :html, :textmate
|
26
|
+
# config.formatter = # :documentation # :progress, :html, :textmate
|
27
27
|
|
28
28
|
config.expect_with :rspec do |c|
|
29
29
|
c.syntax = [:should, :expect] # Disable warnings
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geohash36
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bjoern Rennhak
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-08-
|
12
|
+
date: 2014-08-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -39,20 +39,6 @@ dependencies:
|
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: 1.1.1
|
42
|
-
- !ruby/object:Gem::Dependency
|
43
|
-
name: fpm
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - ">="
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '0'
|
49
|
-
type: :runtime
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: '0'
|
56
42
|
- !ruby/object:Gem::Dependency
|
57
43
|
name: ptools
|
58
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,62 +67,6 @@ dependencies:
|
|
81
67
|
- - ">="
|
82
68
|
- !ruby/object:Gem::Version
|
83
69
|
version: '0'
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
name: msgpack
|
86
|
-
requirement: !ruby/object:Gem::Requirement
|
87
|
-
requirements:
|
88
|
-
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: '0'
|
91
|
-
type: :runtime
|
92
|
-
prerelease: false
|
93
|
-
version_requirements: !ruby/object:Gem::Requirement
|
94
|
-
requirements:
|
95
|
-
- - ">="
|
96
|
-
- !ruby/object:Gem::Version
|
97
|
-
version: '0'
|
98
|
-
- !ruby/object:Gem::Dependency
|
99
|
-
name: amqp
|
100
|
-
requirement: !ruby/object:Gem::Requirement
|
101
|
-
requirements:
|
102
|
-
- - ">="
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
version: '0'
|
105
|
-
type: :runtime
|
106
|
-
prerelease: false
|
107
|
-
version_requirements: !ruby/object:Gem::Requirement
|
108
|
-
requirements:
|
109
|
-
- - ">="
|
110
|
-
- !ruby/object:Gem::Version
|
111
|
-
version: '0'
|
112
|
-
- !ruby/object:Gem::Dependency
|
113
|
-
name: mime-types
|
114
|
-
requirement: !ruby/object:Gem::Requirement
|
115
|
-
requirements:
|
116
|
-
- - ">="
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
version: '0'
|
119
|
-
type: :runtime
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
requirements:
|
123
|
-
- - ">="
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: '0'
|
126
|
-
- !ruby/object:Gem::Dependency
|
127
|
-
name: gettext
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
129
|
-
requirements:
|
130
|
-
- - ">="
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: '0'
|
133
|
-
type: :runtime
|
134
|
-
prerelease: false
|
135
|
-
version_requirements: !ruby/object:Gem::Requirement
|
136
|
-
requirements:
|
137
|
-
- - ">="
|
138
|
-
- !ruby/object:Gem::Version
|
139
|
-
version: '0'
|
140
70
|
- !ruby/object:Gem::Dependency
|
141
71
|
name: andand
|
142
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,48 +81,6 @@ dependencies:
|
|
151
81
|
- - ">="
|
152
82
|
- !ruby/object:Gem::Version
|
153
83
|
version: '0'
|
154
|
-
- !ruby/object:Gem::Dependency
|
155
|
-
name: ick
|
156
|
-
requirement: !ruby/object:Gem::Requirement
|
157
|
-
requirements:
|
158
|
-
- - ">="
|
159
|
-
- !ruby/object:Gem::Version
|
160
|
-
version: '0'
|
161
|
-
type: :runtime
|
162
|
-
prerelease: false
|
163
|
-
version_requirements: !ruby/object:Gem::Requirement
|
164
|
-
requirements:
|
165
|
-
- - ">="
|
166
|
-
- !ruby/object:Gem::Version
|
167
|
-
version: '0'
|
168
|
-
- !ruby/object:Gem::Dependency
|
169
|
-
name: awesome_print
|
170
|
-
requirement: !ruby/object:Gem::Requirement
|
171
|
-
requirements:
|
172
|
-
- - ">="
|
173
|
-
- !ruby/object:Gem::Version
|
174
|
-
version: '0'
|
175
|
-
type: :runtime
|
176
|
-
prerelease: false
|
177
|
-
version_requirements: !ruby/object:Gem::Requirement
|
178
|
-
requirements:
|
179
|
-
- - ">="
|
180
|
-
- !ruby/object:Gem::Version
|
181
|
-
version: '0'
|
182
|
-
- !ruby/object:Gem::Dependency
|
183
|
-
name: uuid
|
184
|
-
requirement: !ruby/object:Gem::Requirement
|
185
|
-
requirements:
|
186
|
-
- - ">="
|
187
|
-
- !ruby/object:Gem::Version
|
188
|
-
version: '0'
|
189
|
-
type: :runtime
|
190
|
-
prerelease: false
|
191
|
-
version_requirements: !ruby/object:Gem::Requirement
|
192
|
-
requirements:
|
193
|
-
- - ">="
|
194
|
-
- !ruby/object:Gem::Version
|
195
|
-
version: '0'
|
196
84
|
description: Commandline interface and library to the Geohash36 Algorithm
|
197
85
|
email:
|
198
86
|
- bjoern@clothesnetwork.com
|
@@ -202,17 +90,19 @@ executables:
|
|
202
90
|
extensions: []
|
203
91
|
extra_rdoc_files: []
|
204
92
|
files:
|
93
|
+
- ".project.yaml"
|
205
94
|
- AUTHORS.md
|
206
95
|
- CHANGELOG.md
|
207
96
|
- COPYING.md
|
97
|
+
- FAQ.md
|
208
98
|
- Gemfile
|
209
99
|
- LICENSE.md
|
210
100
|
- MAINTAINERS.md
|
211
101
|
- README.md
|
212
102
|
- Rakefile
|
213
103
|
- bin/geohash36
|
104
|
+
- examples/demo.rb
|
214
105
|
- geohash36.gemspec
|
215
|
-
- lib/demo.rb
|
216
106
|
- lib/geohash36.rb
|
217
107
|
- lib/geohash36/interface/rake/cucumber.rb
|
218
108
|
- lib/geohash36/interface/rake/default.rb
|
@@ -247,7 +137,7 @@ post_install_message: |2
|
|
247
137
|
| | _| _|| | | | |_| | / _ ___ | |_| | |_ | '_ | |_| | |__| |_| | _ |/ ___ ___) | _ |___) | (_) |
|
248
138
|
____|________/|_| |_/_/ _____/|_| |_|____/ ___/
|
249
139
|
|
250
|
-
(c) 2014-08-
|
140
|
+
(c) 2014-08-17 00:00:00 UTC, All rights reserved
|
251
141
|
Clothes Network Ltd., Bjoern Rennhak
|
252
142
|
|
253
143
|
Don't forget to configure $HOME/.geohash36/config.
|