easypost 2.7.2 → 3.1.4

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
- SHA1:
3
- metadata.gz: 9db550826374cb288e281d0e978fde363528ce88
4
- data.tar.gz: e7d5c09d44c1c0a6d95c14ebfb82a4190fd7593a
2
+ SHA256:
3
+ metadata.gz: 3f2b1945f7283b88880be5fa9700332289d7007137056113d6223a61e59be79a
4
+ data.tar.gz: a168444a606c919ca7a5f1a940040b2822d25ee88d555ca7a11fb289a3e06962
5
5
  SHA512:
6
- metadata.gz: f40477ffd0190c181eb87b44ef6f0671ff2e83a0f63a9cf6564beb5259be875a6974e4bb3d3c9b4c00d23b4566ad700e556defedf3672be7b2e1917e303639be
7
- data.tar.gz: 7879029aa4c3085e6b324c9fec65f0fbe7ff050eff1aacf60804b0eaccee4f13c8b37645544b9e5259f13dc774984b0b95482140f637642c2fe1e082a82d65ff
6
+ metadata.gz: e53924a901d7dc9f25272991d589d7c08b1f28ccba941792925d9fd6ad8b65a57568caf5a15062e227086a2c9d997d85d72d655b21c1be08addc47093a956bff
7
+ data.tar.gz: 6bf95b960ec71c8b79effae947a38fd11a902fba63d98db28b6f7d448a05b4914f7f8a56ffc33452d8660e5898b60a0f953de10f7be0764b9b2b40058034ec4c
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
4
+ - 2.3
5
+ - 2.4
6
+ - 2.5
7
+ - 2.6
8
+ - 2.7
9
+ script: "bundle exec rspec"
data/CHANGELOG CHANGED
@@ -1,3 +1,42 @@
1
+ === 3.1.4 2020-09-29
2
+
3
+ * Don't modify params passed into Address#create (#78; thanks @TheRusskiy)
4
+ * Don't modify `carriers` and `services` parameters to `Shipment.lowest_rate` (#71 / #103, thanks @vladvinnikov and @jurisgalang)
5
+ * When constructing an easypost object, convert the key to a string (#102; thanks @Geesu)
6
+ * Expose the raw HTTP response as `#http_body` on `EasyPost::Error` objects (#101; thanks @Geesu)
7
+
8
+ === 3.1.3 2020-06-26
9
+
10
+ * Fix bug causing Authorization header to be included in User-Agent header. All users must upgrade.
11
+
12
+ === 3.1.2 2020-06-24
13
+
14
+ * Bad gem push. New version required.
15
+
16
+ === 3.1.1 2020-06-23
17
+
18
+ * Fix bug where EasyPost.http_config was invalid when not explicitly initialized.
19
+
20
+ === 3.1.0 2020-06-23
21
+
22
+ * Add Shipment Invoice and Refund Report
23
+ * Remove dependencies on `RestClient` and `MultiJson`
24
+ * Remove some deprecated endpoints
25
+
26
+ === 3.0.1 2018-05-17
27
+
28
+ * Enforce TLS certificate validity by default
29
+
30
+ === 3.0.0 2018-02-09
31
+
32
+ * Require use of ruby ~> 2.0 and TLSv1.2
33
+
34
+
35
+ === 2.7.3 2017-05-25
36
+
37
+ * Fix bug with introduced around certain JSON objects with IDs (thanks vladvinnikov!)
38
+
39
+
1
40
  === 2.7.2 2018-01-31
2
41
 
3
42
  * Removed unused and unsupported code paths for Container model
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # EasyPost Ruby Client Library
2
2
 
3
- [<img src="https://circleci.com/gh/EasyPost/easypost-ruby.png?circle-token=80adb5236ed1fdce20810b055af79c63c3d5796b">](https://circleci.com/gh/EasyPost/easypost-ruby)
3
+ [![Build Status](https://travis-ci.com/EasyPost/easypost-ruby.svg?branch=master)](https://travis-ci.com/EasyPost/easypost-ruby)
4
4
 
5
5
 
6
6
  EasyPost is a simple shipping API. You can sign up for an account at https://easypost.com
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.7.2
1
+ 3.1.4
@@ -1,26 +1,31 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'easypost/version'
5
+ require "easypost/version"
5
6
 
6
7
  Gem::Specification.new do |spec|
7
- spec.name = 'easypost'
8
- spec.version = EasyPost::VERSION
9
- spec.date = Time.now.strftime("%Y-%m-%d")
10
- spec.summary = 'EasyPost Ruby Client Library'
11
- spec.description = 'Client library for accessing the EasyPost shipping API via Ruby.'
12
- spec.authors = ['Sawyer Bateman']
13
- spec.email = 'contact@easypost.com'
14
- spec.homepage = 'https://www.easypost.com/docs'
8
+ spec.name = "easypost"
9
+ spec.version = EasyPost::VERSION
10
+ spec.licenses = ["MIT"]
11
+ spec.date = Time.now.strftime("%Y-%m-%d")
12
+ spec.summary = "EasyPost Ruby Client Library"
13
+ spec.description = "Client library for accessing the EasyPost shipping API via Ruby."
14
+ spec.authors = ["Jake Epstein", "Andrew Tribone", "James Brown"]
15
+ spec.email = "support@easypost.com"
16
+ spec.homepage = "https://www.easypost.com/docs"
15
17
 
16
- spec.files = `git ls-files -z`.split("\x0")
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ['lib']
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ["lib"]
24
+ spec.required_ruby_version = "~> 2.2"
20
25
 
21
- spec.add_dependency 'rest-client', '>= 1.4'
22
- spec.add_dependency 'multi_json', '>= 1.3.0'
23
- spec.add_development_dependency 'bundler', '~> 1.7'
24
- spec.add_development_dependency 'rake', '~> 10.0'
25
- spec.add_development_dependency 'rspec', '~> 2.13'
26
+ spec.add_development_dependency "pry", "~> 0.13"
27
+ spec.add_development_dependency "rake", "~> 13.0"
28
+ spec.add_development_dependency "rspec", "~> 3.9"
29
+ spec.add_development_dependency "webmock", "~> 3.8"
30
+ spec.add_development_dependency "vcr", "~> 5.1"
26
31
  end
@@ -1,157 +1,147 @@
1
- require 'cgi'
2
- require 'set'
3
- require 'openssl'
4
- require 'rest_client'
5
- require 'multi_json'
1
+ require "base64"
2
+ require "cgi"
3
+ require "net/http"
6
4
 
7
5
  # Resources
8
- require 'easypost/version'
9
- require 'easypost/util'
10
- require 'easypost/object'
11
- require 'easypost/resource'
12
- require 'easypost/address'
13
- require 'easypost/parcel'
14
- require 'easypost/customs_item'
15
- require 'easypost/customs_info'
16
- require 'easypost/shipment'
17
- require 'easypost/rate'
18
- require 'easypost/postage_label'
19
- require 'easypost/scan_form'
20
- require 'easypost/refund'
21
- require 'easypost/insurance'
22
- require 'easypost/event'
23
- require 'easypost/batch'
24
- require 'easypost/tracker'
25
- require 'easypost/item'
26
- require 'easypost/order'
27
- require 'easypost/pickup'
28
- require 'easypost/pickup_rate'
29
- require 'easypost/printer'
30
- require 'easypost/print_job'
31
- require 'easypost/carrier_account'
32
- require 'easypost/user'
33
- require 'easypost/report'
34
- require 'easypost/webhook'
35
-
36
- require 'easypost/error'
6
+ require "easypost/version"
7
+ require "easypost/util"
8
+ require "easypost/object"
9
+ require "easypost/resource"
10
+ require "easypost/address"
11
+ require "easypost/parcel"
12
+ require "easypost/customs_item"
13
+ require "easypost/customs_info"
14
+ require "easypost/shipment"
15
+ require "easypost/rate"
16
+ require "easypost/postage_label"
17
+ require "easypost/scan_form"
18
+ require "easypost/refund"
19
+ require "easypost/insurance"
20
+ require "easypost/event"
21
+ require "easypost/batch"
22
+ require "easypost/tracker"
23
+ require "easypost/item"
24
+ require "easypost/order"
25
+ require "easypost/pickup"
26
+ require "easypost/pickup_rate"
27
+ require "easypost/printer"
28
+ require "easypost/print_job"
29
+ require "easypost/carrier_account"
30
+ require "easypost/user"
31
+ require "easypost/report"
32
+ require "easypost/webhook"
33
+
34
+ require "easypost/error"
37
35
 
38
36
  module EasyPost
39
- @@api_key = nil
40
- @@api_base = 'https://api.easypost.com/v2'
41
- @@api_version = nil
42
- @@open_timeout = 30
43
- @@timeout = 60
44
-
45
- def self.api_url(url='')
46
- @@api_base + url
47
- end
37
+ @api_key = nil
38
+ @api_base = "https://api.easypost.com"
48
39
 
49
40
  def self.api_key=(api_key)
50
- @@api_key = api_key
41
+ @api_key = api_key
51
42
  end
52
43
 
53
44
  def self.api_key
54
- @@api_key
45
+ @api_key
55
46
  end
56
47
 
57
48
  def self.api_base=(api_base)
58
- @@api_base = api_base
49
+ @api_base = api_base
59
50
  end
60
51
 
61
52
  def self.api_base
62
- @@api_base
53
+ @api_base
63
54
  end
64
55
 
65
- def self.api_version=(version)
66
- @@api_version = version
67
- end
56
+ def self.reset_http_config
57
+ @http_config = {
58
+ timeout: 60,
59
+ open_timeout: 30,
60
+ verify_ssl: OpenSSL::SSL::VERIFY_PEER,
61
+ }
62
+
63
+ ruby_version = Gem::Version.new(RUBY_VERSION)
64
+ if ruby_version >= Gem::Version.new("2.5.0")
65
+ @http_config[:min_version] = OpenSSL::SSL::TLS1_2_VERSION
66
+ else
67
+ @http_config[:ssl_version] = :TLSv1_2
68
+ end
68
69
 
69
- def self.api_version
70
- @@api_version
70
+ @http_config
71
71
  end
72
72
 
73
73
  def self.http_config
74
- @@http_config ||= {
75
- timeout: 60,
76
- open_timeout: 30,
77
- verify_ssl: false,
78
- ssl_version: "TLSv1",
79
- }
74
+ @http_config ||= reset_http_config
80
75
  end
81
76
 
82
77
  def self.http_config=(http_config_params)
83
- self.http_config.merge!(http_config_params)
78
+ http_config.merge!(http_config_params)
84
79
  end
85
80
 
86
- def self.request(method, url, api_key, params={}, headers={}, api_key_required=true)
87
- api_key ||= @@api_key
88
- if api_key_required
89
- raise Error.new('No API key provided.') unless api_key
90
- end
81
+ def self.make_client(uri)
82
+ client = if http_config[:proxy]
83
+ proxy_uri = URI(http_config[:proxy])
84
+ Net::HTTP.new(
85
+ uri.host,
86
+ uri.port,
87
+ proxy_uri.host,
88
+ proxy_uri.port,
89
+ proxy_uri.user,
90
+ proxy_uri.password
91
+ )
92
+ else
93
+ Net::HTTP.new(uri.host, uri.port)
94
+ end
95
+ client.use_ssl = true
96
+
97
+ http_config.each do |name, value|
98
+ # Discrepancies between RestClient and Net::HTTP.
99
+ if name == :verify_ssl
100
+ name = :verify_mode
101
+ elsif name == :timeout
102
+ name = :read_timeout
103
+ end
91
104
 
92
- params = Util.objects_to_ids(params)
93
- url = self.api_url(url)
94
- case method.to_s.downcase.to_sym
95
- when :get, :head, :delete
96
- # Make params into GET parameters
97
- if params && params.count > 0
98
- query_string = Util.flatten_params(params).collect{|key, value| "#{key}=#{Util.url_encode(value)}"}.join('&')
99
- url += "#{URI.parse(url).query ? '&' : '?'}#{query_string}"
105
+ # Handled in the creation of the client.
106
+ if name == :proxy
107
+ next
100
108
  end
101
- payload = nil
102
- else
103
- payload = Util.flatten_params(params).collect{|(key, value)| "#{key}=#{Util.url_encode(value)}"}.join('&')
109
+
110
+ client.send("#{name}=", value)
104
111
  end
105
112
 
106
- headers = {
107
- :user_agent => "EasyPost/v2 RubyClient/#{VERSION}",
108
- :authorization => "Bearer #{api_key}",
109
- :content_type => 'application/x-www-form-urlencoded'
110
- }.merge(headers)
111
-
112
- opts = http_config.merge(
113
- {
114
- :method => method,
115
- :url => url,
116
- :headers => headers,
117
- :payload => payload
118
- }
119
- )
113
+ client
114
+ end
120
115
 
121
- begin
122
- response = execute_request(opts)
123
- rescue RestClient::ExceptionWithResponse => e
124
- if response_code = e.http_code and response_body = e.http_body
125
- begin
126
- response_json = MultiJson.load(response_body, :symbolize_keys => true)
127
- rescue MultiJson::DecodeError
128
- raise Error.new("Invalid response from API, unable to decode.", response_code, response_body)
129
- end
130
- begin
131
- raise NoMethodError if response_json[:error][:message] == nil
132
- raise Error.new(response_json[:error][:message], response_code, response_body, response_json)
133
- rescue NoMethodError, TypeError
134
- raise Error.new(response_json[:error], response_code, response_body, response_json)
135
- end
136
- else
137
- raise Error.new(e.message)
138
- end
139
- rescue RestClient::Exception, Errno::ECONNREFUSED => e
140
- raise Error.new(e.message)
116
+ def self.make_request(method, path, api_key=nil, body=nil)
117
+ client = make_client(URI(@api_base))
118
+
119
+ request = Net::HTTP.const_get(method.capitalize).new(path)
120
+ if body
121
+ request.body = JSON.dump(Util.objects_to_ids(body))
141
122
  end
142
123
 
143
- begin
144
- response_json = MultiJson.load(response.body, :symbolize_keys => true)
145
- rescue MultiJson::DecodeError
146
- raise Error.new("Invalid response object from API, unable to decode.", response.code, response.body)
124
+ request["Content-Type"] = "application/json"
125
+ request["User-Agent"] = "EasyPost/v2 RubyClient/#{VERSION} Ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
126
+ if api_key = api_key || @api_key
127
+ request["Authorization"] = "Basic #{Base64.strict_encode64("#{api_key}:")}"
147
128
  end
148
129
 
149
- return [response_json, api_key]
150
- end
130
+ response = client.request(request)
151
131
 
152
- private
132
+ if (400..599).include? response.code.to_i
133
+ error = JSON.parse(response.body)["error"]
134
+ raise Error.new(error["message"], response.code.to_i, error["code"], error["errors"], response.body)
135
+ end
153
136
 
154
- def self.execute_request(opts)
155
- RestClient::Request.execute(opts)
137
+ if response["Content-Type"].include? "application/json"
138
+ JSON.parse(response.body)
139
+ else
140
+ response.body
141
+ end
142
+ rescue JSON::ParserError
143
+ raise RuntimeError.new(
144
+ "Invalid response object from API, unable to decode.\n#{response.body}"
145
+ )
156
146
  end
157
147
  end
@@ -5,9 +5,11 @@ module EasyPost
5
5
  def self.create(params={}, api_key=nil)
6
6
  url = self.url
7
7
 
8
+ address = params.reject { |k,_| k == :verify || k == :verify_strict }
9
+
8
10
  if params[:verify] || params[:verify_strict]
9
- verify = params.delete(:verify) || []
10
- verify_strict = params.delete(:verify_strict) || []
11
+ verify = params[:verify] || []
12
+ verify_strict = params[:verify_strict] || []
11
13
 
12
14
  url += "?"
13
15
  verify.each do |verification|
@@ -18,7 +20,7 @@ module EasyPost
18
20
  end
19
21
  end
20
22
 
21
- response, api_key = EasyPost.request(:post, url, api_key, {address: params})
23
+ response = EasyPost.make_request(:post, url, api_key, {address: address})
22
24
  return Util.convert_to_easypost_object(response, api_key)
23
25
  end
24
26
 
@@ -26,7 +28,7 @@ module EasyPost
26
28
  wrapped_params = {}
27
29
  wrapped_params[self.class_name().to_sym] = params
28
30
  wrapped_params[:carrier] = carrier
29
- response, api_key = EasyPost.request(:post, url + '/create_and_verify', api_key, wrapped_params)
31
+ response = EasyPost.make_request(:post, url + '/create_and_verify', api_key, wrapped_params)
30
32
 
31
33
  if response.has_key?(:address)
32
34
  if response.has_key?(:message)
@@ -41,13 +43,13 @@ module EasyPost
41
43
 
42
44
  def verify(params={}, carrier=nil)
43
45
  begin
44
- response, api_key = EasyPost.request(:get, url + '/verify?carrier=' + String(carrier), @api_key, params)
46
+ response = EasyPost.make_request(:get, url + '/verify?carrier=' + String(carrier), @api_key, params)
45
47
  rescue
46
48
  raise Error.new("Unable to verify address.")
47
49
  end
48
50
 
49
- if response.has_key?(:address)
50
- return EasyPost::Util::convert_to_easypost_object(response[:address], api_key)
51
+ if response.has_key?("address")
52
+ return EasyPost::Util::convert_to_easypost_object(response["address"], api_key)
51
53
  else
52
54
  raise Error.new("Unable to verify address.")
53
55
  end
@@ -4,47 +4,47 @@ module EasyPost
4
4
  def self.create_and_buy(params={}, api_key=nil)
5
5
  wrapped_params = {}
6
6
  wrapped_params[self.class_name().to_sym] = params
7
- response, api_key = EasyPost.request(:post, url + '/create_and_buy', api_key, wrapped_params)
7
+ response = EasyPost.make_request(:post, url + '/create_and_buy', api_key, wrapped_params)
8
8
 
9
9
  return Util.convert_to_easypost_object(response, api_key)
10
10
  end
11
11
 
12
12
  def buy(params={})
13
- response, api_key = EasyPost.request(:post, url + '/buy', @api_key, params)
13
+ response = EasyPost.make_request(:post, url + '/buy', @api_key, params)
14
14
  self.refresh_from(response, @api_key, true)
15
15
 
16
16
  return self
17
17
  end
18
18
 
19
19
  def label(params={})
20
- response, api_key = EasyPost.request(:post, url + '/label', @api_key, params)
20
+ response = EasyPost.make_request(:post, url + '/label', @api_key, params)
21
21
  self.refresh_from(response, @api_key, true)
22
22
 
23
23
  return self
24
24
  end
25
25
 
26
26
  def remove_shipments(params={})
27
- response, api_key = EasyPost.request(:post, url + '/remove_shipments', @api_key, params)
27
+ response = EasyPost.make_request(:post, url + '/remove_shipments', @api_key, params)
28
28
  self.refresh_from(response, @api_key, true)
29
29
 
30
30
  return self
31
31
  end
32
32
 
33
33
  def add_shipments(params={})
34
- response, api_key = EasyPost.request(:post, url + '/add_shipments', @api_key, params)
34
+ response = EasyPost.make_request(:post, url + '/add_shipments', @api_key, params)
35
35
  self.refresh_from(response, @api_key, true)
36
36
 
37
37
  return self
38
38
  end
39
39
 
40
40
  def stamp_and_barcode_by_reference(params={})
41
- response, api_key = EasyPost.request(:get, url + '/stamp_and_barcode_by_reference', @api_key, params)
41
+ response = EasyPost.make_request(:get, url + '/stamp_and_barcode_by_reference', @api_key, params)
42
42
 
43
43
  return response
44
44
  end
45
45
 
46
46
  def create_scan_form(params={})
47
- response, api_key = EasyPost.request(:post, url + '/scan_form', @api_key, params)
47
+ response = EasyPost.make_request(:post, url + '/scan_form', @api_key, params)
48
48
 
49
49
  return response
50
50
  end