easypost 3.0.0 → 3.2.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +22 -0
  3. data/CHANGELOG +40 -0
  4. data/README.md +2 -1
  5. data/VERSION +1 -1
  6. data/easypost.gemspec +24 -20
  7. data/lib/easypost.rb +108 -118
  8. data/lib/easypost/address.rb +47 -47
  9. data/lib/easypost/batch.rb +34 -38
  10. data/lib/easypost/carrier_account.rb +4 -6
  11. data/lib/easypost/customs_info.rb +3 -2
  12. data/lib/easypost/customs_item.rb +3 -2
  13. data/lib/easypost/error.rb +25 -33
  14. data/lib/easypost/event.rb +3 -6
  15. data/lib/easypost/insurance.rb +1 -3
  16. data/lib/easypost/item.rb +4 -8
  17. data/lib/easypost/object.rb +111 -113
  18. data/lib/easypost/order.rb +20 -18
  19. data/lib/easypost/parcel.rb +1 -3
  20. data/lib/easypost/pickup.rb +19 -18
  21. data/lib/easypost/pickup_rate.rb +1 -3
  22. data/lib/easypost/postage_label.rb +1 -3
  23. data/lib/easypost/print_job.rb +1 -5
  24. data/lib/easypost/printer.rb +18 -22
  25. data/lib/easypost/rate.rb +1 -3
  26. data/lib/easypost/refund.rb +1 -3
  27. data/lib/easypost/report.rb +22 -24
  28. data/lib/easypost/resource.rb +58 -60
  29. data/lib/easypost/scan_form.rb +4 -6
  30. data/lib/easypost/shipment.rb +84 -92
  31. data/lib/easypost/tracker.rb +10 -12
  32. data/lib/easypost/user.rb +33 -37
  33. data/lib/easypost/util.rb +99 -136
  34. data/lib/easypost/webhook.rb +22 -21
  35. metadata +33 -60
  36. data/circle.yml +0 -3
  37. data/spec/address_spec.rb +0 -81
  38. data/spec/batch_spec.rb +0 -48
  39. data/spec/carrier_account_spec.rb +0 -121
  40. data/spec/insurance_spec.rb +0 -69
  41. data/spec/item_spec.rb +0 -105
  42. data/spec/order_spec.rb +0 -58
  43. data/spec/pickup_spec.rb +0 -83
  44. data/spec/report_spec.rb +0 -59
  45. data/spec/scan_form_spec.rb +0 -46
  46. data/spec/shipment_spec.rb +0 -144
  47. data/spec/spec_helper.rb +0 -10
  48. data/spec/support/constant.rb +0 -106
  49. data/spec/tracker_spec.rb +0 -94
  50. data/spec/user_spec.rb +0 -88
  51. data/spec/webhook_spec.rb +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 677127854c0b4c489ee924bff20fac02917e38bf
4
- data.tar.gz: 443d834ebc6347f523ad956c91706d7cd0e819b2
3
+ metadata.gz: 77a7386297f189954ea974f3704cd7b61317f680
4
+ data.tar.gz: 3f2f2a129f9413f73910743c64a9d1b957998814
5
5
  SHA512:
