usps-imis-api 0.7.1 → 0.8.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: ca358fc80eed74b0335f6137f71e503fffbc84d6c396c8e1c23c90501eab5b36
4
- data.tar.gz: 239111a5dfd7cb186fe358fc0227e3063744225cf619e12a91e994f639142e56
3
+ metadata.gz: 0e1d3316b4676bae03e67aa927632ec91801a6d703c55049c1b11013a20c3e08
4
+ data.tar.gz: 8199c664875cc57e995d73b3a96ce03cd9de2e5460e7a451553df3bb5ca3ff84
5
5
  SHA512:
6
- metadata.gz: 2f31860395762aeead9f002f96867111758a8474ada928ba1369e3122b767f0b27052ed41157d8eac008fade27bdb779389cd65c74ad7cadbb87129ee9c238ff
7
- data.tar.gz: 7c0f5eaae8592a93192e08ca4cf88e604629de246b8e2f9272880d19e39a218d01a027387720a6c289b7f4490bc6617b57c637ab00201868ecd36fd178748031
6
+ metadata.gz: 7015ffe22161d1645959004798ed1fde3e65a66db6695dac75ae84db13177a376a37b083f74abdd9092108ba33d9d0f09fcbaaaa845d861d50af237c77c819b2
7
+ data.tar.gz: 940e05eeeeea390c67e207f4ace40c6befed6dbe355efdc38e3fa6d270c35f6bf5c48c3093808c505c2b26e9f452000ecd384e250451bc8263cce84d43a78238
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- usps-imis-api (0.7.1)
4
+ usps-imis-api (0.8.0)
5
5
  activesupport (~> 8.0)
6
6
 
7
7
  GEM
data/Readme.md CHANGED
@@ -101,6 +101,15 @@ You can also pass in specific field names to filter the returned member data, e.
101
101
  data = api.on('ABC_ASC_Individual_Demog').get('TotMMS', 'MMS_Updated')
102
102
  ```
103
103
 
104
+ The response from `get` behaves like a Hash, but directly accesses property values by name.
105
+ If you need to access the rest of the underlying data, use the `raw` method:
106
+
107
+ ```ruby
108
+ data = api.on('ABC_ASC_Individual_Demog').get
109
+ data['TotMMS']
110
+ data.raw['EntityTypeName']
111
+ ```
112
+
104
113
  Alias: `read`
105
114
 
106
115
  #### GET Field
@@ -111,6 +120,12 @@ To fetch a specific field from member data, run e.g.:
111
120
  tot_mms = api.on('ABC_ASC_Individual_Demog').get_field('TotMMS')
112
121
  ```
113
122
 
123
+ You can also access fields directly on the Business Object like a Hash:
124
+
125
+ ```ruby
126
+ tot_mms = api.on('ABC_ASC_Individual_Demog')['TotMMS']
127
+ ```
128
+
114
129
  Alias: `fetch`
115
130
 
116
131
  #### GET Fields
@@ -171,8 +186,6 @@ To remove member data, run e.g.:
171
186
  api.on('ABC_ASC_Individual_Demog').delete
