firstclasspostcodes 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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/.dependabot/config.yml +12 -0
  3. data/.github/workflows/gem.yml +53 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +78 -0
  7. data/Gemfile +25 -0
  8. data/LICENSE +21 -0
  9. data/Rakefile +11 -0
  10. data/firstclasspostcodes.gemspec +54 -0
  11. data/lib/firstclasspostcodes.rb +33 -0
  12. data/lib/firstclasspostcodes/client.rb +81 -0
  13. data/lib/firstclasspostcodes/configuration.rb +156 -0
  14. data/lib/firstclasspostcodes/events.rb +27 -0
  15. data/lib/firstclasspostcodes/operations.rb +4 -0
  16. data/lib/firstclasspostcodes/operations/get_lookup.rb +52 -0
  17. data/lib/firstclasspostcodes/operations/get_postcode.rb +40 -0
  18. data/lib/firstclasspostcodes/operations/methods/format_address.rb +38 -0
  19. data/lib/firstclasspostcodes/operations/methods/list_addresses.rb +29 -0
  20. data/lib/firstclasspostcodes/response_error.rb +29 -0
  21. data/lib/firstclasspostcodes/version.rb +5 -0
  22. data/spec/firstclasspostcodes/client_spec.rb +94 -0
  23. data/spec/firstclasspostcodes/events_spec.rb +41 -0
  24. data/spec/firstclasspostcodes/operations/get_lookup_spec.rb +103 -0
  25. data/spec/firstclasspostcodes/operations/get_postcode_spec.rb +58 -0
  26. data/spec/firstclasspostcodes/operations/methods/format_address_spec.rb +106 -0
  27. data/spec/firstclasspostcodes/operations/methods/list_addresses_spec.rb +75 -0
  28. data/spec/firstclasspostcodes/response_error_spec.rb +43 -0
  29. data/spec/firstclasspostcodes/version_spec.rb +9 -0
  30. data/spec/firstclasspostcodes_spec.rb +108 -0
  31. data/spec/spec_helper.rb +42 -0
  32. data/spec/support/events_examples.rb +11 -0
  33. metadata +123 -0
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Firstclasspostcodes::Operations::GetPostcode do
6
+ class TestGetPostcode
7
+ attr_accessor :config
8
+
9
+ include Firstclasspostcodes::Operations::GetPostcode
10
+
11
+ def emit(event_name, properties); end
12
+
13
+ def request(params); end
14
+ end
15
+
16
+ subject { TestGetPostcode.new }
17
+
18
+ let(:operation_params) { { path: "/postcode", method: :get } }
19
+
20
+ let(:config) { double(geo_json?: false, debug?: true, logger: double(debug: nil)) }
21
+
22
+ before(:each) { allow(subject).to receive(:emit).with(anything, anything).and_return(true) }
23
+
24
+ before(:each) { subject.config = config }
25
+
26
+ specify { expect(subject).respond_to?(:get_postcode) }
27
+
28
+ describe "when the request is valid" do
29
+ before(:each) { allow(subject).to receive(:request).and_return(double) }
30
+
31
+ let(:postcode) { "test" }
32
+
33
+ it "returns the correct response" do
34
+ expect(subject).to receive(:request).with(operation_params.merge(
35
+ query_params: {
36
+ search: postcode,
37
+ }
38
+ ))
39
+ response = subject.get_postcode(postcode)
40
+ expect(response).respond_to?(:list_addresses)
41
+ expect(response).respond_to?(:format_address)
42
+ end
43
+ end
44
+
45
+ describe "when the request is invalid" do
46
+ describe "when there are no parameters" do
47
+ it "raises an error" do
48
+ expect { subject.get_postcode(23_456) }.to raise_error(StandardError)
49
+ end
50
+ end
51
+
52
+ describe "when there is an empty string" do
53
+ it "raises an error" do
54
+ expect { subject.get_postcode("") }.to raise_error(StandardError)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Firstclasspostcodes::Operations::Methods::FormatAddress do
6
+ class TestFormatAddress < Hash
7
+ include Firstclasspostcodes::Operations::Methods::FormatAddress
8
+ end
9
+
10
+ subject { TestFormatAddress[] }
11
+
12
+ let(:index) { "numbers:0" }
13
+
14
+ before(:each) do
15
+ subject.merge!(
16
+ numbers: [
17
+ {
18
+ number: 1,
19
+ street: "A Street",
20
+ },
21
+ {
22
+ number: "Flat A",
23
+ building: "Crescent",
24
+ street: "A Street",
25
+ },
26
+ ],
27
+ streets: [
28
+ "A Street",
29
+ "B Avenue",
30
+ ],
31
+ locality: "locality",
32
+ city: "city",
33
+ county: "county",
34
+ region: "region",
35
+ country: "country",
36
+ postcode: "postcode"
37
+ )
38
+ end
39
+
40
+ specify { expect(subject.respond_to?(:format_address)) }
41
+
42
+ describe "when the type is invalid" do
43
+ let(:index) { "dadwadada:0" }
44
+
45
+ it "throws an error" do
46
+ expect { subject.format_address(index) }.to raise_error(StandardError)
47
+ end
48
+ end
49
+
50
+ describe 'when the "postcode" type is passed in' do
51
+ let(:index) { "postcode:0" }
52
+
53
+ it "returns a formatted postcode" do
54
+ expect(subject.format_address(index)).to eq(
55
+ locality: "city",
56
+ region: "county",
57
+ postcode: "postcode",
58
+ country: "country"
59
+ )
60
+ end
61
+ end
62
+
63
+ describe 'when the "streets" type is passed in' do
64
+ let(:index) { "streets:1" }
65
+
66
+ it "returns a formatted street" do
67
+ expect(subject.format_address(index)).to eq(
68
+ address: "B Avenue",
69
+ locality: "city",
70
+ region: "county",
71
+ postcode: "postcode",
72
+ country: "country"
73
+ )
74
+ end
75
+
76
+ describe "when there are no streets" do
77
+ before(:each) { subject[:streets] = nil }
78
+
79
+ it "throws an error" do
80
+ expect { subject.format_address(index) }.to raise_error(StandardError)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe 'when the "numbers" type is passed in' do
86
+ let(:index) { "numbers:1" }
87
+
88
+ it "returns a formatted number" do
89
+ expect(subject.format_address(index)).to eq(
90
+ address: "Flat A, Crescent, A Street",
91
+ locality: "city",
92
+ region: "county",
93
+ postcode: "postcode",
94
+ country: "country"
95
+ )
96
+ end
97
+
98
+ describe "when there are no numbers" do
99
+ before(:each) { subject[:numbers] = nil }
100
+
101
+ it "throws an error" do
102
+ expect { subject.format_address(index) }.to raise_error(StandardError)
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Firstclasspostcodes::Operations::Methods::ListAddresses do
6
+ class TestListAddresses < Hash
7
+ include Firstclasspostcodes::Operations::Methods::ListAddresses
8
+ end
9
+
10
+ subject { TestListAddresses[] }
11
+
12
+ specify { expect(subject.respond_to?(:list_addresses)) }
13
+
14
+ describe "when there are no numbers or streets" do
15
+ before(:each) do
16
+ subject.merge!(
17
+ numbers: [],
18
+ streets: [],
19
+ locality: "locality",
20
+ city: "city",
21
+ postcode: "postcode"
22
+ )
23
+ end
24
+
25
+ it "returns a postcode option" do
26
+ expect(subject.list_addresses).to eq([
27
+ ["postcode:0", "city, postcode"],
28
+ ])
29
+ end
30
+ end
31
+
32
+ describe "when there are only streets" do
33
+ before(:each) do
34
+ subject.merge!(
35
+ numbers: [],
36
+ streets: ["A Street", "B Avenue"],
37
+ locality: "locality",
38
+ city: "city",
39
+ postcode: "postcode"
40
+ )
41
+ end
42
+
43
+ it "returns equal number of street options" do
44
+ expect(subject.list_addresses).to eq([
45
+ ["streets:0", "A Street, city, postcode"],
46
+ ["streets:1", "B Avenue, city, postcode"],
47
+ ])
48
+ end
49
+ end
50
+
51
+ describe "when there are streets and numbers" do
52
+ before(:each) do
53
+ subject.merge!(
54
+ numbers: [
55
+ {
56
+ number: 1,
57
+ street: "A Street",
58
+ },
59
+ {
60
+ number: "Flat A",
61
+ building: "Crescent",
62
+ street: "A Street",
63
+ },
64
+ ],
65
+ streets: ["A Street", "B Avenue"],
66
+ locality: "locality",
67
+ city: "city",
68
+ postcode: "postcode"
69
+ )
70
+ end
71
+
72
+ it "returns equal number of street options" do
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Firstclasspostcodes::ResponseError do
6
+ describe "when the error is a hash" do
7
+ let(:error_object) do
8
+ {
9
+ message: "message",
10
+ docUrl: "https://google.com/some-doc",
11
+ type: "type",
12
+ }
13
+ end
14
+
15
+ subject { Firstclasspostcodes::ResponseError.new(error_object) }
16
+
17
+ specify { expect(subject.message).to include error_object[:message] }
18
+
19
+ specify { expect(subject.type).to include error_object[:type] }
20
+
21
+ specify { expect(subject.message).to include error_object[:docUrl] }
22
+
23
+ specify { expect(subject.type).to eq error_object[:type] }
24
+
25
+ specify { expect(subject.doc_url).to eq error_object[:docUrl] }
26
+ end
27
+
28
+ describe "when the error is a message" do
29
+ let(:error_message) { "message" }
30
+
31
+ let(:error_type) { "type" }
32
+
33
+ subject { Firstclasspostcodes::ResponseError.new(error_message, error_type) }
34
+
35
+ specify { expect(subject.type).to eq(error_type) }
36
+
37
+ specify { expect(subject.message).to include error_message }
38
+
39
+ specify { expect(subject.message).to include error_type }
40
+
41
+ specify { expect(subject.doc_url).to include error_type }
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Firstclasspostcodes do
6
+ subject { Firstclasspostcodes::VERSION }
7
+
8
+ specify { expect(subject).to match(/^[0-9]+\.[0-9]+\.[0-9]+$/) }
9
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Firstclasspostcodes do
6
+ describe "#content" do
7
+ let(:config) { Firstclasspostcodes::Configuration.new }
8
+
9
+ it "defaults to json" do
10
+ expect(Firstclasspostcodes::Configuration.default.content).to eq("json")
11
+ expect(config.content).to eq("json")
12
+ end
13
+
14
+ # it 'raises when an invalid type is passed' do
15
+ # expect { config.content = "awdgfde" }.to raise_error(StandardError)
16
+ # end
17
+ end
18
+
19
+ describe "#configure" do
20
+ it "calls a configuration block" do
21
+ expect { |b| Firstclasspostcodes.configure(&b) }.to yield_control
22
+ end
23
+ end
24
+
25
+ describe "#protocol" do
26
+ it "removes :// from the protocol" do
27
+ Firstclasspostcodes.configure { |c| c.protocol = "https://" }
28
+ expect(Firstclasspostcodes::Configuration.default.protocol).to eq("https")
29
+ end
30
+ end
31
+
32
+ describe "#host" do
33
+ it "removes http from host" do
34
+ Firstclasspostcodes.configure { |c| c.host = "http://example.com" }
35
+ expect(Firstclasspostcodes::Configuration.default.host).to eq("example.com")
36
+ end
37
+
38
+ it "removes https from host" do
39
+ Firstclasspostcodes.configure { |c| c.host = "https://wookiee.com" }
40
+ expect(Firstclasspostcodes::Configuration.default.host).to eq("wookiee.com")
41
+ end
42
+
43
+ it "removes trailing path from host" do
44
+ Firstclasspostcodes.configure { |c| c.host = "hobo.com/v4" }
45
+ expect(Firstclasspostcodes::Configuration.default.host).to eq("hobo.com")
46
+ end
47
+ end
48
+
49
+ describe "#base_path" do
50
+ it "prepends a slash to base_path" do
51
+ Firstclasspostcodes.configure { |c| c.base_path = "v4/dog" }
52
+ expect(Firstclasspostcodes::Configuration.default.base_path).to eq("/v4/dog")
53
+ end
54
+
55
+ it "doesn't prepend a slash if one is already there" do
56
+ Firstclasspostcodes.configure { |c| c.base_path = "/v4/dog" }
57
+ expect(Firstclasspostcodes::Configuration.default.base_path).to eq("/v4/dog")
58
+ end
59
+
60
+ it "ends up as a blank string if nil" do
61
+ Firstclasspostcodes.configure { |c| c.base_path = nil }
62
+ expect(Firstclasspostcodes::Configuration.default.base_path).to eq("")
63
+ end
64
+ end
65
+
66
+ describe "#geo_json?" do
67
+ let(:config) { Firstclasspostcodes::Configuration.new }
68
+
69
+ it "defaults to false" do
70
+ expect(Firstclasspostcodes::Configuration.default.geo_json?).to be_falsey
71
+ expect(config.geo_json?).to be_falsey
72
+ end
73
+
74
+ it "can be customized" do
75
+ config.content = "geo+json"
76
+ expect(config.geo_json?).to be_truthy
77
+ end
78
+ end
79
+
80
+ describe "#debug?" do
81
+ let(:config) { Firstclasspostcodes::Configuration.new }
82
+
83
+ it "defaults to false" do
84
+ expect(Firstclasspostcodes::Configuration.default.debug?).to be_falsey
85
+ expect(config.debug?).to be_falsey
86
+ end
87
+
88
+ it "can be customized" do
89
+ config.debug = true
90
+ expect(config.debug?).to be_truthy
91
+ end
92
+ end
93
+
94
+ describe "timeout in #build_request" do
95
+ let(:config) { Firstclasspostcodes::Configuration.new }
96
+
97
+ it "defaults to 0" do
98
+ expect(Firstclasspostcodes::Configuration.default.timeout).to eq(0)
99
+ expect(config.timeout).to eq(0)
100
+ expect(config.to_request_params[:timeout]).to eq(0)
101
+ end
102
+
103
+ it "can be customized" do
104
+ config.timeout = 100
105
+ expect(config.to_request_params[:timeout]).to eq(100)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "simplecov"
5
+
6
+ SimpleCov.start
7
+
8
+ if ENV["CI"] == "true"
9
+ require "codecov"
10
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
11
+ end
12
+
13
+ # load the gem
14
+ require "firstclasspostcodes"
15
+
16
+ API_URL = ENV["API_URL"]
17
+
18
+ API_KEY = ENV["API_KEY"]
19
+
20
+ RSpec.configure do |config|
21
+ config.expect_with :rspec do |expectations|
22
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
23
+ end
24
+
25
+ config.mock_with :rspec do |mocks|
26
+ mocks.verify_partial_doubles = true
27
+ end
28
+
29
+ config.before(:each) do
30
+ Typhoeus::Expectation.clear
31
+
32
+ uri = URI.parse(API_URL)
33
+
34
+ Firstclasspostcodes.configure do |c|
35
+ c.api_key = API_KEY
36
+ c.base_path = uri.path
37
+ c.protocol = uri.scheme
38
+ c.host = uri.host
39
+ c.host = "#{uri.host}:#{uri.port}" if uri.port
40
+ end
41
+ end
42
+ end