easypost 1.1.3 → 2.0.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.
@@ -0,0 +1,4 @@
1
+ module EasyPost
2
+ class CustomsInfo < Resource
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module EasyPost
2
+ class CustomsItem < Resource
3
+ end
4
+ end
@@ -1,15 +1,24 @@
1
1
  module EasyPost
2
- class EasyPostError < StandardError
2
+ class Error < StandardError
3
3
  attr_reader :message
4
4
  attr_reader :http_status
5
5
  attr_reader :http_body
6
6
  attr_reader :json_body
7
+ attr_reader :param
7
8
 
8
9
  def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
9
10
  @message = message
10
11
  @http_status = http_status
11
12
  @http_body = http_body
12
13
  @json_body = json_body
14
+
15
+ begin
16
+ @param = @json_body[:error][:param]
17
+ rescue
18
+ @param = nil
19
+ end
20
+
21
+ super(message)
13
22
  end
14
23
 
15
24
  def to_s
@@ -0,0 +1,120 @@
1
+ module EasyPost
2
+ class EasyPostObject
3
+ include Enumerable
4
+
5
+ attr_accessor :api_key
6
+ @@immutable_values = Set.new([:api_key, :id])
7
+
8
+ def initialize(id=nil, api_key=nil)
9
+ @api_key = api_key
10
+ @values = {}
11
+ @unsaved_values = Set.new
12
+ @transient_values = Set.new
13
+ self.id = id if id
14
+ end
15
+
16
+ def self.construct_from(values, api_key=nil)
17
+ obj = self.new(values[:id], api_key)
18
+ obj.refresh_from(values, api_key)
19
+ obj
20
+ end
21
+
22
+ def to_s(*args)
23
+ MultiJson.dump(@values, :pretty => true)
24
+ end
25
+
26
+ def inspect()
27
+ id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
28
+ "#<#{self.class}:#{id_string}> JSON: " + MultiJson.dump(@values, :pretty => true)
29
+ end
30
+
31
+ def refresh_from(values, api_key, partial=false)
32
+ @api_key = api_key
33
+
34
+ added = Set.new(values.keys - @values.keys)
35
+
36
+ instance_eval do
37
+ add_accessors(added)
38
+ end
39
+
40
+ values.each do |k, v|
41
+ @values[k] = Util.convert_to_easypost_object(v, api_key)
42
+ @transient_values.delete(k)
43
+ @unsaved_values.delete(k)
44
+ end
45
+ end
46
+
47
+ def [](k)
48
+ k = k.to_sym if k.is_a?(String)
49
+ @values[k]
50
+ end
51
+
52
+ def []=(k, v)
53
+ send(:"#{k}=", v)
54
+ end
55
+
56
+ def keys
57
+ @values.keys
58
+ end
59
+
60
+ def values
61
+ @values.values
62
+ end
63
+
64
+ def to_json(options = {})
65
+ MultiJson.dump(@values)
66
+ end
67
+
68
+ def as_json(options = {})
69
+ @values.as_json
70
+ end
71
+
72
+ def to_hash
73
+ @values
74
+ end
75
+
76
+ def each(&blk)
77
+ @values.each(&blk)
78
+ end
79
+
80
+ def id=(id)
81
+ @values[:id] = id
82
+ end
83
+
84
+ def id
85
+ @values[:id]
86
+ end
87
+
88
+ protected
89
+
90
+ def metaclass
91
+ class << self; self; end
92
+ end
93
+
94
+ def remove_accessors(keys)
95
+ metaclass.instance_eval do
96
+ keys.each do |k|
97
+ next if @@immutable_values.include?(k)
98
+ k_eq = :"#{k}="
99
+ remove_method(k) if method_defined?(k)
100
+ remove_method(k_eq) if method_defined?(k_eq)
101
+ end
102
+ end
103
+ end
104
+
105
+ def add_accessors(keys)
106
+ metaclass.instance_eval do
107
+ keys.each do |k|
108
+ next if @@immutable_values.include?(k)
109
+ k_eq = :"#{k}="
110
+ define_method(k) { @values[k] }
111
+ define_method(k_eq) do |v|
112
+ @values[k] = v
113
+ @unsaved_values.add(k)
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,4 @@
1
+ module EasyPost
2
+ class Parcel < Resource
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module EasyPost
2
+ class PostageLabel < Resource
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module EasyPost
2
+ class Rate < Resource
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module EasyPost
2
+ class Refund < Resource
3
+ end
4
+ end
@@ -0,0 +1,67 @@
1
+ module EasyPost
2
+ class Resource < EasyPostObject
3
+ def self.class_name
4
+ camel = self.name.split('::')[-1]
5
+ snake = camel[0..0] + camel[1..-1].gsub(/([A-Z])/, '_\1')
6
+ return snake.downcase
7
+ end
8
+
9
+ def self.url
10
+ if self.class_name == 'resource'
11
+ raise NotImplementedError.new('Resource is an abstract class. You should perform actions on its subclasses (Address, Shipment, etc.)')
12
+ end
13
+ if(self.class_name[-1..-1] == 's' || self.class_name[-1..-1] == 'h')
14
+ return "/#{CGI.escape(self.class_name.downcase)}es"
15
+ else
16
+ return "/#{CGI.escape(class_name.downcase)}s"
17
+ end
18
+ end
19
+
20
+ def url
21
+ unless self.id
22
+ raise Error.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{self.id.inspect}")
23
+ end
24
+ return "#{self.class.url}/#{CGI.escape(id)}"
25
+ end
26
+
27
+ def refresh
28
+ response, api_key = EasyPost.request(:get, url, @api_key, @retrieve_options)
29
+ refresh_from(response, api_key)
30
+ return self
31
+ end
32
+
33
+ def self.all(filters={}, api_key=nil)
34
+ response, api_key = EasyPost.request(:get, url, api_key, filters)
35
+ return Util.convert_to_easypost_object(response, api_key)
36
+ end
37
+
38
+ def self.retrieve(id, api_key=nil)
39
+ instance = self.new(id, api_key)
40
+ instance.refresh
41
+ return instance
42
+ end
43
+
44
+ def self.create(params={}, api_key=nil)
45
+ wrapped_params = {}
46
+ wrapped_params[self.class_name().to_sym] = params
47
+ response, api_key = EasyPost.request(:post, self.url, api_key, wrapped_params)
48
+ return Util.convert_to_easypost_object(response, api_key)
49
+ end
50
+
51
+ def delete
52
+ response, api_key = EasyPost.request(:delete, url, @api_key)
53
+ refresh_from(response, api_key)
54
+ return self
55
+ end
56
+
57
+ def save
58
+ if @unsaved_values.length > 0
59
+ values = {}
60
+ @unsaved_values.each { |k| values[k] = @values[k] }
61
+ response, api_key = EasyPost.request(:post, url, @api_key, values)
62
+ refresh_from(response, api_key)
63
+ end
64
+ return self
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,4 @@
1
+ module EasyPost
2
+ class ScanForm < Resource
3
+ end
4
+ end
@@ -0,0 +1,82 @@
1
+ module EasyPost
2
+ class Shipment < Resource
3
+
4
+ def get_rates(params={})
5
+ response, api_key = EasyPost.request(:get, url + '/rates', @api_key, params)
6
+ self.refresh_from(response, @api_key, true)
7
+
8
+ return self
9
+ end
10
+
11
+ def buy(params={})
12
+ response, api_key = EasyPost.request(:post, url + '/buy', @api_key, params)
13
+ self.refresh_from(response, @api_key, true)
14
+
15
+ return self
16
+ end
17
+
18
+ def refund(params={})
19
+ response, api_key = EasyPost.request(:get, url + '/refund', @api_key, params)
20
+ self.refresh_from(response, @api_key, true)
21
+
22
+ return self
23
+ end
24
+
25
+ def track(params={})
26
+ response, api_key = EasyPost.request(:get, url + '/track', @api_key, params)
27
+ self.refresh_from(response, @api_key, true)
28
+
29
+ return self
30
+ end
31
+
32
+ def stamp(params={})
33
+ response, api_key = EasyPost.request(:get, url + '/stamp', @api_key, params)
34
+
35
+ return response[:stamp_url]
36
+ end
37
+
38
+ def barcode(params={})
39
+ response, api_key = EasyPost.request(:get, url + '/barcode', @api_key, params)
40
+
41
+ return response[:barcode_url]
42
+ end
43
+
44
+ def lowest_rate(carriers=[], services=[])
45
+ lowest = nil
46
+
47
+ self.get_rates unless self.rates
48
+
49
+ if !carriers.is_a?(Array)
50
+ carriers = carriers.split(',')
51
+ end
52
+ carriers.map!(&:downcase)
53
+
54
+ if !services.is_a?(Array)
55
+ services = services.split(',')
56
+ end
57
+ services.map!(&:downcase)
58
+
59
+ self.rates.each do |k|
60
+
61
+ rate_carrier = k.carrier.downcase
62
+ if carriers.size() > 0 && !carriers.include?(rate_carrier)
63
+ next
64
+ end
65
+
66
+ rate_service = k.service.downcase
67
+ if services.size() > 0 && !services.include?(rate_service)
68
+ next
69
+ end
70
+
71
+ if lowest == nil || k.rate.to_f < lowest.rate.to_f
72
+ lowest = k
73
+ end
74
+ end
75
+
76
+ raise Error.new('No rates found.') if lowest == nil
77
+
78
+ return lowest
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,102 @@
1
+ module EasyPost
2
+ module Util
3
+ def self.objects_to_ids(obj)
4
+ case obj
5
+ when Resource
6
+ return {:id => obj.id}
7
+ when Hash
8
+ result = {}
9
+ obj.each { |k, v| result[k] = objects_to_ids(v) unless v.nil? }
10
+ return result
11
+ when Array
12
+ return obj.map { |v| objects_to_ids(v) }
13
+ else
14
+ return obj
15
+ end
16
+ end
17
+
18
+ def self.convert_to_easypost_object(response, api_key)
19
+ types = { 'Address' => Address,
20
+ 'ScanForm' => ScanForm,
21
+ 'CustomsItem' => CustomsItem,
22
+ 'CustomsInfo' => CustomsInfo,
23
+ 'Parcel' => Parcel,
24
+ 'Shipment' => Shipment,
25
+ 'Rate' => Rate,
26
+ 'Refund' => Refund,
27
+ 'Batch' => Batch,
28
+ 'PostageLabel' => PostageLabel }
29
+
30
+ prefixes = { 'adr' => Address,
31
+ 'sf' => ScanForm,
32
+ 'cstitem' => CustomsItem,
33
+ 'cstinfo' => CustomsInfo,
34
+ 'prcl' => Parcel,
35
+ 'shp' => Shipment,
36
+ 'rate' => Rate,
37
+ 'rfnd' => Refund,
38
+ 'batch' => Batch,
39
+ 'pl' => PostageLabel }
40
+
41
+ case response
42
+ when Array
43
+ return response.map { |i| convert_to_easypost_object(i, api_key) }
44
+ when Hash
45
+ if cls_name = response[:object]
46
+ cls = types[cls_name]
47
+ elsif response[:id] && cls_prefix = response[:id][0..response[:id].index('_')]
48
+ cls = prefixes[cls_prefix[0..-2]]
49
+ end
50
+
51
+ cls ||= EasyPostObject
52
+ return cls.construct_from(response, api_key)
53
+ else
54
+ return response
55
+ end
56
+ end
57
+
58
+ def self.symbolize_names(obj)
59
+ case obj
60
+ when Hash
61
+ result = {}
62
+ obj.each do |k, v|
63
+ k = (k.to_sym rescue k) || k
64
+ obj[k] = symbolize_names(v)
65
+ end
66
+ return result
67
+ when Array
68
+ return obj.map { |v| symbolize_names(v) }
69
+ else
70
+ return obj
71
+ end
72
+ end
73
+
74
+ def self.url_encode(key)
75
+ URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
76
+ end
77
+
78
+ def self.flatten_params(params, parent_key=nil)
79
+ result = []
80
+ if params.is_a?(Hash)
81
+ params.each do |k, v|
82
+ calculated_key = parent_key ? "#{parent_key}[#{url_encode(k)}]" : url_encode(k)
83
+ if v.is_a?(Hash) or v.is_a?(Array)
84
+ result += flatten_params(v, calculated_key)
85
+ else
86
+ result << [calculated_key, v]
87
+ end
88
+ end
89
+ elsif params.is_a?(Array)
90
+ params.each_with_index do |v, i|
91
+ calculated_key = parent_key ? "#{parent_key}[#{i}]" : i
92
+ if v.is_a?(Hash) or v.is_a?(Array)
93
+ result += flatten_params(v, calculated_key)
94
+ else
95
+ result << [calculated_key, v]
96
+ end
97
+ end
98
+ end
99
+ return result
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,3 @@
1
+ module EasyPost
2
+ VERSION = "2.0.0"
3
+ end