usps-imis-api 1.0.0.pre.rc.5 → 1.0.0.pre.rc.8

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/Gemfile.lock +36 -30
  4. data/Readme.md +149 -33
  5. data/lib/usps/imis/api.rb +32 -39
  6. data/lib/usps/imis/business_object.rb +97 -47
  7. data/lib/usps/imis/config.rb +14 -3
  8. data/lib/usps/imis/data.rb +72 -0
  9. data/lib/usps/imis/error.rb +53 -0
  10. data/lib/usps/imis/errors/api_error.rb +11 -0
  11. data/lib/usps/imis/errors/config_error.rb +11 -0
  12. data/lib/usps/imis/errors/locked_id_error.rb +15 -0
  13. data/lib/usps/imis/errors/mapper_error.rb +29 -0
  14. data/lib/usps/imis/errors/not_found_error.rb +11 -0
  15. data/lib/usps/imis/errors/panel_unimplemented_error.rb +34 -0
  16. data/lib/usps/imis/{error → errors}/response_error.rb +5 -8
  17. data/lib/usps/imis/errors/unexpected_property_type_error.rb +31 -0
  18. data/lib/usps/imis/mapper.rb +51 -20
  19. data/lib/usps/imis/mocks/business_object.rb +47 -0
  20. data/lib/usps/imis/mocks.rb +11 -0
  21. data/lib/usps/imis/panels/base_panel.rb +154 -0
  22. data/lib/usps/imis/{panel → panels}/education.rb +2 -2
  23. data/lib/usps/imis/{panel → panels}/vsc.rb +2 -2
  24. data/lib/usps/imis/panels.rb +25 -0
  25. data/lib/usps/imis/properties.rb +50 -0
  26. data/lib/usps/imis/query.rb +94 -0
  27. data/lib/usps/imis/requests.rb +27 -3
  28. data/lib/usps/imis/version.rb +1 -1
  29. data/lib/usps/imis.rb +20 -15
  30. data/spec/lib/usps/imis/api_spec.rb +26 -13
  31. data/spec/lib/usps/imis/business_object_spec.rb +70 -33
  32. data/spec/lib/usps/imis/config_spec.rb +2 -2
  33. data/spec/lib/usps/imis/data_spec.rb +66 -0
  34. data/spec/lib/usps/imis/{error/api_error_spec.rb → error_spec.rb} +1 -1
  35. data/spec/lib/usps/imis/{error → errors}/response_error_spec.rb +4 -4
  36. data/spec/lib/usps/imis/mapper_spec.rb +27 -3
  37. data/spec/lib/usps/imis/mocks/business_object_spec.rb +65 -0
  38. data/spec/lib/usps/imis/panels/base_panel_spec.rb +33 -0
  39. data/spec/lib/usps/imis/panels/education_spec.rb +70 -0
  40. data/spec/lib/usps/imis/{panel → panels}/vsc_spec.rb +6 -7
  41. data/spec/lib/usps/imis/properties_spec.rb +19 -0
  42. data/spec/spec_helper.rb +2 -0
  43. data/usps-imis-api.gemspec +1 -1
  44. metadata +28 -16
  45. data/lib/ext/hash.rb +0 -10
  46. data/lib/usps/imis/error/api_error.rb +0 -44
  47. data/lib/usps/imis/error/mapper_error.rb +0 -11
  48. data/lib/usps/imis/panel/base_panel.rb +0 -101
  49. data/lib/usps/imis/panel/panel_properties.rb +0 -52
  50. data/spec/lib/usps/imis/panel/base_panel_spec.rb +0 -32
  51. data/spec/lib/usps/imis/panel/education_spec.rb +0 -55
  52. data/spec/lib/usps/imis/panel/panel_properties_spec.rb +0 -19
@@ -28,6 +28,37 @@ module Usps
28
28
  @api.imis_id = imis_id if imis_id
29
29
  end
30
30
 
