geohash36 0.3.0 → 0.3.1
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.
- 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
|
+
[](http://badge.fury.io/rb/geohash36)
|
5
|
+
[](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.
|