6
- metadata.gz: bd9b8a2b041853716139a7d8913d51539b166408d3dea0eba5772b6ab2ce643b0d89e19c2f4c55c9c3c124567c9fb4edeb11535f788af273d697c011b1787364
7
- data.tar.gz: fc58e08a4a748c936d60b048d2c1ce38191acde4a7a4f76653017ffb89e846f9551dbdbca6c4adf3a556ee5019cc8e7b4890631253f01db5bf9589b01ebb63d4
6
+ metadata.gz: 73d59ca7ab531ee6bd6b5bae9d5d8cb862501ba1e3a41d3a218c3853f9a7c96dc69fb5c0a67a94fd068c123f76037aaa8bd64ab0ddff01fe80e446aac254100c
7
+ data.tar.gz: 77174452488594f5b154548a784c9e294aa66e3a54b1267d1d3a7076475ed41fa6027db1af2a4b2b0b869588853982770e0d43bd797755fe68ed5bbd5f124487
@@ -0,0 +1,22 @@
1
+ name: 'CI'
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request: ~
7
+
8
+ jobs:
9
+ run-tests:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ rubyversion: ['2.4', '2.5', '2.6', '2.7', '3.0']
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: set up ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.rubyversion }}
20
+ bundler-cache: true
21
+ - name: run tests
22
+ run: bundle exec rspec
data/CHANGELOG CHANGED
@@ -1,3 +1,43 @@
1
+ === 3.2.0 2021-01-14
2
+
3
+ * Replace Travis CI with Github Actions
4
+ * Add Ruby 3.0 to supported platforms (#110; thanks @maxwell)
5
+
6
+ === 3.1.5 2020-12-16
7
+
8
+ * Fix attribute lookup when manually constructing objects (#105; thanks @drewtempelmeyer)
9
+ * Flatten class names and clean up some other style issues
10
+ * Fix `EasyPost::Address.create_and_verify`, broken since 3.1.0 (#108; thanks @rajbirverma)
11
+
12
+ === 3.1.4 2020-09-29
13
+
14
+ * Don't modify params passed into Address#create (#78; thanks @TheRusskiy)
15
+ * Don't modify `carriers` and `services` parameters to `Shipment.lowest_rate` (#71 / #103, thanks @vladvinnikov and @jurisgalang)
16
+ * When constructing an easypost object, convert the key to a string (#102; thanks @Geesu)
17
+ * Expose the raw HTTP response as `#http_body` on `EasyPost::Error` objects (#101; thanks @Geesu)
18
+
19
+ === 3.1.3 2020-06-26
20
+
21
+ * Fix bug causing Authorization header to be included in User-Agent header. All users must upgrade.
22
+
23
+ === 3.1.2 2020-06-24
24
+
25
+ * Bad gem push. New version required.
26
+
27
+ === 3.1.1 2020-06-23
28
+
29
+ * Fix bug where EasyPost.http_config was invalid when not explicitly initialized.
30
+
31
+ === 3.1.0 2020-06-23
32
+
33
+ * Add Shipment Invoice and Refund Report
34
+ * Remove dependencies on `RestClient` and `MultiJson`
35
+ * Remove some deprecated endpoints
36
+
37
+ === 3.0.1 2018-05-17
38
+
39
+ * Enforce TLS certificate validity by default
40
+
1
41
  === 3.0.0 2018-02-09
2
42
 
3
43
  * Require use of ruby ~> 2.0 and TLSv1.2
data/README.md CHANGED
@@ -1,6 +1,7 @@
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://github.com/EasyPost/easypost-ruby/workflows/CI/badge.svg)](https://github.com/EasyPost/easypost-ruby/actions?query=workflow%3ACI)
4
+ [![Gem Version](https://badge.fury.io/rb/easypost.svg)](https://badge.fury.io/rb/easypost)
4
5
 
5
6
 
6
7
  EasyPost is a simple shipping API. You can sign up for an account at https://easypost.com
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.0
1
+ 3.2.0
@@ -1,27 +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']
20
- spec.required_ruby_version = '~> 2.0'
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"
21
25
 
22
- spec.add_dependency 'rest-client', '>= 1.7'
23
- spec.add_dependency 'multi_json', '>= 1.3.0'
24
- spec.add_development_dependency 'bundler', '~> 1.7'
25
- spec.add_development_dependency 'rake', '~> 10.0'
26
- 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"
27
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_2,
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(EasyPost::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 EasyPost::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
@@ -1,58 +1,58 @@
1
- module EasyPost
2
- class Address < Resource
3
- attr_accessor :message # Backwards compatibility
4
-
5
- def self.create(params={}, api_key=nil)
6
- url = self.url
7
-
8
- if params[:verify] || params[:verify_strict]
9
- verify = params.delete(:verify) || []
10
- verify_strict = params.delete(:verify_strict) || []
11
-
12
- url += "?"
13
- verify.each do |verification|
14
- url += "verify[]=#{verification}&"
15
- end
16
- verify_strict.each do |verification|
17
- url += "verify_strict[]=#{verification}&"
18
- end
19
- end
1
+ class EasyPost::Address < EasyPost::Resource
2
+ attr_accessor :message # Backwards compatibility
20
3
 
21
- response, api_key = EasyPost.request(:post, url, api_key, {address: params})
22
- return Util.convert_to_easypost_object(response, api_key)
23
- end
4
+ def self.create(params={}, api_key=nil)
5
+ url = self.url
6
+
7
+ address = params.reject { |k,_| k == :verify || k == :verify_strict }
8
+
9
+ if params[:verify] || params[:verify_strict]
10
+ verify = params[:verify] || []
11
+ verify_strict = params[:verify_strict] || []
24
12
 
25
- def self.create_and_verify(params={}, carrier=nil, api_key=nil)
26
- wrapped_params = {}
27
- wrapped_params[self.class_name().to_sym] = params
28
- wrapped_params[:carrier] = carrier
29
- response, api_key = EasyPost.request(:post, url + '/create_and_verify', api_key, wrapped_params)
30
-
31
- if response.has_key?(:address)
32
- if response.has_key?(:message)
33
- response[:address][:message] = response[:message]
34
- end
35
- verified_address = EasyPost::Util::convert_to_easypost_object(response[:address], api_key)
36
- return verified_address
37
- else
38
- raise Error.new("Unable to verify address.")
13
+ url += "?"
14
+ verify.each do |verification|
15
+ url += "verify[]=#{verification}&"
16
+ end
17
+ verify_strict.each do |verification|
18
+ url += "verify_strict[]=#{verification}&"
39
19
  end
40
20
  end
41
21
 
42
- def verify(params={}, carrier=nil)
43
- begin
44
- response, api_key = EasyPost.request(:get, url + '/verify?carrier=' + String(carrier), @api_key, params)
45
- rescue
46
- raise Error.new("Unable to verify address.")
47
- end
22
+ response = EasyPost.make_request(:post, url, api_key, {address: address})
23
+ return EasyPost::Util.convert_to_easypost_object(response, api_key)
24
+ end
48
25
 
49
- if response.has_key?(:address)
50
- return EasyPost::Util::convert_to_easypost_object(response[:address], api_key)
51
- else
52
- raise Error.new("Unable to verify address.")
26
+ def self.create_and_verify(params={}, carrier=nil, api_key=nil)
27
+ wrapped_params = {}
28
+ wrapped_params[self.class_name().to_sym] = params
29
+ wrapped_params[:carrier] = carrier
30
+ response = EasyPost.make_request(:post, url + '/create_and_verify', api_key, wrapped_params)
31
+
32
+ if response.has_key?("address")
33
+ if response.has_key?("message")
34
+ response["address"]["message"] = response["message"]
53
35
  end
36
+ verified_address = EasyPost::Util::convert_to_easypost_object(response["address"], api_key)
37
+ return verified_address
38
+ else
39
+ raise EasyPost::Error.new("Unable to verify address.")
40
+ end
41
+ end
54
42
 
55
- return self
43
+ def verify(params={}, carrier=nil)
44
+ begin
45
+ response = EasyPost.make_request(:get, url + '/verify?carrier=' + String(carrier), @api_key, params)
46
+ rescue
47
+ raise EasyPost::Error.new("Unable to verify address.")
56
48
  end
49
+
50
+ if response.has_key?("address")
51
+ return EasyPost::Util::convert_to_easypost_object(response["address"], api_key)
52
+ else
53
+ raise EasyPost::Error.new("Unable to verify address.")
54
+ end
55
+
56
+ return self
57
57
  end
58
58
  end