172
187
  ```
173
188
 
174
- This returns a blank string on success.
175
-
176
189
  Alias: `destroy`
177
190
 
178
191
  ### QUERY
@@ -214,11 +227,24 @@ vsc = Usps::Imis::Panels::Vsc.new(imis_id: 6374)
214
227
 
215
228
  vsc.get(1417)
216
229
 
230
+ # All of these options are identical
231
+ #
232
+ vsc.get(1417, 'Quantity')
233
+ vsc.get(1417)['Quantity']
234
+ vsc.get[1417, 'Quantity']
235
+ vsc.get(1417).raw['Properties']['$values'].find { it['Name'] == 'Quantity' }['Value']['$value']
217
236
  vsc.get_field(1417, 'Quantity')
218
237
 
219
238
  created = vsc.create(certificate: 'E136924', year: 2024, count: 42)
220
- ordinal = created['Properties']['$values'].find { it['Name'] == 'Ordinal' }['Value']['$value']
221
- # ordinal = created['Identity']['IdentityElements']['$values'][1] # Alternative
239
+
240
+ # Get the Ordinal identifier from the response
241
+ #
242
+ # All of these options are identical
243
+ #
244
+ ordinal = created.ordinal
245
+ ordinal = created['Ordinal']
246
+ ordinal = created.raw['Properties']['$values'].find { it['Name'] == 'Ordinal' }['Value']['$value']
247
+ ordinal = created.raw['Identity']['IdentityElements']['$values'][1] # Value is duplicated here
222
248
 
223
249
  vsc.update(certificate: 'E136924', year: 2024, count: 43, ordinal: ordinal)
224
250
 
@@ -270,12 +296,18 @@ api.with(31092) do
270
296
  # These requests are identical:
271
297
 
272
298
  on('ABC_ASC_Individual_Demog') do
273
- get['Properties']['$values'].find { it['Name'] == 'TotMMS' }['Value']['$value']
274
- end
299
+ get.raw['Properties']['$values'].find { it['Name'] == 'TotMMS' }['Value']['$value']
275
300
 
276
- on('ABC_ASC_Individual_Demog') { get_field('TotMMS') }
301
+ get['TotMMS']
302
+
303
+ get_field('TotMMS')
304
+
305
+ get_fields('TotMMS').first
306
+ end
277
307
 
278
308
  on('ABC_ASC_Individual_Demog').get_field('TotMMS')
309
+
310
+ on('ABC_ASC_Individual_Demog')['TotMMS']
279
311
  end
280
312
 
281
313
  # This request fetches the same data, but leaves the iMIS ID selected
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'requests'
4
+ require_relative 'data'
4
5
 
5
6
  module Usps
6
7
  module Imis
@@ -38,7 +39,7 @@ module Usps
38
39
  #
39
40
  # @param fields [String] Field names to return
40
41
  #
41
- # @return [Hash, Array<Hash>] Response data from the API
42
+ # @return [Usps::Imis::Data, Array<Usps::Imis::Data>] Response data from the API
42
43
  #
43
44
  def get(*fields) = fields.any? ? get_fields(*fields) : raw_object
44
45
  alias read get
@@ -47,20 +48,21 @@ module Usps
47
48
  #
48
49
  # @param field [String] Field name to return
49
50
  #
50
- # @return [Hash] Response data from the API
51
+ # @return Response data field value from the API
51
52
  #
52
- def get_field(field) = extract_field_value(raw_object_values, field)
53
+ def get_field(field) = raw_object[field]
53
54
  alias fetch get_field
55
+ alias [] get_field
54
56
 
55
57
  # Get named fields from a business object for the current member
56
58
  #
57
59
  # @param names [Array<String>] Field names to return
58
60
  #
59
- # @return [Array<Hash>] Response data from the API
61
+ # @return [Array] Response data from the API
60
62
  #
61
63
  def get_fields(*fields)
62
- values = raw_object_values
63
- fields.map { extract_field_value(values, it) }
64
+ values = raw_object
65
+ fields.map { values[it] }
64
66
  end
65
67
  alias fetch_all get_fields
66
68
 
@@ -68,7 +70,7 @@ module Usps
68
70
  #
69
71
  # @param fields [Hash] Conforms to pattern +{ field_key => value }+
70
72
  #
71
- # @return [Hash] Response data from the API
73
+ # @return [Usps::Imis::Data] Response data from the API
72
74
  #
73
75
  def put_fields(fields) = put(filter_fields(fields))
74
76
  alias patch put_fields
@@ -79,7 +81,7 @@ module Usps
79
81
  #
80
82
  # @param body [Hash] Full raw API object data
81
83
  #
82
- # @return [Hash] Response data from the API
84
+ # @return [Usps::Imis::Data] Response data from the API
83
85
  #
84
86
  def put(body) = put_object(Net::HTTP::Put.new(uri), body)
85
87
  alias update put
@@ -88,7 +90,7 @@ module Usps
88
90
  #
89
91
  # @param body [Hash] Full raw API object data
90
92
  #
91
- # @return [Hash] Response data from the API
93
+ # @return [Usps::Imis::Data] Response data from the API
92
94
  #
93
95
  def post(body) = put_object(Net::HTTP::Post.new(uri(id: '')), body)
94
96
  alias create post
@@ -129,7 +131,7 @@ module Usps
129
131
  JSON.parse(JSON.dump(existing)).tap do |updated|
130
132
  # Preserve the iMIS ID, as well as the Ordinal (if present)
131
133
  updated['Properties']['$values'], properties =
132
- existing['Properties']['$values'].partition { %w[ID Ordinal].include?(it['Name']) }
134
+ existing.raw['Properties']['$values'].partition { %w[ID Ordinal].include?(it['Name']) }
133
135
 
134
136
  # Iterate through all existing fields
135
137
  properties.each do |value|
@@ -157,18 +159,7 @@ module Usps
157
159
  def raw_object
158
160
  request = Net::HTTP::Get.new(uri)
159
161
  result = submit(uri, authorize(request))
160
- JSON.parse(result.body)
161
- end
162
-
163
- # Get just the property values from an object response from the API
164
- #
165
- def raw_object_values
166
- raw_object['Properties']['$values']
167
- end
168
-
169
- def extract_field_value(values, field)
170
- value = values.find { it['Name'] == field }['Value']
171
- value.is_a?(String) ? value : value['$value']
162
+ Data.from_json(result.body)
172
163
  end
173
164
 
174
165
  # Upload an object to the API
@@ -176,7 +167,7 @@ module Usps
176
167
  def put_object(request, body)
177
168
  request.body = JSON.dump(body)
178
169
  result = submit(uri, authorize(request))
179
- JSON.parse(result.body)
170
+ Data.from_json(result.body)
180
171
  end
181
172
  end
182
173
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pp'
4
+ require 'stringio'
5
+
6
+ module Usps
7
+ module Imis
8
+ # Convenience wrapper for accessing specific properties within an API data response
9
+ #
10
+ class Data < Hash
11
+ # Load raw API response JSON to access properties
12
+ #
13
+ # @param json [String] Raw API response JSON
14
+ #
15
+ def self.from_json(json) = self[JSON.parse(json)]
16
+
17
+ alias raw to_h
18
+
19
+ # Access the iMIS ID property
20
+ #
21
+ def imis_id = self['ID']
22
+ alias id imis_id
23
+
24
+ # Access the Ordinal identifier property (if present)
25
+ #
26
+ def ordinal = self['Ordinal']
27
+
28
+ # Access an individual property value by name
29
+ #
30
+ def [](property_name)
31
+ property = raw['Properties']['$values'].find { it['Name'] == property_name }
32
+ return if property.nil?
33
+
34
+ value = property['Value']
35
+ value.is_a?(String) ? value : value['$value']
36
+ end
37
+
38
+ def inspect
39
+ stringio = StringIO.new
40
+ PP.pp(self, stringio)
41
+ stringio.string.delete("\n")
42
+ end
43
+
44
+ def pretty_print(pp)
45
+ data = {
46
+ entity_type_name: raw['EntityTypeName'],
47
+ imis_id:,
48
+ ordinal:
49
+ }.compact
50
+
51
+ pp.group(1, "#<#{self.class}", '>') do
52
+ data.each do |key, value|
53
+ pp.breakable
54
+ pp.text "#{key}="
55
+ pp.pp value
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -23,7 +23,7 @@ module Usps
23
23
  #
24
24
  # @param ordinal [Integer] The ordinal identifier for the desired object
25
25
  #
26
- # @return [Hash, Array<Hash>] Response data from the API
26
+ # @return [Usps::Imis::Data, Array<Usps::Imis::Data>] Response data from the API
27
27
  #
28
28
  def get(ordinal, *fields) = api.on(business_object, ordinal:).get(*fields)
29
29
  alias read get
@@ -33,17 +33,18 @@ module Usps
33
33
  # @param ordinal [Integer] The ordinal identifier for the desired object
34
34
  # @param field [String] Field name to return
35
35
  #
36
- # @return [Hash] Response data from the API
36
+ # @return Response data field value from the API
37
37
  #
38
38
  def get_field(ordinal, field) = api.on(business_object, ordinal:).get_field(field)
39
39
  alias fetch get_field
40
+ alias [] get_field
40
41
 
41
42
  # Get named fields from a Panel for the current member
42
43
  #
43
44
  # @param ordinal [Integer] The ordinal identifier for the desired object
44
45
  # @param fields [Array<String>] Field names to return
45
46
  #
46
- # @return [Hash] Response data from the API
47
+ # @return [Array] Response data from the API
47
48
  #
48
49
  def get_fields(ordinal, *fields) = api.on(business_object, ordinal:).get_fields(*fields)
49
50
  alias fetch_all get_fields
@@ -53,7 +54,7 @@ module Usps
53
54
  # @param ordinal [Integer] The ordinal identifier for the desired object
54
55
  # @param fields [Hash] Conforms to pattern +{ field_key => value }+
55
56
  #
56
- # @return [Hash] Response data from the API
57
+ # @return [Usps::Imis::Data] Response data from the API
57
58
  #
58
59
  def put_fields(ordinal, fields) = api.on(business_object, ordinal:).put_fields(fields)
59
60
  alias patch put_fields
@@ -63,6 +64,8 @@ module Usps
63
64
  # @param data [Hash] The record data for the desired object -- including the required
64
65
  # +ordinal+ identifier
65
66
  #
67
+ # @return [Usps::Imis::Data] Response data from the API
68
+ #
66
69
  def put(data) = api.on(business_object, ordinal: data[:ordinal]).put(payload(data))
67
70
  alias update put
68
71
 
@@ -70,6 +73,8 @@ module Usps
70
73
  #
71
74
  # @param data [Hash] The record data for the desired object
72
75
  #
76
+ # @return [Usps::Imis::Data] Response data from the API
77
+ #
73
78
  def post(data) = api.on(business_object).post(payload(data))
74
79
  alias create post
75
80
 
@@ -77,6 +82,8 @@ module Usps
77
82
  #
78
83
  # @param ordinal [Integer] The ordinal identifier for the desired object
79
84
  #
85
+ # @return [true] Only on success response (i.e. blank string from the API)
86
+ #
80
87
  def delete(ordinal) = api.on(business_object, ordinal:).delete
81
88
  alias destroy delete
82
89
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- VERSION = '0.7.1'
5
+ VERSION = '0.8.0'
6
6
  end
7
7
  end
@@ -7,15 +7,17 @@ describe Usps::Imis::BusinessObject do
7
7
  let(:api) { Usps::Imis::Api.new }
8
8
 
9
9
  before do
10
- allow(business_object).to receive(:raw_object).and_return({
11
- 'Properties' => {
12
- '$values' => [
13
- { 'Name' => 'ID', 'Value' => { '$value' => '31092' } },
14
- { 'Name' => 'Stub Integer', 'Value' => { '$value' => 42 } },
15
- { 'Name' => 'Stub String', 'Value' => 'something' }
16
- ]
17
- }
18
- })
10
+ allow(business_object).to receive(:raw_object).and_return(
11
+ Usps::Imis::Data[
12
+ 'Properties' => {
13
+ '$values' => [
14
+ { 'Name' => 'ID', 'Value' => { '$value' => '31092' } },
15
+ { 'Name' => 'Stub Integer', 'Value' => { '$value' => 42 } },
16
+ { 'Name' => 'Stub String', 'Value' => 'something' }
17
+ ]
18
+ }
19
+ ]
20
+ )
19
21
  end
20
22
 
21
23
  describe '#get' do
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Usps::Imis::Data do
6
+ let(:data) do
7
+ described_class[
8
+ 'EntityTypeName' => 'ABC_ASC_Individual_Demog',
9
+ 'Properties' => {
10
+ '$values' => [
11
+ { 'Name' => 'ID', 'Value' => { '$value' => '31092' } },
12
+ { 'Name' => 'Stub Integer', 'Value' => { '$value' => 42 } },
13
+ { 'Name' => 'Stub String', 'Value' => 'something' }
14
+ ]
15
+ }
16
+ ]
17
+ end
18
+
19
+ describe 'missing property' do
20
+ it 'returns nil for missing properties' do
21
+ expect(data['Not Found']).to be_nil
22
+ end
23
+ end
24
+
25
+ describe '#inspect' do
26
+ it 'generates the correct inspect string' do
27
+ expect(data.inspect).to eq('#<Usps::Imis::Data entity_type_name="ABC_ASC_Individual_Demog" imis_id="31092">')
28
+ end
29
+
30
+ context 'with data from a Panel' do
31
+ let(:data) do
32
+ described_class[
33
+ 'EntityTypeName' => 'ABC_ASC_Individual_Demog',
34
+ 'Properties' => {
35
+ '$values' => [
36
+ { 'Name' => 'ID', 'Value' => { '$value' => '31092' } },
37
+ { 'Name' => 'Ordinal', 'Value' => { '$value' => '99' } },
38
+ { 'Name' => 'Stub Integer', 'Value' => { '$value' => 42 } },
39
+ { 'Name' => 'Stub String', 'Value' => 'something' }
40
+ ]
41
+ }
42
+ ]
43
+ end
44
+
45
+ it 'generates the correct inspect string with an ordinal' do
46
+ expect(data.inspect).to eq(
47
+ '#<Usps::Imis::Data entity_type_name="ABC_ASC_Individual_Demog" imis_id="31092" ordinal="99">'
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end
@@ -21,7 +21,7 @@ describe Usps::Imis::Panels::Education do
21
21
 
22
22
  describe '#get' do
23
23
  it 'loads a specific object' do
24
- expect(education.get(90737)).to be_a(Hash)
24
+ expect(education.get(90737)).to be_a(Usps::Imis::Data)
25
25
  end
26
26
 
27
27
  it 'returns specific fields' do
@@ -44,22 +44,16 @@ describe Usps::Imis::Panels::Education do
44
44
  # rubocop:disable RSpec/ExampleLength
45
45
  it 'interacts with records correctly', :aggregate_failures do
46
46
  new_record = education.create(details)
47
- expect(new_record).to be_a(Hash)
47
+ expect(new_record).to be_a(Usps::Imis::Data)
48
48
 
49
- ordinal = new_record['Identity']['IdentityElements']['$values'][1]
49
+ ordinal = new_record.ordinal
50
50
 
51
51
  update_result =
52
52
  education.update(details.merge(source: 'Online Exams System - Modified', ordinal:))
53
- updated = update_result['Properties']['$values'].find do |v|
54
- v['Name'] == 'ABC_Educ_Source_System'
55
- end
56
- expect(updated['Value']).to eq('Online Exams System - Modified')
53
+ expect(update_result['ABC_Educ_Source_System']).to eq('Online Exams System - Modified')
57
54
 
58
55
  put_fields_result = education.put_fields(ordinal, 'ABC_Educ_Source_System' => 'Online Exams System - Mod2')
59
- patched = put_fields_result['Properties']['$values'].find do |v|
60
- v['Name'] == 'ABC_Educ_Source_System'
61
- end
62
- expect(patched['Value']).to eq('Online Exams System - Mod2')
56
+ expect(put_fields_result['ABC_Educ_Source_System']).to eq('Online Exams System - Mod2')
63
57
 
64
58
  expect(education.destroy(ordinal)).to be(true)
65
59
  end
@@ -17,20 +17,19 @@ describe Usps::Imis::Panels::Vsc do
17
17
 
18
18
  describe '#get' do
19
19
  it 'loads a specific object' do
20
- expect(vsc.get(1433)).to be_a(Hash)
20
+ expect(vsc.get(1433)).to be_a(Usps::Imis::Data)
21
21
  end
22
22
  end
23
23
 
24
24
  # rubocop:disable RSpec/ExampleLength
25
25
  it 'handles new records correctly', :aggregate_failures do
26
26
  new_record = vsc.create(details)
27
- expect(new_record).to be_a(Hash)
27
+ expect(new_record).to be_a(Usps::Imis::Data)
28
28
 
29
- ordinal = new_record['Identity']['IdentityElements']['$values'][1]
29
+ ordinal = new_record.ordinal
30
30
 
31
31
  update_result = vsc.update(details.merge(count: 43, ordinal:))
32
- updated = update_result['Properties']['$values'].find { it['Name'] == 'Quantity' }
33
- expect(updated['Value']['$value']).to eq(43)
32
+ expect(update_result['Quantity']).to eq(43)
34
33
 
35
34
  expect(vsc.destroy(ordinal)).to be(true)
36
35
  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.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Fiander
@@ -45,6 +45,7 @@ files:
45
45
  - lib/usps/imis/api.rb
46
46
  - lib/usps/imis/business_object.rb
47
47
  - lib/usps/imis/config.rb
48
+ - lib/usps/imis/data.rb
48
49
  - lib/usps/imis/error.rb
49
50
  - lib/usps/imis/errors/api_error.rb
50
51
  - lib/usps/imis/errors/config_error.rb
@@ -67,6 +68,7 @@ files:
67
68
  - spec/lib/usps/imis/api_spec.rb
68
69
  - spec/lib/usps/imis/business_object_spec.rb
69
70
  - spec/lib/usps/imis/config_spec.rb
71
+ - spec/lib/usps/imis/data_spec.rb
70
72
  - spec/lib/usps/imis/error_spec.rb
71
73
  - spec/lib/usps/imis/errors/response_error_spec.rb
72
74
  - spec/lib/usps/imis/mapper_spec.rb