usps-imis-api 0.5.0 → 0.6.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: 1febbdb28781a5589ce97b66eb071728aef8b8e81991970854620c9fc128cf54
4
- data.tar.gz: cc5aeb7ddab766c885d4bb009b1fa9afcdaa8f71d68b56f2e86861c12f8eda72
3
+ metadata.gz: 5db9ae9c192ad976e8a08ddaea01218cb36ab043e550108b08582c782cb43705
4
+ data.tar.gz: 52951b92b37e906ddd9faa2aedc44d3000e541301e8411227220094bb9dc9525
5
5
  SHA512:
6
- metadata.gz: '09fdb03097ef67813356bf1a4378f53827bcacc3c8115fb9128ce0f2a8dcdceb26aafc3296b8132468860906ac3884965c53b4e47729aa8dc0a964a13346717e'
7
- data.tar.gz: 3703f4325f53afde2c9350c4382d0cbfeb4d53489275c866a1041749ba5324d7833c4a3fe14f11e70bcd3a1729981f2b3b3befcd3a603a5ab5703a03ae6a9cc5
6
+ metadata.gz: b32e24b9550ed06bd3971d0ac9072b3011a4fc59734874bfa8e916b6d8832739f8967318e9ca9fc037e24c9b57d9cbe3f2bb37a3a649af95c24e9b5cc8b74033
7
+ data.tar.gz: fc1934e11eb736e2b91c48cc9a7806f8645f0a5f9b0be87a2e30b309b57b023289dd007e154ce4ba6fc880876671961823229a45cb1a4897e68cde5cb89e3c31
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- usps-imis-api (0.5.0)
4
+ usps-imis-api (0.6.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/Readme.md CHANGED
@@ -82,7 +82,7 @@ To fetch member data, run e.g.:
82
82
  ```ruby
83
83
  api.imis_id = 31092
84
84
 
85
- data = api.get('ABC_ASC_Individual_Demog')
85
+ data = api.on('ABC_ASC_Individual_Demog').get
86
86
  ```
87
87
 
88
88
  ### PUT Fields
@@ -93,7 +93,7 @@ To update member data, run e.g.:
93
93
  api.imis_id = 31092
94
94
 
95
95
  data = { 'MMS_Updated' => Time.now.strftime('%Y-%m-%dT%H:%M:%S'), 'TotMMS' => new_total }
96
- update = api.put_fields('ABC_ASC_Individual_Demog', data)
96
+ update = api.on('ABC_ASC_Individual_Demog').put_fields(data)
97
97
  ```
98
98
 
99
99
  This method fetches the current data structure, and filters it down to just what you want to
@@ -106,7 +106,7 @@ To update member data, run e.g.:
106
106
  ```ruby
107
107
  api.imis_id = 31092
108
108
 
109
- update = api.put('ABC_ASC_Individual_Demog', complete_imis_object)
109
+ update = api.on('ABC_ASC_Individual_Demog').put(complete_imis_object)
110
110
  ```
111
111
 
112
112
  This method requires a complete iMIS data structure.
@@ -116,7 +116,7 @@ This method requires a complete iMIS data structure.
116
116
  To create new member data, run e.g.:
117
117
 
118
118
  ```ruby
119
- created = api.post('ABC_ASC_Individual_Demog', complete_imis_object)
119
+ created = api.on('ABC_ASC_Individual_Demog').post(complete_imis_object)
120
120
  ```
121
121
 
122
122
  This method requires a complete iMIS data structure.
@@ -128,7 +128,7 @@ To remove member data, run e.g.:
128
128
  ```ruby
129
129
  api.imis_id = 31092
130
130
 
131
- api.delete('ABC_ASC_Individual_Demog')
131
+ api.on('ABC_ASC_Individual_Demog').delete
132
132
  ```
133
133
 
134
134
  This returns a blank string on success.
@@ -202,9 +202,11 @@ previous value.
202
202
 
203
203
  ```ruby
204
204
  api.with(31092) do
205
- # These three requests are identical:
205
+ # These four requests are identical:
206
206
 
207
- put('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 })
207
+ on('ABC_ASC_Individual_Demog') { put('TotMMS' => 15) }
208
+
209
+ on('ABC_ASC_Individual_Demog').put('TotMMS' => 15)
208
210
 
209
211
  mapper.update(mm: 15)
210
212
 
data/lib/usps/imis/api.rb CHANGED
@@ -5,14 +5,12 @@ module Usps
5
5
  # The core API wrapper
6
6
  #
7
7
  class Api
8
+ include Requests
9
+
8
10
  # Endpoint for (re-)authentication requests
9
11
  #
10
12
  AUTHENTICATION_PATH = 'Token'
11
13
 
12
- # Endpoint for general API requests
13
- #
14
- API_PATH = 'api'
15
-
16
14
  # Endpoint for IQA query requests
17
15
  #
18
16
  QUERY_PATH = 'api/Query'
@@ -31,6 +29,10 @@ module Usps
31
29
  #
32
30
  attr_reader :imis_id
33
31
 
32
+ # Whether to lock changes to the selected iMIS ID
33
+ #
34
+ attr_reader :lock_imis_id
35
+
34
36
  # A new instance of +Api+
35
37
  #
36
38
  # @param skip_authentication [bool] Skip authentication on initialization (used for tests)
@@ -46,7 +48,9 @@ module Usps
46
48
  # @param id [Integer, String] iMIS ID to select for future requests
47
49
  #
48
50
  def imis_id=(id)
49
- @imis_id = id.to_i.to_s
51
+ raise Error::ApiError, 'Cannot change iMIS ID while locked' if lock_imis_id
52
+
53
+ @imis_id = id&.to_i&.to_s
50
54
  end
51
55
 
52
56
  # Convert a member's certificate number into an iMIS ID number
@@ -56,15 +60,21 @@ module Usps
56
60
  # @return [String] Corresponding iMIS ID
57
61
  #
58
62
  def imis_id_for(certificate)
59
- result = query(Imis.configuration.imis_id_query_name, { certificate: })
60
- @imis_id = result['Items']['$values'][0]['ID']
61
- rescue StandardError
62
- raise Error::ApiError, 'Member not found'
63
+ raise Error::ApiError, 'Cannot change iMIS ID while locked' if lock_imis_id
64
+
65
+ begin
66
+ result = query(Imis.configuration.imis_id_query_name, { certificate: })
67
+ @imis_id = result['Items']['$values'][0]['ID']
68
+ rescue StandardError
69
+ raise Error::ApiError, 'Member not found'
70
+ end
63
71
  end
64
72
 
65
73
  # Run requests as DSL, with specific iMIS ID only maintained for this scope
66
74
  #
67
- # This should be used with methods that do not change the value of `imis_id`
75
+ # While in this block, changes to the value of +imis_id+ are not allowed
76
+ #
77
+ # If no block is given, this sets the iMIS ID and returns self.
68
78
  #
69
79
  # @param id [Integer, String] iMIS ID to select for requests within the block
70
80
  #
@@ -76,104 +86,68 @@ module Usps
76
86
  def with(id, &)
77
87
  old_id = imis_id
78
88
  self.imis_id = id
89
+ return self unless block_given?
90
+
91
+ @lock_imis_id = true
79
92
  instance_eval(&)
80
93
  ensure
81
- self.imis_id = old_id
94
+ if block_given?
95
+ @lock_imis_id = false
96
+ self.imis_id = old_id
97
+ end
82
98
  end
83
99
 
84
- # Get a business object for the current member
100
+ # Run an IQA Query
85
101
  #
86
- # @param business_object_name [String] Name of the business object
87
- # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
102
+ # @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
103
+ # @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
88
104
  #
89
105
  # @return [Hash] Response data from the API
90
106
  #
91
- def get(business_object_name, url_id: nil)
92
- uri = uri_for(business_object_name, url_id:)
107
+ def query(query_name, query_params = {})
108
+ query_params[:QueryName] = query_name
109
+ path = "#{QUERY_PATH}?#{query_params.to_query}"
110
+ uri = URI(File.join(Imis.configuration.hostname, path))
93
111
  request = Net::HTTP::Get.new(uri)
94
112
  result = submit(uri, authorize(request))
95
113
  JSON.parse(result.body)
96
114
  end
97
115
 
98
- # Update only specific fields on a business object for the current member
116
+ # An instance of +BusinessObject+, using this instance as its parent +Api+
99
117
  #
100
118
  # @param business_object_name [String] Name of the business object
101
- # @param fields [Hash] Conforms to pattern +{ field_key => value }+
102
119
  # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
103
120
  #
104
- # @return [Hash] Response data from the API
105
- #
106
- def put_fields(business_object_name, fields, url_id: nil)
107
- updated = filter_fields(business_object_name, fields)
108
- put(business_object_name, updated, url_id:)
121
+ def business_object(business_object_name, url_id: nil)
122
+ BusinessObject.new(self, business_object_name, url_id:)
109
123
  end
110
124
 
111
- # Update a business object for the current member
125
+ # Run requests as DSL, with specific +BusinessObject+ only maintained for this scope
112
126
  #
113
- # @param business_object_name [String] Name of the business object
114
- # @param body [Hash] Full raw API object data
115
- # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
116
- #
117
- # @return [Hash] Response data from the API
118
- #
119
- def put(business_object_name, body, url_id: nil)
120
- uri = uri_for(business_object_name, url_id:)
121
- request = Net::HTTP::Put.new(uri)
122
- request.body = JSON.dump(body)
123
- result = submit(uri, authorize(request))
124
- JSON.parse(result.body)
125
- end
126
-
127
- # Create a business object for the current member
127
+ # If no block is given, this returns the specified +BusinessObject+.
128
128
  #
129
129
  # @param business_object_name [String] Name of the business object
130
- # @param body [Hash] Full raw API object data
131
130
  # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
132
131
  #
133
- # @return [Hash] Response data from the API
134
- #
135
- def post(business_object_name, body, url_id: nil)
136
- uri = uri_for(business_object_name, url_id:)
137
- request = Net::HTTP::Post.new(uri)
138
- request.body = JSON.dump(body)
139
- result = submit(uri, authorize(request))
140
- JSON.parse(result.body)
141
- end
132
+ def on(business_object_name, url_id: nil, &)
133
+ object = business_object(business_object_name, url_id:)
134
+ return object unless block_given?
142
135
 
143
- # Remove a business object for the current member
144
- #
145
- # @param business_object_name [String] Name of the business object
146
- # @param url_id [String] Override the ID param of the URL (e.g. used for Panels)
147
- #
148
- # @return [String] Error response body from the API, or empty string on success
149
- #
150
- def delete(business_object_name, url_id: nil)
151
- uri = uri_for(business_object_name, url_id:)
152
- request = Net::HTTP::Delete.new(uri)
153
- result = submit(uri, authorize(request))
154
- result.body
136
+ result = nil
137
+ object.tap { |obj| result = obj.instance_eval(&) }
138
+ result
155
139
  end
156
140
 
157
- # Run an IQA Query
158
- #
159
- # @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
160
- # @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
141
+ # An instance of +Mapper+, using this instance as its parent +Api+
161
142
  #
162
- # @return [Hash] Response data from the API
163
- #
164
- def query(query_name, query_params = {})
165
- query_params[:QueryName] = query_name
166
- path = "#{QUERY_PATH}?#{query_params.to_query}"
167
- uri = URI(File.join(imis_hostname, path))
168
- request = Net::HTTP::Get.new(uri)
169
- result = submit(uri, authorize(request))
170
- JSON.parse(result.body)
143
+ def mapper
144
+ @mapper ||= Mapper.new(self)
171
145
  end
172
146
 
173
- # An instance of Mapper, using this instance as its parent +Api+
147
+ # Convenience alias for updating mapped fields
174
148
  #
175
- def mapper
176
- @mapper ||= Mapper.new(self)
149
+ def update(data)
150
+ mapper.update(data)
177
151
  end
178
152
 
179
153
  # Convenience accessor for available Panel objects, each using this instance as its parent
@@ -186,56 +160,16 @@ module Usps
186
160
  )
187
161
  end
188
162
 
189
- # Convenience alias for updating mapped fields
190
- #
191
- def update(data)
192
- mapper.update(data)
193
- end
194
-
195
163
  # Ruby 3.5 instance variable filter
196
164
  #
197
165
  def instance_variables_to_inspect = %i[@token_expiration @imis_id]
198
166
 
199
167
  private
200
168
 
201
- def client(uri)
202
- Net::HTTP.new(uri.host, uri.port).tap do |http|
203
- http.use_ssl = true
204
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
205
- end
206
- end
207
-
208
- def imis_hostname
209
- Imis.configuration.hostname
210
- end
211
-
212
- # Authorize a request prior to submitting
213
- #
214
- # If the current token is missing/expired, request a new one
215
- #
216
- def authorize(request)
217
- authenticate if token_expiration < Time.now
218
- request.tap { |r| r.add_field('Authorization', "Bearer #{token}") }
219
- end
220
-
221
- # Construct a business object API endpoint address
222
- #
223
- def uri_for(business_object_name, url_id: nil)
224
- url_id ||= imis_id
225
- url_id = CGI.escape(url_id)
226
- URI(File.join(imis_hostname, "#{API_PATH}/#{business_object_name}/#{url_id}"))
227
- end
228
-
229
- def submit(uri, request)
230
- client(uri).request(request).tap do |result|
231
- raise Error::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
232
- end
233
- end
234
-
235
169
  # Authenticate to the iMIS API, and store the access token and expiration time
236
170
  #
237
171
  def authenticate
238
- uri = URI(File.join(imis_hostname, AUTHENTICATION_PATH))
172
+ uri = URI(File.join(Imis.configuration.hostname, AUTHENTICATION_PATH))
239
173
  req = Net::HTTP::Post.new(uri)
240
174
  authentication_data = {
241
175
  grant_type: 'password',
@@ -249,33 +183,6 @@ module Usps
249
183
  @token = json['access_token']
250
184
  @token_expiration = Time.parse(json['.expires'])
251
185
  end
252
-
253
- # Manually assemble the matching data structure, with fields in the correct order
254
- #
255
- def filter_fields(business_object_name, fields)
256
- existing = get(business_object_name)
257
-
258
- JSON.parse(JSON.dump(existing)).tap do |updated|
259
- # The first property is always the iMIS ID again
260
- updated['Properties']['$values'] = [existing['Properties']['$values'][0]]
261
-
262
- # Iterate through all existing fields
263
- existing['Properties']['$values'].each do |value|
264
- next unless fields.keys.include?(value['Name'])
265
-
266
- # Strings are not wrapped in the type definition structure
267
- new_value = fields[value['Name']]
268
- if new_value.is_a?(String)
269
- value['Value'] = new_value
270
- else
271
- value['Value']['$value'] = new_value
272
- end
273
-
274
- # Add the completed field with the updated value
275
- updated['Properties']['$values'] << value
276
- end
277
- end
278
- end
279
186
  end
280
187
  end
281
188
  end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ # DEV
6
+ class BusinessObject
7
+ include Requests
8
+
9
+ # Endpoint for general API requests
10
+ #
11
+ API_PATH = 'api'
12
+
13
+ # The parent +Api+ object
14
+ #
15
+ attr_reader :api
16
+
17
+ # Name of the iMIS Business Object
18
+ #
19
+ attr_reader :business_object_name
20
+
21
+ # Override ID param of the URL (e.g. used for Panels)
22
+ #
23
+ attr_reader :url_id
24
+
25
+ # A new instance of +BusinessObject+
26
+ #
27
+ def initialize(api, business_object_name, url_id: nil)
28
+ @api = api
29
+ @business_object_name = business_object_name
30
+ @url_id = url_id
31
+ end
32
+
33
+ # Get a business object for the current member
34
+ #
35
+ # @return [Hash] Response data from the API
36
+ #
37
+ def get
38
+ request = Net::HTTP::Get.new(uri)
39
+ result = submit(uri, authorize(request))
40
+ JSON.parse(result.body)
41
+ end
42
+
43
+ # Update only specific fields on a business object for the current member
44
+ #
45
+ # @param fields [Hash] Conforms to pattern +{ field_key => value }+
46
+ #
47
+ # @return [Hash] Response data from the API
48
+ #
49
+ def put_fields(fields)
50
+ updated = filter_fields(fields)
51
+ put(updated)
52
+ end
53
+
54
+ # Update a business object for the current member
55
+ #
56
+ # @param body [Hash] Full raw API object data
57
+ #
58
+ # @return [Hash] Response data from the API
59
+ #
60
+ def put(body)
61
+ request = Net::HTTP::Put.new(uri)
62
+ request.body = JSON.dump(body)
63
+ result = submit(uri, authorize(request))
64
+ JSON.parse(result.body)
65
+ end
66
+
67
+ # Create a business object for the current member
68
+ #
69
+ # @param body [Hash] Full raw API object data
70
+ #
71
+ # @return [Hash] Response data from the API
72
+ #
73
+ def post(body)
74
+ request = Net::HTTP::Post.new(uri)
75
+ request.body = JSON.dump(body)
76
+ result = submit(uri, authorize(request))
77
+ JSON.parse(result.body)
78
+ end
79
+
80
+ # Remove a business object for the current member
81
+ #
82
+ # @return [String] Error response body from the API, or empty string on success
83
+ #
84
+ def delete
85
+ request = Net::HTTP::Delete.new(uri)
86
+ result = submit(uri, authorize(request))
87
+ result.body
88
+ end
89
+
90
+ private
91
+
92
+ def token = api.token
93
+ def token_expiration = api.token_expiration
94
+
95
+ # Construct a business object API endpoint address
96
+ #
97
+ def uri
98
+ id_for_url = url_id ? CGI.escape(url_id) : api.imis_id
99
+ full_path = "#{API_PATH}/#{business_object_name}/#{id_for_url}"
100
+ URI(File.join(Imis.configuration.hostname, full_path))
101
+ end
102
+
103
+ # Manually assemble the matching data structure, with fields in the correct order
104
+ #
105
+ def filter_fields(fields)
106
+ existing = get
107
+
108
+ JSON.parse(JSON.dump(existing)).tap do |updated|
109
+ # The first property is always the iMIS ID again
110
+ updated['Properties']['$values'] = [existing['Properties']['$values'][0]]
111
+
112
+ # Iterate through all existing fields
113
+ existing['Properties']['$values'].each do |value|
114
+ next unless fields.keys.include?(value['Name'])
115
+
116
+ # Strings are not wrapped in the type definition structure
117
+ new_value = fields[value['Name']]
118
+ if new_value.is_a?(String)
119
+ value['Value'] = new_value
120
+ else
121
+ value['Value']['$value'] = new_value
122
+ end
123
+
124
+ # Add the completed field with the updated value
125
+ updated['Properties']['$values'] << value
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -47,7 +47,7 @@ module Usps
47
47
  end
48
48
 
49
49
  updates.map do |business_object_name, field_updates|
50
- api.put_fields(business_object_name, field_updates)
50
+ api.business_object(business_object_name).put_fields(field_updates)
51
51
  end
52
52
  end
53
53
 
@@ -20,7 +20,7 @@ module Usps
20
20
  # @param ordinal [Integer] The ordinal identifier for the desired object
21
21
  #
22
22
  def get(ordinal)
23
- api.get(business_object, url_id: "~#{api.imis_id}|#{ordinal}")
23
+ api.business_object(business_object, url_id: "~#{api.imis_id}|#{ordinal}").get
24
24
  end
25
25
 
26
26
  # Create a new object in the Panel
@@ -28,7 +28,7 @@ module Usps
28
28
  # @param data [Hash] The record data for the desired object
29
29
  #
30
30
  def create(data)
31
- api.post(business_object, payload(data), url_id: '')
31
+ api.business_object(business_object, url_id: '').post(payload(data))
32
32
  end
33
33
 
34
34
  # Update an existing object in the Panel
@@ -37,7 +37,9 @@ module Usps
37
37
  # +ordinal+ identifier
38
38
  #
39
39
  def update(data)
40
- api.put(business_object, payload(data), url_id: "~#{api.imis_id}|#{data[:ordinal]}")
40
+ api
41
+ .business_object(business_object, url_id: "~#{api.imis_id}|#{data[:ordinal]}")
42
+ .put(payload(data))
41
43
  end
42
44
 
43
45
  # Remove a specific object from the Panel
@@ -45,7 +47,7 @@ module Usps
45
47
  # @param ordinal [Integer] The ordinal identifier for the desired object
46
48
  #
47
49
  def destroy(ordinal)
48
- api.delete(business_object, url_id: "~#{api.imis_id}|#{ordinal}")
50
+ api.business_object(business_object, url_id: "~#{api.imis_id}|#{ordinal}").delete
49
51
  end
50
52
 
51
53
  private
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Requests
6
+ private
7
+
8
+ def client(uri)
9
+ Net::HTTP.new(uri.host, uri.port).tap do |http|
10
+ http.use_ssl = true
11
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
12
+ end
13
+ end
14
+
15
+ # Authorize a request prior to submitting
16
+ #
17
+ # If the current token is missing/expired, request a new one
18
+ #
19
+ def authorize(request)
20
+ authenticate if token_expiration < Time.now
21
+ request.tap { |r| r.add_field('Authorization', "Bearer #{token}") }
22
+ end
23
+
24
+ def submit(uri, request)
25
+ client(uri).request(request).tap do |result|
26
+ raise Error::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- VERSION = '0.5.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
data/lib/usps/imis.rb CHANGED
@@ -16,6 +16,8 @@ require_relative 'imis/config'
16
16
  require_relative 'imis/error/api_error'
17
17
  require_relative 'imis/error/mapper_error'
18
18
  require_relative 'imis/error/response_error'
19
+ require_relative 'imis/requests'
20
+ require_relative 'imis/business_object'
19
21
  require_relative 'imis/api'
20
22
  require_relative 'imis/mapper'
21
23
  require_relative 'imis/panel/base_panel'
@@ -41,7 +41,9 @@ describe Usps::Imis::Api do
41
41
  before { api.imis_id = 31092 }
42
42
 
43
43
  it 'sends an update' do
44
- expect(api.put_fields('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 })).to be_a(Hash)
44
+ expect(api.business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15)).to(
45
+ be_a(Hash)
46
+ )
45
47
  end
46
48
 
47
49
  context 'when receiving a response error' do
@@ -61,8 +63,8 @@ describe Usps::Imis::Api do
61
63
  end
62
64
 
63
65
  it 'wraps the error' do
64
- expect { api.put_fields('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 }) }.to raise_error(
65
- Usps::Imis::Error::ApiError, warning_text
66
+ expect { api.business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }.to(
67
+ raise_error(Usps::Imis::Error::ApiError, warning_text)
66
68
  )
67
69
  end
68
70
  end
@@ -71,7 +73,7 @@ describe Usps::Imis::Api do
71
73
  describe '#with' do
72
74
  it 'sends an update from put' do
73
75
  expect(
74
- api.with(31092) { put_fields('ABC_ASC_Individual_Demog', { 'TotMMS' => 15 }) }
76
+ api.with(31092) { business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }
75
77
  ).to be_a(Hash)
76
78
  end
77
79
 
@@ -82,6 +84,51 @@ describe Usps::Imis::Api do
82
84
  it 'uses a panel correctly' do
83
85
  expect(api.with(6374) { panels.vsc.get(1433) }).to be_a(Hash)
84
86
  end
87
+
88
+ it 'blocks calling imis_id=' do
89
+ expect do
90
+ api.with(31092) { self.imis_id = 31092 }
91
+ end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
92
+ end
93
+
94
+ it 'blocks calling imis_id_for' do
95
+ expect do
96
+ api.with(31092) { imis_id_for('E231625') }
97
+ end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
98
+ end
99
+ end
100
+
101
+ describe '#on' do
102
+ it 'returns a BusinessObject without a block' do
103
+ expect(api.on('ABC_ASC_Individual_Demog')).to be_a(Usps::Imis::BusinessObject)
104
+ end
105
+
106
+ it 'sends an update from put', :aggregate_failures do
107
+ result = api.with(31092) do
108
+ on('ABC_ASC_Individual_Demog') { put_fields({ 'TotMMS' => 15 }) }
109
+ end
110
+
111
+ expect(result).to be_a(Hash)
112
+ expect(api.imis_id).to be_nil
113
+ end
114
+
115
+ it 'chains .with().on() to a single block', :aggregate_failures do
116
+ result = api.with(31092).on('ABC_ASC_Individual_Demog') do
117
+ put_fields({ 'TotMMS' => 15 })
118
+ end
119
+
120
+ expect(result).to be_a(Hash)
121
+ expect(api.imis_id).to eq('31092')
122
+ end
123
+
124
+ it 'nests on and with', :aggregate_failures do
125
+ result = api.on('ABC_ASC_Individual_Demog') do |object|
126
+ api.with(31092) { object.put_fields({ 'TotMMS' => 15 }) }
127
+ end
128
+
129
+ expect(result).to be_a(Hash)
130
+ expect(api.imis_id).to be_nil
131
+ end
85
132
  end
86
133
 
87
134
  describe '#inspect' do
@@ -108,36 +155,4 @@ describe Usps::Imis::Api do
108
155
  expect(api).to have_received(:authenticate)
109
156
  end
110
157
  end
111
-
112
- describe '#filter_fields' do
113
- let(:expected) do
114
- {
115
- 'Properties' => {
116
- '$values' => [
117
- { 'Name' => 'Stub iMIS ID', 'Value' => { '$value' => '31092' } },
118
- { 'Name' => 'Stub Integer', 'Value' => { '$value' => 43 } },
119
- { 'Name' => 'Stub String', 'Value' => 'other' }
120
- ]
121
- }
122
- }
123
- end
124
-
125
- before do
126
- allow(api).to receive(:get).and_return({
127
- 'Properties' => {
128
- '$values' => [
129
- { 'Name' => 'Stub iMIS ID', 'Value' => { '$value' => '31092' } },
130
- { 'Name' => 'Stub Integer', 'Value' => { '$value' => 42 } },
131
- { 'Name' => 'Stub String', 'Value' => 'something' }
132
- ]
133
- }
134
- })
135
- end
136
-
137
- it 'formats fields correctly' do
138
- updated = api.send(:filter_fields, 'Stub', { 'Stub Integer' => 43, 'Stub String' => 'other' })
139
-
140
- expect(updated).to eq(expected)
141
- end
142
- end
143
158
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Usps::Imis::BusinessObject do
6
+ let(:business_object) { described_class.new(api, 'Stub') }
7
+ let(:api) { Usps::Imis::Api.new }
8
+
9
+ describe '#filter_fields' do
10
+ let(:expected) do
11
+ {
12
+ 'Properties' => {
13
+ '$values' => [
14
+ { 'Name' => 'Stub iMIS ID', 'Value' => { '$value' => '31092' } },
15
+ { 'Name' => 'Stub Integer', 'Value' => { '$value' => 43 } },
16
+ { 'Name' => 'Stub String', 'Value' => 'other' }
17
+ ]
18
+ }
19
+ }
20
+ end
21
+
22
+ before do
23
+ allow(business_object).to receive(:get).and_return({
24
+ 'Properties' => {
25
+ '$values' => [
26
+ { 'Name' => 'Stub iMIS ID', 'Value' => { '$value' => '31092' } },
27
+ { 'Name' => 'Stub Integer', 'Value' => { '$value' => 42 } },
28
+ { 'Name' => 'Stub String', 'Value' => 'something' }
29
+ ]
30
+ }
31
+ })
32
+ end
33
+
34
+ it 'formats fields correctly' do
35
+ updated = business_object.send(:filter_fields, 'Stub Integer' => 43, 'Stub String' => 'other')
36
+
37
+ expect(updated).to eq(expected)
38
+ end
39
+ end
40
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: usps-imis-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Fiander
@@ -30,6 +30,7 @@ files:
30
30
  - lib/ext/hash.rb
31
31
  - lib/usps/imis.rb
32
32
  - lib/usps/imis/api.rb
33
+ - lib/usps/imis/business_object.rb
33
34
  - lib/usps/imis/config.rb
34
35
  - lib/usps/imis/error/api_error.rb
35
36
  - lib/usps/imis/error/mapper_error.rb
@@ -38,8 +39,10 @@ files:
38
39
  - lib/usps/imis/panel/base_panel.rb
39
40
  - lib/usps/imis/panel/education.rb
40
41
  - lib/usps/imis/panel/vsc.rb
42
+ - lib/usps/imis/requests.rb
41
43
  - lib/usps/imis/version.rb
42
44
  - spec/lib/usps/imis/api_spec.rb
45
+ - spec/lib/usps/imis/business_object_spec.rb
43
46
  - spec/lib/usps/imis/config_spec.rb
44
47
  - spec/lib/usps/imis/error/api_error_spec.rb
45
48
  - spec/lib/usps/imis/error/response_error_spec.rb