ideal_postcodes 0.1.1 → 2.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 +5 -5
- data/.github/workflows/ci.yml +22 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE +21 -0
- data/README.md +289 -43
- data/Rakefile +13 -6
- data/ideal-postcodes-ruby.gemspec +11 -11
- data/lib/ideal_postcodes.rb +1 -1
- data/lib/idealpostcodes/address.rb +31 -0
- data/lib/idealpostcodes/errors.rb +31 -26
- data/lib/idealpostcodes/key.rb +14 -0
- data/lib/idealpostcodes/postcode.rb +20 -32
- data/lib/idealpostcodes/util.rb +38 -25
- data/lib/idealpostcodes/version.rb +2 -2
- data/lib/idealpostcodes.rb +114 -81
- data/spec/addresses_spec.rb +68 -0
- data/spec/idealpostcodes_spec.rb +56 -0
- data/spec/keys_spec.rb +25 -0
- data/spec/postcodes_spec.rb +77 -0
- data/spec/spec_helper.rb +89 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_lookup_raises_an_exception_if_invalid_key.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_lookup_raises_an_exception_if_limit_breached.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_lookup_raises_an_exception_if_no_lookups_remaining.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_lookup_returns_an_address_for_a_valid_UDPRN.yml +74 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_lookup_returns_nil_for_an_invalid_UDPRN.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_search_is_sensitive_to_limit.yml +81 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_search_is_sensitive_to_page.yml +369 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_search_raises_an_exception_if_invalid_key.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_search_raises_an_exception_if_limit_breached.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_search_raises_an_exception_if_no_lookups_remaining.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Address_search_returns_results_in_a_SearchResult_object.yml +273 -0
- data/spec/vcr_cassettes/IdealPostcodes_Key_lookup_details_returns_key_details.yml +62 -0
- data/spec/vcr_cassettes/IdealPostcodes_Key_lookup_returns_the_availability_status_of_a_key_false_key_.yml +45 -0
- data/spec/vcr_cassettes/IdealPostcodes_Key_lookup_returns_the_availability_status_of_a_key_true_key_.yml +45 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_find_by_location_is_sensitive_to_limit_parameter.yml +52 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_find_by_location_is_sensitive_to_radius_parament.yml +133 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_find_by_location_returns_an_array_of_postcodes_and_locations.yml +84 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_find_by_location_returns_an_empty_array_if_no_results_are_found.yml +43 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_lookup_raises_an_exception_if_invalid_key.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_lookup_raises_an_exception_if_key_has_run_out_of_balance.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_lookup_raises_an_exception_if_limit_has_been_reached.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_lookup_returns_a_list_of_addresses_for_a_postcode.yml +268 -0
- data/spec/vcr_cassettes/IdealPostcodes_Postcode_lookup_returns_an_empty_array_if_postcode_does_not_exist.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_key_available_returns_false_if_key_is_unavailable.yml +45 -0
- data/spec/vcr_cassettes/IdealPostcodes_key_available_returns_true_if_key_is_available.yml +45 -0
- data/spec/vcr_cassettes/IdealPostcodes_key_details_raises_an_exception_if_no_secret_is_provided.yml +45 -0
- data/spec/vcr_cassettes/IdealPostcodes_key_details_returns_key_information.yml +62 -0
- data/spec/vcr_cassettes/IdealPostcodes_request_generates_a_HTTP_request.yml +268 -0
- data/spec/vcr_cassettes/IdealPostcodes_request_raises_authentication_error_if_invalid_key_is_provided.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_request_raises_limit_reached_error_if_a_limit_has_been_breached.yml +42 -0
- data/spec/vcr_cassettes/IdealPostcodes_request_raises_token_exhausted_error_if_key_balance_is_depleted.yml +42 -0
- metadata +117 -52
- data/test/test_helper.rb +0 -77
- data/test/test_ideal_postcodes.rb +0 -78
@@ -1,35 +1,23 @@
|
|
1
1
|
module IdealPostcodes
|
2
|
-
|
2
|
+
module Postcode
|
3
|
+
def self.lookup(postcode)
|
4
|
+
begin
|
5
|
+
response = IdealPostcodes.request :get, "postcodes/#{postcode}"
|
6
|
+
addresses = response[:result]
|
7
|
+
rescue IdealPostcodes::ResourceNotFoundError => e
|
8
|
+
raise e unless e.response_code == 4040
|
3
9
|
|
4
|
-
|
10
|
+
addresses = []
|
11
|
+
end
|
12
|
+
addresses
|
13
|
+
end
|
5
14
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
rescue IdealPostcodes::ResourceNotFoundError => error
|
16
|
-
raise error unless error.response_code == 4040
|
17
|
-
response = nil
|
18
|
-
end
|
19
|
-
new postcode, response
|
20
|
-
end
|
21
|
-
|
22
|
-
def empty?
|
23
|
-
@raw.nil?
|
24
|
-
end
|
25
|
-
|
26
|
-
def addresses
|
27
|
-
@addresses
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_s
|
31
|
-
addresses.to_s
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
15
|
+
def self.find_by_location(geolocation)
|
16
|
+
query = { lonlat: "#{geolocation[:longitude]},#{geolocation[:latitude]}" }
|
17
|
+
query[:limit] = geolocation[:limit] unless geolocation[:limit].nil?
|
18
|
+
query[:radius] = geolocation[:radius] unless geolocation[:radius].nil?
|
19
|
+
response = IdealPostcodes.request :get, 'postcodes', query
|
20
|
+
response[:result]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/idealpostcodes/util.rb
CHANGED
@@ -1,29 +1,42 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
1
3
|
module IdealPostcodes
|
2
|
-
|
4
|
+
DEFAULT_PARSER = URI::Parser.new
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
result.join("&")
|
10
|
-
end
|
6
|
+
class Util
|
7
|
+
def self.escape(str)
|
8
|
+
IdealPostcodes::DEFAULT_PARSER.escape(str)
|
9
|
+
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
temp
|
21
|
-
when Array
|
22
|
-
object.map { |elem| keys_to_sym(elem) }
|
23
|
-
else
|
24
|
-
object
|
25
|
-
end
|
26
|
-
end
|
11
|
+
def self.merge_params(hash)
|
12
|
+
result = []
|
13
|
+
hash.each do |key, value|
|
14
|
+
result << "#{escape(key.to_s)}=#{escape(value.to_s)}"
|
15
|
+
end
|
16
|
+
result.join('&')
|
17
|
+
end
|
27
18
|
|
28
|
-
|
29
|
-
|
19
|
+
def self.keys_to_sym(object)
|
20
|
+
case object
|
21
|
+
when Hash
|
22
|
+
temp = {}
|
23
|
+
object.each do |key, value|
|
24
|
+
key =
|
25
|
+
(
|
26
|
+
begin
|
27
|
+
key.to_sym
|
28
|
+
rescue StandardError
|
29
|
+
key
|
30
|
+
end
|
31
|
+
) || key
|
32
|
+
temp[key] = keys_to_sym(value)
|
33
|
+
end
|
34
|
+
temp
|
35
|
+
when Array
|
36
|
+
object.map { |elem| keys_to_sym(elem) }
|
37
|
+
else
|
38
|
+
object
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
1
|
module IdealPostcodes
|
2
|
-
|
3
|
-
end
|
2
|
+
VERSION = '2.0.1'
|
3
|
+
end
|
data/lib/idealpostcodes.rb
CHANGED
@@ -1,91 +1,124 @@
|
|
1
|
-
require 'rest-client'
|
2
|
-
require 'uri'
|
3
|
-
require 'multi_json'
|
4
1
|
require 'cgi'
|
2
|
+
require 'uri'
|
3
|
+
require 'json'
|
4
|
+
require 'rest-client'
|
5
5
|
require 'idealpostcodes/version'
|
6
|
-
|
6
|
+
|
7
|
+
# Require utility libraries
|
7
8
|
require 'idealpostcodes/util'
|
8
9
|
require 'idealpostcodes/errors'
|
9
10
|
|
11
|
+
# Require Resources
|
12
|
+
require 'idealpostcodes/key'
|
13
|
+
require 'idealpostcodes/address'
|
14
|
+
require 'idealpostcodes/postcode'
|
15
|
+
|
10
16
|
module IdealPostcodes
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def self.parse(response)
|
57
|
-
begin
|
58
|
-
Util.keys_to_sym MultiJson.load(response)
|
59
|
-
rescue MultiJson::DecodeError => e
|
60
|
-
raise handle_client_error(e)
|
17
|
+
@base_url = 'https://api.ideal-postcodes.co.uk'
|
18
|
+
@version = '1'
|
19
|
+
|
20
|
+
class << self
|
21
|
+
attr_accessor :api_key, :base_url, :version, :secret
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.request(method, path, params = {})
|
25
|
+
unless @api_key
|
26
|
+
raise IdealPostcodes::AuthenticationError, 'No API Key provided. ' +
|
27
|
+
'Set your key with IdealPostcodes.api_key = #your_key'
|
28
|
+
end
|
29
|
+
|
30
|
+
url = URI.parse(resource_url(path))
|
31
|
+
params.merge! api_key: @api_key
|
32
|
+
url.query = Util.merge_params(params)
|
33
|
+
request_options = { method: method.downcase.to_sym, url: url.to_s }
|
34
|
+
|
35
|
+
begin
|
36
|
+
response = generate_request(request_options)
|
37
|
+
rescue RestClient::ExceptionWithResponse => e
|
38
|
+
if rcode = e.http_code && rbody = e.http_body
|
39
|
+
handle_error(rcode, rbody)
|
40
|
+
else
|
41
|
+
handle_client_error(e)
|
42
|
+
end
|
43
|
+
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
44
|
+
handle_client_error(e)
|
45
|
+
end
|
46
|
+
parse response.body
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.apply_secret(secret)
|
50
|
+
@secret = secret
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.key_available
|
54
|
+
response = Key.lookup @api_key
|
55
|
+
response[:available]
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.key_details
|
59
|
+
if @secret.nil?
|
60
|
+
raise IdealPostcodes::AuthenticationError, 'No Secret Key provided. ' +
|
61
|
+
'Set your secret key with IdealPostcodes.apply_secret #your_key'
|
61
62
|
end
|
62
|
-
|
63
|
+
response = Key.lookup_details @api_key, @secret
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.resource_url(path = '')
|
67
|
+
IdealPostcodes::Util.escape "#{@base_url}/v#{@version}/#{path}"
|
68
|
+
end
|
63
69
|
|
64
|
-
|
70
|
+
def self.generate_request(options)
|
71
|
+
RestClient::Request.execute(options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.parse(response)
|
75
|
+
Util.keys_to_sym JSON.parse(response)
|
76
|
+
rescue JSON::ParserError => e
|
77
|
+
raise handle_client_error(e)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.handle_error(http_code, http_body)
|
65
81
|
error = parse http_body
|
66
82
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
83
|
+
ideal_code = error[:code]
|
84
|
+
ideal_message = error[:message]
|
85
|
+
|
86
|
+
case ideal_code
|
87
|
+
when 4010
|
88
|
+
raise AuthenticationError.new ideal_message,
|
89
|
+
http_code,
|
90
|
+
http_body,
|
91
|
+
ideal_code
|
92
|
+
when 4020
|
93
|
+
raise TokenExhaustedError.new ideal_message,
|
94
|
+
http_code,
|
95
|
+
http_body,
|
96
|
+
ideal_code
|
97
|
+
when 4021
|
98
|
+
raise LimitReachedError.new ideal_message,
|
99
|
+
http_code,
|
100
|
+
http_body,
|
101
|
+
ideal_code
|
102
|
+
when 4040
|
103
|
+
raise ResourceNotFoundError.new ideal_message,
|
104
|
+
http_code,
|
105
|
+
http_body,
|
106
|
+
ideal_code
|
107
|
+
else
|
108
|
+
raise IdealPostcodesError.new ideal_message,
|
109
|
+
http_code,
|
110
|
+
http_body,
|
111
|
+
ideal_code
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.handle_client_error(error)
|
116
|
+
raise IdealPostcodesError, "An unexpected error occured: #{error.message})"
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.general_error(response_code, response_body)
|
120
|
+
IdealPostcodesError.new 'Invalid response object',
|
121
|
+
response_code,
|
122
|
+
response_body
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe IdealPostcodes::Address do
|
4
|
+
describe '.lookup' do
|
5
|
+
it 'returns an address for a valid UDPRN' do
|
6
|
+
address = IdealPostcodes::Address.lookup 0
|
7
|
+
expect(is_address(address)).to eq(true)
|
8
|
+
end
|
9
|
+
it 'returns nil for an invalid UDPRN' do
|
10
|
+
address = IdealPostcodes::Address.lookup -1
|
11
|
+
expect(address).to be_nil
|
12
|
+
end
|
13
|
+
it 'raises an exception if invalid key' do
|
14
|
+
IdealPostcodes.api_key = 'foo'
|
15
|
+
expect { IdealPostcodes::Address.lookup 0 }.to raise_error(
|
16
|
+
IdealPostcodes::AuthenticationError
|
17
|
+
)
|
18
|
+
end
|
19
|
+
it 'raises an exception if no lookups remaining' do
|
20
|
+
expect { IdealPostcodes::Address.lookup -2 }.to raise_error(
|
21
|
+
IdealPostcodes::TokenExhaustedError
|
22
|
+
)
|
23
|
+
end
|
24
|
+
it 'raises an exception if limit breached' do
|
25
|
+
expect { IdealPostcodes::Address.lookup -3 }.to raise_error(
|
26
|
+
IdealPostcodes::LimitReachedError
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.search' do
|
32
|
+
it 'returns results in a SearchResult object' do
|
33
|
+
results = IdealPostcodes::Address.search 'ID1 1QD'
|
34
|
+
expect(results).to be_a(IdealPostcodes::Address::SearchResult)
|
35
|
+
expect(results.addresses.length).to be > 0
|
36
|
+
results.addresses.each do |address|
|
37
|
+
expect(is_address(address)).to eq(true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
it 'is sensitive to limit' do
|
41
|
+
limit = 1
|
42
|
+
results = IdealPostcodes::Address.search 'High Street', limit: limit
|
43
|
+
expect(results.addresses.length).to equal(limit)
|
44
|
+
expect(results.limit).to equal(limit)
|
45
|
+
end
|
46
|
+
it 'is sensitive to page' do
|
47
|
+
page = 1
|
48
|
+
results = IdealPostcodes::Address.search 'High Street', page: page
|
49
|
+
expect(results.page).to equal(page)
|
50
|
+
end
|
51
|
+
it 'raises an exception if invalid key' do
|
52
|
+
IdealPostcodes.api_key = 'foo'
|
53
|
+
expect {
|
54
|
+
results = IdealPostcodes::Address.search 'ID1 1QD'
|
55
|
+
}.to raise_error(IdealPostcodes::AuthenticationError)
|
56
|
+
end
|
57
|
+
it 'raises an exception if no lookups remaining' do
|
58
|
+
expect {
|
59
|
+
results = IdealPostcodes::Address.search 'ID1 CLIP'
|
60
|
+
}.to raise_error(IdealPostcodes::TokenExhaustedError)
|
61
|
+
end
|
62
|
+
it 'raises an exception if limit breached' do
|
63
|
+
expect {
|
64
|
+
results = IdealPostcodes::Address.search 'ID1 CHOP'
|
65
|
+
}.to raise_error(IdealPostcodes::LimitReachedError)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe IdealPostcodes do
|
4
|
+
describe '#request' do
|
5
|
+
it 'generates a HTTP request' do
|
6
|
+
response = IdealPostcodes.request :get, 'postcodes/ID1 1QD'
|
7
|
+
expect(response[:code]).to eq(2000)
|
8
|
+
end
|
9
|
+
it 'raises an error if no key is provided' do
|
10
|
+
IdealPostcodes.api_key = nil
|
11
|
+
expect do
|
12
|
+
response = IdealPostcodes.request :get, 'postcodes/ID1 1QD'
|
13
|
+
end.to raise_error(IdealPostcodes::AuthenticationError)
|
14
|
+
end
|
15
|
+
it 'raises authentication error if invalid key is provided' do
|
16
|
+
IdealPostcodes.api_key = 'foo'
|
17
|
+
expect do
|
18
|
+
response = IdealPostcodes.request :get, 'postcodes/ID1 1QD'
|
19
|
+
end.to raise_error(IdealPostcodes::AuthenticationError)
|
20
|
+
end
|
21
|
+
it 'raises token exhausted error if key balance is depleted' do
|
22
|
+
expect do
|
23
|
+
response = IdealPostcodes.request :get, 'postcodes/ID1 CLIP'
|
24
|
+
end.to raise_error(IdealPostcodes::TokenExhaustedError)
|
25
|
+
end
|
26
|
+
it 'raises limit reached error if a limit has been breached' do
|
27
|
+
expect do
|
28
|
+
response = IdealPostcodes.request :get, 'postcodes/ID1 CHOP'
|
29
|
+
end.to raise_error(IdealPostcodes::LimitReachedError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '.key_available' do
|
34
|
+
it 'returns true if key is available' do
|
35
|
+
IdealPostcodes.api_key = 'iddqd'
|
36
|
+
expect(IdealPostcodes.key_available).to equal(true)
|
37
|
+
end
|
38
|
+
it 'returns false if key is unavailable' do
|
39
|
+
IdealPostcodes.api_key = 'idkfa'
|
40
|
+
expect(IdealPostcodes.key_available).to equal(false)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '.key_details' do
|
45
|
+
it 'raises an exception if no secret is provided' do
|
46
|
+
expect { IdealPostcodes.key_details }.to raise_error(
|
47
|
+
IdealPostcodes::AuthenticationError
|
48
|
+
)
|
49
|
+
end
|
50
|
+
it 'returns key information' do
|
51
|
+
IdealPostcodes.apply_secret(secret_key)
|
52
|
+
response = IdealPostcodes.key_details
|
53
|
+
expect(is_key(response)).to eq(true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/spec/keys_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe IdealPostcodes::Key do
|
4
|
+
describe '.lookup' do
|
5
|
+
it 'returns the availability status of a key (true key)' do
|
6
|
+
result = IdealPostcodes::Key.lookup 'iddqd'
|
7
|
+
expect(result[:available]).to eq(true)
|
8
|
+
end
|
9
|
+
it 'returns the availability status of a key (false key)' do
|
10
|
+
result = IdealPostcodes::Key.lookup 'idkfa'
|
11
|
+
expect(result[:available]).to eq(false)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '.lookup_details' do
|
16
|
+
it 'returns key details' do
|
17
|
+
result = IdealPostcodes::Key.lookup_details 'gandhi', secret_key
|
18
|
+
expect(result[:lookups_remaining]).to_not be_nil
|
19
|
+
expect(result[:daily_limit]).to_not be_nil
|
20
|
+
expect(result[:individual_limit]).to_not be_nil
|
21
|
+
expect(result[:allowed_urls]).to_not be_nil
|
22
|
+
expect(result[:notifications]).to_not be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe IdealPostcodes::Postcode do
|
4
|
+
describe '.lookup' do
|
5
|
+
it 'returns a list of addresses for a postcode' do
|
6
|
+
addresses = IdealPostcodes::Postcode.lookup 'ID1 1QD'
|
7
|
+
expect(addresses.length).to be > 0
|
8
|
+
addresses.each do |address|
|
9
|
+
expect(is_address(address)).to eq(true)
|
10
|
+
expect(address[:postcode]).to eq('ID1 1QD')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
it 'returns an empty array if postcode does not exist' do
|
14
|
+
addresses = IdealPostcodes::Postcode.lookup 'ID1 KFA'
|
15
|
+
expect(addresses.length).to eq(0)
|
16
|
+
end
|
17
|
+
it 'raises an exception if key has run out of balance' do
|
18
|
+
expect { IdealPostcodes::Postcode.lookup 'ID1 CLIP' }.to raise_error(
|
19
|
+
IdealPostcodes::TokenExhaustedError
|
20
|
+
)
|
21
|
+
end
|
22
|
+
it 'raises an exception if limit has been reached' do
|
23
|
+
expect { IdealPostcodes::Postcode.lookup 'ID1 CHOP' }.to raise_error(
|
24
|
+
IdealPostcodes::LimitReachedError
|
25
|
+
)
|
26
|
+
end
|
27
|
+
it 'raises an exception if invalid key' do
|
28
|
+
IdealPostcodes.api_key = 'foo'
|
29
|
+
expect { IdealPostcodes::Postcode.lookup 'ID1 1QD' }.to raise_error(
|
30
|
+
IdealPostcodes::AuthenticationError
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
describe '.find_by_location' do
|
35
|
+
it 'returns an array of postcodes and locations' do
|
36
|
+
lon = 0.6298
|
37
|
+
lat = 51.7923
|
38
|
+
postcodes =
|
39
|
+
IdealPostcodes::Postcode.find_by_location longitude: lon, latitude: lat
|
40
|
+
expect(postcodes.length).to be > 0
|
41
|
+
postcodes.each do |postcode|
|
42
|
+
expect(is_postcode_location(postcode)).to eq(true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
it 'returns an empty array if no results are found' do
|
46
|
+
lon = 0
|
47
|
+
lat = 0
|
48
|
+
postcodes =
|
49
|
+
IdealPostcodes::Postcode.find_by_location longitude: lon, latitude: lat
|
50
|
+
expect(postcodes).to be_a(Array)
|
51
|
+
expect(postcodes.length).to eq(0)
|
52
|
+
end
|
53
|
+
it 'is sensitive to limit parameter' do
|
54
|
+
lon = 0.6298
|
55
|
+
lat = 51.7923
|
56
|
+
limit = 1
|
57
|
+
postcodes =
|
58
|
+
IdealPostcodes::Postcode.find_by_location longitude: lon,
|
59
|
+
latitude: lat,
|
60
|
+
limit: limit
|
61
|
+
expect(postcodes.length).to eq(limit)
|
62
|
+
end
|
63
|
+
it 'is sensitive to radius parament' do
|
64
|
+
lon = 0.6298
|
65
|
+
lat = 51.7923
|
66
|
+
small_radius =
|
67
|
+
IdealPostcodes::Postcode.find_by_location longitude: lon,
|
68
|
+
latitude: lat,
|
69
|
+
radius: 10
|
70
|
+
large_radius =
|
71
|
+
IdealPostcodes::Postcode.find_by_location longitude: lon,
|
72
|
+
latitude: lat,
|
73
|
+
radius: 100
|
74
|
+
expect(large_radius.length > small_radius.length).to eq(true)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Enable VCR
|
2
|
+
require 'vcr'
|
3
|
+
require 'webmock'
|
4
|
+
|
5
|
+
WebMock.enable!
|
6
|
+
|
7
|
+
VCR.configure do |c|
|
8
|
+
c.cassette_library_dir = 'spec/vcr_cassettes'
|
9
|
+
c.hook_into :webmock
|
10
|
+
end
|
11
|
+
|
12
|
+
# Configure Ideal Postcodes lib
|
13
|
+
require 'ideal_postcodes'
|
14
|
+
|
15
|
+
RSpec.configure do |c|
|
16
|
+
c.before(:each) do
|
17
|
+
IdealPostcodes.base_url = 'https://localhost:1337'
|
18
|
+
IdealPostcodes.api_key = 'gandhi'
|
19
|
+
IdealPostcodes.apply_secret nil
|
20
|
+
end
|
21
|
+
|
22
|
+
c.around(:each) do |example|
|
23
|
+
VCR.use_cassette(example.metadata[:full_description]) { example.run }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def contains_attributes(attribute_list, target)
|
28
|
+
result = true
|
29
|
+
attribute_list.each { |attribute| result = false if target[attribute].nil? }
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
def postcode_location_elements
|
34
|
+
%i[postcode longitude latitude northings eastings]
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_postcode_location(postcode)
|
38
|
+
contains_attributes postcode_location_elements, postcode
|
39
|
+
end
|
40
|
+
|
41
|
+
def address_elements
|
42
|
+
%i[
|
43
|
+
postcode
|
44
|
+
postcode_inward
|
45
|
+
postcode_outward
|
46
|
+
post_town
|
47
|
+
dependant_locality
|
48
|
+
double_dependant_locality
|
49
|
+
thoroughfare
|
50
|
+
dependant_thoroughfare
|
51
|
+
building_number
|
52
|
+
building_name
|
53
|
+
sub_building_name
|
54
|
+
po_box
|
55
|
+
department_name
|
56
|
+
organisation_name
|
57
|
+
udprn
|
58
|
+
postcode_type
|
59
|
+
su_organisation_indicator
|
60
|
+
delivery_point_suffix
|
61
|
+
line_1
|
62
|
+
line_2
|
63
|
+
line_3
|
64
|
+
premise
|
65
|
+
county
|
66
|
+
district
|
67
|
+
ward
|
68
|
+
longitude
|
69
|
+
latitude
|
70
|
+
eastings
|
71
|
+
northings
|
72
|
+
]
|
73
|
+
end
|
74
|
+
|
75
|
+
def is_address(address)
|
76
|
+
contains_attributes address_elements, address
|
77
|
+
end
|
78
|
+
|
79
|
+
def key_elements
|
80
|
+
%i[lookups_remaining daily_limit individual_limit allowed_urls notifications]
|
81
|
+
end
|
82
|
+
|
83
|
+
def is_key(key)
|
84
|
+
contains_attributes key_elements, key
|
85
|
+
end
|
86
|
+
|
87
|
+
def secret_key
|
88
|
+
'uk_hxp6ouk0rmyXoobVJnehrsQcdvTfb'
|
89
|
+
end
|