loqate 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1f1396b79c0115311d766dd1b8fb7f4b0325596d27293d1b1d4af7c0d3d4a29
4
- data.tar.gz: e2a275316138017ec971b0a4412e8cc92a872983a523067c33c1ea2c88785de3
3
+ metadata.gz: fff6b4e7b798fed1a00eb2acfa53ffd3997820f815e1ef780ab46d4e8efbb68b
4
+ data.tar.gz: d442998133eaafc167db8a823b87703021bbf72c061237cac7a0dbb659d9a271
5
5
  SHA512:
6
- metadata.gz: abf8817900f777554ded8b558dd43e4f94ebead001fb53c9ac012e8d462f7b4c3926e86a00ea1ac3d5b9230376c19af03931d08c4a0c684bf137369dd8ce332b
7
- data.tar.gz: 470d80e084b048173e3ae34d230227308c2855fbb2fa26be93897464ba9c9fd9a0490f0ee9062302107315f4ecb168db50c39e6799af009e492af223b2dad2b2
6
+ metadata.gz: d57781e89b7743e9c315d97e821cb31d56b0a1b2458cf1d2a640908e9d6e9bd45f8d64f155b63ccd2b704fa1b1b9b71bf700acd7c10ac08afcdf3c1e99e62020
7
+ data.tar.gz: 794e2d39014cc609fb708989785c74c551ad895bff4565b2f00cc67351353587b2bf3974c91fec54b53e02a7fb44668529c79058318444e8f5bbd00ba1985edd
@@ -47,6 +47,7 @@ rules:
47
47
  - Loqate::Result::Failure#failure?
48
48
  - Loqate::Result#code
49
49
  - Loqate::Result#value
50
+ - Loqate::Result::Failure#error
50
51
  ReturnTag:
51
52
  enabled: true
52
53
  exclude:
@@ -60,9 +61,9 @@ rules:
60
61
  - Loqate::AddressGateway#client
61
62
  - Loqate::AddressGateway#mapper
62
63
  - Loqate::AddressGateway#error_mapper
63
- - Loqate::AddressGateway#build_errors_from
64
- - Loqate::AddressGateway#build_address_from
65
- - Loqate::AddressGateway#build_detailed_addresses_from
64
+ - Loqate::AddressGateway#build_error_from
65
+ - Loqate::AddressGateway#build_addresses_from
66
+ - Loqate::AddressGateway#build_detailed_address_from
66
67
  - Loqate::Client#configuration
67
68
  - Loqate::Client#authenticate_params
68
69
  - Loqate::Client#format_params
@@ -73,6 +74,7 @@ rules:
73
74
  - Loqate::Util#underscore
74
75
  - Loqate::Error#attributes
75
76
  - Loqate::Gateway#client
77
+ - Loqate::Result::Failure#error
76
78
  Summary::Presence:
77
79
  enabled: true
78
80
  exclude:
@@ -86,9 +88,9 @@ rules:
86
88
  - Loqate::AddressGateway#client
87
89
  - Loqate::AddressGateway#mapper
88
90
  - Loqate::AddressGateway#error_mapper
89
- - Loqate::AddressGateway#build_errors_from
90
- - Loqate::AddressGateway#build_address_from
91
- - Loqate::AddressGateway#build_detailed_addresses_from
91
+ - Loqate::AddressGateway#build_error_from
92
+ - Loqate::AddressGateway#build_addresses_from
93
+ - Loqate::AddressGateway#build_detailed_address_from
92
94
  - Loqate::Client#configuration
93
95
  - Loqate::Client#authenticate_params
94
96
  - Loqate::Client#format_params
@@ -96,6 +98,7 @@ rules:
96
98
  - Loqate::DetailedAddress#==
97
99
  - Loqate::Error#attributes
98
100
  - Loqate::Gateway#client
101
+ - Loqate::Result::Failure#error
99
102
  Summary::Length:
100
103
  enabled: false
101
104
  Summary::Delimiter:
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
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
6
 
7
+ ## [0.3.0] - 2018-11-10
8
+ ### Changed
9
+ - `address.retrieve` and `address.find` return a single error, not an array with a single item
10
+ - `address.retrieve` returns a single address, not an array of addresses
11
+ - `Loqate::Error` inherits from `StandardError` so that it can be raised as an exception
12
+ - Improved the documentation of `Success` and `Failure`
13
+
14
+ ## Added
15
+ - `find!` to find an address or raise an exception
16
+ - `retrieve!` to retrieve the details of an address or raise an exception
17
+ - Aliased `Failure#value` to `Failure#error`
18
+
19
+ ## Fixed
20
+ - Fixed the documentation of `AddressGateway`
21
+
7
22
  ## [0.2.0] - 2018-10-31