31
+ # Get a member's data for a specific field by arbitrary field name
32
+ #
33
+ # Does not require knowing which business object / iMIS-specific field name to use
34
+ #
35
+ # Only available for fields defined in +FIELD_MAPPING+
36
+ #
37
+ # @param field_key [Symbol] Internal name of the field
38
+ #
39
+ # @return Value of the field
40
+ #
41
+ def fetch(field_key)
42
+ missing_mapping!(field_key) unless FIELD_MAPPING.key?(field_key.to_sym)
43
+
44
+ business_object_name, field = FIELD_MAPPING[field_key]
45
+ api.on(business_object_name)[field]
46
+ end
47
+ alias [] fetch
48
+
49
+ # Update a member's data for a specific field by arbitrary field name
50
+ #
51
+ # Does not require knowing which business object / iMIS-specific field name to use
52
+ #
53
+ # Only available for fields defined in +FIELD_MAPPING+
54
+ #
55
+ # @param field_key [Symbol] Internal name of the field
56
+ #
57
+ # @return Value of the field
58
+ #
59
+ def put_field(field_key, value) = update(field_key => value)
60
+ alias []= put_field
61
+
31
62
  # Update a member's data on multiple affected business objects by arbitrary field names
32
63
  #
33
64
  # Does not require knowing which business object / iMIS-specific field name to use
@@ -36,7 +67,7 @@ module Usps
36
67
  #
37
68
  # @param data [Hash] Conforms to pattern +{ field_key => value }+
38
69
  #
39
- # @return [Array<Hash>] Response data from the API for each internal update request
70
+ # @return [Array<Usps::Imis::Data>] Response data from the API for each internal update request
40
71
  #
41
72
  def update(data)
42
73
  updates = data.each_with_object({}) do |(field_key, value), hash|
@@ -47,37 +78,37 @@ module Usps
47
78
  end
48
79
 
49
80
  updates.map do |business_object_name, field_updates|
50
- api.business_object(business_object_name).put_fields(field_updates)
81
+ api.on(business_object_name).put_fields(field_updates)
51
82
  end
52
83
  end
53
84
 
85
+ # Ruby 3.5 instance variable filter
86
+ #
87
+ def instance_variables_to_inspect = instance_variables - %i[@api]
88
+
54
89
  private
55
90
 
56
- def map_update(field_name)
57
- if FIELD_MAPPING.key?(field_name.to_sym)
58
- business_object_name, field = FIELD_MAPPING[field_name.to_sym]
59
- yield(business_object_name, field)
60
- else
61
- missing_mapping(field_name)
62
- end
91
+ def logger = Imis.logger('Mapper')
92
+
93
+ def map_update(field_key)
94
+ missing_mapping!(field_key) unless FIELD_MAPPING.key?(field_key.to_sym)
95
+
96
+ business_object_name, field = FIELD_MAPPING[field_key.to_sym]
97
+ yield(business_object_name, field)
63
98
  end
64
99
 
65
- def missing_mapping(field_name)
100
+ def missing_mapping!(field_key)
66
101
  unless ENV['TESTING']
67
102
  # :nocov:
68
- warn(
69
- "Mapper does not know how to handle field \"#{field_name}\".\n\n" \
70
- 'You can use api.put_fields(business_object_name, { field_name => value }) ' \
71
- "if you know the business object and iMIS-specific field name.\n\n"
72
- )
103
+ "Mapper does not know how to handle field \"#{field_key}\".\n\n" \
104
+ 'You can use api.put_fields(business_object_name, { field_name => value }) ' \
105
+ "if you know the business object and iMIS-specific field name.\n\n"
106
+ .split("\n")
107
+ .each { logger.warn(it) }
73
108
  # :nocov:
74
109
  end
75
110
 
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
- )
111
+ raise Errors::MapperError.new({ field_key: })
81
112
  end
82
113
  end
83
114
  end
