usps-imis-api 0.6.15 → 0.7.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -3
  3. data/Gemfile.lock +36 -30
  4. data/Readme.md +48 -23
  5. data/lib/usps/imis/api.rb +9 -17
  6. data/lib/usps/imis/business_object.rb +2 -0
  7. data/lib/usps/imis/config.rb +1 -1
  8. data/lib/usps/imis/error.rb +51 -0
  9. data/lib/usps/imis/errors/api_error.rb +11 -0
  10. data/lib/usps/imis/errors/config_error.rb +11 -0
  11. data/lib/usps/imis/errors/locked_id_error.rb +15 -0
  12. data/lib/usps/imis/errors/mapper_error.rb +29 -0
  13. data/lib/usps/imis/errors/not_found_error.rb +11 -0
  14. data/lib/usps/imis/errors/panel_unimplemented_error.rb +34 -0
  15. data/lib/usps/imis/{error → errors}/response_error.rb +4 -7
  16. data/lib/usps/imis/errors/unexpected_property_type_error.rb +31 -0
  17. data/lib/usps/imis/mapper.rb +2 -6
  18. data/lib/usps/imis/mocks/business_object.rb +37 -0
  19. data/lib/usps/imis/mocks.rb +11 -0
  20. data/lib/usps/imis/{panel → panels}/base_panel.rb +3 -3
  21. data/lib/usps/imis/{panel → panels}/education.rb +1 -1
  22. data/lib/usps/imis/{panel → panels}/vsc.rb +1 -1
  23. data/lib/usps/imis/panels.rb +25 -0
  24. data/lib/usps/imis/properties.rb +1 -1
  25. data/lib/usps/imis/requests.rb +1 -1
  26. data/lib/usps/imis/version.rb +1 -1
  27. data/lib/usps/imis.rb +5 -15
  28. data/spec/lib/usps/imis/api_spec.rb +8 -8
  29. data/spec/lib/usps/imis/config_spec.rb +1 -1
  30. data/spec/lib/usps/imis/{error/api_error_spec.rb → error_spec.rb} +1 -1
  31. data/spec/lib/usps/imis/{error → errors}/response_error_spec.rb +4 -4
  32. data/spec/lib/usps/imis/mapper_spec.rb +2 -2
  33. data/spec/lib/usps/imis/{business_object_mock_spec.rb → mocks/business_object_spec.rb} +1 -1
  34. data/spec/lib/usps/imis/panels/base_panel_spec.rb +33 -0
  35. data/spec/lib/usps/imis/{panel → panels}/education_spec.rb +1 -1
  36. data/spec/lib/usps/imis/{panel → panels}/vsc_spec.rb +1 -1
  37. data/spec/lib/usps/imis/properties_spec.rb +1 -1
  38. metadata +22 -15
  39. data/lib/ext/hash.rb +0 -10
  40. data/lib/usps/imis/business_object_mock.rb +0 -35
  41. data/lib/usps/imis/error/api_error.rb +0 -44
  42. data/lib/usps/imis/error/mapper_error.rb +0 -11
  43. data/spec/lib/usps/imis/panel/base_panel_spec.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ece5a19e925e1ef85b9e54b1d8fe7139c4015b0a1fe7ddcb602e172fbb50cab
4
- data.tar.gz: 723eb4ccbf3b0c86c3f309c83d32d2b892420c688fd1f8aa2bfedcc47d61d2a9
3
+ metadata.gz: bc6237ee6d52c0fdfc8cd33809a90600b68a19926490facab194e751b8c983d3
4
+ data.tar.gz: f66d10f8a53e2df13e42a96fec6a4fc2cb61d798f80dbe7ddc88cf2f84418277
5
5
  SHA512:
6
- metadata.gz: fbca9aeda6a7a4e7fc6701c2767da349ab49e6b9126b36ea0a6225b4c18b2c7970dc22390ddabfbf571411d76b86ab2b37bbde79f471f4b5a3ceba9d271fdd5c
7
- data.tar.gz: 3b09c75a050ad32e8077d9bc07772d91bb37a7e4628734c0159cb05a206f7f9128059532e22e90f014f07041f2ac87d0d37c2d7878845069c1220ec221cb4e69
6
+ metadata.gz: 16b7a7e05c2fa1cb5d3e2de1604a4a06e5d551a650f7ee451662afa7f43b2b1917f0be04a2c3d4af063a18c0b22515d304bcc25afca79e9214e76542d3b39438
7
+ data.tar.gz: bfe78effec93b84b65963c54decb29ae114e10231e537ad216d1c3d2b250348474efeb0bd20b5f5759a7b6440eca6b28660a10c94d617c90fa70708c1c85727e
data/.rubocop.yml CHANGED
@@ -1,4 +1,4 @@
1
- require:
1
+ plugins:
2
2
  - rubocop-rspec
3
3
 
4
4
  AllCops:
@@ -37,8 +37,6 @@ Lint/UnusedMethodArgument:
37
37
  Enabled: true
38
38
  Lint/UselessAssignment:
39
39
  Enabled: true
40
- Lint/ItWithoutArgumentsInBlock:
41
- Enabled: false
42
40
 
43
41
  Metrics/MethodLength:
44
42
  Enabled: true