8
23
  ### Added
9
24
  - VCR and WebMock to record HTTP interactions
@@ -20,4 +35,5 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
20
35
  - Initial core functionality
21
36
  - Codebase maintenance tools
22
37
 
23
- [0.2.0]: https://github.com/wilsonsilva/memoria/compare/v0.1.0...v0.2.0
38
+ [0.3.0]: https://github.com/wilsonsilva/loqate/compare/v0.2.0...v0.3.0
39
+ [0.2.0]: https://github.com/wilsonsilva/loqate/compare/v0.1.0...v0.2.0
data/README.md CHANGED
@@ -38,7 +38,41 @@ To get started, initialize an API gateway with [your API key](https://account.lo
38
38
  gateway = Loqate::Gateway.new(api_key: '<YOUR_API_KEY>')
39
39
  ```
40
40
 
41
- Every call to a gateway method will return a `Loqate::Result` object, which will respond to `success?` and `failure?`.
41
+ ### Bang Methods
42
+
43
+ Most methods have a bang and a non-bang version (e.g. `gateway.address.find` and `gateway.address.find!`).
44
+ The non-bang version will either return a `Loqate::Success` or an `Loqate::Failure`. The bang version will
45
+ either return the desired resource, or it will raise an exception.
46
+
47
+ #### Example of using non-bang method
48
+
49
+ ```ruby
50
+ result = gateway.address.find(text: 'EC1Y 8AF', country: 'GB', limit: 5)
51
+
52
+ if result.success?
53
+ addresses = result.value
54
+ addresses.first.id # => 'GB|RM|B|8144611'
55
+ else
56
+ error = result.error
57
+ puts "Error retrieving the address: #{error.description}. Resolution: #{error.resolution}"
58
+ end
59
+
60
+ result.failure? # => false
61
+ ```
62
+
63
+ #### Example of using bang method
64
+
65
+ ```ruby
66
+ begin
67
+ addresses = gateway.address.find!(text: 'EC1Y 8AF', country: 'GB', limit: 5)
68
+ addresses.first.id # => 'GB|RM|B|8144611'
69
+ rescue Loqate::Error => e
70
+ puts "Error retrieving the address: #{e.description}. Resolution: #{e.resolution}"
71
+ end
72
+ ```
73
+
74
+ It is recommended that you use the bang methods when you assume that the data is valid and do not expect validations
75
+ to fail. Otherwise, use the non-bang methods.
42
76
 
43
77
  ### Address API
44
78
 
@@ -56,9 +90,6 @@ selection.
56
90
  ```ruby
57
91
  result = gateway.address.find(text: 'EC1Y 8AF', country: 'GB', limit: 5)
58
92
 
59
- result.success? # => true
60
- result.failure? # => false
61
-
62
93
  addresses = result.value
63
94
  addresses.first.id # => 'GB|RM|B|8144611'
64
95
  ```
@@ -68,15 +99,10 @@ addresses.first.id # => 'GB|RM|B|8144611'
68
99
  ```ruby
69
100
  result = gateway.address.retrieve(id: 'GB|RM|B|8144611')
70
101
 
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'
102
+ address = result.value
103
+ address.city # 'London'
104
+ address.line1 # '148 Warner Road'
105
+ address.postal_code # 'E17 7EA'
80
106
  ```
81
107
 
82
108
  ## Development
data/ROADMAP.md CHANGED
@@ -7,6 +7,7 @@
7
7
  - [ ] Logging
8
8
  - [x] Domain error handling
9
9
  - [x] Configuration
10
+ - [ ] Unwrap request results
10
11
  - [ ] Validate request parameters
11
12
  - [ ] API/Service versioning
12
13
  - [ ] Integration with RSpec
@@ -46,33 +46,79 @@ module Loqate
46
46
  # @example Retrieving an address in the UK
47
47
  # address = address_gateway.find(countries: 'GB', text: 'Scrubs Lane')
48
48
  #
49
- # @return [Array<Address>] A list of addresses
49
+ # @return [Result] A result wrapping a list of addresses
50
50
  #
51
51
  def find(options)
52
52
  response = client.get(FIND_ENDPOINT, options)
53
53
 
54
- response.errors? && build_errors_from(response.items) || build_address_from(response.items)
54
+ response.errors? && build_error_from(response.items.first) || build_addresses_from(response.items)
55
55
  end
56
56
 
57
57
  # Returns the full address details based on the id.
58
58
  #
59
59
  # @param [Hash] options The options to retrieve the address.
60
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.
61
+ # @option options [String] :field_1_format Format of a custom address field.
62
+ # @option options [String] :field_2_format Format of a custom address field.
63
+ # @option options [String] :field_3_format Format of a custom address field.
64
+ # @option options [String] :field_4_format Format of a custom address field.
65
+ # @option options [String] :field_5_format Format of a custom address field.
66
66
  #
67
67
  # @example Retrieving the details of an address
68
68
  # detailed_address = gateway.retrieve(id: 'GB|RM|ENG|6RB-NW10')
69
69
  #
70
- # @return [Array<DetailedAddress>] A list of detailed addresses
70
+ # @return [Result] A result wrapping a detailed address
71
71
  #
72
72
  def retrieve(options)
73
73
  response = client.get(RETRIEVE_ENDPOINT, options)
74
74
 
75
- response.errors? && build_errors_from(response.items) || build_detailed_addresses_from(response.items)
75
+ response.errors? && build_error_from(response.items.first) || build_detailed_address_from(response.items.first)
76
+ end
77
+
78
+ # Find addresses and places.
79
+ #
80
+ # @param [Hash] options The options to find an address or a list of addresses.
81
+ # @option options [String] :text The search text to find. Ideally a postcode or the start of the address.
82
+ # @option options [String] countries A comma separated list of ISO 2 or 3 character country codes to limit
83
+ # the search within.
84
+ # @option options [String] origin A starting location for the search. This can be the name or ISO 2 or 3 character
85
+ # code of a country, WGS84 coordinates (comma separated) or IP address to search from.
86
+ # @option options [String] container A container for the search. This should only be another Id previously returned
87
+ # from this service when the Type of the result was not 'Address'.
88
+ # @option options [Integer] limit The maximum number of results to return.
89
+ # @option options [String] language The preferred language for results. This should be a 2 or 4 character language
90
+ # code e.g. (en, fr, en-gb, en-us etc).
91
+ #
92
+ # @example Retrieving addresses in the UK
93
+ # addresses = address_gateway.find!(countries: 'GB', text: 'Scrubs Lane')
94
+ #
95
+ # @raise [Error] If the result is not a success
96
+ #
97
+ # @return [Array<Address>] A list of addresses
98
+ #
99
+ def find!(options)
100
+ unwrap_result_or_raise { find(options) }
101
+ end
102
+
103
+ # Returns the full address details based on the id.
104
+ #
105
+ # @param [Hash] options The options to retrieve the address.
106
+ # @option options [String] :id The Id from a Find method to retrieve the details for.
107
+ # @option options [String] :field_1_format Format of a custom address field.
108
+ # @option options [String] :field_2_format Format of a custom address field.
109
+ # @option options [String] :field_3_format Format of a custom address field.
110
+ # @option options [String] :field_4_format Format of a custom address field.
111
+ # @option options [String] :field_5_format Format of a custom address field.
112
+ #
113
+ # @example Retrieving the details of an address
114
+ # detailed_address = gateway.retrieve!(id: 'GB|RM|ENG|6RB-NW10')
115
+ #
116
+ # @raise [Error] If the result is not a success
117
+ #
118
+ # @return [DetailedAddress] A detailed address
119
+ #
120
+ def retrieve!(options)
121
+ unwrap_result_or_raise { retrieve(options) }
76
122
  end
77
123
 
78
124
  private
@@ -81,20 +127,20 @@ module Loqate
81
127
  attr_reader :client, :mapper, :error_mapper
82
128
 
83
129
  # @api private
84
- def build_errors_from(items)
85
- errors = error_mapper.map(items)
86
- Failure(errors)
130
+ def build_error_from(item)
131
+ error = error_mapper.map_one(item)
132
+ Failure(error)
87
133
  end
88
134
 
89
135
  # @api private
90
- def build_address_from(items)
136
+ def build_addresses_from(items)
91
137
  address = mapper.map(items, Address)
92
138
  Success(address)
93
139
  end
94
140
 
95
141
  # @api private
96
- def build_detailed_addresses_from(items)
97
- detailed_address = mapper.map(items, DetailedAddress)
142
+ def build_detailed_address_from(item)
143
+ detailed_address = mapper.map_one(item, DetailedAddress)
98
144
  Success(detailed_address)
99
145
  end
100
146
  end
@@ -1,6 +1,6 @@
1
1
  module Loqate
2
2
  # Generic error returned from an API call
3
- class Error
3
+ class Error < StandardError
4
4
  # Unique identifier for the error
5
5
  #
6
6
  # @return [Integer]
@@ -33,6 +33,8 @@ module Loqate
33
33
  # @param [String] resolution How to solve the error
34
34
  #
35
35
  def initialize(id:, description:, cause:, resolution:)
36
+ super(description)
37
+
36
38
  @id = id
37
39
  @cause = cause
38
40
  @resolution = resolution
@@ -14,12 +14,18 @@ module Loqate
14
14
  # @return [Array<Error>] An array of errors
15
15
  #
16
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
17
+ items.map { |item| map_one(item) }
18
+ end
19
+
20
+ # Creates an error from an API response
21
+ #
22
+ # @return [Error] A concrete instance of Error
23
+ #
24
+ def map_one(item)
25
+ attributes = item.transform_keys { |attribute| Util.underscore(attribute) }
26
+ attributes[:id] = attributes.delete(:error).to_i
20
27
 
21
- Loqate::Error.new(attributes)
22
- end
28
+ Loqate::Error.new(attributes)
23
29
  end
24
30
  end
25
31
  end
@@ -15,10 +15,19 @@ module Loqate
15
15
  # @return An array of objects of the given class
16
16
  #
17
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
18
+ items.map { |item| map_one(item, object_class) }
19
+ end
20
+
21
+ # Creates a single object from an API response. The object will be an instance of +object_class+.
22
+ #
23
+ # @param [Class] object_class Class of the final object
24
+ # @param [Hash] item Attributes to instantiate the final object
25
+ #
26
+ # @return An object of the given class
27
+ #
28
+ def map_one(item, object_class)
29
+ attributes = item.transform_keys { |attribute| Util.underscore(attribute) }
30
+ object_class.new(attributes)
22
31
  end
23
32
  end
24
33
  end
@@ -31,7 +31,7 @@ module Loqate
31
31
  class Success < Result
32
32
  # Always true
33
33
  #
34
- # @return [Boolean]
34
+ # @return [TrueClass]
35
35
  #
36
36
  def success?
37
37
  true
@@ -39,7 +39,7 @@ module Loqate
39
39
 
40
40
  # Always false
41
41
  #
42
- # @return [Boolean]
42
+ # @return [FalseClass]
43
43
  #
44
44
  def failure?
45
45
  false
@@ -50,7 +50,7 @@ module Loqate
50
50
  class Failure < Result
51
51
  # Always false
52
52
  #
53
- # @return [Boolean]
53
+ # @return [FalseClass]
54
54
  #
55
55
  def success?
56
56
  false
@@ -58,11 +58,13 @@ module Loqate
58
58
 
59
59
  # Always true
60
60
  #
61
- # @return [Boolean]
61
+ # @return [TrueClass]
62
62
  #
63
63
  def failure?
64
64
  true
65
65
  end
66
+
67
+ alias error value
66
68
  end
67
69
 
68
70
  # Utility methods to conveniently return +Success+ or +Failure+ results.
@@ -97,6 +99,43 @@ module Loqate
97
99
  def Failure(value, code: nil)
98
100
  Failure.new(value: value, code: code)
99
101
  end
102
+
103
+ # Unwraps a Result object. Returns the unwrapped value if the result is successful or raise
104
+ # an exception otherwise.
105
+ #
106
+ # @example When the given block returns a success
107
+ # class Action
108
+ # include Loqate::Result::Mixin
109
+ #
110
+ # def call
111
+ # Success('the value')
112
+ # end
113
+ # end
114
+ #
115
+ # operation.unwrap_result_or_raise { call } # => 'the value'
116
+ #
117
+ # @example When the given block returns a failure
118
+ # class Action
119
+ # include Loqate::Result::Mixin
120
+ #
121
+ # def call
122
+ # Failure(StandardError.new)
123
+ # end
124
+ # end
125
+ #
126
+ # operation.unwrap_result_or_raise { call } # => raises StandardError
127
+ #
128
+ # @raise [Object] If the result is not a success.
129
+ #
130
+ # @return [Object] The unwrapped object.
131
+ #
132
+ def unwrap_result_or_raise
133
+ result = yield
134
+
135
+ raise result.error if result.failure?
136
+
137
+ result.value
138
+ end
100
139
  end
101
140
  end
102
141
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loqate
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loqate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.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-10-31 00:00:00.000000000 Z
11
+ date: 2018-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http