easypost 1.1.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,27 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+
20
+ # iOS
21
+ .DS_Store
22
+ .AppleDouble
23
+ .LSOverride
24
+ Icon
25
+ ._*
26
+ .Spotlight-V100
27
+ .Trashes
data/CHANGELOG ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ easypost (2.0.0)
5
+ multi_json (>= 1.0.4, < 2)
6
+ rest-client (~> 1.4)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.2.4)
12
+ mime-types (1.23)
13
+ multi_json (1.7.7)
14
+ rest-client (1.6.7)
15
+ mime-types (>= 1.16)
16
+ rspec (2.13.0)
17
+ rspec-core (~> 2.13.0)
18
+ rspec-expectations (~> 2.13.0)
19
+ rspec-mocks (~> 2.13.0)
20
+ rspec-core (2.13.1)
21
+ rspec-expectations (2.13.0)
22
+ diff-lcs (>= 1.1.3, < 2.0)
23
+ rspec-mocks (2.13.1)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ easypost!
30
+ rspec (~> 2.13.0)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2013 EasyPost (Simpler Postage, Inc)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # EasyPost Ruby Client Library
2
+
3
+ EasyPost is a simple shipping API. You can sign up for an account at https://easypost.com
4
+
5
+ Installation
6
+ ---------------
7
+
8
+ Install the gem:
9
+
10
+ ```
11
+ gem install
12
+ ```
13
+
14
+ Import the EasyPost client in your application:
15
+
16
+ ```
17
+ require 'easypost'
18
+ ```
19
+
20
+ Example
21
+ ------------------
22
+
23
+ ```ruby
24
+ require 'easypost'
25
+ EasyPost.api_key = 'cueqNZUb3ldeWTNX7MU3Mel8UXtaAMUi'
26
+
27
+ to_address = EasyPost::Address.create(
28
+ :name => 'Sawyer Bateman',
29
+ :street1 => '1A Larkspur Cres.',
30
+ :city => 'St. Albert',
31
+ :state => 'AB',
32
+ :zip => 't8n2m4',
33
+ :country => 'CA',
34
+ :phone => '780-273-8374'
35
+ )
36
+ from_address = EasyPost::Address.create(
37
+ :company => 'Simpler Postage Inc',
38
+ :street1 => '388 Townsend Street',
39
+ :street2 => 'Apt 20',
40
+ :city => 'San Francisco',
41
+ :state => 'CA',
42
+ :zip => '94107',
43
+ :phone => '415-456-7890'
44
+ )
45
+
46
+ parcel = EasyPost::Parcel.create(
47
+ :width => 15.2,
48
+ :length => 18,
49
+ :height => 9.5,
50
+ :weight => 35.1
51
+ )
52
+
53
+ customs_item = EasyPost::CustomsItem.create(
54
+ :description => 'EasyPost T-shirts',
55
+ :quantity => 2,
56
+ :value => 23.56,
57
+ :weight => 33,
58
+ :origin_country => 'us',
59
+ :hs_tariff_number => 123456
60
+ )
61
+ customs_info = EasyPost::CustomsInfo.create(
62
+ :integrated_form_type => 'form_2976',
63
+ :customs_certify => true,
64
+ :customs_signer => 'Dr. Pepper',
65
+ :contents_type => 'gift',
66
+ :contents_explanation => '', # only required when contents_type => 'other'
67
+ :eel_pfc => 'NOEEI 30.37(a)',
68
+ :non_delivery_option => 'abandon',
69
+ :restriction_type => 'none',
70
+ :restriction_comments => '',
71
+ :customs_items => [customs_item]
72
+ )
73
+
74
+ shipment = EasyPost::Shipment.create(
75
+ :to_address => to_address,
76
+ :from_address => from_address,
77
+ :parcel => parcel,
78
+ :customs_info => customs_info
79
+ )
80
+
81
+ shipment.buy(
82
+ :rate => shipment.lowest_rate
83
+ )
84
+
85
+ puts shipment.postage_label.label_url
86
+
87
+ ```
88
+
89
+ Documentation
90
+ --------------------
91
+
92
+ Up-to-date documentation at: https://easypost.com/docs
93
+
94
+ Tests
95
+ --------------------
96
+
97
+ ```
98
+ rspec spec
99
+ ```
data/Rakefile ADDED
File without changes
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/bin/easypost-irb ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
3
+
4
+ libs = " -r irb/completion"
5
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/easypost'}"
6
+ puts "Initializing EasyPost..."
7
+ exec "#{irb} #{libs} --simple-prompt"
data/easypost.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'easypost/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'easypost'
8
+ spec.version = EasyPost::VERSION
9
+ spec.date = '2013-06-25'
10
+ spec.summary = 'EasyPost Ruby Client Library'
11
+ spec.description = 'Client library for accessing the EasyPost shipping API via Ruby.'
12
+ spec.authors = ['Jon Calhoun', 'Sawyer Bateman']
13
+ spec.email = 'contact@easypost.com'
14
+ spec.homepage = 'https://easypost.com/docs'
15
+
16
+ spec.files = `git ls-files`.split("\n")
17
+ spec.test_files = `git ls-files -- test/*`.split("\n")
18
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ spec.require_path = 'lib'
20
+
21
+ spec.add_dependency('rest-client', '~> 1.4')
22
+ spec.add_dependency('multi_json', '>= 1.0.4', '< 2')
23
+ spec.add_development_dependency('rspec', "~> 2.13.0")
24
+ end
data/lib/easypost.rb CHANGED
@@ -1,13 +1,33 @@
1
- require 'typhoeus'
2
- require 'json'
1
+ require 'cgi'
2
+ require 'set'
3
+ require 'openssl'
4
+ require 'rest_client'
5
+ require 'multi_json'
6
+
7
+ # Resources
8
+ require 'easypost/util'
9
+ require 'easypost/object'
10
+ require 'easypost/resource'
11
+ require 'easypost/address'
12
+ require 'easypost/parcel'
13
+ require 'easypost/customs_item'
14
+ require 'easypost/customs_info'
15
+ require 'easypost/shipment'
16
+ require 'easypost/rate'
17
+ require 'easypost/postage_label'
18
+ require 'easypost/scan_form'
19
+ require 'easypost/refund'
20
+ require 'easypost/batch'
21
+
22
+ require 'easypost/error'
3
23
 