data/Gemfile.lock CHANGED
@@ -1,37 +1,36 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- usps-imis-api (0.6.15)
4
+ usps-imis-api (0.7.0)
5
5
  activesupport (~> 8.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (8.0.3)
10
+ activesupport (8.1.0)
11
11
  base64
12
- benchmark (>= 0.3)
13
12
  bigdecimal
14
13
  concurrent-ruby (~> 1.0, >= 1.3.1)
15
14
  connection_pool (>= 2.2.5)
16
15
  drb
17
16
  i18n (>= 1.6, < 2)
17
+ json
18
18
  logger (>= 1.4.2)
19
19
  minitest (>= 5.1)
20
20
  securerandom (>= 0.3)
21
21
  tzinfo (~> 2.0, >= 2.0.5)
22
22
  uri (>= 0.13.1)
23
- ast (2.4.2)
23
+ ast (2.4.3)
24
24
  base64 (0.3.0)
25
- benchmark (0.4.1)
26
25
  bigdecimal (3.3.1)
27
26
  concurrent-ruby (1.3.5)
28
27
  connection_pool (2.5.4)
29
28
  date (3.4.1)
30
- diff-lcs (1.5.1)
29
+ diff-lcs (1.6.2)
31
30
  docile (1.4.1)
32
- dotenv (3.1.4)
31
+ dotenv (3.1.8)
33
32
  drb (2.2.3)
34
- erb (5.0.3)
33
+ erb (5.1.1)
35
34
  i18n (1.14.7)
36
35
  concurrent-ruby (~> 1.0)
37
36
  io-console (0.8.1)
@@ -39,70 +38,77 @@ GEM
39
38
  pp (>= 0.6.0)
40
39
  rdoc (>= 4.0.0)
41
40
  reline (>= 0.4.2)
42
- json (2.7.2)
43
- language_server-protocol (3.17.0.3)
41
+ json (2.15.1)
42
+ language_server-protocol (3.17.0.5)
43
+ lint_roller (1.1.0)
44
44
  logger (1.7.0)
45
45
  minitest (5.26.0)
46
- parallel (1.26.3)
47
- parser (3.3.5.0)
46
+ parallel (1.27.0)
47
+ parser (3.3.9.0)
48
48
  ast (~> 2.4.1)
49
49
  racc
50
50
  pp (0.6.3)
51
51
  prettyprint
52
52
  prettyprint (0.2.0)
53
+ prism (1.6.0)
53
54
  psych (5.2.6)
54
55
  date
55
56
  stringio
56
57
  racc (1.8.1)
57
58
  rainbow (3.1.1)
58
- rake (13.2.1)
59
+ rake (13.3.0)
59
60
  rdoc (6.15.0)
60
61
  erb
61
62
  psych (>= 4.0.0)
62
63
  tsort
63
- regexp_parser (2.9.2)
64
+ regexp_parser (2.11.3)
64
65
  reline (0.6.2)
65
66
  io-console (~> 0.5)
66
- rspec (3.13.0)
67
+ rspec (3.13.2)
67
68
  rspec-core (~> 3.13.0)
68
69
  rspec-expectations (~> 3.13.0)
69
70
  rspec-mocks (~> 3.13.0)
70
- rspec-core (3.13.1)
71
+ rspec-core (3.13.6)
71
72
  rspec-support (~> 3.13.0)
72
- rspec-expectations (3.13.3)
73
+ rspec-expectations (3.13.5)
73
74
  diff-lcs (>= 1.2.0, < 2.0)
74
75
  rspec-support (~> 3.13.0)
75
- rspec-mocks (3.13.2)
76
+ rspec-mocks (3.13.6)
76
77
  diff-lcs (>= 1.2.0, < 2.0)
77
78
  rspec-support (~> 3.13.0)
78
- rspec-support (3.13.1)
79
- rubocop (1.66.1)
79
+ rspec-support (3.13.6)
80
+ rubocop (1.81.6)
80
81
  json (~> 2.3)
81
- language_server-protocol (>= 3.17.0)
82
+ language_server-protocol (~> 3.17.0.2)
83
+ lint_roller (~> 1.1.0)
82
84
  parallel (~> 1.10)
83
85
  parser (>= 3.3.0.2)
84
86
  rainbow (>= 2.2.2, < 4.0)
85
- regexp_parser (>= 2.4, < 3.0)
86
- rubocop-ast (>= 1.32.2, < 2.0)
87
+ regexp_parser (>= 2.9.3, < 3.0)
88
+ rubocop-ast (>= 1.47.1, < 2.0)
87
89
  ruby-progressbar (~> 1.7)
88
- unicode-display_width (>= 2.4.0, < 3.0)
89
- rubocop-ast (1.32.3)
90
- parser (>= 3.3.1.0)
91
- rubocop-rspec (3.1.0)
92
- rubocop (~> 1.61)
90
+ unicode-display_width (>= 2.4.0, < 4.0)
91
+ rubocop-ast (1.47.1)
92
+ parser (>= 3.3.7.2)
93
+ prism (~> 1.4)
94
+ rubocop-rspec (3.7.0)
95
+ lint_roller (~> 1.1)
96
+ rubocop (~> 1.72, >= 1.72.1)
93
97
  ruby-progressbar (1.13.0)
94
98
  securerandom (0.4.1)
95
99
  simplecov (0.22.0)
96
100
  docile (~> 1.1)
97
101
  simplecov-html (~> 0.11)
98
102
  simplecov_json_formatter (~> 0.1)
99
- simplecov-html (0.13.1)
103
+ simplecov-html (0.13.2)
100
104
  simplecov_json_formatter (0.1.4)
101
105
  stringio (3.1.7)
102
106
  tsort (0.2.0)
103
107
  tzinfo (2.0.6)
104
108
  concurrent-ruby (~> 1.0)
105
- unicode-display_width (2.6.0)
109
+ unicode-display_width (3.2.0)
110
+ unicode-emoji (~> 4.1)
111
+ unicode-emoji (4.1.0)
106
112
  uri (1.0.4)
107
113
 
108
114
  PLATFORMS
data/Readme.md CHANGED
@@ -77,33 +77,37 @@ You can also manually set the current ID, if you already have it for a given mem
77
77
  api.imis_id = imis_id
78
78
  ```
79
79
 
80
- ### GET
80
+ ### Business Object and Panel Actions
81
+
82
+ Business Objects and Panels support the following actions.
83
+
84
+ Panels require passing in the ordinal identifier as an argument, except for `POST`.
85
+
86
+ #### GET
81
87
 
82
88
  To fetch member data, run e.g.:
83
89
 
84
90
  ```ruby
85
- api.imis_id = 31092
86
-
87
91
  data = api.on('ABC_ASC_Individual_Demog').get
88
92
  ```
89
93
 
90
- ### GET Field
94
+ Alias: `read`
95
+
96
+ #### GET Field
91
97
 
92
98
  To fetch a specific field from member data, run e.g.:
93
99
 
94
100
  ```ruby
95
- api.imis_id = 31092
96
-
97
101
  tot_mms = api.on('ABC_ASC_Individual_Demog').get_field('TotMMS')
98
102
  ```
99
103
 
100
- ### PUT Fields
104
+ Alias: `fetch`
105
+
106
+ #### PUT Fields
101
107
 
102
108
  To update member data, run e.g.:
103
109
 
104
110
  ```ruby
105
- api.imis_id = 31092
106
-
107
111
  data = { 'MMS_Updated' => Time.now.strftime('%Y-%m-%dT%H:%M:%S'), 'TotMMS' => new_total }
108
112
  update = api.on('ABC_ASC_Individual_Demog').put_fields(data)
109
113
  ```
@@ -111,19 +115,23 @@ update = api.on('ABC_ASC_Individual_Demog').put_fields(data)
111
115
  This method fetches the current data structure, and filters it down to just what you want to
112
116
  update, to reduce the likelihood of update collisions or type validation failures.
113
117
 
114
- ### PUT
118
+ Alias: `patch`
119
+
120
+ #### PUT
115
121
 
116
122
  To update member data, run e.g.:
117
123
 
118
124
  ```ruby
119
- api.imis_id = 31092
120
-
121
125
  update = api.on('ABC_ASC_Individual_Demog').put(complete_imis_object)
122
126
  ```
123
127
 
124
- This method requires a complete iMIS data structure.
128
+ This method requires a complete iMIS data structure. However, any properties not included will be
129
+ left unmodified (meaning this also effectively handles `PATCH`, though iMIS does not accept that
130
+ HTTP verb).
131
+
132
+ Alias: `update`
125
133
 
126
- ### POST
134
+ #### POST
127
135
 
128
136
  To create new member data, run e.g.:
129
137
 
@@ -133,18 +141,20 @@ created = api.on('ABC_ASC_Individual_Demog').post(complete_imis_object)
133
141
 
134
142
  This method requires a complete iMIS data structure.
135
143
 
136
- ### DELETE
144
+ Alias: `create`
145
+
146
+ #### DELETE
137
147
 
138
148
  To remove member data, run e.g.:
139
149
 
140
150
  ```ruby
141
- api.imis_id = 31092
142
-
143
151
  api.on('ABC_ASC_Individual_Demog').delete
144
152
  ```
145
153
 
146
154
  This returns a blank string on success.
147
155
 
156
+ Alias: `destroy`
157
+
148
158
  ### QUERY
149
159
 
150
160
  Run an IQA Query
@@ -180,24 +190,27 @@ For supported panels (usually, business objects with composite identity keys), y
180
190
  with them in the same general way:
181
191
 
182
192
  ```ruby
183
- vsc = Usps::Imis::Panel::Vsc.new
184
-
185
- vsc.api.imis_id = 6374
193
+ vsc = Usps::Imis::Panels::Vsc.new(imis_id: 6374)
186
194
 
187
195
  vsc.get(1417)
188
196
 
197
+ vsc.get_field(1417, 'Quantity')
198
+
189
199
  created = vsc.create(certificate: 'E136924', year: 2024, count: 42)
190
- ordinal = created['Properties']['$values'][1]['Value']['$value']
200
+ ordinal = created['Properties']['$values'].find { it['Name'] == 'Ordinal' }['Value']['$value']
201
+ # ordinal = created['Identity']['IdentityElements']['$values'][1] # Alternative
191
202
 
192
203
  vsc.update(certificate: 'E136924', year: 2024, count: 43, ordinal: ordinal)
193
204
 
205
+ vsc.put_fields(ordinal, 'Quantity' => 44)
206
+
194
207
  vsc.destroy(ordinal)
195
208
  ```
196
209
 
197
210
  If you already have an iMIS ID to work with, you can pass that in immediately:
198
211
 
199
212
  ```ruby
200
- vsc = Usps::Imis::Panel::Vsc.new(imis_id: imis_id)
213
+ vsc = Usps::Imis::Panels::Vsc.new(imis_id: imis_id)
201
214
  ```
202
215
 
203
216
  Panels are also accessible directly from the API object:
@@ -249,9 +262,21 @@ end
249
262
  api.with(31092).on('ABC_ASC_Individual_Demog').get_field('TotMMS')
250
263
  ```
251
264
 
265
+ ## Test Data Mocking
266
+
267
+ You can use the provided Business Object Mock to generate stub data for rspec:
268
+
269
+ ```ruby
270
+ allow(api).to(
271
+ receive(:on).with('ABC_ASC_Individual_Demog').and_return(
272
+ Usps::Imis::Mocks::BusinessObject.new(TotMMS: 2)
273
+ )
274
+ )
275
+ ```
276
+
252
277
  ## Exception Handling
253
278
 
254
- All internal exceptions inherit from `Usps::Imis::ApiError`.
279
+ All internal exceptions inherit from `Usps::Imis::Error`.
255
280
 
256
281
  ## Automated Testing and Linting
257
282
 
data/lib/usps/imis/api.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'requests'
4
+ require_relative 'business_object'
5
+ require_relative 'mapper'
6
+
3
7
  module Usps
4
8
  module Imis
5
9
  # The core API wrapper
@@ -48,7 +52,7 @@ module Usps
48
52
  # @param id [Integer, String] iMIS ID to select for future requests
49
53
  #
50
54
  def imis_id=(id)
51
- raise Error::ApiError, 'Cannot change iMIS ID while locked' if lock_imis_id
55
+ raise Errors::LockedIdError if lock_imis_id
52
56
 
53
57
  @imis_id = id&.to_i&.to_s
54
58
  end
@@ -60,13 +64,13 @@ module Usps
60
64
  # @return [String] Corresponding iMIS ID
61
65
  #
62
66
  def imis_id_for(certificate)
63
- raise Error::ApiError, 'Cannot change iMIS ID while locked' if lock_imis_id
67
+ raise Errors::LockedIdError if lock_imis_id
64
68
 
65
69
  begin
66
70
  result = query(Imis.configuration.imis_id_query_name, { certificate: })
67
71
  @imis_id = result['Items']['$values'][0]['ID']
68
72
  rescue StandardError
69
- raise Error::ApiError, 'Member not found'
73
+ raise Errors::NotFoundError, 'Member not found'
70
74
  end
71
75
  end
72
76
 
@@ -132,15 +136,6 @@ module Usps
132
136
  results
133
137
  end
134
138
 
135
- # An instance of +BusinessObject+, using this instance as its parent +Api+
136
- #
137
- # @param business_object_name [String] Name of the business object
138
- # @param ordinal [Integer] Ordinal to build override ID param of the URL (e.g. used for Panels)
139
- #
140
- def business_object(business_object_name, ordinal: nil)
141
- BusinessObject.new(self, business_object_name, ordinal:)
142
- end
143
-
144
139
  # Run requests as DSL, with specific +BusinessObject+ only maintained for this scope
145
140
  #
146
141
  # If no block is given, this returns the specified +BusinessObject+.
@@ -149,7 +144,7 @@ module Usps
149
144
  # @param ordinal [Integer] Ordinal to build override ID param of the URL (e.g. used for Panels)
150
145
  #
151
146
  def on(business_object_name, ordinal: nil, &)
152
- object = business_object(business_object_name, ordinal:)
147
+ object = BusinessObject.new(self, business_object_name, ordinal:)
153
148
  return object unless block_given?
154
149
 
155
150
  object.instance_eval(&)
@@ -171,10 +166,7 @@ module Usps
171
166
  # +Api+
172
167
  #
173
168
  def panels
174
- @panels ||= Struct.new(:vsc, :education).new(
175
- Panel::Vsc.new(self),
176
- Panel::Education.new(self)
177
- )
169
+ @panels ||= Panels.all(self)
178
170
  end
179
171
 
180
172
  # Ruby 3.5 instance variable filter
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'requests'
4
+
3
5
  module Usps
4
6
  module Imis
5
7
  # DEV
@@ -32,7 +32,7 @@ module Usps
32
32
  return IMIS_ROOT_URL_PROD if environment.production?
33
33
  return IMIS_ROOT_URL_DEV if environment.development?
34
34
 
35
- raise Error::ApiError, "Unexpected API environment: #{environment}"
35
+ raise Errors::ConfigError, "Unexpected API environment: #{environment}"
36
36
  end
37
37
 
38
38
  # Ruby 3.5 instance variable filter
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ # Base error class for all internal exceptions
6
+ #
7
+ class Error < StandardError
8
+ # Additional call-specific metadata to pass through to Bugsnag
9
+ #
10
+ attr_accessor :metadata
11
+
12
+ # A new instance of +ApiError+
13
+ #
14
+ # @param message [String] The base exception message
15
+ # @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
16
+ #
17
+ def initialize(message, metadata = {})
18
+ super(message)
19
+ @metadata = metadata
20
+ end
21
+
22
+ # Additional metadata to include in Bugsnag reports
23
+ #
24
+ # Can include fields at the top level, which will be shows on the custom tab
25
+ #
26
+ # Can include fields nested under a top-level key, which will be shown on a tab with the
27
+ # top-level key as its name
28
+ #
29
+ # @return [Hash]
30
+ #
31
+ def bugsnag_meta_data
32
+ metadata == {} ? {} : base_metadata
33
+ end
34
+
35
+ private
36
+
37
+ def base_metadata
38
+ { api: metadata }
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ require_relative 'errors/api_error'
45
+ require_relative 'errors/config_error'
46
+ require_relative 'errors/locked_id_error'
47
+ require_relative 'errors/mapper_error'
48
+ require_relative 'errors/not_found_error'
49
+ require_relative 'errors/response_error'
50
+ require_relative 'errors/panel_unimplemented_error'
51
+ require_relative 'errors/unexpected_property_type_error'
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Generic exception raised from within the gem
7
+ #
8
+ class ApiError < Error; end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Exception raised for invalid configuration
7
+ #
8
+ class ConfigError < Error; end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Exception raised when attempting to change the iMIS ID while it is locked
7
+ #
8
+ class LockedIdError < Error
9
+ def initialize = super(message)
10
+
11
+ def message = 'Cannot change iMIS ID while locked'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Exception raised by a +Mapper+
7
+ #
8
+ class MapperError < Error
9
+ # Create a new instance of +MapperError+
10
+ #
11
+ # @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
12
+ #
13
+ def initialize(metadata = {})
14
+ @metadata = metadata
15
+ super(message, metadata)
16
+ end
17
+
18
+ # Exception message including the unrecognized field
19
+ #
20
+ def message
21
+ <<~MESSAGE.chomp
22
+ Mapper does not recognize field: "#{metadata[:field_name]}".
23
+ Please report what data you are attempting to work with to ITCom leadership.
24
+ MESSAGE
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Exception raised when the requested object cannot be found
7
+ #
8
+ class NotFoundError < Error; end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Exception raised when a panel is missing required method definitions
7
+ #
8
+ class PanelUnimplementedError < Error
9
+ # Create a new instance of +PanelUnimplementedError+ from the class name and missing method
10
+ #
11
+ # @param class_name [String] Name of the Panel class that is missing a method definition
12
+ # @param method [String] Method definition that is not defined on the Panel
13
+ #
14
+ def self.from(class_name, method) = new(class_name, method)
15
+
16
+ # Create a new instance of +PanelUnimplementedError+
17
+ #
18
+ # @param class_name [String] Name of the Panel class that is missing a method definition
19
+ # @param method [String] Method definition that is not defined on the Panel
20
+ # @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
21
+ #
22
+ def initialize(class_name, method, metadata = {})
23
+ @class_name = class_name
24
+ @method = method
25
+ super(message, metadata)
26
+ end
27
+
28
+ # Exception message including the undefined method
29
+ #
30
+ def message = "#{@class_name} must implement ##{@method}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- module Error
5
+ module Errors
6
6
  # Exception raised due to receiving an error response from the API
7
7
  #
8
- class ResponseError < ApiError
8
+ class ResponseError < Error
9
9
  # [Net::HTTPResponse] The response received from the API
10
10
  #
11
11
  attr_reader :response
@@ -18,17 +18,14 @@ module Usps
18
18
  #
19
19
  # @param response [Net::HTTPResponse] The response received from the API
20
20
  #
21
- def self.from(response)
22
- new(nil, response)
23
- end
21
+ def self.from(response) = new(response)
24
22
 
25
23
  # Create a new instance of +ResponseError+
26
24
  #
27
- # @param _message Ignored
28
25
  # @param response [Net::HTTPResponse] The response received from the API
29
26
  # @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
30
27
  #
31
- def initialize(_message, response, metadata = {})
28
+ def initialize(response, metadata = {})
32
29
  @response = response
33
30
  super(message, metadata)
34
31
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Errors
6
+ # Exception raised when attempting to wrap an unexpected property type
7
+ #
8
+ class UnexpectedPropertyTypeError < Error
9
+ # Create a new instance of +UnexpectedPropertyTypeError+ from an unexpected value
10
+ #
11
+ # @param value Unexpected value
12
+ #
13
+ def self.from(value) = new(value)
14
+
15
+ # Create a new instance of +UnexpectedPropertyTypeError+
16
+ #
17
+ # @param value Unexpected value
18
+ # @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
19
+ #
20
+ def initialize(value, metadata = {})
21
+ @value = value
22
+ super(message, metadata)
23
+ end
24
+
25
+ # Exception message including the undefined method
26
+ #
27
+ def message = "Unexpected property type: #{@value.inspect}"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -47,7 +47,7 @@ module Usps
47
47
  end
48
48
 
49
49
  updates.map do |business_object_name, field_updates|
50
- api.business_object(business_object_name).put_fields(field_updates)
50
+ api.on(business_object_name).put_fields(field_updates)
51
51
  end
52
52
  end
53
53
 
@@ -73,11 +73,7 @@ module Usps
73
73
  # :nocov:
74
74
  end
75
75
 
76
- raise(
77
- Error::MapperError,
78
- "Unrecognized field: \"#{field_name}\". " \
79
- 'Please report what data you are attempting to work with to ITCom leadership.'
80
- )
76
+ raise Errors::MapperError.new({ field_name: })
81
77
  end
82
78
  end
83
79
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Mocks
6
+ # Mock data response for testing
7
+ #
8
+ class BusinessObject
9
+ attr_reader :fields
10
+
11
+ def initialize(**fields)
12
+ @fields = fields.transform_keys(&:to_s)
13
+ end
14
+
15
+ def get_field(name) = fields[name]
16
+
17
+ def get
18
+ Usps::Imis::Properties.build do |props|
19
+ fields.each { |name, value| props.add(name, value) }
20
+ end
21
+ end
22
+
23
+ def put_fields(data)
24
+ Usps::Imis::Properties.build do |props|
25
+ fields.merge(data.transform_keys(&:to_s)).each { |name, value| props.add(name, value) }
26
+ end
27
+ end
28
+
29
+ def put(data) = data
30
+
31
+ def post(data) = data
32
+
33
+ def delete = ''
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mocks/business_object'
4
+
5
+ module Usps
6
+ module Imis
7
+ # Namespace for all Mocks
8
+ #
9
+ module Mocks; end
10
+ end
11
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- module Panel
5
+ module Panels
6
6
  # Base class for configuring Panels
7
7
  #
8
8
  class BasePanel
@@ -79,11 +79,11 @@ module Usps
79
79
  private
80
80
 
81
81
  def business_object
82
- raise Error::ApiError, "#{self.class.name} must implement #business_object"
82
+ raise Errors::PanelUnimplementedError.from(self.class.name, 'business_object')
83
83
  end
84
84
 
85
85
  def payload(_data)
86
- raise Error::ApiError, "#{self.class.name} must implement #payload(data)"
86
+ raise Errors::PanelUnimplementedError.from(self.class.name, 'payload(data)')
87
87
  end
88
88
 
89
89
  def payload_header(data)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- module Panel
5
+ module Panels
6
6
  # Panel for accessing the Educational completions business object
7
7
  #
8
8
  class Education < BasePanel
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- module Panel
5
+ module Panels
6
6
  # Panel for accessing the annual VSC completed counts business object
7
7
  #
8
8
  class Vsc < BasePanel
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'panels/base_panel'
4
+ require_relative 'panels/vsc'
5
+ require_relative 'panels/education'
6
+
7
+ module Usps
8
+ module Imis
9
+ # Namespace for all Panels
10
+ #
11
+ module Panels
12
+ # Convenience accessor for available Panel objects
13
+ #
14
+ # @param api [Api] Parent to use for making requests
15
+ #
16
+ def self.all(api = Api.new)
17
+ panels = constants.reject { it == :BasePanel }
18
+
19
+ Struct
20
+ .new(*panels.map { it.to_s.underscore.to_sym })
21
+ .new(*panels.map { const_get(it).new(api) })
22
+ end
23
+ end
24
+ end
25
+ end
@@ -42,7 +42,7 @@ module Usps
42
42
  when Integer then { '$type' => 'System.Int32', '$value' => value }
43
43
  when true, false then { '$type' => 'System.Boolean', '$value' => value }
44
44
  else
45
- raise Error::ApiError, "Unexpected property type: #{value.inspect}"
45
+ raise Errors::UnexpectedPropertyTypeError.from(value)
46
46
  end
47
47
  end
48
48
  end
@@ -25,7 +25,7 @@ module Usps
25
25
 
26
26
  def submit(uri, request)
27
27
  client(uri).request(request).tap do |result|
28
- raise Error::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
28
+ raise Errors::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
29
29
  end
30
30
  end
31
31
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- VERSION = '0.6.15'
5
+ VERSION = '0.7.0'
6
6
  end
7
7
  end
data/lib/usps/imis.rb CHANGED
@@ -6,27 +6,17 @@ require 'json'
6
6
  require 'time'
7
7
  require 'cgi'
8
8
 
9
+ require 'active_support/core_ext/string/inflections'
10
+ require 'active_support/core_ext/object/to_query'
9
11
  require 'active_support/string_inquirer'
10
12
 
11
- # Extensions
12
- # :nocov:
13
- require 'ext/hash' unless defined?(Rails)
14
- # :nocov:
15
-
16
13
  # Internal requires
17
14
  require_relative 'imis/config'
18
- require_relative 'imis/error/api_error'
19
- require_relative 'imis/error/mapper_error'
20
- require_relative 'imis/error/response_error'
21
- require_relative 'imis/requests'
22
- require_relative 'imis/business_object'
15
+ require_relative 'imis/error'
23
16
  require_relative 'imis/api'
24
- require_relative 'imis/mapper'
25
17
  require_relative 'imis/properties'
26
- require_relative 'imis/business_object_mock'
27
- require_relative 'imis/panel/base_panel'
28
- require_relative 'imis/panel/vsc'
29
- require_relative 'imis/panel/education'
18
+ require_relative 'imis/panels'
19
+ require_relative 'imis/mocks'
30
20
 
31
21
  module Usps
32
22
  # API wrapper for interacting with iMIS
@@ -31,7 +31,7 @@ describe Usps::Imis::Api do
31
31
 
32
32
  it 'wraps errors' do
33
33
  expect { api.imis_id_for('E231625') }.to raise_error(
34
- Usps::Imis::Error::ApiError, 'Member not found'
34
+ Usps::Imis::Errors::NotFoundError, 'Member not found'
35
35
  )
36
36
  end
37
37
  end
@@ -56,7 +56,7 @@ describe Usps::Imis::Api do
56
56
  before { api.imis_id = 31092 }
57
57
 
58
58
  it 'sends an update' do
59
- expect(api.business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15)).to(
59
+ expect(api.on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15)).to(
60
60
  be_a(Hash)
61
61
  )