@@ -0,0 +1,47 @@
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
16
+ Usps::Imis::Properties.build do |props|
17
+ fields.each { |name, value| props.add(name, value) }
18
+ end
19
+ end
20
+ alias read get
21
+
22
+ def get_field(name) = fields[name]
23
+ alias fetch get_field
24
+ alias [] get_field
25
+
26
+ def get_fields(*field_names) = field_names.map { fields[it] }
27
+ alias fetch_all get_fields
28
+
29
+ def put_fields(data)
30
+ Usps::Imis::Properties.build do |props|
31
+ fields.merge(data.transform_keys(&:to_s)).each { |name, value| props.add(name, value) }
32
+ end
33
+ end
34
+ alias patch put_fields
35
+
36
+ def put(data) = data
37
+ alias update put
38
+
39
+ def post(data) = data
40
+ alias create post
41
+
42
+ def delete = ''
43
+ alias destroy delete
44
+ end
45
+ end
46
+ end
47
+ 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
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ module Panels
6
+ # Base class for configuring Panels
7
+ #
8
+ class BasePanel
9
+ # The parent +Api+ object
10
+ #
11
+ attr_reader :api
12
+
13
+ def initialize(api = nil, imis_id: nil)
14
+ @api = api || Api.new
15
+ @api.imis_id = imis_id if imis_id
16
+ end
17
+
18
+ # Get a specific object from the Panel
19
+ #
20
+ # If +fields+ is provided, will return only those field values
21
+ #
22
+ # @param fields [String] Field names to return
23
+ #
24
+ # @param ordinal [Integer] The ordinal identifier for the desired object
25
+ #
26
+ # @return [Usps::Imis::Data, Array<Usps::Imis::Data>] Response data from the API
27
+ #
28
+ def get(ordinal, *fields) = api.on(business_object, ordinal:).get(*fields)
29
+ alias read get
30
+
31
+ # Get a single named field from a Panel for the current member
32
+ #
33
+ # @param ordinal [Integer] The ordinal identifier for the desired object
34
+ # @param field [String] Field name to return
35
+ #
36
+ # @return Response data field value from the API
37
+ #
38
+ def get_field(ordinal, field) = api.on(business_object, ordinal:).get_field(field)
39
+ alias fetch get_field
40
+ alias [] get_field
41
+
42
+ # Get named fields from a Panel for the current member
43
+ #
44
+ # @param ordinal [Integer] The ordinal identifier for the desired object
45
+ # @param fields [Array<String>] Field names to return
46
+ #
47
+ # @return [Array] Response data from the API
48
+ #
49
+ def get_fields(ordinal, *fields) = api.on(business_object, ordinal:).get_fields(*fields)
50
+ alias fetch_all get_fields
51
+
52
+ # Update a single named field on a business object for the current member
53
+ #
54
+ # @param field [String] Name of the field
55
+ # @param value Value of the field
56
+ #
57
+ # @return [Usps::Imis::Data] Response data from the API
58
+ #
59
+ def put_field(field, value) = api.on(business_object, ordinal:).put_field(field, value)
60
+ alias []= put_field
61
+
62
+ # Update only specific fields on a Panel for the current member
63
+ #
64
+ # @param ordinal [Integer] The ordinal identifier for the desired object
65
+ # @param fields [Hash] Conforms to pattern +{ field_key => value }+
66
+ #
67
+ # @return [Usps::Imis::Data] Response data from the API
68
+ #
69
+ def put_fields(ordinal, fields) = api.on(business_object, ordinal:).put_fields(fields)
70
+ alias patch put_fields
71
+
72
+ # Update an existing object in the Panel
73
+ #
74
+ # @param data [Hash] The record data for the desired object -- including the required
75
+ # +ordinal+ identifier
76
+ #
77
+ # @return [Usps::Imis::Data] Response data from the API
78
+ #
79
+ def put(data) = api.on(business_object, ordinal: data[:ordinal]).put(payload(data))
80
+ alias update put
81
+
82
+ # Create a new object in the Panel
83
+ #
84
+ # @param data [Hash] The record data for the desired object
85
+ #
86
+ # @return [Usps::Imis::Data] Response data from the API
87
+ #
88
+ def post(data) = api.on(business_object).post(payload(data))
89
+ alias create post
90
+
91
+ # Remove a specific object from the Panel
92
+ #
93
+ # @param ordinal [Integer] The ordinal identifier for the desired object
94
+ #
95
+ # @return [true] Only on success response (i.e. blank string from the API)
96
+ #
97
+ def delete(ordinal) = api.on(business_object, ordinal:).delete
98
+ alias destroy delete
99
+
100
+ # Ruby 3.5 instance variable filter
101
+ #
102
+ def instance_variables_to_inspect = instance_variables - %i[@api]
103
+
104
+ private
105
+
106
+ def logger = Imis.logger('Panel')
107
+
108
+ def business_object
109
+ raise Errors::PanelUnimplementedError.from(self.class.name, 'business_object')
110
+ end
111
+
112
+ def payload(_data)
113
+ raise Errors::PanelUnimplementedError.from(self.class.name, 'payload(data)')
114
+ end
115
+
116
+ def payload_header(data)
117
+ {
118
+ '$type' => 'Asi.Soa.Core.DataContracts.GenericEntityData, Asi.Contracts',
119
+ 'EntityTypeName' => business_object,
120
+ 'PrimaryParentEntityTypeName' => 'Party',
121
+ 'Identity' => identity(data[:ordinal]),
122
+ 'PrimaryParentIdentity' => primary_parent_identity
123
+ }
124
+ end
125
+
126
+ def identity(ordinal = nil)
127
+ {
128
+ '$type' => 'Asi.Soa.Core.DataContracts.IdentityData, Asi.Contracts',
129
+ 'EntityTypeName' => business_object,
130
+ 'IdentityElements' => {
131
+ '$type' => identity_type,
132
+ '$values' => [api.imis_id.to_s, ordinal&.to_s].compact
133
+ }
134
+ }
135
+ end
136
+
137
+ def primary_parent_identity
138
+ {
139
+ '$type' => 'Asi.Soa.Core.DataContracts.IdentityData, Asi.Contracts',
140
+ 'EntityTypeName' => 'Party',
141
+ 'IdentityElements' => {
142
+ '$type' => identity_type,
143
+ '$values' => [api.imis_id.to_s]
144
+ }
145
+ }
146
+ end
147
+
148
+ def identity_type = 'System.Collections.ObjectModel.Collection`1[[System.String, mscorlib]], mscorlib'
149
+
150
+ def build_payload(data, &) = payload_header(data).merge(Properties.build(&))
151
+ end
152
+ end
153
+ end
154
+ end
@@ -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
@@ -14,7 +14,7 @@ module Usps
14
14
 