4
24
  module EasyPost
5
- @@api_key = "..."
6
- @@api_base = 'https://www.geteasypost.com/api/'
25
+ @@api_key = nil
26
+ @@api_base = 'https://api.easypost.com/v2'
27
+ @@api_version = nil
7
28
 
8
- def self.api_url(args={})
9
- raise ArgumentError unless args.keys.eql?([:type, :action])
10
- return "#{@@api_base}#{args[:type]}/#{args[:action]}"
29
+ def self.api_url(url='')
30
+ @@api_base + url
11
31
  end
12
32
 
13
33
  def self.api_key=(api_key)
@@ -18,40 +38,91 @@ module EasyPost
18
38
  @@api_key
19
39
  end
20
40
 
21
- def self.symbolize_keys(hash={})
22
- hash.keys.each do |key|
23
- hash[(key.to_sym rescue key) || key] = hash.delete(key)
24
- end
25
- return hash
41
+ def self.api_base=(api_base)
42
+ @@api_base = api_base
26
43
  end
27
44
 
28
- def self.symbolize_keys_recursive(hash={})
29
- hash.keys.each do |key|
30
- keysym = (key.to_sym rescue key) || key
31
- hash[keysym] = hash.delete(key)
32
- if hash[keysym].is_a?(Hash)
33
- hash[keysym] = symbolize_keys_recursive(hash[keysym])
34
- end
35
- end
36
- return hash
45
+ def self.api_base
46
+ @@api_base
37
47
  end
38
48
 
39
- def self.get(url, params={})
40
- params = {:userpwd => @@api_key, :params => params}
41
- @response = Typhoeus::Request.get(url, params)
42
- return EasyPost.symbolize_keys_recursive(JSON.parse(@response.body))
49
+ def self.api_version=(version)
50
+ @@api_version = version
43
51
  end
44
52
 
45
- def self.post(url, params={})
46
- params = {:userpwd => @@api_key, :params => params}
47
- @response = Typhoeus::Request.post(url, params)
48
- return EasyPost.symbolize_keys_recursive(JSON.parse(@response.body))
53
+ def self.api_version
54
+ @@api_version
49
55
  end
50
56
 
51
- end
57
+ def self.request(method, url, api_key, params={}, headers={})
58
+ api_key ||= @@api_key
59
+ raise Error.new('No API key provided.') unless api_key
52
60
 