62
62
  end
@@ -64,7 +64,7 @@ describe Usps::Imis::Api do
64
64
  context 'when receiving a response error' do
65
65
  let(:warning_text) do
66
66
  <<~WARNING.chomp
67
- Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
67
+ Usps::Imis::Errors::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
68
68
  Something went wrong
69
69
  WARNING
70
70
  end
@@ -78,8 +78,8 @@ describe Usps::Imis::Api do
78
78
  end
79
79
 
80
80
  it 'wraps the error' do
81
- expect { api.business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }.to(
82
- raise_error(Usps::Imis::Error::ApiError, warning_text)
81
+ expect { api.on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }.to(
82
+ raise_error(Usps::Imis::Errors::ResponseError, warning_text)
83
83
  )
84
84
  end
85
85
  end
@@ -88,7 +88,7 @@ describe Usps::Imis::Api do
88
88
  describe '#with' do
89
89
  it 'sends an update from put' do
90
90
  expect(
91
- api.with(31092) { business_object('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }
91
+ api.with(31092) { on('ABC_ASC_Individual_Demog').put_fields('TotMMS' => 15) }
92
92
  ).to be_a(Hash)
93
93
  end
94
94
 
@@ -103,13 +103,13 @@ describe Usps::Imis::Api do
103
103
  it 'blocks calling imis_id=' do
104
104
  expect do
105
105
  api.with(31092) { self.imis_id = 31092 }
106
- end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
106
+ end.to raise_error(Usps::Imis::Errors::LockedIdError, 'Cannot change iMIS ID while locked')
107
107
  end
108
108
 
109
109
  it 'blocks calling imis_id_for' do
110
110
  expect do
111
111
  api.with(31092) { imis_id_for('E231625') }
112
- end.to raise_error(Usps::Imis::Error::ApiError, 'Cannot change iMIS ID while locked')
112
+ end.to raise_error(Usps::Imis::Errors::LockedIdError, 'Cannot change iMIS ID while locked')
113
113
  end
114
114
  end
115
115
 
@@ -51,7 +51,7 @@ describe Usps::Imis::Config do
51
51
 
52
52
  it 'raises an error' do
53
53
  expect { config.hostname }.to raise_error(
54
- Usps::Imis::Error::ApiError, 'Unexpected API environment: nothing'
54
+ Usps::Imis::Errors::ConfigError, 'Unexpected API environment: nothing'
55
55
  )
56
56
  end
57
57
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Usps::Imis::Error::ApiError do
5
+ describe Usps::Imis::Error do
6
6
  it 'builds Bugsnag metadata' do
7
7
  error = described_class.new('Example', something: :else)
8
8
 
@@ -4,7 +4,7 @@ require 'spec_helper'
4
4
 
5
5
  ApiResponseStub = Struct.new(:code, :body)
6
6
 
7
- describe Usps::Imis::Error::ResponseError do
7
+ describe Usps::Imis::Errors::ResponseError do
8
8
  let(:error) { described_class.from(response) }
9
9
 
10
10
  describe 'error codes' do
@@ -61,7 +61,7 @@ describe Usps::Imis::Error::ResponseError do
61
61
  let(:response) { ApiResponseStub.new('500', 'Body of the API response error') }
62
62
  let(:warning_text) do
63
63
  <<~WARNING.chomp
64
- Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
64
+ Usps::Imis::Errors::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
65
65
  Body of the API response error
66
66
  WARNING
67
67
  end
@@ -78,7 +78,7 @@ describe Usps::Imis::Error::ResponseError do
78
78
  let(:response) { ApiResponseStub.new('500', response_body) }
79
79
  let(:warning_text) do
80
80
  <<~WARNING.chomp
81
- Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
81
+ Usps::Imis::Errors::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
82
82
  description
83
83
  WARNING
84
84
  end
@@ -95,7 +95,7 @@ describe Usps::Imis::Error::ResponseError do
95
95
  let(:response) { ApiResponseStub.new('500', response_body) }
96
96
  let(:warning_text) do
97
97
  <<~WARNING.chomp
98
- Usps::Imis::Error::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
98
+ Usps::Imis::Errors::ResponseError: [INTERNAL_SERVER_ERROR] The iMIS API returned an error.
99
99
  #{response_body}
100
100
  WARNING
101
101
  end
@@ -22,8 +22,8 @@ describe Usps::Imis::Mapper do
22
22
 
23
23
  it 'raises for unmapped updates' do
24
24
  expect { api.mapper.update(something: 'anything') }.to raise_error(
25
- Usps::Imis::Error::MapperError,
26
- 'Unrecognized field: "something". ' \
25
+ Usps::Imis::Errors::MapperError,
26
+ %(Mapper does not recognize field: "something".\n) \
27
27
  'Please report what data you are attempting to work with to ITCom leadership.'
28
28
  )
29
29
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Usps::Imis::BusinessObjectMock do
5
+ describe Usps::Imis::Mocks::BusinessObject do
6
6
  let(:mock) { described_class.new(**fields) }
7
7
  let(:fields) { { TotMMS: 2 } }
8
8
 
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ module Usps
6
+ module Imis
7
+ module Panels
8
+ class InvalidPanel < BasePanel; end
9
+
10
+ class InvalidPanelWithBusinessObject < BasePanel
11
+ private
12
+
13
+ def business_object = 'Something'
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ describe Usps::Imis::Panels::BasePanel do
20
+ it 'requires #business_object to be defined' do
21
+ expect { Usps::Imis::Panels::InvalidPanel.new.get(1) }.to raise_error(
22
+ Usps::Imis::Errors::PanelUnimplementedError,
23
+ 'Usps::Imis::Panels::InvalidPanel must implement #business_object'
24
+ )
25
+ end
26
+
27
+ it 'requires #payload(data) to be defined' do
28
+ expect { Usps::Imis::Panels::InvalidPanelWithBusinessObject.new.create({}) }.to raise_error(
29
+ Usps::Imis::Errors::PanelUnimplementedError,
30
+ 'Usps::Imis::Panels::InvalidPanelWithBusinessObject must implement #payload(data)'
31
+ )
32
+ end
33
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Usps::Imis::Panel::Education do
5
+ describe Usps::Imis::Panels::Education do
6
6
  describe 'api example' do
7
7
  let(:education) { described_class.new }
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Usps::Imis::Panel::Vsc do
5
+ describe Usps::Imis::Panels::Vsc do
6
6
  let(:vsc) { described_class.new }
7
7
 
8
8
  let(:details) do
@@ -13,7 +13,7 @@ describe Usps::Imis::Properties do
13
13
 
14
14
  it 'raises an error for unexpected property types' do
15
15
  expect { builder.send(:wrap, {}) }.to raise_error(
16
- Usps::Imis::Error::ApiError, 'Unexpected property type: {}'
16
+ Usps::Imis::Errors::UnexpectedPropertyTypeError, 'Unexpected property type: {}'
17
17
  )
18
18
  end
19
19
  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.6.15
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Fiander
@@ -41,32 +41,39 @@ files:
41
41
  - Readme.md
42
42
  - bin/console
43
43
  - bin/setup
44
- - lib/ext/hash.rb
45
44
  - lib/usps/imis.rb
46
45
  - lib/usps/imis/api.rb
47
46
  - lib/usps/imis/business_object.rb
48
- - lib/usps/imis/business_object_mock.rb
49
47
  - lib/usps/imis/config.rb
50
- - lib/usps/imis/error/api_error.rb
51
- - lib/usps/imis/error/mapper_error.rb
52
- - lib/usps/imis/error/response_error.rb
48
+ - lib/usps/imis/error.rb
49
+ - lib/usps/imis/errors/api_error.rb
50
+ - lib/usps/imis/errors/config_error.rb
51
+ - lib/usps/imis/errors/locked_id_error.rb
52
+ - lib/usps/imis/errors/mapper_error.rb
53
+ - lib/usps/imis/errors/not_found_error.rb
54
+ - lib/usps/imis/errors/panel_unimplemented_error.rb
55
+ - lib/usps/imis/errors/response_error.rb
56
+ - lib/usps/imis/errors/unexpected_property_type_error.rb
53
57
  - lib/usps/imis/mapper.rb
54
- - lib/usps/imis/panel/base_panel.rb
55
- - lib/usps/imis/panel/education.rb
56
- - lib/usps/imis/panel/vsc.rb
58
+ - lib/usps/imis/mocks.rb
59
+ - lib/usps/imis/mocks/business_object.rb
60
+ - lib/usps/imis/panels.rb
61
+ - lib/usps/imis/panels/base_panel.rb
62
+ - lib/usps/imis/panels/education.rb
63
+ - lib/usps/imis/panels/vsc.rb
57
64
  - lib/usps/imis/properties.rb
58
65
  - lib/usps/imis/requests.rb
59
66
  - lib/usps/imis/version.rb
60
67
  - spec/lib/usps/imis/api_spec.rb
61
- - spec/lib/usps/imis/business_object_mock_spec.rb
62
68
  - spec/lib/usps/imis/business_object_spec.rb
63
69
  - spec/lib/usps/imis/config_spec.rb
64
- - spec/lib/usps/imis/error/api_error_spec.rb
65
- - spec/lib/usps/imis/error/response_error_spec.rb
70
+ - spec/lib/usps/imis/error_spec.rb
71
+ - spec/lib/usps/imis/errors/response_error_spec.rb
66
72
  - spec/lib/usps/imis/mapper_spec.rb
67
- - spec/lib/usps/imis/panel/base_panel_spec.rb
68
- - spec/lib/usps/imis/panel/education_spec.rb
69
- - spec/lib/usps/imis/panel/vsc_spec.rb
73
+ - spec/lib/usps/imis/mocks/business_object_spec.rb
74
+ - spec/lib/usps/imis/panels/base_panel_spec.rb
75
+ - spec/lib/usps/imis/panels/education_spec.rb
76
+ - spec/lib/usps/imis/panels/vsc_spec.rb
70
77
  - spec/lib/usps/imis/properties_spec.rb
71
78
  - spec/lib/usps/imis_spec.rb
72
79
  - spec/spec_helper.rb
data/lib/ext/hash.rb DELETED
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Import a simplified version of to_query from Rails if not already defined
4
- class Hash
5
- def to_query
6
- map do |key, value|
7
- "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"
8
- end.sort * '&'
9
- end
10
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Usps
4
- module Imis
5
- # Mock data response for testing
6
- #
7
- class BusinessObjectMock
8
- attr_reader :fields
9
-
10
- def initialize(**fields)
11
- @fields = fields.transform_keys(&:to_s)
12
- end
13
-
14
- def get_field(name) = fields[name]
15
-
16
- def get
17
- Usps::Imis::Properties.build do |props|
18
- fields.each { |name, value| props.add(name, value) }
19
- end
20
- end
21
-
22
- def put_fields(data)
23
- Usps::Imis::Properties.build do |props|
24
- fields.merge(data.transform_keys(&:to_s)).each { |name, value| props.add(name, value) }
25
- end
26
- end
27
-
28
- def put(data) = data
29
-
30
- def post(data) = data
31
-
32
- def delete = ''
33
- end
34
- end
35
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Usps
4
- module Imis
5
- module Error
6
- # Base error class for all internal exceptions
7
- #
8
- class ApiError < StandardError
9
- # Additional call-specific metadata to pass through to Bugsnag
10
- #
11
- attr_accessor :metadata
12
-
13
- # A new instance of +ApiError+
14
- #
15
- # @param message [String] The base exception message
16
- # @param metadata [Hash] Additional call-specific metadata to pass through to Bugsnag
17
- #
18
- def initialize(message, metadata = {})
19
- super(message)
20
- @metadata = metadata
21
- end
22
-
23
- # Additional metadata to include in Bugsnag reports
24
- #
25
- # Can include fields at the top level, which will be shows on the custom tab
26
- #
27
- # Can include fields nested under a top-level key, which will be shown on a tab with the
28
- # top-level key as its name
29
- #
30
- # @return [Hash]
31
- #
32
- def bugsnag_meta_data
33
- metadata == {} ? {} : base_metadata
34
- end
35
-
36
- private
37
-
38
- def base_metadata
39
- { api: metadata }
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Usps
4
- module Imis
5
- module Error
6
- # Exception raised by a +Mapper+
7
- #
8
- class MapperError < ApiError; end
9
- end
10
- end
11
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- module Usps
6
- module Imis
7
- module Panel
8
- class InvalidPanel < BasePanel; end
9
-
10
- class InvalidPanelWithBusinessObject < BasePanel
11
- private
12
-
13
- def business_object = 'Something'
14
- end
15
- end
16
- end
17
- end
18
-
19
- describe Usps::Imis::Panel::BasePanel do
20
- it 'requires #business_object to be defined' do
21
- expect { Usps::Imis::Panel::InvalidPanel.new.get(1) }.to raise_error(
22
- Usps::Imis::Error::ApiError, 'Usps::Imis::Panel::InvalidPanel must implement #business_object'
23
- )
24
- end
25
-
26
- it 'requires #payload(data) to be defined' do
27
- expect { Usps::Imis::Panel::InvalidPanelWithBusinessObject.new.create({}) }.to raise_error(
28
- Usps::Imis::Error::ApiError,
29
- 'Usps::Imis::Panel::InvalidPanelWithBusinessObject must implement #payload(data)'
30
- )
31
- end
32
- end