15
15
  def payload(data)
16
16
  build_payload(data) do |props|
17
- props.add 'ID', api.imis_id
17
+ props.add 'ID', api.imis_id.to_s
18
18
  props.add 'Ordinal', data[:ordinal] if data[:ordinal]
19
19
  props.add 'ABC_EDUC_THRU_DATE', data[:thru_date] || '0001-01-01T00:00:00'
20
20
  props.add 'ABC_ECertificate', data[:certificate]
@@ -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
@@ -14,7 +14,7 @@ module Usps
14
14
 
15
15
  def payload(data)
16
16
  build_payload(data) do |props|
17
- props.add 'ID', api.imis_id
17
+ props.add 'ID', api.imis_id.to_s
18
18
  props.add 'Ordinal', data[:ordinal] if data[:ordinal]
19
19
  props.add 'Source_System', 'Manual ITCom Entry'
20
20
  props.add 'ABC_ECertificate', data[:certificate]
@@ -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
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ # Constructor for the Properties field
6
+ #
7
+ class Properties
8
+ # Build the data for a new Properties field
9
+ #
10
+ def self.build(&) = new.build(&)
11
+
12
+ # Build the data for the Properties field
13
+ #
14
+ def build
15
+ yield(self)
16
+
17
+ {
18
+ 'Properties' => {
19
+ '$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyDataCollection, Asi.Contracts',
20
+ '$values' => @properties
21
+ }
22
+ }
23
+ end
24
+
25
+ # Add an individual property to the field
26
+ #
27
+ def add(name, value)
28
+ @properties ||= []
29
+ @properties << {
30
+ '$type' => 'Asi.Soa.Core.DataContracts.GenericPropertyData, Asi.Contracts',
31
+ 'Name' => name,
32
+ 'Value' => wrap(value)
33
+ }
34
+ end
35
+
36
+ private
37
+
38
+ def wrap(value)
39
+ case value
40
+ when String then value
41
+ when Time, DateTime then value.strftime('%Y-%m-%dT%H:%I:%S')
42
+ when Integer then { '$type' => 'System.Int32', '$value' => value }
43
+ when true, false then { '$type' => 'System.Boolean', '$value' => value }
44
+ else
45
+ raise Errors::UnexpectedPropertyTypeError.from(value)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Usps
4
+ module Imis
5
+ # API wrapper for IQA Queries
6
+ #
7
+ class Query
8
+ include Enumerable
9
+ include Requests
10
+
11
+ # Endpoint for IQA query requests
12
+ #
13
+ QUERY_PATH = 'api/Query'
14
+
15
+ # The parent +Api+ object
16
+ #
17
+ attr_reader :api
18
+
19
+ # Name of the Query to run
20
+ #
21
+ attr_reader :query_name
22
+
23
+ # Parameters for the Query
24
+ #
25
+ attr_reader :query_params
26
+
27
+ # Current offset for paging through the Query
28
+ #
29
+ attr_reader :offset
30
+
31
+ # A new instance of +Query+
32
+ #
33
+ # @param api [Api] Parent to use for making requests
34
+ # @param query_name [String] Full path of the query in IQA, e.g. +$/_ABC/Fiander/iMIS_ID+
35
+ # @query_params [Hash] Conforms to pattern +{ param_name => param_value }+
36
+ #
37
+ def initialize(api, query_name, query_params)
38
+ @api = api
39
+ @query_name = query_name
40
+ @query_params = query_params
41
+ end
42
+
43
+ # Iterate through all results from the query
44
+ #
45
+ def each(&)
46
+ logger.info 'Running IQA Query on iMIS'
47
+
48
+ items = []
49
+ find_each { items << it }
50
+ items.each(&)
51
+ end
52
+
53
+ # Iterate through all results from the query, fetching one page at a time
54
+ #
55
+ def find_each(&)
56
+ result = { 'HasNext' => true }
57
+ count = 0
58
+
59
+ while result['HasNext']
60
+ logger.info 'Fetching IQA Query page'
61
+
62
+ result = fetch
63
+
64
+ count += result['Count'] || 0
65
+ logger.info " -> #{count} / #{result['TotalCount']} #{'item'.pluralize(count)}"
66
+ logger.debug ' -> Query page data:'
67
+ JSON.pretty_generate(result).split("\n").each { logger.debug " -> #{it}" }
68
+
69
+ items = result['Items']['$values'].map { it.except('$type') }
70
+ @offset = result['NextOffset']
71
+
72
+ items.each(&)
73
+ end
74
+
75
+ nil
76
+ end
77
+
78
+ # Ruby 3.5 instance variable filter
79
+ #
80
+ def instance_variables_to_inspect = instance_variables - %i[@api]
81
+
82
+ private
83
+
84
+ def token = api.token
85
+ def token_expiration = api.token_expiration
86
+
87
+ def path = "#{QUERY_PATH}?#{query_params.merge(QueryName: query_name, Offset: offset).to_query}"
88
+ def uri = URI(File.join(Imis.configuration.hostname, path))
89
+ def fetch = JSON.parse(submit(uri, authorize(Net::HTTP::Get.new(uri))).body)
90
+
91
+ def logger = Imis.logger('Query')
92
+ end
93
+ end
94
+ end
@@ -7,6 +7,8 @@ module Usps
7
7
  module Requests
