loqate 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47002dc81cfda694969dd28475fbe196b99f00e72df5bd6ef5cfe05172d853f1
4
- data.tar.gz: 59bfa426b7132b601e84ea52dacfcfc9650b428beb1e7142738faf0743166e69
3
+ metadata.gz: e1f1396b79c0115311d766dd1b8fb7f4b0325596d27293d1b1d4af7c0d3d4a29
4
+ data.tar.gz: e2a275316138017ec971b0a4412e8cc92a872983a523067c33c1ea2c88785de3
5
5
  SHA512:
6
- metadata.gz: 9fe20f3fbe659b7116e648ff538652be8417693d825fa4c8f73b50898ddd95fbad9c9d071e9eb506b0957ddfb01dcb60d13175c9fc54d2648a7a08d2ae79d92a
7
- data.tar.gz: 51c9b923de5ec21e2c3ad61de941a114d2d52a690d7f8614ae257ae952fef0175486a85c66d627212e70af5b4c4881d8808e199871bd1b44b59ddc88ab4f3685
6
+ metadata.gz: abf8817900f777554ded8b558dd43e4f94ebead001fb53c9ac012e8d462f7b4c3926e86a00ea1ac3d5b9230376c19af03931d08c4a0c684bf137369dd8ce332b
7
+ data.tar.gz: 470d80e084b048173e3ae34d230227308c2855fbb2fa26be93897464ba9c9fd9a0490f0ee9062302107315f4ecb168db50c39e6799af009e492af223b2dad2b2
data/.gitignore CHANGED
@@ -10,3 +10,5 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+ .api_key
14
+ /Gemfile.lock
data/.rubocop.yml CHANGED
@@ -5,11 +5,16 @@ AllCops:
5
5
 
6
6
  Metrics/BlockLength:
7
7
  Exclude:
8
+ - spec/**/*_spec.rb
8
9
  - loqate.gemspec
9
10
 
10
11
  Metrics/LineLength:
11
12
  Max: 120
12
13
 
14
+ Naming/MethodName:
15
+ Exclude:
16
+ - lib/loqate/result.rb
17
+
13
18
  # ----------------------- Style -----------------------
14
19
 
15
20
  Style/FrozenStringLiteralComment:
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/.travis.yml CHANGED
@@ -13,6 +13,7 @@ rvm:
13
13
  before_install: gem install bundler -v 1.16.5
14
14
 
15
15
  before_script:
16
+ - echo 'fake-key' > .api_key
16
17
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
17
18
  - chmod +x ./cc-test-reporter
18
19
  - ./cc-test-reporter before-build
data/.yardstick.yml CHANGED
@@ -1,10 +1,10 @@
1
1
  threshold: 100
2
2
  rules:
3
3
  ApiTag::Presence:
4
- enabled: true
4
+ enabled: false
5
5
  exclude: []
6
6
  ApiTag::Inclusion:
7
- enabled: true
7
+ enabled: false
8
8
  exclude: []
9
9
  ApiTag::ProtectedMethod:
10
10
  enabled: true
@@ -14,18 +14,93 @@ rules:
14
14
  exclude: []
15
15
  ExampleTag:
16
16
  enabled: true
17
- exclude: []
17
+ exclude:
18
+ - Loqate::Address#==
19
+ - Loqate::Address#attributes
20
+ - Loqate::Address#id
21
+ - Loqate::Address#initialize
22
+ - Loqate::Address#type
23
+ - Loqate::Address#text
24
+ - Loqate::Address#highlight
25
+ - Loqate::Address#description
26
+ - Loqate::AddressGateway#initialize
27
+ - Loqate::APIResult#errors?
28
+ - Loqate::APIResult#items
29
+ - Loqate::APIResult#initialize
30
+ - Loqate::Configuration#api_key
31
+ - Loqate::Configuration#host
32
+ - Loqate::Configuration#language
33
+ - Loqate::Configuration#initialize
34
+ - Loqate::DetailedAddress#initialize
35
+ - Loqate::DetailedAddress#==
36
+ - Loqate::Error#id
37
+ - Loqate::Error#description
38
+ - Loqate::Error#cause
39
+ - Loqate::Error#resolution
40
+ - Loqate::Error#initialize
41
+ - Loqate::Gateway#config
42
+ - Loqate::Gateway#initialize
43
+ - Loqate::Gateway#address
44
+ - Loqate::Result::Success#success?
45
+ - Loqate::Result::Success#failure?
46
+ - Loqate::Result::Failure#success?
47
+ - Loqate::Result::Failure#failure?
48
+ - Loqate::Result#code
49
+ - Loqate::Result#value
18
50
  ReturnTag:
19
51
  enabled: true
20
- exclude: []
52
+ exclude:
53
+ - Loqate::Address#==
54
+ - Loqate::Address#attributes
55
+ - Loqate::Address#id
56
+ - Loqate::Address#type
57
+ - Loqate::Address#text
58
+ - Loqate::Address#highlight
59
+ - Loqate::Address#description
60
+ - Loqate::AddressGateway#client
61
+ - Loqate::AddressGateway#mapper
62
+ - Loqate::AddressGateway#error_mapper
63
+ - Loqate::AddressGateway#build_errors_from
64
+ - Loqate::AddressGateway#build_address_from
65
+ - Loqate::AddressGateway#build_detailed_addresses_from
66
+ - Loqate::Client#configuration
67
+ - Loqate::Client#authenticate_params
68
+ - Loqate::Client#format_params
69
+ - Loqate::DetailedAddress#==
70
+ - Loqate::Util.camelize
71
+ - Loqate::Util#camelize
72
+ - Loqate::Util.underscore
73
+ - Loqate::Util#underscore
74
+ - Loqate::Error#attributes
75
+ - Loqate::Gateway#client
21
76
  Summary::Presence:
