shippo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/example.rb +59 -0
- data/lib/shippo.rb +86 -0
- data/lib/shippo/address.rb +6 -0
- data/lib/shippo/api_object.rb +89 -0
- data/lib/shippo/container_object.rb +28 -0
- data/lib/shippo/create.rb +19 -0
- data/lib/shippo/error.rb +18 -0
- data/lib/shippo/list.rb +22 -0
- data/lib/shippo/parcel.rb +6 -0
- data/lib/shippo/rate.rb +5 -0
- data/lib/shippo/resource.rb +23 -0
- data/lib/shippo/shipment.rb +10 -0
- data/lib/shippo/transaction.rb +6 -0
- data/test/test.rb +26 -0
- metadata +57 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0e17e4581ec82ca7bb1242373d0f42045696f9a8
|
4
|
+
data.tar.gz: b159bf9011321abef4e546f7a60b276de4b09d93
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 48150a7adda38b277e70b3e031229456086a74472e5836892c3d42158445fe1e747e7bc3aef25de24c9a078354c424f53dae96de3b92671b3905180297a3436b
|
7
|
+
data.tar.gz: 5d2a381f23176b9c45a8c772fee6588facf4134e00e974581fb93edec09fa000d3b0b7d3b8b5d11ea9855e23505bcd207b1a4ca8af226ad99240bac15738db8d
|
data/example.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'shippo'
|
2
|
+
Shippo::api_user = 'YOUR_API_USER'
|
3
|
+
Shippo::api_pass = 'YOUR_API_PASS'
|
4
|
+
|
5
|
+
from = Shippo::Address.create(
|
6
|
+
:object_purchase => 'QUOTE',
|
7
|
+
:name => 'Laura Behrens Wu',
|
8
|
+
:company => 'Shippo',
|
9
|
+
:street1 => 'Clayton St.',
|
10
|
+
:street_no => '215',
|
11
|
+
:street2 => '',
|
12
|
+
:city => 'San Francisco',
|
13
|
+
:state => 'CA',
|
14
|
+
:zip => '94117',
|
15
|
+
:country => 'US',
|
16
|
+
:phone => '+1 555 341 9393',
|
17
|
+
:email => 'laura@goshippo.com',
|
18
|
+
:ip => '',
|
19
|
+
:metadata => 'Customer ID 123456'
|
20
|
+
)
|
21
|
+
puts from
|
22
|
+
to = Shippo::Address.create(
|
23
|
+
:object_purchase => 'QUOTE',
|
24
|
+
:name => 'Mr. John Doe',
|
25
|
+
:company => 'ACME Inc.',
|
26
|
+
:street1 => nil,
|
27
|
+
:street_no => '',
|
28
|
+
:street2 => '',
|
29
|
+
:city => 'Berlin',
|
30
|
+
:country => 'DE',
|
31
|
+
:ip => '',
|
32
|
+
:metadata => ''
|
33
|
+
)
|
34
|
+
puts to
|
35
|
+
parcel = Shippo::Parcel.create(
|
36
|
+
:length => 5,
|
37
|
+
:width => 1,
|
38
|
+
:height => 5.555,
|
39
|
+
:distance_unit => :cm,
|
40
|
+
:weight => '2.122',
|
41
|
+
:mass_unit => :lb,
|
42
|
+
:metadata => 'Customer ID 123456'
|
43
|
+
)
|
44
|
+
puts parcel
|
45
|
+
shipment = Shippo::Shipment.create(
|
46
|
+
:object_purpose => 'QUOTE',
|
47
|
+
# you can also put in the object_id directly, but this is more convenient
|
48
|
+
:address_from => from,
|
49
|
+
:address_to => to,
|
50
|
+
:parcel => parcel,
|
51
|
+
:metadata => 'Quote Shipment'
|
52
|
+
)
|
53
|
+
puts shipment
|
54
|
+
# never do this in real life
|
55
|
+
sleep(5)
|
56
|
+
|
57
|
+
rates = shipment.rates
|
58
|
+
|
59
|
+
puts "Shipment #{shipment[:object_id]} has the following rates:\n\n#{rates}"
|
data/lib/shippo.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'json'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
require 'shippo/error.rb'
|
6
|
+
require 'shippo/container_object.rb'
|
7
|
+
require 'shippo/api_object.rb'
|
8
|
+
require 'shippo/list.rb'
|
9
|
+
require 'shippo/create.rb'
|
10
|
+
require 'shippo/resource.rb'
|
11
|
+
require 'shippo/address.rb'
|
12
|
+
require 'shippo/parcel.rb'
|
13
|
+
require 'shippo/shipment.rb'
|
14
|
+
require 'shippo/transaction.rb'
|
15
|
+
require 'shippo/rate.rb'
|
16
|
+
|
17
|
+
module Shippo
|
18
|
+
@api_base = 'https://api.goshippo.com/v1'
|
19
|
+
@api_version = 1.0
|
20
|
+
@api_user = ''
|
21
|
+
@api_pass = ''
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_accessor :api_base, :api_version, :api_user, :api_pass
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.api_url(url='')
|
28
|
+
@api_base + url
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.request(method, url, params = {}, headers = {})
|
32
|
+
unless @api_user && @api_pass
|
33
|
+
raise AuthError.new("API credentials missing! Make sure to set Shippo.api_user, Shippo.api_Pass")
|
34
|
+
end
|
35
|
+
begin
|
36
|
+
payload = {}
|
37
|
+
url = api_url(url)
|
38
|
+
case method
|
39
|
+
when :get
|
40
|
+
pairs = []
|
41
|
+
params.each { |k, v|
|
42
|
+
pairs.push "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
43
|
+
}
|
44
|
+
url += "?#{pairs.join('&')}" unless pairs.empty?
|
45
|
+
when :post
|
46
|
+
payload = params
|
47
|
+
end
|
48
|
+
opts = { :headers => headers,
|
49
|
+
:method => method,
|
50
|
+
:payload => payload,
|
51
|
+
:url => url,
|
52
|
+
:open_timeout => 15,
|
53
|
+
:timeout => 30,
|
54
|
+
:user => @api_user,
|
55
|
+
:password => @api_pass
|
56
|
+
}
|
57
|
+
res = make_request(opts)
|
58
|
+
rescue => e
|
59
|
+
case e
|
60
|
+
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
61
|
+
msg = "Could not connect to the Shippo API at #{@api_base}. " +
|
62
|
+
"Please proceed to check your connection, try again and " +
|
63
|
+
"contact Shippo support should the issue persist."
|
64
|
+
when SocketError
|
65
|
+
msg = "Unexpected error connecting to the Shippo API at #{@api_base}."
|
66
|
+
else
|
67
|
+
msg = "Connection error"
|
68
|
+
end
|
69
|
+
raise ConnectionError.new msg + "\n\n(e.message)"
|
70
|
+
end
|
71
|
+
parse(res)
|
72
|
+
end
|
73
|
+
def self.parse(response)
|
74
|
+
JSON::parse(response.body, { :symbolize_names => true })
|
75
|
+
end
|
76
|
+
end
|
77
|
+
def make_request(opts)
|
78
|
+
RestClient::Request.execute(opts){ |response, request, result, &block|
|
79
|
+
if [301, 302, 307].include? response.code
|
80
|
+
response.follow_redirection(request, result, &block)
|
81
|
+
else
|
82
|
+
response.return!(request, result, &block)
|
83
|
+
end
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Shippo
|
2
|
+
class ApiObject < ContainerObject
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize(id=nil)
|
6
|
+
# parameter overloading!
|
7
|
+
if id.kind_of?(Hash)
|
8
|
+
id = id[:id]
|
9
|
+
end
|
10
|
+
|
11
|
+
@values = {}
|
12
|
+
@values[:id] = id if id
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.construct_from(values)
|
16
|
+
# recursive on arrays
|
17
|
+
case values
|
18
|
+
when Array
|
19
|
+
values.map { |v| self.construct_from(v) }
|
20
|
+
when Hash
|
21
|
+
obj = self.new(values[:id])
|
22
|
+
obj.refresh_from(values)
|
23
|
+
obj
|
24
|
+
else
|
25
|
+
# on scalar types, just identity
|
26
|
+
values
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s(*args)
|
31
|
+
JSON.pretty_generate @values
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect()
|
35
|
+
id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
|
36
|
+
"#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + self.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
def refresh_from(values)
|
40
|
+
values.each do |k, v|
|
41
|
+
@values[k.to_sym] = v
|
42
|
+
end
|
43
|
+
instance_eval do
|
44
|
+
add_accessors(@values.keys)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
def [](k)
|
49
|
+
@values[k.to_sym]
|
50
|
+
end
|
51
|
+
|
52
|
+
def []=(k, v)
|
53
|
+
send(:"#{k}=", v)
|
54
|
+
end
|
55
|
+
def keys
|
56
|
+
@values.keys
|
57
|
+
end
|
58
|
+
|
59
|
+
def values
|
60
|
+
@values.values
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_json(*a)
|
64
|
+
JSON.dump(@values)
|
65
|
+
end
|
66
|
+
|
67
|
+
def as_json(*a)
|
68
|
+
@values.as_json(*a)
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_hash
|
72
|
+
@values
|
73
|
+
end
|
74
|
+
|
75
|
+
def each(&blk)
|
76
|
+
@values.each(&blk)
|
77
|
+
end
|
78
|
+
|
79
|
+
if RUBY_VERSION < '1.9.2'
|
80
|
+
def respond_to?(symbol)
|
81
|
+
@values.has_key?(symbol) || super
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Shippo
|
2
|
+
class ContainerObject
|
3
|
+
protected
|
4
|
+
def create_accessor(k_name, k_index)
|
5
|
+
metaclass.instance_eval do
|
6
|
+
define_method(k_name) { @values[k_index] }
|
7
|
+
define_method(:"#{k_name}=") do |v|
|
8
|
+
@values[k_index] = v unless k_index == ''
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def add_accessors(keys)
|
13
|
+
keys.each do |k|
|
14
|
+
#TODO raise something here, should filter this before
|
15
|
+
orig_k = k
|
16
|
+
while respond_to?(k) do
|
17
|
+
k = "_#{k}".to_sym
|
18
|
+
end
|
19
|
+
create_accessor(k, orig_k)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
def metaclass
|
23
|
+
class << self
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Shippo
|
2
|
+
module Operations
|
3
|
+
module Create
|
4
|
+
module ClassMethods
|
5
|
+
def create(params={})
|
6
|
+
params.each do |k, v|
|
7
|
+
params[k] = v[:object_id] if v.is_a?(ApiObject)
|
8
|
+
end
|
9
|
+
response = Shippo.request(:post, "#{self.url}/", params)
|
10
|
+
self.construct_from(response)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
base.extend(ClassMethods)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/shippo/error.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Shippo
|
2
|
+
class APIError < StandardError
|
3
|
+
attr_reader :message
|
4
|
+
def initialize(message=nil)
|
5
|
+
@message = message
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
@message
|
10
|
+
end
|
11
|
+
end
|
12
|
+
class ConnectionError < APIError
|
13
|
+
end
|
14
|
+
class MissingDataError < APIError
|
15
|
+
end
|
16
|
+
class AuthError < APIError
|
17
|
+
end
|
18
|
+
end
|
data/lib/shippo/list.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Shippo
|
2
|
+
module Operations
|
3
|
+
module List
|
4
|
+
module ClassMethods
|
5
|
+
# return all items
|
6
|
+
def all(params={})
|
7
|
+
response = Shippo.request(:get, "#{url}/", params)
|
8
|
+
self.construct_from(response[:results] || [])
|
9
|
+
end
|
10
|
+
# return a specific item
|
11
|
+
def get(id, params={})
|
12
|
+
response = Shippo.request(:get, "#{url}/#{CGI.escape(id)}/", params)
|
13
|
+
self.construct_from(response)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/shippo/rate.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Shippo
|
2
|
+
class Resource < ApiObject
|
3
|
+
def self.class_name
|
4
|
+
self.name.split('::')[-1]
|
5
|
+
end
|
6
|
+
def self.url()
|
7
|
+
dc = class_name.downcase
|
8
|
+
"/" + dc + (dc[-1] == 's' ? 'es' : 's')
|
9
|
+
end
|
10
|
+
def url
|
11
|
+
unless id = self['object_id']
|
12
|
+
raise MissingDataError.new("#{self.class} has no object_id")
|
13
|
+
end
|
14
|
+
"#{self.class.url}/#{CGI.escape(id)}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def refresh
|
18
|
+
response, api_key = Shippo.request(:get, url, @retrieve_options)
|
19
|
+
refresh_from(response)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Shippo
|
2
|
+
class Shipment < Resource
|
3
|
+
include Shippo::Operations::List
|
4
|
+
include Shippo::Operations::Create
|
5
|
+
def rates(params={})
|
6
|
+
response = Shippo.request(:get, "#{url}/rates/", params)
|
7
|
+
Shippo::Rate.construct_from(response[:results])
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/test/test.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'mocha'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'mocha/test_unit'
|
5
|
+
require 'shippo'
|
6
|
+
def parcel_list_result
|
7
|
+
JSON::parse File.open('./parcel_list.json').read
|
8
|
+
end
|
9
|
+
|
10
|
+
module Shippo
|
11
|
+
class ParcelTest < Test::Unit::TestCase
|
12
|
+
def test_import
|
13
|
+
# get an array of test parcels from JSON
|
14
|
+
ret = Shippo::Parcel.construct_from(parcel_list_result)
|
15
|
+
# test the various options of accessing the parcel data
|
16
|
+
assert_equal ret[:metadata], "Customer ID 123456"
|
17
|
+
ret["metadata"] = "Customer ID 007"
|
18
|
+
assert_equal ret.metadata, "Customer ID 007"
|
19
|
+
assert_equal ret.object_owner, "tobias.schottdorf@gmail.com"
|
20
|
+
ret[:object_owner] = "hans.wurst@gmail.com"
|
21
|
+
assert_equal ret["object_owner"], "hans.wurst@gmail.com"
|
22
|
+
assert_equal ret.object_state, "VALID"
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shippo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Schottdorf
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-03 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Quick and easy access to the Shippo API
|
14
|
+
email: tobias.schottdorf@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- example.rb
|
20
|
+
- test/test.rb
|
21
|
+
- lib/shippo.rb
|
22
|
+
- ./lib/shippo/address.rb
|
23
|
+
- ./lib/shippo/api_object.rb
|
24
|
+
- ./lib/shippo/container_object.rb
|
25
|
+
- ./lib/shippo/create.rb
|
26
|
+
- ./lib/shippo/error.rb
|
27
|
+
- ./lib/shippo/list.rb
|
28
|
+
- ./lib/shippo/parcel.rb
|
29
|
+
- ./lib/shippo/rate.rb
|
30
|
+
- ./lib/shippo/resource.rb
|
31
|
+
- ./lib/shippo/shipment.rb
|
32
|
+
- ./lib/shippo/transaction.rb
|
33
|
+
homepage: http://goshippo.com
|
34
|
+
licenses:
|
35
|
+
- MIT
|
36
|
+
metadata: {}
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 2.0.14
|
54
|
+
signing_key:
|
55
|
+
specification_version: 4
|
56
|
+
summary: Shippo API
|
57
|
+
test_files: []
|