53
- require 'easypost/address'
54
- require 'easypost/postage'
55
- require 'easypost/errors/easypost_error'
56
- require 'easypost/errors/authentication_error'
61
+ ssl_opts = { :verify_ssl => false }
62
+
63
+ params = Util.objects_to_ids(params)
64
+ url = self.api_url(url)
65
+ case method.to_s.downcase.to_sym
66
+ when :get, :head, :delete
67
+ # Make params into GET parameters
68
+ if params && params.count > 0
69
+ query_string = Util.flatten_params(params).collect{|key, value| "#{key}=#{Util.url_encode(value)}"}.join('&')
70
+ url += "#{URI.parse(url).query ? '&' : '?'}#{query_string}"
71
+ end
72
+ payload = nil
73
+ else
74
+ payload = Util.flatten_params(params).collect{|(key, value)| "#{key}=#{Util.url_encode(value)}"}.join('&')
75
+ end
76
+
77
+ headers = {
78
+ :user_agent => "EasyPost/v2 RubyClient/2.0.0",
79
+ :authorization => "Bearer #{api_key}",
80
+ :content_type => 'application/x-www-form-urlencoded'
81
+ }.merge(headers)
57
82
 
83
+ opts = {
84
+ :method => method,
85
+ :url => url,
86
+ :headers => headers,
87
+ :open_timeout => 30,
88
+ :payload => payload,
89
+ :timeout => 60
90
+ }.merge(ssl_opts)
91
+
92
+ begin
93
+ response = execute_request(opts)
94
+ rescue RestClient::ExceptionWithResponse => e
95
+ if response_code = e.http_code and response_body = e.http_body
96
+ begin
97
+ response_json = MultiJson.load(response_body, :symbolize_keys => true)
98
+ rescue MultiJson::DecodeError
99
+ raise Error.new("Invalid response from API, unable to decode.", response_code, response_body)
100
+ end
101
+ begin
102
+ raise NoMethodError if response_json[:error][:message] == nil
103
+ raise Error.new(response_json[:error][:message], response_code, response_body, response_json)
104
+ rescue NoMethodError, TypeError
105
+ raise Error.new(response_json[:error], response_code, response_body, response_json)
106
+ end
107
+ else
108
+ raise Error.new(e.message)
109
+ end
110
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
111
+ raise Error.new(e.message)
112
+ end
113
+
114
+ begin
115
+ response_json = MultiJson.load(response.body, :symbolize_keys => true)
116
+ rescue MultiJson::DecodeError
117
+ raise Error.new("Invalid response object from API, unable to decode.", response.code, response.body)
118
+ end
119
+
120
+ return [response_json, api_key]
121
+ end
122
+
123
+ private
124
+
125
+ def self.execute_request(opts)
126
+ RestClient::Request.execute(opts)
127
+ end
128
+ end
@@ -1,13 +1,20 @@
1
1
  module EasyPost
2
- class Address
3
- @@type = "address"
2
+ class Address < Resource
4
3
 
5
- def self.test
6
- puts EasyPost.api_url("verify")
7
- end
4
+ def verify(params={})
5
+ response, api_key = EasyPost.request(:get, url + '/verify', @api_key, params)
6
+
7
+ if response.has_key?(:address)
8
+ if response.has_key?(:message)
9
+ response[:address][:message] = response[:message]
10
+ end
11
+ verified_address = EasyPost::Util::convert_to_easypost_object(response[:address], api_key)
12
+ return verified_address
13
+ else
14
+ raise Error.new("Unable to verify address.")
15
+ end
8
16
 
9
- def self.verify(address={})
10
- @verified_address = EasyPost.get(EasyPost.api_url(:type => @@type, :action => "verify"), :address => address)
17
+ return self
11
18
  end
12
19
 
13
20
  end
@@ -0,0 +1,34 @@
1
+ module EasyPost
2
+ class Batch < Resource
3
+
4
+ def self.create_and_buy(params={})
5
+ wrapped_params = {}
6
+ wrapped_params[self.class_name().to_sym] = params
7
+ response, api_key = EasyPost.request(:post, url + '/create_and_buy', @api_key, wrapped_params)
8
+
9
+ return Util.convert_to_easypost_object(response, api_key)
10
+ end
11
+
12
+ def label(params={})
13
+ response, api_key = EasyPost.request(:post, url + '/label', @api_key, params)
14
+ self.refresh_from(response, @api_key, true)
15
+
16
+ return self
17
+ end
18
+
19
+ def remove_shipments(params={})
20
+ response, api_key = EasyPost.request(:post, url + '/remove_shipments', @api_key, params)
21
+ self.refresh_from(response, @api_key, true)
22
+
23
+ return self
24
+ end
25
+
26
+ def add_shipments(params={})
27
+ response, api_key = EasyPost.request(:post, url + '/add_shipments', @api_key, params)
28
+ self.refresh_from(response, @api_key, true)
29
+
30
+ return self
31
+ end
32
+
33
+ end
34
+ end