8
8
  private
9
9
 
10
+ def logger = Imis.logger
11
+
10
12
  def client(uri)
11
13
  Net::HTTP.new(uri.host, uri.port).tap do |http|
12
14
  http.use_ssl = true
@@ -19,15 +21,37 @@ module Usps
19
21
  # If the current token is missing/expired, request a new one
20
22
  #
21
23
  def authorize(request)
22
- authenticate if token_expiration < Time.now
23
- request.tap { |r| r.add_field('Authorization', "Bearer #{token}") }
24
+ if token_expiration < Time.now
25
+ logger.debug 'Token expired: re-authenticating with iMIS'
26
+ authenticate
27
+ end
28
+ request.tap { it.add_field('Authorization', "Bearer #{token}") }
24
29
  end
25
30
 
26
31
  def submit(uri, request)
32
+ logger.info 'Submitting request to iMIS'
33
+ logger.debug " -> #{request.class.name.demodulize.upcase} #{uri}"
34
+ sanitized_request_body(request).split("\n").each { logger.debug " -> #{it}" }
27
35
  client(uri).request(request).tap do |result|
28
- raise Error::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
36
+ raise Errors::ResponseError.from(result) unless result.is_a?(Net::HTTPSuccess)
37
+
38
+ logger.info 'Request succeeded'
29
39
  end
