locality 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc08ca579c909a36f517e55af8c15dbc8b3e7bf6
4
+ data.tar.gz: 5eb0d6c9e2e211110857db7fb3be22e4d22fb1f3
5
+ SHA512:
6
+ metadata.gz: 5d1b4079773f7ec8b22c2687a9e10ca2861eba4f8bb48a9512a1ee0b016af10b5deee0e20c4ccb88d489d7eb5009fcdd203441a1106ddc6b2d867ff2d37c31bc
7
+ data.tar.gz: 1f3157cf23f35c5b8a221631dcc8fd5c717c92167013c1bfe67b2cc945d16eac5bd985c39669d45c233ed0573c5756bb3bfaaee96e7abb2f6574b074c86b099d
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Locality
2
+
3
+ ## Swedish A-Region
4
+
5
+ See https://sv.wikipedia.org/wiki/A-region
6
+
7
+ ### Installation
8
+
9
+ ```bash
10
+ # Go and buy the rec2LK database from postnummerservice.se
11
+ # Put it in the ./db directory
12
+ ```
13
+
14
+ ### Configuration
15
+
16
+ ```ruby
17
+ Locality.configure do |config|
18
+
19
+ # By default, locality will look for the rec2LK database in
20
+ # these locations: `Locality.config.postnummerfilen_paths`
21
+ # You can add a custom location like so:
22
+ config.postnummerfilen_path = '/some/custom/rec2LK.csv'
23
+
24
+ end
25
+
26
+ ```
27
+ ### Usage
28
+
29
+ ```ruby
30
+ lookup = Locality::Aregion.new 21 # Gotland
31
+
32
+ lookup.zip_codes # => Array of Integers
33
+ # More to come...
34
+ ```
35
+
36
+ ## IP Lookup
37
+
38
+ ### Installation
39
+
40
+ ```bash
41
+ # Get the libmaxminddb, e.g. via homebrew on Mac OS
42
+ brew install libmaxminddb
43
+ # Tell bundler where to find it
44
+ bundle config build.hive_geoip2 --with-opt-dir=$(brew --prefix)
45
+ # Download and extract the MaxMind GeoIp2 database
46
+ curl http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz -o ./db && gunzip ./db/GeoLite2-City.mmdb.gz
47
+ ```
48
+
49
+ ### Configuration
50
+
51
+ ```ruby
52
+ Locality.configure do |config|
53
+
54
+ # By default, locality will look for the maxmind database in
55
+ # these locations: `Locality.config.maxmind_geoip2_path`
56
+ # You can add a custom location like so:
57
+ config.maxmind_geoip2_path = '/some/custom/maxmind_geolite2.mmdb'
58
+
59
+ # If you want, you can add custom lookups like so:
60
+ config.add_custom_ip_location '198.51.100.99/24', city_name: 'Main Office', country_name: 'Australia'
61
+ end
62
+ ```
63
+
64
+ ### Usage
65
+
66
+ ```ruby
67
+ lookup = Locality::IP.new '198.51.100.55'
68
+
69
+ # All these attributes return either a String or nil.
70
+ lookup.ip
71
+ lookup.city_name
72
+ lookup.province_name
73
+ lookup.state_name
74
+ lookup.country_name
75
+ lookup.human_readable_name
76
+
77
+ # Get them all combined in a Hash
78
+ lookup.to_hash
79
+ ```
80
+
@@ -0,0 +1,22 @@
1
+ require 'locality/postnummerservice'
2
+
3
+ module Locality
4
+ # See https://sv.wikipedia.org/wiki/A-region
5
+ class Aregion
6
+
7
+ def initialize(raw_code)
8
+ @raw_code = raw_code
9
+ end
10
+
11
+ def zip_codes
12
+ @zip_codes ||= backend.aregions[1].map(&:zip_code)
13
+ end
14
+
15
+ private
16
+
17
+ def backend
18
+ Locality::Postnummerservice
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require 'locality/configuration'
2
+
3
+ module Locality
4
+ module Configurable
5
+
6
+ # Public: Returns the the configuration instance.
7
+ #
8
+ def config
9
+ @config ||= Configuration.new
10
+ end
11
+
12
+ # Public: Yields the configuration instance.
13
+ #
14
+ def configure(&block)
15
+ yield config
16
+ end
17
+
18
+ # Public: Reset the configuration (useful for testing)
19
+ #
20
+ def reset!
21
+ @config = nil
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,68 @@
1
+ require 'pathname'
2
+
3
+ module Locality
4
+ class Configuration
5
+
6
+ # IP
7
+
8
+ attr_writer :maxmind_geoip2_path
9
+
10
+ def custom_ip_locations
11
+ @custom_ip_locations ||= {}
12
+ end
13
+
14
+ def add_custom_ip_location(ip, data)
15
+ custom_ip_locations[IPAddr.new(ip)] = data.to_hash
16
+ end
17
+
18
+ def maxmind_geoip2_path
19
+ maxmind_geoip2_paths.detect &:readable?
20
+ end
21
+
22
+ def maxmind_geoip2_paths
23
+ paths maxmind_geoip2_filename, custom_maxmind_geoip2_path
24
+ end
25
+
26
+ # Postnummerservice
27
+
28
+ attr_writer :postnummerfilen_path
29
+
30
+ def postnummerfilen_path
31
+ postnummerfilen_paths.detect &:readable?
32
+ end
33
+
34
+ def postnummerfilen_paths
35
+ paths postnummerfilen_filename, custom_postnummerfilen_path
36
+ end
37
+
38
+ private
39
+
40
+ def maxmind_geoip2_filename
41
+ 'GeoLite2-City.mmdb'
42
+ end
43
+
44
+ def postnummerfilen_filename
45
+ 'rec2LK.csv'
46
+ end
47
+
48
+ def custom_maxmind_geoip2_path
49
+ return unless @maxmind_geoip2_path
50
+ Pathname.new @maxmind_geoip2_path
51
+ end
52
+
53
+ def custom_postnummerfilen_path
54
+ return unless @postnummerfilen_path
55
+ Pathname.new @postnummerfilen_path
56
+ end
57
+
58
+ def paths(appendix = nil, additional = nil)
59
+ result = []
60
+ result << Rails.root.join('db', appendix) if defined?(Rails)
61
+ result << Pathname.new('/mnt').join('databases', appendix)
62
+ result << Pathname.new(Dir.pwd).join('db', appendix)
63
+ result << additional
64
+ result.compact
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,96 @@
1
+ require 'active_support/core_ext/object/blank'
2
+ require 'ipaddr'
3
+ require 'operation'
4
+ require 'trouble'
5
+ require 'geocoder'
6
+
7
+ require 'locality/configurable'
8
+
9
+ module Locality
10
+ class IP
11
+
12
+ def initialize(raw_ip)
13
+ @raw_ip = raw_ip
14
+ end
15
+
16
+ def to_hash
17
+ {
18
+ ip: ip.to_s,
19
+ city_name: city_name,
20
+ province_name: province_name,
21
+ state_name: state_name,
22
+ country_name: country_name,
23
+ human_readable_location: human_readable_location,
24
+ }
25
+ end
26
+
27
+ def ip
28
+ @ip ||= ::IPAddr.new raw_ip
29
+ rescue => exception
30
+ nil
31
+ end
32
+
33
+ def human_readable_location
34
+ city_name || province_name || state_name || country_name
35
+ end
36
+
37
+ def city_name
38
+ return unless lookup
39
+ lookup.city.presence
40
+ end
41
+
42
+ def province_name
43
+ return unless lookup
44
+ lookup.province.presence
45
+ end
46
+
47
+ def state_name
48
+ return unless lookup
49
+ lookup.state.presence
50
+ end
51
+
52
+ def country_name
53
+ return unless lookup
54
+ lookup.country.presence
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :raw_ip
60
+
61
+ def lookup
62
+ @lookup ||= custom_lookup! || lookup!
63
+ end
64
+
65
+ def lookup!
66
+ return unless ip.present?
67
+ ensure_upstream_configuration
68
+ Geocoder::Lookup.get(:geoip2).search(ip.to_s).first
69
+
70
+ rescue IOError => exception
71
+ Trouble.notify exception
72
+ configure_upstream! # Maybe the database file just moved somewhere else, repair by force-reconfiguring
73
+ nil
74
+ end
75
+
76
+ def custom_lookup!
77
+ ::Locality.config.custom_ip_locations.each do |key, value|
78
+ next unless key.include? ip
79
+ input = Hashie::Mash.new value
80
+ # Quacking like Geocoder::Result::GeoIP2
81
+ return Hashie::Mash.new(city: input.city_name, province: input.province_name, state: input.state_name, country: input.country_name)
82
+ end
83
+ nil
84
+ end
85
+
86
+ def ensure_upstream_configuration
87
+ return if Geocoder.config[:ip_lookup] == :geoip2
88
+ configure_upstream!
89
+ end
90
+
91
+ def configure_upstream!
92
+ Geocoder.configure ip_lookup: :geoip2, units: :km, geoip2: { cache: Hash.new, lib: 'hive_geoip2', file: ::Locality.config.maxmind_geoip2_path }
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,35 @@
1
+ module Locality
2
+ module Postnummerservice
3
+ class Entry < Array
4
+
5
+ def zip_code
6
+ self[0].to_i
7
+ end
8
+
9
+ def city_name
10
+ self[1]
11
+ end
12
+
13
+ def state_code
14
+ self[2]
15
+ end
16
+
17
+ def state_name
18
+ self[3]
19
+ end
20
+
21
+ def province_name
22
+ self[4]
23
+ end
24
+
25
+ def province_code
26
+ self[5]
27
+ end
28
+
29
+ def aregion
30
+ self[6].to_i
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ require 'csv'
2
+ require 'locality/postnummerservice/entry'
3
+
4
+ module Locality
5
+ module Postnummerservice
6
+
7
+ def self.aregions
8
+ load
9
+ @aregions
10
+ end
11
+
12
+ private
13
+
14
+ def self.load
15
+ load! unless loaded?
16
+ end
17
+
18
+ def self.loaded?
19
+ !!@loaded
20
+ end
21
+
22
+ def self.load!
23
+ @aregions = {}
24
+
25
+ ::CSV.foreach(::Locality.config.postnummerfilen_path, encoding: encoding) do |row|
26
+ next if row.blank?
27
+ entry = Entry.new(row)
28
+ @aregions[entry.aregion] ||= []
29
+ @aregions[entry.aregion] << entry
30
+ end
31
+
32
+ @loaded = true
33
+ end
34
+
35
+ def self.encoding
36
+ 'ISO-8859-1:UTF-8' # from:to
37
+ end
38
+
39
+ end
40
+ end
data/lib/locality.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'locality/aregion'
2
+ require 'locality/configurable'
3
+ require 'locality/ip'
4
+ require 'locality/aregion'
5
+
6
+ module Locality
7
+ extend Configurable
8
+ end
metadata ADDED
@@ -0,0 +1,205 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: locality
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - bukowskis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: geocoder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.6
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.6
41
+ - !ruby/object:Gem::Dependency
42
+ name: hashie
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: hive_geoip2
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: i18n
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: operation
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: trouble
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rb-fsevent
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: See https://github.com/bukowskis/locality
168
+ email:
169
+ executables: []
170
+ extensions: []
171
+ extra_rdoc_files: []
172
+ files:
173
+ - README.md
174
+ - lib/locality.rb
175
+ - lib/locality/aregion.rb
176
+ - lib/locality/configurable.rb
177
+ - lib/locality/configuration.rb
178
+ - lib/locality/ip.rb
179
+ - lib/locality/postnummerservice.rb
180
+ - lib/locality/postnummerservice/entry.rb
181
+ homepage: https://github.com/bukowskis/locality
182
+ licenses: []
183
+ metadata: {}
184
+ post_install_message:
185
+ rdoc_options: []
186
+ require_paths:
187
+ - lib
188
+ required_ruby_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ required_rubygems_version: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - ">="
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ requirements: []
199
+ rubyforge_project:
200
+ rubygems_version: 2.2.2
201
+ signing_key:
202
+ specification_version: 4
203
+ summary: Wrapping databases provided by maxmind.com and postnummerservice.se
204
+ test_files: []
205
+ has_rdoc: