eligible 2.4.3 → 2.5.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.
data/eligible.gemspec CHANGED
@@ -4,24 +4,23 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'eligible/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "eligible"
7
+ gem.name = 'eligible'
8
8
  gem.version = Eligible::VERSION
9
- gem.authors = ["Katelyn Gleaon", "Rodrigo Dominguez", "Andry Brett"]
10
- gem.email = ["k@eligibleapi.com", "rod@eligibleapi.com", "andy@andybrett.com"]
11
- gem.description = 'Eligible is a developer-friendly way to process health care eligibility checks. Learn more at https://www.eligibleapi.com'
9
+ gem.authors = ['Katelyn Gleaon', 'Rodrigo Dominguez', 'Aaron Bedra']
10
+ gem.email = ['k@eligible.com', 'rod@eligible.com', 'abedra@eligible.com']
11
+ gem.description = 'Eligible is a developer-friendly way to process health care eligibility checks. Learn more at https://eligible.com'
12
12
  gem.summary = 'Ruby wrapper for the Eligible API'
13
- gem.homepage = "https://www.eligibleapi.com/"
14
- gem.license = "MIT"
13
+ gem.homepage = 'https://github.com/eligible/eligible-ruby'
14
+ gem.license = 'MIT'
15
15
 
16
- gem.files = `git ls-files`.split($/)
17
- gem.test_files = `git ls-files -- test/*`.split("\n")
18
- gem.require_paths = ["lib"]
16
+ gem.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ gem.require_paths = ['lib']
19
18
 
20
- gem.add_development_dependency('mocha')
21
- gem.add_development_dependency('shoulda')
22
- gem.add_development_dependency('test-unit')
23
- gem.add_development_dependency('rake')
19
+ gem.add_dependency('rest-client', '~> 1.8')
20
+ gem.add_dependency('multi_json', '~> 1.7')
24
21
 
25
- gem.add_dependency('rest-client', '~> 1.6.7')
26
- gem.add_dependency('multi_json', '~> 1.7.9')
22
+ gem.add_development_dependency('rake', '~> 10.5')
23
+ gem.add_development_dependency('rspec', '~> 3.4')
24
+ gem.add_development_dependency('rubocop', '= 0.35.0')
25
+ gem.add_development_dependency('simplecov', '~> 0.11')
27
26
  end
data/lib/eligible.rb CHANGED
@@ -28,13 +28,15 @@ require 'eligible/errors/authentication_error'
28
28
  require 'eligible/errors/api_error'
29
29
  require 'eligible/errors/invalid_request_error'
30
30
 
31
+ # rubocop:disable Metrics/ModuleLength, Style/ClassVars
31
32
  module Eligible
32
33
  @@api_key = nil
33
34
  @@test = false
34
- @@api_base = 'https://gds.eligibleapi.com/v1.1'
35
35
  @@api_version = 1.1
36
+ @@api_base = "https://gds.eligibleapi.com/v#{@@api_version}"
37
+ @@fingerprints = %w(79d62e8a9d59ae687372f8e71345c76d92527fac 4b2c6888ede79d0ee47339dc6fab5a6d0dc3cb0e)
36
38
 
37
- def self.api_url(url='')
39
+ def self.api_url(url = '')
38
40
  @@api_base + url.to_s
39
41
  end
40
42
 
@@ -70,87 +72,98 @@ module Eligible
70
72
  @@api_version
71
73
  end
72
74
 
73
- def self.request(method, url, api_key, params={}, headers={})
75
+ def self.fingerprints
76
+ @@fingerprints
77
+ end
78
+
79
+ def self.add_fingerprint(digest)
80
+ $stderr.puts 'The embedded certificate fingerprint was modified. This should only be done if instructed to by eligible support staff'
81
+ @@fingerprints << digest
82
+ end
83
+
84
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
85
+ def self.request(method, url, api_key, params = {}, headers = {})
74
86
  api_key ||= @@api_key
75
87
  test = self.test
76
- api_key = params[:api_key] if params.has_key?(:api_key)
77
- test = params[:test] if params.has_key?(:test)
88
+ api_key = params[:api_key] if params.key?(:api_key)
89
+ test = params[:test] if params.key?(:test)
78
90
 
79
- raise AuthenticationError.new('No API key provided. (HINT: set your API key using "Eligible.api_key = <API-KEY>".') unless api_key
91
+ fail AuthenticationError, 'No API key provided. (HINT: set your API key using "Eligible.api_key = <API-KEY>".' unless api_key
80
92
 
81
93
  lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
82
- ua = {
83
- :bindings_version => Eligible::VERSION,
84
- :lang => 'ruby',
85
- :lang_version => lang_version,
86
- :platform => RUBY_PLATFORM,
87
- :publisher => 'eligible',
88
- :uname => uname
94
+ debug_info = {
95
+ bindings_version: Eligible::VERSION,
96
+ lang: 'ruby',
97
+ lang_version: lang_version,
98
+ platform: RUBY_PLATFORM,
99
+ publisher: 'eligible',
100
+ uname: uname
89
101
  }
90
102
 
91
103
  # GET requests, parameters on the query string
92
104
  # POST requests, parameters as json in the body
93
- url = self.api_url(url)
105
+ url = api_url(url)
94
106
  case method.to_s.downcase.to_sym
95
- when :get, :head
96
- url += "?api_key=#{api_key}"
97
- if params && params.count > 0
98
- query_string = Util.flatten_params(params).collect { |key, value| "#{key}=#{Util.url_encode(value)}" }.join('&')
99
- url += "&#{query_string}"
100
- end
101
- url +="&test=#{test}"
102
- payload = nil
103
- else
104
- payload = Eligible::JSON.dump(params.merge!({ 'api_key' => api_key, 'test' => test }))
107
+ when :get, :head
108
+ url += "?api_key=#{api_key}"
109
+ if params && params.count > 0
110
+ query_string = Util.flatten_params(params).collect { |key, value| "#{key}=#{Util.url_encode(value)}" }.join('&')
111
+ url += "&#{query_string}"
112
+ end
113
+ url += "&test=#{test}"
114
+ payload = nil
115
+ else
116
+ payload = Eligible::JSON.dump(params.merge!('api_key' => api_key, 'test' => test))
105
117
  end
106
118
 
107
119
  begin
108
- headers = { :x_eligible_client_user_agent => Eligible::JSON.dump(ua) }.merge(headers)
120
+ headers = { x_eligible_debuginfo: Eligible::JSON.dump(debug_info) }.merge(headers)
109
121
  rescue => e
110
122
  headers = {
111
- :x_eligible_client_raw_user_agent => ua.inspect,
112
- :error => "#{e} (#{e.class})"
123
+ x_eligible_client_raw_user_agent: debug_info.inspect,
124
+ error: "#{e} (#{e.class})"
113
125
  }.merge(headers)
114
126
  end
115
127
 
116
128
  headers = {
117
- :user_agent => "Eligible/v1 RubyBindings/#{Eligible::VERSION}",
118
- :authorization => "Bearer #{api_key}",
119
- :content_type => 'application/x-www-form-urlencoded'
129
+ user_agent: "eligible-ruby/#{Eligible::VERSION}",
130
+ authorization: "Bearer #{api_key}",
131
+ content_type: 'application/x-www-form-urlencoded'
120
132
  }.merge(headers)
121
133
 
122
- headers[:eligible_version] = self.api_version if self.api_version
134
+ headers[:eligible_version] = api_version if api_version
123
135
 
124
136
  opts = {
125
- :method => method,
126
- :url => url,
127
- :headers => headers,
128
- :open_timeout => 30,
129
- :payload => payload,
130
- :timeout => 80
137
+ method: method,
138
+ url: url,
139
+ headers: headers,
140
+ open_timeout: 30,
141
+ payload: payload,
142
+ timeout: 80,
143
+ ssl_verify_callback: verify_certificate
131
144
  }
132
145
 
133
146
  begin
134
147
  response = execute_request(opts)
135
-
136
148
  rescue SocketError => e
137
- self.handle_restclient_error(e)
149
+ handle_restclient_error(e)
138
150
  rescue NoMethodError => e
139
151
  # Work around RestClient bug
140
152
  if e.message =~ /\WRequestFailed\W/
141
153
  e = APIConnectionError.new('Unexpected HTTP response code')
142
- self.handle_restclient_error(e)
154
+ handle_restclient_error(e)
143
155
  else
144
156
  raise
145
157
  end
158
+ # rubocop:disable Lint/AssignmentInCondition, Style/AndOr
146
159
  rescue RestClient::ExceptionWithResponse => e
147
160
  if rcode = e.http_code and rbody = e.http_body
148
- self.handle_api_error(rcode, rbody)
161
+ handle_api_error(rcode, rbody)
149
162
  else
150
- self.handle_restclient_error(e)
163
+ handle_restclient_error(e)
151
164
  end
152
165
  rescue RestClient::Exception, Errno::ECONNREFUSED => e
153
- self.handle_restclient_error(e)
166
+ handle_restclient_error(e)
154
167
  end
155
168
 
156
169
  rbody = response.body
@@ -171,6 +184,20 @@ module Eligible
171
184
  [resp, api_key]
172
185
  end
173
186
 
187
+ def self.verify_certificate
188
+ lambda do |preverify_ok, certificate_store|
189
+ return true if test == 'true'
190
+ return false unless preverify_ok
191
+ received = certificate_store.chain.first
192
+ return true unless received.to_der == certificate_store.current_cert.to_der
193
+ valid_fingerprint?(received)
194
+ end
195
+ end
196
+
197
+ def self.valid_fingerprint?(received)
198
+ fingerprints.include?(OpenSSL::Digest::SHA1.hexdigest(received.to_der))
199
+ end
200
+
174
201
  private
175
202
 
176
203
  def self.uname
@@ -181,51 +208,52 @@ module Eligible
181
208
  RestClient::Request.execute(opts)
182
209
  end
183
210
 
211
+ # rubocop:disable Style/SignalException
184
212
  def self.handle_api_error(rcode, rbody)
185
213
  begin
186
214
  error_obj = Eligible::JSON.load(rbody)
187
215
  error_obj = Util.symbolize_names(error_obj)
188
- error = error_obj[:error] or raise EligibleError.new # escape from parsing
216
+ fail EligibleError unless error_obj.key?(:error)
217
+ error = error_obj[:error]
189
218
  rescue MultiJson::DecodeError, EligibleError
190
219
  raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
191
220
  end
192
221
 
222
+ error_msg = error[:details] || error[:reject_reason_description]
223
+
193
224
  case rcode
194
- when 400, 404 then
195
- raise invalid_request_error(error, rcode, rbody, error_obj)
196
- when 401
197
- raise authentication_error(error, rcode, rbody, error_obj)
198
- else
199
- raise api_error(error, rcode, rbody, error_obj)
225
+ when 400, 404 then
226
+ raise invalid_request_error(error_msg, rcode, rbody, error_obj)
227
+ when 401
228
+ raise authentication_error(error_msg, rcode, rbody, error_obj)
229
+ else
230
+ raise api_error(error_msg, rcode, rbody, error_obj)
200
231
  end
201
232
  end
202
233
 
203
- def self.invalid_request_error(error, rcode, rbody, error_obj)
204
- InvalidRequestError.new(error, rcode, rbody, error_obj)
234
+ def self.invalid_request_error(error_msg, rcode, rbody, error_obj)
235
+ InvalidRequestError.new(error_msg, rcode, rbody, error_obj)
205
236
  end
206
237
 
207
- def self.authentication_error(error, rcode, rbody, error_obj)
208
- AuthenticationError.new(error[0][:message], rcode, rbody, error_obj)
238
+ def self.authentication_error(error_msg, rcode, rbody, error_obj)
239
+ AuthenticationError.new(error_msg, rcode, rbody, error_obj)
209
240
  end
210
241
 
211
- def self.api_error(error, rcode, rbody, error_obj)
212
- APIError.new(error[0][:message], rcode, rbody, error_obj)
242
+ def self.api_error(error_msg, rcode, rbody, error_obj)
243
+ APIError.new(error_msg, rcode, rbody, error_obj)
213
244
  end
214
245
 
215
246
  def self.handle_restclient_error(e)
216
247
  case e
217
- when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
218
- message = "Could not connect to Eligible (#{@@api_base}). Please check your internet connection and try again."
219
- when RestClient::SSLCertificateNotVerified
220
- message = "Could not verify Eligible's SSL certificate."
221
- when SocketError
222
- message = 'Unexpected error communicating when trying to connect to Eligible.'
223
- else
224
- message = 'Unexpected error communicating with Eligible. If this problem persists, let us know at support@eligible.com.'
248
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
249
+ message = "Could not connect to Eligible (#{@@api_base}). Please check your internet connection and try again."
250
+ when RestClient::SSLCertificateNotVerified
251
+ message = "Could not verify Eligible's SSL certificate."
252
+ when SocketError
253
+ message = 'Unexpected error communicating when trying to connect to Eligible.'
254
+ else
255
+ message = 'Unexpected error communicating with Eligible. If this problem persists, let us know at support@eligible.com.'
225
256
  end
226
- message += "\n\n(Network error: #{e.message})"
227
- raise APIConnectionError.new(message)
257
+ fail APIConnectionError, "#{message}\n\n(Network error: #{e.message})"
228
258
  end
229
-
230
259
  end
231
-
@@ -1,16 +1,14 @@
1
1
  module Eligible
2
2
  class APIResource < EligibleObject
3
-
4
3
  def self.class_name
5
- self.name.split('::')[-1]
4
+ name.split('::').last
6
5
  end
7
6
 
8
- def self.url()
7
+ def self.url
9
8
  if self == APIResource
10
- raise NotImplementedError.new('APIResource is an abstract class. You should perform actions on its subclasses (Plan, Service, etc.)')
9
+ fail NotImplementedError, 'APIResource is an abstract class. You should perform actions on its subclasses (Plan, Service, etc.)'
11
10
  end
12
11
  "/#{CGI.escape(class_name.downcase)}/"
13
12
  end
14
-
15
13
  end
16
- end
14
+ end
@@ -1,28 +1,22 @@
1
1
  module Eligible
2
2
  class Claim < APIResource
3
+ def self.get(params, api_key = nil)
4
+ response, api_key = Eligible.request(:get, "/claims/acknowledgements/#{params[:reference_id]}.json", api_key, params)
5
+ Util.convert_to_eligible_object(response, api_key)
6
+ end
3
7
 
4
- class << self
5
-
6
- def get(params, api_key = nil)
7
- response, api_key = Eligible.request(:get, "/claims/acknowledgements/#{params[:reference_id]}.json", api_key, params)
8
- Util.convert_to_eligible_object(response, api_key)
9
- end
10
-
11
- def post(params, api_key = nil)
12
- response, api_key = Eligible.request(:post, '/claims.json', api_key, params)
13
- Util.convert_to_eligible_object(response, api_key)
14
- end
15
-
16
- def all(api_key = nil)
17
- response, api_key = Eligible.request(:get, '/claims/acknowledgements.json', api_key)
18
- Util.convert_to_eligible_object(response, api_key)
19
- end
8
+ def self.post(params, api_key = nil)
9
+ response, api_key = Eligible.request(:post, '/claims.json', api_key, params)
10
+ Util.convert_to_eligible_object(response, api_key)
11
+ end
20
12
 
13
+ def self.all(api_key = nil)
14
+ response, api_key = Eligible.request(:get, '/claims/acknowledgements.json', api_key)
15
+ Util.convert_to_eligible_object(response, api_key)
21
16
  end
22
17
 
23
18
  def status
24
19
  error ? nil : to_hash
25
20
  end
26
-
27
21
  end
28
- end
22
+ end
@@ -1,24 +1,23 @@
1
1
  module Eligible
2
2
  class Coverage < APIResource
3
+ def self.get(params, api_key = nil)
4
+ response, api_key = Eligible.request(:get, '/coverage/all.json', api_key, params)
5
+ Util.convert_to_eligible_object(response, api_key)
6
+ end
3
7
 
4
- class << self
5
-
6
- def get(params, api_key=nil)
7
- response, api_key = Eligible.request(:get, '/coverage/all.json', api_key, params)
8
- Util.convert_to_eligible_object(response, api_key)
9
- end
10
-
11
- def batch_post(params, api_key=nil)
12
- response, api_key = Eligible.request(:post, '/coverage/all/batch.json', api_key, params)
13
- Util.convert_to_eligible_object(response, api_key)
14
- end
15
-
16
- def batch_medicare_post(params, api_key=nil)
17
- response, api_key = Eligible.request(:post, '/medicare/coverage/batch.json', api_key, params)
18
- Util.convert_to_eligible_object(response, api_key)
19
- end
8
+ def self.cost_estimate(params, api_key = nil)
9
+ response, api_key = Eligible.request(:get, '/coverage/cost_estimate.json', api_key, params)
10
+ Util.convert_to_eligible_object(response, api_key)
11
+ end
20
12
 
13
+ def self.batch_post(params, api_key = nil)
14
+ response, api_key = Eligible.request(:post, '/coverage/all/batch.json', api_key, params)
15
+ Util.convert_to_eligible_object(response, api_key)
21
16
  end
22
17
 
18
+ def self.batch_medicare_post(params, api_key = nil)
19
+ response, api_key = Eligible.request(:post, '/medicare/coverage/batch.json', api_key, params)
20
+ Util.convert_to_eligible_object(response, api_key)
21
+ end
23
22
  end
24
- end
23
+ end
@@ -1,16 +1,13 @@
1
1
  module Eligible
2
2
  class Demographic < APIResource
3
- class << self
4
-
5
- def get(params, api_key=nil)
6
- response, api_key = Eligible.request(:get, '/demographic/all.json', api_key, params)
7
- Util.convert_to_eligible_object(response, api_key)
8
- end
3
+ def self.get(params, api_key = nil)
4
+ response, api_key = Eligible.request(:get, '/demographic/all.json', api_key, params)
5
+ Util.convert_to_eligible_object(response, api_key)
6
+ end
9
7
 
10
- def batch_post(params, api_key=nil)
11
- response, api_key = Eligible.request(:post, '/demographic/all/batch.json', api_key, params)
12
- Util.convert_to_eligible_object(response, api_key)
13
- end
8
+ def self.batch_post(params, api_key = nil)
9
+ response, api_key = Eligible.request(:post, '/demographic/all/batch.json', api_key, params)
10
+ Util.convert_to_eligible_object(response, api_key)
14
11
  end
15
12
  end
16
13
  end
@@ -1,18 +1,16 @@
1
1
  module Eligible
2
-
3
2
  class EligibleObject
4
3
  include Enumerable
5
4
 
6
5
  attr_accessor :api_key
7
6
  attr_accessor :eligible_id
7
+ # rubocop:disable Style/ClassVars
8
8
  @@permanent_attributes = Set.new([:api_key, :error, :balance, :address, :dob])
9
9
 
10
10
  # The default :id method is deprecated and isn't useful to us
11
- if method_defined?(:id)
12
- undef :id
13
- end
11
+ undef :id if method_defined?(:id)
14
12
 
15
- def initialize(id=nil, api_key=nil)
13
+ def initialize(id = nil, api_key = nil)
16
14
  @api_key = api_key
17
15
  @values = {}
18
16
  # This really belongs in APIResource, but not putting it there allows us
@@ -22,13 +20,14 @@ module Eligible
22
20
  self.eligible_id = id if id
23
21
  end
24
22
 
25
- def self.construct_from(values, api_key=nil)
26
- obj = self.new(values[:eligible_id], api_key)
23
+ def self.construct_from(values, api_key = nil)
24
+ obj = new(values[:eligible_id], api_key)
27
25
  obj.refresh_from(values, api_key)
28
26
  obj
29
27
  end
30
28
 
31
- def refresh_from(values, api_key, partial=false)
29
+ # rubocop:disable Metrics/AbcSize
30
+ def refresh_from(values, api_key, partial = false)
32
31
  @api_key = api_key
33
32
 
34
33
  removed = partial ? Set.new : Set.new(@values.keys - values.keys)
@@ -54,7 +53,7 @@ module Eligible
54
53
  end
55
54
 
56
55
  def [](k)
57
- k = k.to_sym if k.kind_of?(String)
56
+ k = k.to_sym if k.is_a?(String)
58
57
  @values[k]
59
58
  end
60
59
 
@@ -70,7 +69,7 @@ module Eligible
70
69
  @values.values
71
70
  end
72
71
 
73
- def to_json(*a)
72
+ def to_json
74
73
  Eligible::JSON.dump(@values)
75
74
  end
76
75
 
@@ -90,7 +89,7 @@ module Eligible
90
89
 
91
90
  def metaclass
92
91
  class << self; self; end
93
- end
92
+ end
94
93
 
95
94
  def remove_accessors(keys)
96
95
  metaclass.instance_eval do
@@ -115,7 +114,6 @@ module Eligible
115
114
  end
116
115
  end
117
116
  end
118
- end
117
+ end
119
118
  end
120
-
121
- end
119
+ end