22
77
  enabled: true
23
- exclude: []
78
+ exclude:
79
+ - Loqate::Address#==
80
+ - Loqate::Address#attributes
81
+ - Loqate::Address#id
82
+ - Loqate::Address#type
83
+ - Loqate::Address#text
84
+ - Loqate::Address#highlight
85
+ - Loqate::Address#description
86
+ - Loqate::AddressGateway#client
87
+ - Loqate::AddressGateway#mapper
88
+ - Loqate::AddressGateway#error_mapper
89
+ - Loqate::AddressGateway#build_errors_from
90
+ - Loqate::AddressGateway#build_address_from
91
+ - Loqate::AddressGateway#build_detailed_addresses_from
92
+ - Loqate::Client#configuration
93
+ - Loqate::Client#authenticate_params
94
+ - Loqate::Client#format_params
95
+ - Loqate::DetailedAddress#initialize
96
+ - Loqate::DetailedAddress#==
97
+ - Loqate::Error#attributes
98
+ - Loqate::Gateway#client
24
99
  Summary::Length:
25
100
  enabled: false
26
101
  Summary::Delimiter:
27
102
  enabled: false
28
103
  exclude: []
29
104
  Summary::SingleLine:
30
- enabled: true
105
+ enabled: false
31
106
  exclude: []