30
40
  end
41
+
42
+ def sanitized_request_body(request)
43
+ return '*** empty request body ***' if request.body.nil?
44
+
45
+ body = request.body.dup
46
+
47
+ Imis.config.filtered_parameters.each do |parameter|
48
+ body =
49
+ body.gsub(Imis.config.public_send(parameter), '[FILTERED]')
50
+ .gsub(CGI.escape(Imis.config.public_send(parameter)), '[FILTERED]')
51
+ end
52
+
53
+ body
54
+ end
31
55
  end
32
56
  end
33
57
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Usps
4
4
  module Imis
5
- VERSION = '1.0.0-rc.5'
5
+ VERSION = '1.0.0-rc.8'
6
6
  end
7
7
  end
data/lib/usps/imis.rb CHANGED
@@ -6,26 +6,22 @@ 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'
11
+ require 'active_support/core_ext/enumerable'
9
12
  require 'active_support/string_inquirer'
10
-
11
- # Extensions
12
- # :nocov:
13
- require 'ext/hash' unless defined?(Rails)
14
- # :nocov:
13
+ require 'logger'
14
+ require 'active_support/isolated_execution_state' # Fix costant loading issue with TaggedLogging
15
+ require 'active_support/tagged_logging'
15
16
 
16
17
  # Internal requires
17
18
  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'
19
+ require_relative 'imis/error'
23
20
  require_relative 'imis/api'
24
- require_relative 'imis/mapper'
25
- require_relative 'imis/panel/base_panel'
26
- require_relative 'imis/panel/panel_properties'
27
- require_relative 'imis/panel/vsc'
28
- require_relative 'imis/panel/education'
21
+ require_relative 'imis/properties'
22
+ require_relative 'imis/panels'
23
+ require_relative 'imis/mocks'
24
+ require_relative 'imis/version'
29
25
 
30
26
  module Usps
31
27
  # API wrapper for interacting with iMIS
@@ -39,6 +35,7 @@ module Usps
39
35
  def configuration
40
36
  @configuration ||= Config.new
41
37
  end
38
+ alias config configuration
42
39
 
43
40
  # Used to define a block of configuration settings
44
41
  #
@@ -48,6 +45,14 @@ module Usps
48
45
  yield(configuration) if block_given?
49
46
  configuration
50
47
  end
48
+
49
+ # Logger (with optional nested tags) to write to
50
+ #
51
+ def logger(*tags) = configuration.logger.tagged('iMIS', *tags)
52
+
53
+ # Gem version
54
+ #
55
+ def version = Gem::Version.new(VERSION)
51
56
  end
52
57
  end
53
58
  end