data/CHANGELOG.md CHANGED
@@ -3,3 +3,21 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.2.0] - 2018-10-31
8
+ ### Added
9
+ - VCR and WebMock to record HTTP interactions
10
+ - A file to hold a development API key (`.api_key`)
11
+ - A ruby version dotfile (`.ruby-version`)
12
+ - Core of the gem
13
+ - Address API
14
+
15
+ ### Changed
16
+ - Document the available code maintenance Rake tasks.
17
+
18
+ ## [0.1.0] - 2018-09-29
19
+ ### Added
20
+ - Initial core functionality
21
+ - Codebase maintenance tools
22
+
23
+ [0.2.0]: https://github.com/wilsonsilva/memoria/compare/v0.1.0...v0.2.0
data/README.md CHANGED
@@ -7,9 +7,7 @@
7
7
  [![Security](https://hakiri.io/github/wilsonsilva/loqate/master.svg)](https://hakiri.io/github/wilsonsilva/loqate/master)
8
8
  [![Inline docs](http://inch-ci.org/github/wilsonsilva/loqate.svg?branch=master)](http://inch-ci.org/github/wilsonsilva/loqate)
9
9
 
10
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/loqate`. To experiment with that code, run `bin/console` for an interactive prompt.
11
-
12
- TODO: Delete this and the text above, and describe your gem
10
+ Client to address verification, postcode lookup, & data quality services from Loqate.
13
11
 
14
12
  ## Installation
15
13
 
@@ -29,12 +27,67 @@ Or install it yourself as:
29
27
 
30
28
  ## Usage
31
29
 
32
- TODO: Write usage instructions here
30
+ ### Getting started
31
+
32
+ Loqate provides multiple APIs. And each API provides several services. This gem exposes these APIs through
33
+ an API gateway.
34
+
35
+ To get started, initialize an API gateway with [your API key](https://account.loqate.com/account#/):
36
+
37
+ ```ruby
38
+ gateway = Loqate::Gateway.new(api_key: '<YOUR_API_KEY>')
39
+ ```
40
+
41
+ Every call to a gateway method will return a `Loqate::Result` object, which will respond to `success?` and `failure?`.
42
+
43
+ ### Address API
44
+
45
+ The Address API consists of two main API requests:
46
+ [Find](https://www.loqate.com/resources/support/apis/Capture/Interactive/Find/1/) request is used to narrow down a
47
+ possible list of addresses;
48
+ and a [Retrieve](https://www.loqate.com/resources/support/apis/Capture/Interactive/Retrieve/1/) request is used to
49
+ retrieve a fully formatted address.
50
+
51
+ A typical address search is made up of a series of `find` requests, followed by a `retrieve` based on the user
52
+ selection.
53
+
54
+ #### Finding addresses
55
+
56
+ ```ruby
57
+ result = gateway.address.find(text: 'EC1Y 8AF', country: 'GB', limit: 5)
58
+
59
+ result.success? # => true
60
+ result.failure? # => false
61
+
62
+ addresses = result.value
63
+ addresses.first.id # => 'GB|RM|B|8144611'
64
+ ```
65
+
66
+ #### Retrieving the details of an address
67
+
68
+ ```ruby
69
+ result = gateway.address.retrieve(id: 'GB|RM|B|8144611')
70
+
71
+ result.success? # => true
72
+ result.failure? # => false
73
+
74
+ addresses = result.value
75
+ address = addresses.first
76
+
77
+ address.city # 'London'
78
+ address.line1 # '148 Warner Road'
79
+ address.postal_code # 'E17 7EA'
80
+ ```
33
81
 
34
82
  ## Development
35
83
 
36
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive
37
- prompt that will allow you to experiment. The health and maintainability of the codebase is ensured through a set of
84
+ After checking out the repo, run `bin/setup` to install dependencies, configure git hooks and create support files.
85
+
86
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
87
+
88
+ Then add your Loqate API key to `.api_key`. It will be used by RSpec and VCR, but not stored in the codebase.
89
+
90
+ The health and maintainability of the codebase is ensured through a set of
38
91
  Rake tasks to test, lint and audit the gem for security vulnerabilities and documentation:
39
92
 
40
93
  ```
@@ -51,4 +104,4 @@ rake yardstick_measure # Measure docs in lib/**/*.rb with yardstick
51
104
 
52
105
  ## Contributing
53
106
 
54
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/loqate.
107
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wilsonsilva/loqate.
data/ROADMAP.md CHANGED
@@ -2,17 +2,18 @@
2
2
 
3
3
  ## Core
4
4
 
5
- - [ ] HTTP Client
6
- - [ ] Core Client
5
+ - [x] HTTP Client
6
+ - [x] Core Client
7
7
  - [ ] Logging
8
- - [ ] Domain error handling
9
- - [ ] Configuration
10
- - [ ] Versioning
8
+ - [x] Domain error handling
9
+ - [x] Configuration
10
+ - [ ] Validate request parameters
11
+ - [ ] API/Service versioning
11
12
  - [ ] Integration with RSpec
12
13
 
13
14
  ## APIs
14
15
 
15
- - [ ] Address Verification
16
+ - [x] Address Verification
16
17
  - [ ] Geocode
17
18
  - [ ] Data Cleanse
18
19
  - [ ] Email Verification
@@ -26,7 +27,7 @@
26
27
  - [ ] File Renderer
27
28
  - [ ] HTML Table
28
29
  - [ ] Image Renderer
29
- - [ ] JSON
30
+ - [x] JSON
30
31
  - [ ] JSON (with extra)
31
32
  - [ ] JSONP (JavaScript)
32
33
  - [ ] PDF
data/bin/setup CHANGED
@@ -12,3 +12,5 @@ if ! which overcommit >/dev/null; then
12
12
  fi
13
13
 
14
14
  overcommit --install
15
+
16
+ touch ../.api_key
data/lib/loqate.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'loqate/version'
4
+ require 'loqate/gateway'
4
5
 
5
6
  # Encapsulates all the code of the gem.
6
7
  module Loqate
@@ -0,0 +1,71 @@
1
+ module Loqate
2
+ # A result from the address find service.
3
+ class Address
4
+ # An address ID or a container ID for further results
5
+ #
6
+ # @return [String]
7
+ #
8
+ attr_reader :id
9
+
10
+ # If the Type is 'Address' then the ID can be passed to the Retrieve service.
11
+ # Any other ID should be passed as the Container to a further Find request to get more results.
12
+ #
13
+ # @return [String]
14
+ #
15
+ attr_reader :type
16
+
17
+ # The name of the result
18
+ #
19
+ # @return [String]
20
+ #
21
+ attr_reader :text
22
+
23
+ # A list of number ranges identifying the matched characters in the Text and Description
24
+ #
25
+ # @return [String]
26
+ #
27
+ attr_reader :highlight
28
+
29
+ # Descriptive information about the result
30
+ #
31
+ # @return [String]
32
+ #
33
+ attr_reader :description
34
+
35
+ # Creates an address
36
+ #
37
+ # @param [String] id An address ID or a container ID for further results
38
+ # @param [String] type If the Type is 'Address' then the ID can be passed to the Retrieve service.
39
+ # Any other ID should be passed as the Container to a further Find request to get more results.
40
+ # @param [String] text The name of the result
41
+ # @param [String] highlight A list of number ranges identifying the matched characters in the Text and Description
42
+ # @param [String] description Descriptive information about the result
43
+ #
44
+ def initialize(id:, type:, text:, highlight:, description:)
45
+ @id = id
46
+ @type = type
47
+ @text = text
48
+ @highlight = highlight
49
+ @description = description
50
+ end
51
+
52
+ # @!visibility private
53
+ # @api private
54
+ def ==(other)
55
+ attributes == other.send(:attributes)
56
+ end
57
+
58
+ private
59
+
60
+ # @api private
61
+ def attributes
62
+ @attributes ||= {
63
+ id: id,
64
+ type: type,
65
+ text: text,
66
+ highlight: highlight,
67
+ description: description
68
+ }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,101 @@
1
+ require 'loqate/address'
2
+ require 'loqate/detailed_address'
3
+ require 'loqate/error'
4
+ require 'loqate/client'
5
+ require 'loqate/result'
6
+ require 'loqate/mappers/error_mapper'
7
+ require 'loqate/mappers/generic_mapper'
8
+
9
+ module Loqate
10
+ # Address Verification consists of two main API requests: a Find request is used to narrow down a possible
11
+ # list of addresses; and a Retrieve request is used to retrieve a fully formatted address.
12
+ #
13
+ # A typical address search is made up of a series of Find requests, followed by a Retrieve based on the
14
+ # user selection. Choose a service below to find out how to use each request.
15
+ #
16
+ class AddressGateway
17
+ FIND_ENDPOINT = '/Capture/Interactive/Find/v1.00/json3.ws'.freeze
18
+ RETRIEVE_ENDPOINT = '/Capture/Interactive/Retrieve/v1.00/json3.ws'.freeze
19
+
20
+ include Result::Mixin
21
+
22
+ # Creates an address gateway
23
+ #
24
+ # @param [Client] client The client responsible for the HTTP interactions
25
+ #
26
+ def initialize(client)
27
+ @client = client
28
+ @mapper = Mappers::GenericMapper.new
29
+ @error_mapper = Mappers::ErrorMapper.new
30
+ end
31
+
32
+ # Find addresses and places.
33
+ #
34
+ # @param [Hash] options The options to find an address or a list of addresses.
35
+ # @option options [String] :text The search text to find. Ideally a postcode or the start of the address.
36
+ # @option options [String] countries A comma separated list of ISO 2 or 3 character country codes to limit
37
+ # the search within.
38
+ # @option options [String] origin A starting location for the search. This can be the name or ISO 2 or 3 character
39
+ # code of a country, WGS84 coordinates (comma separated) or IP address to search from.
40
+ # @option options [String] container A container for the search. This should only be another Id previously returned
41
+ # from this service when the Type of the result was not 'Address'.
42
+ # @option options [Integer] limit The maximum number of results to return.
43
+ # @option options [String] language The preferred language for results. This should be a 2 or 4 character language
44
+ # code e.g. (en, fr, en-gb, en-us etc).
45
+ #
46
+ # @example Retrieving an address in the UK
47
+ # address = address_gateway.find(countries: 'GB', text: 'Scrubs Lane')
48
+ #
49
+ # @return [Array<Address>] A list of addresses
50
+ #
51
+ def find(options)
52
+ response = client.get(FIND_ENDPOINT, options)
53
+
54
+ response.errors? && build_errors_from(response.items) || build_address_from(response.items)
55
+ end
56
+
57
+ # Returns the full address details based on the id.
58
+ #
59
+ # @param [Hash] options The options to retrieve the address.
60
+ # @option options [String] :id The Id from a Find method to retrieve the details for.
61
+ # @option options [String] :field_1_format a.
62
+ # @option options [String] :field_2_format b.
63
+ # @option options [String] :field_3_format c.
64
+ # @option options [String] :field_4_format d.
65
+ # @option options [String] :field_5_format e.
66
+ #
67
+ # @example Retrieving the details of an address
68
+ # detailed_address = gateway.retrieve(id: 'GB|RM|ENG|6RB-NW10')
69
+ #
70
+ # @return [Array<DetailedAddress>] A list of detailed addresses
71
+ #
72
+ def retrieve(options)
73
+ response = client.get(RETRIEVE_ENDPOINT, options)
74
+
75
+ response.errors? && build_errors_from(response.items) || build_detailed_addresses_from(response.items)
76
+ end
77
+
78
+ private
79
+
80
+ # @api private
81
+ attr_reader :client, :mapper, :error_mapper
82
+
83
+ # @api private
84
+ def build_errors_from(items)
85
+ errors = error_mapper.map(items)
86
+ Failure(errors)
87
+ end
88
+
89
+ # @api private
90
+ def build_address_from(items)
91
+ address = mapper.map(items, Address)
92
+ Success(address)
93
+ end
94
+
95
+ # @api private
96
+ def build_detailed_addresses_from(items)
97
+ detailed_address = mapper.map(items, DetailedAddress)
98
+ Success(detailed_address)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,26 @@
1
+ module Loqate
2
+ # Generic response of a request to Loqate's API
3
+ class APIResult
4
+ # Array of hashes representing each item in the response body
5
+ #
6
+ # @return [Array<Hash>]
7
+ #
8
+ attr_reader :items
9
+
10
+ # Instantiates a new API result
11
+ #
12
+ # @param [Array<Hash>] items Array of hashes representing each item in the response body
13
+ #
14
+ def initialize(items)
15
+ @items = items
16
+ end
17
+
18
+ # Whether the response contains errors
19
+ #
20
+ # @return [Boolean] true if the response has errors and false otherwise
21
+ #
22
+ def errors?
23
+ !items.dig(0, 'Error').nil?
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ require 'http'
2
+ require 'loqate/configuration'
3
+ require 'loqate/api_result'
4
+
5
+ module Loqate
6
+ # Responsible for the HTTP interactions. The only entity aware of HTTP concerns such as status codes and headers.
7
+ class Client
8
+ # Instantiates a new client
9
+ #
10
+ # @example
11
+ # configuration = Configuration.new(api_key: 'EA69-CD23-CV99-HL18')
12
+ # client = Client.new(configuration)
13
+ #
14
+ # @param [Configuration] configuration The configuration of the gem
15
+ #
16
+ def initialize(configuration)
17
+ @configuration = configuration
18
+ end
19
+
20
+ # Performs a GET request to Loqate's API. Every request returns the status code 200.
21
+ #
22
+ # @example Retrieving a resource
23
+ # client = Client.new
24
+ # result = client.get('/Capture/Interactive/Find/v1.00/json3.ws')
25
+ #
26
+ # @example Retrieving a resource using options
27
+ # client = Client.new
28
+ # result = client.get('/Capture/Interactive/Find/v1.00/json3.ws', countries: 'GB', text: 'Scrubs Lane')
29
+ #
30
+ # @param [String] endpoint URL of the API endpoint where the GET request
31
+ # @param [Hash] params Options for the GET request
32
+ #
33
+ # @return [APIResult] Generic response of a request to Loqate's API
34
+ #
35
+ def get(endpoint, params = {})
36
+ authenticated_params = authenticate_params(params)
37
+ formatted_params = format_params(authenticated_params)
38
+
39
+ response = HTTP.get(configuration.host + endpoint, params: formatted_params)
40
+
41
+ body = JSON.parse(response.body)
42
+ APIResult.new(body.fetch('Items'))
43
+ end
44
+
45
+ private
46
+
47
+ # @api private
48
+ attr_reader :configuration
49
+
50
+ # @api private
51
+ def authenticate_params(params)
52
+ params.merge(key: configuration.api_key)
53
+ end
54
+
55
+ # @api private
56
+ def format_params(params)
57
+ params.transform_keys { |key| Util.camelize(key) }
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,34 @@
1
+ module Loqate
2
+ # Configuration for the gem
3
+ class Configuration
4
+ DEFAULT_LANGUAGE = 'en-gb'.freeze
5
+ DEFAULT_HOST = 'https://api.addressy.com'.freeze
6
+
7
+ # API key that will give you access to all services.
8
+ #
9
+ # @return [String]
10
+ attr_reader :api_key
11
+
12
+ # Base URL for Loqate's services. Defaults to https://api.addressy.com
13
+ #
14
+ # @return [String]
15
+ attr_reader :host
16
+
17
+ # Preferred language for results. This should be a 2 or 4 character language code e.g. (en, fr, en-gb, etc).
18
+ #
19
+ # @return [String]
20
+ attr_reader :language
21
+
22
+ # Instantiates the gem configuration
23
+ #
24
+ # @param [String] api_key API key that will give you access to all services
25
+ # @param [String] host Base URL for Loqate's services
26
+ # @param [String] language Preferred language for results
27
+ #
28
+ def initialize(api_key:, host: DEFAULT_HOST, language: DEFAULT_LANGUAGE)
29
+ @api_key = api_key
30
+ @host = host
31
+ @language = language
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,83 @@
1
+ module Loqate
2
+ # A result from the address retrieve service.
3
+ class DetailedAddress
4
+ # For the first version, this will be a flat structure, exactly as it is defined in Loqate's API.
5
+ # But this many attributes is too much for a single object to hold.
6
+ #
7
+ # @api private
8
+ #
9
+ ATTRIBUTES = %i[
10
+ admin_area_code
11
+ admin_area_name
12
+ barcode
13
+ block
14
+ building_name
15
+ building_number
16
+ city
17
+ company
18
+ country_iso2
19
+ country_iso3
20
+ country_iso_number
21
+ country_name
22
+ data_level
23
+ department
24
+ district
25
+ domestic_id
26
+ field1
27
+ field2
28
+ field3
29
+ field4
30
+ field5
31
+ field6
32
+ field7
33
+ field8
34
+ field9
35
+ field10
36
+ field11
37
+ field12
38
+ field13
39
+ field14
40
+ field15
41
+ field16
42
+ field17
43
+ field18
44
+ field19
45
+ field20
46
+ id
47
+ label
48
+ language
49
+ language_alternatives
50
+ line1
51
+ line2
52
+ line3
53
+ line4
54
+ line5
55
+ neighbourhood
56
+ po_box_number
57
+ postal_code
58
+ province
59
+ province_code
60
+ province_name
61
+ secondary_street
62
+ sorting_number1
63
+ sorting_number2
64
+ street
65
+ sub_building
66
+ type
67
+ ].freeze
68
+
69
+ ATTRIBUTES.each do |attribute|
70
+ attr_reader attribute
71
+ end
72
+
73
+ def initialize(options = {})
74
+ options.each_pair do |key, value|
75
+ instance_variable_set("@#{key}", value) if ATTRIBUTES.include?(key)
76
+ end
77
+ end
78
+
79
+ def ==(other)
80
+ other.is_a?(DetailedAddress) && id == other.id
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,54 @@
1
+ module Loqate
2
+ # Generic error returned from an API call
3
+ class Error
4
+ # Unique identifier for the error
5
+ #
6
+ # @return [Integer]
7
+ #
8
+ attr_reader :id
9
+
10
+ # Descriptive information about the error
11
+ #
12
+ # @return [String]
13
+ #
14
+ attr_reader :description
15
+
16
+ # What caused the error
17
+ #
18
+ # @return [String]
19
+ #
20
+ attr_reader :cause
21
+
22
+ # How to solve the error
23
+ #
24
+ # @return [String]
25
+ #
26
+ attr_reader :resolution
27
+
28
+ # Instantiates an error
29
+ #
30
+ # @param [Integer] id Unique identifier for the error
31
+ # @param [String] description Descriptive information about the error
32
+ # @param [String] cause What caused the error
33
+ # @param [String] resolution How to solve the error
34
+ #
35
+ def initialize(id:, description:, cause:, resolution:)
36
+ @id = id
37
+ @cause = cause
38
+ @resolution = resolution
39
+ @description = description
40
+ end
41
+
42
+ # Compare the equality of this error with +other+. Two errors are considered equal if they have the same +id+.
43
+ #
44
+ # @param [Error] other Another error
45
+ #
46
+ # @return [Boolean]
47
+ #
48
+ # @api private
49
+ #
50
+ def ==(other)
51
+ other.is_a?(Error) && id == other.id
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,39 @@
1
+ require 'loqate/address_gateway'
2
+
3
+ module Loqate
4
+ # Acts as a single point of entry for a defined group of API's.
5
+ class Gateway
6
+ # The gem configuration.
7
+ #
8
+ # @return [Configuration]
9
+ #
10
+ attr_reader :config
11
+
12
+ # Creates a new gateway.
13
+ #
14
+ # @param [Hash] options Options to configure the gem.
15
+ # @option options [String] :api_key API key that will give you access to all services
16
+ # @option options [String] :host Base URL for Loqate's services
17
+ # @option options [String] :language Preferred language for results
18
+ #
19
+ # @see Configuration
20
+ #
21
+ def initialize(options)
22
+ @config = Configuration.new(options)
23
+ @client = Client.new(config)
24
+ end
25
+
26
+ # Gateway to the Address APIs.
27
+ #
28
+ # @return [AddressGateway] An instance of an address gateway.
29
+ #
30
+ def address
31
+ @address ||= AddressGateway.new(client)
32
+ end
33
+
34
+ private
35
+
36
+ # @api private
37
+ attr_reader :client
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ require 'loqate/mappers/generic_mapper'
2
+ require 'loqate/error'
3
+ require 'loqate/util'
4
+
5
+ module Loqate
6
+ module Mappers
7
+ # Transforms erroneous responses into concrete error objects.
8
+ #
9
+ # @api private
10
+ #
11
+ class ErrorMapper
12
+ # Creates errors from an API response
13
+ #
14
+ # @return [Array<Error>] An array of errors
15
+ #
16
+ def map(items)
17
+ items.map do |item|
18
+ attributes = item.transform_keys { |attribute| Util.underscore(attribute) }
19
+ attributes[:id] = attributes.delete(:error).to_i
20
+
21
+ Loqate::Error.new(attributes)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ require 'loqate/util'
2
+
3
+ module Loqate
4
+ module Mappers
5
+ # Transforms arrays of hashes into concrete instances of classes.
6
+ #
7
+ # @api private
8
+ #
9
+ class GenericMapper
10
+ # Creates objects from an API response. The objects will be an instance of +object_class+.
11
+ #
12
+ # @param [Class] object_class Class of the final objects
13
+ # @param [Array<Hash>] items Array of attributes to instantiate the final objects
14
+ #
15
+ # @return An array of objects of the given class
16
+ #
17
+ def map(items, object_class)
18
+ items.map do |item|
19
+ attributes = item.transform_keys { |attribute| Util.underscore(attribute) }
20
+ object_class.new(attributes)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,102 @@
1
+ module Loqate
2
+ # Generic return value of an operation. Provides a consistent way to determine if an operation
3
+ # has succeeded or failed.
4
+ class Result
5
+ # Creates a new Result
6
+ #
7
+ # @param [Object] value The original return value of an operation.
8
+ # @param [Symbol] code A code to describe the kind of result.
9
+ #
10
+ # @example Creating a new +Result+
11
+ # Result.new(value: person.errors, code: :not_updated)
12
+ #
13
+ def initialize(value:, code: nil)
14
+ @value = value
15
+ @code = code
16
+ end
17
+
18
+ # A code to describe the kind of result.
19
+ #
20
+ # @return [Symbol]
21
+ #
22
+ attr_reader :code
23
+
24
+ # The original return value of an operation.
25
+ #
26
+ # @return [Object]
27
+ #
28
+ attr_reader :value
29
+
30
+ # Wraps the result of a successful operation.
31
+ class Success < Result
32
+ # Always true
33
+ #
34
+ # @return [Boolean]
35
+ #
36
+ def success?
37
+ true
38
+ end
39
+
40
+ # Always false
41
+ #
42
+ # @return [Boolean]
43
+ #
44
+ def failure?
45
+ false
46
+ end
47
+ end
48
+
49
+ # Wraps the result of a failed operation.
50
+ class Failure < Result
51
+ # Always false
52
+ #
53
+ # @return [Boolean]
54
+ #
55
+ def success?
56
+ false
57
+ end
58
+
59
+ # Always true
60
+ #
61
+ # @return [Boolean]
62
+ #
63
+ def failure?
64
+ true
65
+ end
66
+ end
67
+
68
+ # Utility methods to conveniently return +Success+ or +Failure+ results.
69
+ module Mixin
70
+ Success = Success
71
+ Failure = Failure
72
+
73
+ # Wraps the result of an operation in a +Success+ result.
74
+ #
75
+ # @param [Object] value The original return value of an operation.
76
+ #
77
+ # @example Creating a success result
78
+ # Success(value: Person.new)
79
+ #
80
+ # @return [Success]
81
+ #
82
+ def Success(value)
83
+ Success.new(value: value)
84
+ end
85
+
86
+ # Wraps the result of an operation in a +Failure+ result.
87
+ #
88
+ # @param [Object] value The original return value of an operation.
89
+ # @param [Symbol] code A unique
90
+ #
91
+ # @example Creating a failure result
92
+ # error = { message: 'Name cannot be blank' }
93
+ # Success(value: error, code: :not_persisted)
94
+ #
95
+ # @return [Success]
96
+ #
97
+ def Failure(value, code: nil)
98
+ Failure.new(value: value, code: code)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,34 @@
1
+ module Loqate
2
+ # Provides methods for string manipulation
3
+ #
4
+ # @api private
5
+ module Util
6
+ module_function
7
+
8
+ # Converts a string to snake case
9
+ #
10
+ # @param [String|Symbol] term The term to be converted.
11
+ #
12
+ def underscore(term)
13
+ term
14
+ .to_s
15
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
16
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
17
+ .tr('-', '_')
18
+ .downcase
19
+ .to_sym
20
+ end
21
+
22
+ # Converts a string to camel case
23
+ #
24
+ # @param [String|Symbol] term The term to be converted.
25
+ #
26
+ def camelize(term)
27
+ string = term.to_s
28
+ string = string.sub(/^[a-z\d]*/, &:capitalize)
29
+ string.gsub!(%r{(?:_|(\/))([a-z\d]*)}) { "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}" }
30
+ string.gsub!('/'.freeze, '::'.freeze)
31
+ string
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loqate
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
data/loqate.gemspec CHANGED
@@ -24,6 +24,8 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ['lib']
26
26
 
27
+ spec.add_runtime_dependency 'http', '~> 3.3.0'
28
+
27
29
  spec.add_development_dependency 'bundler', '~> 1.16'
28
30
  spec.add_development_dependency 'bundler-audit', '~> 0.6'
29
31
  spec.add_development_dependency 'guard', '~> 2.14'
@@ -39,6 +41,8 @@ Gem::Specification.new do |spec|
39
41
  spec.add_development_dependency 'rubocop-rspec', '~> 1.29'
40
42
  spec.add_development_dependency 'simplecov', '~> 0.16'
41
43
  spec.add_development_dependency 'simplecov-console', '~> 0.4'
44
+ spec.add_development_dependency 'vcr', '~> 4.0'
45
+ spec.add_development_dependency 'webmock', '~> 3.4'
42
46
  spec.add_development_dependency 'yard', '~> 0.9'
43
47
  spec.add_development_dependency 'yard-junk', '~> 0.0.7'
44
48
  spec.add_development_dependency 'yardstick', '~> 0.9'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loqate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wilson Silva
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-29 00:00:00.000000000 Z
11
+ date: 2018-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: http
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.3.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +234,34 @@ dependencies:
220
234
  - - "~>"
221
235
  - !ruby/object:Gem::Version
222
236
  version: '0.4'
237
+ - !ruby/object:Gem::Dependency
238
+ name: vcr
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: '4.0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - "~>"
249
+ - !ruby/object:Gem::Version
250
+ version: '4.0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: webmock
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - "~>"
256
+ - !ruby/object:Gem::Version
257
+ version: '3.4'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - "~>"
263
+ - !ruby/object:Gem::Version
264
+ version: '3.4'
223
265
  - !ruby/object:Gem::Dependency
224
266
  name: yard
225
267
  requirement: !ruby/object:Gem::Requirement
@@ -274,12 +316,12 @@ files:
274
316
  - ".overcommit.yml"
275
317
  - ".rspec"
276
318
  - ".rubocop.yml"
319
+ - ".ruby-version"
277
320
  - ".travis.yml"
278
321
  - ".yardopts"
279
322
  - ".yardstick.yml"
280
323
  - CHANGELOG.md
281
324
  - Gemfile
282
- - Gemfile.lock
283
325
  - Guardfile
284
326
  - README.md
285
327
  - ROADMAP.md
@@ -287,6 +329,18 @@ files:
287
329
  - bin/console
288
330
  - bin/setup
289
331
  - lib/loqate.rb
332
+ - lib/loqate/address.rb
333
+ - lib/loqate/address_gateway.rb
334
+ - lib/loqate/api_result.rb
335
+ - lib/loqate/client.rb
336
+ - lib/loqate/configuration.rb
337
+ - lib/loqate/detailed_address.rb
338
+ - lib/loqate/error.rb
339
+ - lib/loqate/gateway.rb
340
+ - lib/loqate/mappers/error_mapper.rb
341
+ - lib/loqate/mappers/generic_mapper.rb
342
+ - lib/loqate/result.rb
343
+ - lib/loqate/util.rb
290
344
  - lib/loqate/version.rb
291
345
  - loqate.gemspec
292
346
  homepage: https://github.com/wilsonsilva/loqate
data/Gemfile.lock DELETED
@@ -1,147 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- loqate (0.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- ansi (1.5.0)
10
- ast (2.4.0)
11
- backports (3.11.4)
12
- bundler-audit (0.6.0)
13
- bundler (~> 1.2)
14
- thor (~> 0.18)
15
- childprocess (0.9.0)
16
- ffi (~> 1.0, >= 1.0.11)
17
- coderay (1.1.2)
18
- diff-lcs (1.3)
19
- docile (1.3.1)
20
- ffi (1.9.25)
21
- formatador (0.2.5)
22
- guard (2.14.2)
23
- formatador (>= 0.2.4)
24
- listen (>= 2.7, < 4.0)
25
- lumberjack (>= 1.0.12, < 2.0)
26
- nenv (~> 0.1)
27
- notiffany (~> 0.0)
28
- pry (>= 0.9.12)
29
- shellany (~> 0.0)
30
- thor (>= 0.18.1)
31
- guard-bundler (2.1.0)
32
- bundler (~> 1.0)
33
- guard (~> 2.2)
34
- guard-compat (~> 1.1)
35
- guard-bundler-audit (0.1.4)
36
- bundler-audit (>= 0.3.1)
37
- guard (~> 2.0)
38
- guard-compat (1.2.1)
39
- guard-rspec (4.7.3)
40
- guard (~> 2.1)
41
- guard-compat (~> 1.1)
42
- rspec (>= 2.99.0, < 4.0)
43
- guard-rubocop (1.3.0)
44
- guard (~> 2.0)
45
- rubocop (~> 0.20)
46
- hirb (0.7.3)
47
- iniparse (1.4.4)
48
- jaro_winkler (1.5.1)
49
- json (2.1.0)
50
- listen (3.1.5)
51
- rb-fsevent (~> 0.9, >= 0.9.4)
52
- rb-inotify (~> 0.9, >= 0.9.7)
53
- ruby_dep (~> 1.2)
54
- lumberjack (1.0.13)
55
- method_source (0.9.0)
56
- nenv (0.3.0)
57
- notiffany (0.1.1)
58
- nenv (~> 0.1)
59
- shellany (~> 0.0)
60
- overcommit (0.46.0)
61
- childprocess (~> 0.6, >= 0.6.3)
62
- iniparse (~> 1.4)
63
- parallel (1.12.1)
64
- parser (2.5.1.2)
65
- ast (~> 2.4.0)
66
- powerpack (0.1.2)
67
- pry (0.11.3)
68
- coderay (~> 1.1.0)
69
- method_source (~> 0.9.0)
70
- rainbow (3.0.0)
71
- rake (10.5.0)
72
- rb-fsevent (0.10.3)
73
- rb-inotify (0.9.10)
74
- ffi (>= 0.5.0, < 2)
75
- rspec (3.7.0)
76
- rspec-core (~> 3.7.0)
77
- rspec-expectations (~> 3.7.0)
78
- rspec-mocks (~> 3.7.0)
79
- rspec-core (3.7.1)
80
- rspec-support (~> 3.7.0)
81
- rspec-expectations (3.7.0)
82
- diff-lcs (>= 1.2.0, < 2.0)
83
- rspec-support (~> 3.7.0)
84
- rspec-mocks (3.7.0)
85
- diff-lcs (>= 1.2.0, < 2.0)
86
- rspec-support (~> 3.7.0)
87
- rspec-support (3.7.1)
88
- rubocop (0.59.2)
89
- jaro_winkler (~> 1.5.1)
90
- parallel (~> 1.10)
91
- parser (>= 2.5, != 2.5.1.1)
92
- powerpack (~> 0.1)
93
- rainbow (>= 2.2.2, < 4.0)
94
- ruby-progressbar (~> 1.7)
95
- unicode-display_width (~> 1.0, >= 1.0.1)
96
- rubocop-rspec (1.29.1)
97
- rubocop (>= 0.58.0)
98
- ruby-progressbar (1.10.0)
99
- ruby_dep (1.5.0)
100
- shellany (0.0.1)
101
- simplecov (0.16.1)
102
- docile (~> 1.1)
103
- json (>= 1.8, < 3)
104
- simplecov-html (~> 0.10.0)
105
- simplecov-console (0.4.2)
106
- ansi
107
- hirb
108
- simplecov
109
- simplecov-html (0.10.2)
110
- thor (0.20.0)
111
- tty-color (0.4.2)
112
- unicode-display_width (1.4.0)
113
- yard (0.9.16)
114
- yard-junk (0.0.7)
115
- backports
116
- rainbow
117
- tty-color
118
- yard
119
- yardstick (0.9.9)
120
- yard (~> 0.8, >= 0.8.7.2)
121
-
122
- PLATFORMS
123
- ruby
124
-
125
- DEPENDENCIES
126
- bundler (~> 1.16)
127
- bundler-audit (~> 0.6)
128
- guard (~> 2.14)
129
- guard-bundler (~> 2.1)
130
- guard-bundler-audit (~> 0.1)
131
- guard-rspec (~> 4.7)
132
- guard-rubocop (~> 1.2)
133
- loqate!
134
- overcommit (~> 0.46)
135
- pry (~> 0.11)
136
- rake (~> 10.0)
137
- rspec (~> 3.0)
138
- rubocop (~> 0.59)
139
- rubocop-rspec (~> 1.29)
140
- simplecov (~> 0.16)
141
- simplecov-console (~> 0.4)
142
- yard (~> 0.9)
143
- yard-junk (~> 0.0.7)
144
- yardstick (~> 0.9)
145
-
146
- BUNDLED WITH
147
- 1.16.5