shippo 1.0.4 → 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.
- checksums.yaml +4 -4
- data/.atom-build.json +22 -0
- data/.codeclimate.yml +30 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +50 -0
- data/Gemfile +5 -0
- data/Guardfile +39 -0
- data/README.md +288 -0
- data/Rakefile +24 -0
- data/bin/example +114 -0
- data/lib/shippo.rb +23 -97
- data/lib/shippo/api.rb +52 -0
- data/lib/shippo/api/api_object.rb +133 -0
- data/lib/shippo/api/category.rb +49 -0
- data/lib/shippo/api/category/base.rb +144 -0
- data/lib/shippo/api/category/purpose.rb +13 -0
- data/lib/shippo/api/category/source.rb +16 -0
- data/lib/shippo/api/category/state.rb +13 -0
- data/lib/shippo/api/category/status.rb +17 -0
- data/lib/shippo/api/extend/operation.rb +21 -0
- data/lib/shippo/api/extend/transformers.rb +12 -0
- data/lib/shippo/api/extend/url.rb +26 -0
- data/lib/shippo/api/operations.rb +8 -0
- data/lib/shippo/api/operations/create.rb +33 -0
- data/lib/shippo/api/operations/list.rb +22 -0
- data/lib/shippo/api/operations/rates.rb +16 -0
- data/lib/shippo/api/operations/update.rb +12 -0
- data/lib/shippo/api/operations/validate.rb +12 -0
- data/lib/shippo/api/request.rb +159 -0
- data/lib/shippo/api/resource.rb +104 -0
- data/lib/shippo/api/transformers/list.rb +73 -0
- data/lib/shippo/api/version.rb +5 -0
- data/lib/shippo/exceptions.rb +7 -0
- data/lib/shippo/exceptions/api_error.rb +20 -0
- data/lib/shippo/exceptions/error.rb +22 -0
- data/lib/shippo/model/address.rb +5 -0
- data/lib/shippo/model/carrieraccount.rb +5 -0
- data/lib/shippo/model/customs_declaration.rb +6 -0
- data/lib/shippo/model/customs_item.rb +5 -0
- data/lib/shippo/model/manifest.rb +5 -0
- data/lib/shippo/model/parcel.rb +5 -0
- data/lib/shippo/model/rate.rb +5 -0
- data/lib/shippo/model/refund.rb +5 -0
- data/lib/shippo/model/shipment.rb +5 -0
- data/lib/shippo/model/transaction.rb +5 -0
- data/lib/shippo/tasks/shippo.rb +22 -0
- data/shippo.gemspec +34 -0
- metadata +226 -40
- data/example.rb +0 -71
- data/lib/shippo/address.rb +0 -10
- data/lib/shippo/api_object.rb +0 -89
- data/lib/shippo/carrieraccount.rb +0 -8
- data/lib/shippo/container_object.rb +0 -28
- data/lib/shippo/create.rb +0 -18
- data/lib/shippo/customs_declaration.rb +0 -7
- data/lib/shippo/customs_item.rb +0 -7
- data/lib/shippo/error.rb +0 -18
- data/lib/shippo/list.rb +0 -23
- data/lib/shippo/manifest.rb +0 -6
- data/lib/shippo/parcel.rb +0 -6
- data/lib/shippo/rate.rb +0 -5
- data/lib/shippo/refund.rb +0 -6
- data/lib/shippo/resource.rb +0 -29
- data/lib/shippo/shipment.rb +0 -14
- data/lib/shippo/transaction.rb +0 -6
- data/lib/shippo/update.rb +0 -15
- data/test/test.rb +0 -26
data/lib/shippo.rb
CHANGED
@@ -1,104 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
require_relative 'shippo/update.rb'
|
13
|
-
require_relative 'shippo/list.rb'
|
14
|
-
|
15
|
-
|
16
|
-
# api objects
|
17
|
-
require_relative 'shippo/address.rb'
|
18
|
-
require_relative 'shippo/carrieraccount.rb'
|
19
|
-
require_relative 'shippo/customs_item.rb'
|
20
|
-
require_relative 'shippo/customs_declaration.rb'
|
21
|
-
require_relative 'shippo/manifest.rb'
|
22
|
-
require_relative 'shippo/parcel.rb'
|
23
|
-
require_relative 'shippo/rate.rb'
|
24
|
-
require_relative 'shippo/refund.rb'
|
25
|
-
require_relative 'shippo/shipment.rb'
|
26
|
-
require_relative 'shippo/transaction.rb'
|
1
|
+
#
|
2
|
+
# +Shippo+ is the ruby module enclosing all and any ruby-based
|
3
|
+
# functionality developed by Shippo, Inc.
|
4
|
+
#
|
5
|
+
# This gem providers wrappers for Shippo API in ruby. You are
|
6
|
+
# not required to use any particular library to access Shippo
|
7
|
+
# API, but it is our hope that this gem helps you bootstrap your
|
8
|
+
# Shippo integration.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'require_dir'
|
27
12
|
|
28
13
|
module Shippo
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
class << self
|
34
|
-
attr_accessor :api_base, :api_version, :api_token
|
35
|
-
end
|
14
|
+
extend ::RequireDir
|
15
|
+
init_from_source __FILE__
|
16
|
+
end
|
36
17
|
|
37
|
-
|
38
|
-
@api_base + url
|
39
|
-
end
|
18
|
+
require 'shippo/api'
|
40
19
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
begin
|
46
|
-
payload = {}
|
47
|
-
url = api_url(url)
|
48
|
-
headers.merge!(
|
49
|
-
:accept => :json,
|
50
|
-
:content_type => :json,
|
51
|
-
:Authorization => "ShippoToken #{@api_token}"
|
52
|
-
)
|
53
|
-
case method
|
54
|
-
when :get
|
55
|
-
pairs = []
|
56
|
-
params.each { |k, v|
|
57
|
-
pairs.push "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
58
|
-
}
|
59
|
-
url += "?#{pairs.join('&')}" unless pairs.empty?
|
60
|
-
else
|
61
|
-
payload = params.to_json
|
62
|
-
end
|
63
|
-
opts = { :headers => headers,
|
64
|
-
:method => method,
|
65
|
-
:payload => payload,
|
66
|
-
:url => url,
|
67
|
-
:open_timeout => 15,
|
68
|
-
:timeout => 30,
|
69
|
-
:user => @api_user,
|
70
|
-
:password => @api_pass,
|
71
|
-
:user_agent => "Shippo/v1 RubyBindings"
|
72
|
-
}
|
73
|
-
res = make_request(opts)
|
74
|
-
rescue => e
|
75
|
-
case e
|
76
|
-
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
77
|
-
msg = "Could not connect to the Shippo API at #{@api_base}. " +
|
78
|
-
"Please proceed to check your connection, try again and " +
|
79
|
-
"contact Shippo support should the issue persist."
|
80
|
-
raise ConnectionError.new msg + "\n\n(e.message)"
|
81
|
-
when SocketError
|
82
|
-
msg = "Unexpected error connecting to the Shippo API at #{@api_base}."
|
83
|
-
when RestClient::ExceptionWithResponse
|
84
|
-
msg = "error: #{e} #{e.http_body}"
|
85
|
-
else
|
86
|
-
msg = "error: #{e}"
|
87
|
-
end
|
88
|
-
raise APIError.new msg
|
89
|
-
end
|
90
|
-
parse(res)
|
20
|
+
# Backwards compatibility
|
21
|
+
module Shippo
|
22
|
+
def self.api_key(value)
|
23
|
+
::Shippo::API.token = value
|
91
24
|
end
|
92
|
-
|
93
|
-
|
25
|
+
class << self
|
26
|
+
alias_method :api_key=, :api_key
|
27
|
+
alias_method :api_token=, :api_key
|
94
28
|
end
|
95
29
|
end
|
96
|
-
|
97
|
-
RestClient::Request.execute(opts){ |response, request, result, &block|
|
98
|
-
if [301, 302, 307].include? response.code
|
99
|
-
response.follow_redirection(request, result, &block)
|
100
|
-
else
|
101
|
-
response.return!(request, result, &block)
|
102
|
-
end
|
103
|
-
}
|
104
|
-
end
|
30
|
+
|
data/lib/shippo/api.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'json'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
require_relative '../shippo' unless defined?(Shippo) && Shippo.respond_to?(:dir_r)
|
6
|
+
|
7
|
+
require 'shippo/exceptions'
|
8
|
+
require 'shippo/api/category'
|
9
|
+
require 'shippo/api/request'
|
10
|
+
require 'shippo/api/resource'
|
11
|
+
|
12
|
+
module Shippo
|
13
|
+
module API
|
14
|
+
@base = 'https://api.goshippo.com/v1'
|
15
|
+
@version = 1.0
|
16
|
+
@token = ''
|
17
|
+
@debug = Integer(ENV['SHIPPO_DEBUG'] || 0) > 0 ? true : false
|
18
|
+
@warnings = true
|
19
|
+
|
20
|
+
class << self
|
21
|
+
attr_accessor :base, :version, :token, :debug, :warnings
|
22
|
+
# @param [Symbol] method One of :get, :put, :post
|
23
|
+
# @param [String] uri the URL component after the first slash but before params
|
24
|
+
# @param [Hash] params hash of optional parameters to add to the URL
|
25
|
+
# @param [Hash] headers optionally added headers
|
26
|
+
def request(method, uri, params = {}, headers = {})
|
27
|
+
::Shippo::API::Request.new(method: method,
|
28
|
+
uri: uri,
|
29
|
+
params: params,
|
30
|
+
headers: headers).execute
|
31
|
+
end
|
32
|
+
|
33
|
+
%i[get put post].each do |method|
|
34
|
+
define_method method do |*args|
|
35
|
+
uri, params, headers = *args
|
36
|
+
request(method, uri, params || {}, headers || {})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def debug?
|
41
|
+
Shippo::API.debug
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Shippo.dir('shippo/api')
|
48
|
+
Shippo.dir('shippo/api/transformers')
|
49
|
+
Shippo.dir('shippo/api/extend')
|
50
|
+
Shippo.dir('shippo/model')
|
51
|
+
|
52
|
+
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'hashie/dash'
|
2
|
+
require 'hashie/extensions/stringify_keys'
|
3
|
+
require 'hashie/extensions/symbolize_keys'
|
4
|
+
require 'hashie/extensions/dash/property_translation'
|
5
|
+
require 'active_support/inflector'
|
6
|
+
|
7
|
+
module Shippo
|
8
|
+
module API
|
9
|
+
# +ApiObject+ is a class that contains only a set of specific fields
|
10
|
+
# that can be used in both requests and responses from Shippo API.
|
11
|
+
# Upon return with each response, +ApiObject+ instance is automatically
|
12
|
+
# created and populated with fields that begin with a prefix `object_`.
|
13
|
+
# The prefix is deleted, and the fields are made available through the
|
14
|
+
# non-prefixed accessors.
|
15
|
+
#
|
16
|
+
# This class uses +Hashie::Dash+ under the hood, in order to provide convenient
|
17
|
+
# transformations, support required/optional attributes, etc.
|
18
|
+
#
|
19
|
+
#
|
20
|
+
# == Example
|
21
|
+
#
|
22
|
+
# ```ruby
|
23
|
+
# response = {
|
24
|
+
# "object_state" => "VALID",
|
25
|
+
# "object_purpose" => "PURCHASE",
|
26
|
+
# "object_source" => "FULLY_ENTERED",
|
27
|
+
# "object_created" => "2014-07-16T23:20:31.089Z",
|
28
|
+
# "object_updated" => "2014-07-16T23:20:31.089Z",
|
29
|
+
# "object_id" => "747207de2ba64443b645d08388d0309c",
|
30
|
+
# "object_owner" => "shippotle@goshippo.com",
|
31
|
+
# "name" => "Shawn Ippotle",
|
32
|
+
# "company" => "Shippo",
|
33
|
+
# "street1" => "215 Clayton St.",
|
34
|
+
# "street2" => "",
|
35
|
+
# "city" => "San Francisco",
|
36
|
+
# "state" => "CA",
|
37
|
+
# "zip" => "94117",
|
38
|
+
# "country" => "US",
|
39
|
+
# "phone" => "+1 555 341 9393",
|
40
|
+
# "email" => "shippotle@goshippo.com"
|
41
|
+
# }
|
42
|
+
#
|
43
|
+
# require 'shippo'
|
44
|
+
# address = Shippo::Address.from(response)
|
45
|
+
# address.name
|
46
|
+
# # ⤷ Shawn Ippotle
|
47
|
+
# require 'ap'
|
48
|
+
# ap address.object
|
49
|
+
# # ⤷
|
50
|
+
# {
|
51
|
+
# :state => #<Shippo::API::Category::State:0x007fd374b4d0d0 @name=:state, @value=:valid>,
|
52
|
+
# :purpose => #<Shippo::API::Category::Purpose:0x007fd373df2070 @name=:purpose, @value=:purchase>,
|
53
|
+
# :source => #<Shippo::API::Category::Source:0x007fd374b4fbf0 @name=:source, @value=:fully_entered>,
|
54
|
+
# :created => 2014-07-16 23:20:31 UTC,
|
55
|
+
# :updated => 2014-07-16 23:20:31 UTC,
|
56
|
+
# :id => "747207de2ba64443b645d08388d0309c",
|
57
|
+
# :owner => "shippotle@goshippo.com"
|
58
|
+
# }
|
59
|
+
# ```
|
60
|
+
class ApiObject < Hashie::Dash
|
61
|
+
include Hashie::Extensions::Dash::PropertyTranslation
|
62
|
+
|
63
|
+
PREFIX = { id: 'resource_', default: 'object_' }.freeze
|
64
|
+
|
65
|
+
class << self
|
66
|
+
def field_name(property)
|
67
|
+
"#{PREFIX[property.to_sym] || PREFIX[:default]}#{property}".to_sym
|
68
|
+
end
|
69
|
+
|
70
|
+
def matches_prefix?(value)
|
71
|
+
%r[^(#{PREFIX.values.join('|')})].match(value.to_s)
|
72
|
+
end
|
73
|
+
|
74
|
+
def mk_opts(property)
|
75
|
+
{ with: ->(value) { value }, from: "#{field_name(property)}".to_sym, required: false }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# list of allowed properties, of a given type.
|
80
|
+
PROPS_ID = %i(id).freeze
|
81
|
+
PROPS_CATEG = %i(state purpose source status).freeze
|
82
|
+
PROPS_EMAIL = %i(owner).freeze
|
83
|
+
PROPS_TIMED = %i(created updated).freeze
|
84
|
+
|
85
|
+
PROPS = (PROPS_ID + PROPS_EMAIL + PROPS_TIMED + PROPS_CATEG ).flatten.freeze
|
86
|
+
PROPS_AS_IS = (PROPS_EMAIL + PROPS_ID).freeze
|
87
|
+
|
88
|
+
def self.setup_property(prop, custom = {})
|
89
|
+
property prop, self.mk_opts(prop).merge(custom)
|
90
|
+
end
|
91
|
+
|
92
|
+
PROPS_AS_IS.each { |prop| setup_property(prop) }
|
93
|
+
PROPS_TIMED.each { |prop| setup_property(prop, with: ->(value) { Time.parse(value) } ) }
|
94
|
+
PROPS_EMAIL.each { |prop| setup_property(prop, with: ->(value) {
|
95
|
+
value && value.strip!
|
96
|
+
value = "#{value}@gmail.com" if value and value !~ %r[.*@.*\..*]
|
97
|
+
value
|
98
|
+
})
|
99
|
+
}
|
100
|
+
PROPS_CATEG.each { |prop| setup_property(prop, with: ->(value) {
|
101
|
+
Shippo::API::Category.for(prop, value)
|
102
|
+
})
|
103
|
+
}
|
104
|
+
|
105
|
+
def self.create_object(h)
|
106
|
+
object_keys = h.keys.select { |k| matches_prefix?(k) }
|
107
|
+
h_object = {}
|
108
|
+
object_keys.each { |k| h_object[k.to_s] = h[k] }
|
109
|
+
instance = self.new(h_object)
|
110
|
+
object_keys.each { |k| h.delete(k) if h.key(k) }
|
111
|
+
instance
|
112
|
+
end
|
113
|
+
|
114
|
+
def initialize(*args)
|
115
|
+
opts = args.first
|
116
|
+
if opts && opts.respond_to?(:keys)
|
117
|
+
Hashie::Extensions::SymbolizeKeys.symbolize_keys!(opts)
|
118
|
+
if opts[:object_id]
|
119
|
+
opts[(PREFIX[:id] + 'id').to_sym] = opts[:object_id]
|
120
|
+
opts.delete(:object_id)
|
121
|
+
end
|
122
|
+
super(opts)
|
123
|
+
else
|
124
|
+
super(args)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_s
|
129
|
+
Shippo::API::Resource.short_name(self.class.name) + self.to_hash.to_s
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'hashie/dash'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'shippo/exceptions'
|
4
|
+
module Shippo
|
5
|
+
module API
|
6
|
+
# For enumerations with discrete possible set of values, +Category+ class
|
7
|
+
# offers it's subclasses and users tremendous benefits.
|
8
|
+
#
|
9
|
+
# Categories should be always created via the Facåde
|
10
|
+
# +Shippo::API::Category.for(name, value)+. Although it is possible to
|
11
|
+
# directly instantiate subclasses, it is not recommended for performance reasons.
|
12
|
+
#
|
13
|
+
# == Example
|
14
|
+
#
|
15
|
+
# ```ruby
|
16
|
+
# require 'shippo/api'
|
17
|
+
# class My::Big::Module::Size < ::Shippo::API::Category::Base
|
18
|
+
# allowed_values :small, :medium, :large, :xlarge, :xxlarge
|
19
|
+
# end
|
20
|
+
# # ⤷ [:small, :medium, :large, :xlarge, :xxlarge]
|
21
|
+
#
|
22
|
+
# my_size = Shippo::API::Category.for('size', 'xlarge')
|
23
|
+
# # ⤷ XLARGE
|
24
|
+
# my_size.class.name
|
25
|
+
# # ⤷ My::Big::Module::Size
|
26
|
+
# ```
|
27
|
+
|
28
|
+
module Category
|
29
|
+
@categories = {}
|
30
|
+
class << self
|
31
|
+
attr_accessor :categories
|
32
|
+
end
|
33
|
+
|
34
|
+
class DuplicateValueError < ::Shippo::Exceptions::APIError;
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.key(value)
|
38
|
+
value.to_s.downcase.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.for(name, value)
|
42
|
+
cat = self.categories[name.to_s.downcase.to_sym]
|
43
|
+
cat ? cat[value.to_s.downcase.to_sym] : nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Shippo.dir('shippo/api/category')
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module Shippo
|
2
|
+
module API
|
3
|
+
module Category
|
4
|
+
# +Base+ is a convenience abstract class that provides the following functionality
|
5
|
+
# to it's subclasses, which are meant to be enumerations with a fixed number of possible
|
6
|
+
# values.
|
7
|
+
#
|
8
|
+
# Base populates a global hash +Shippo::API::Category.categories+ which is keyed by the
|
9
|
+
# lower cased and symbolized category name (eg, :status or :purpose), each value is another
|
10
|
+
# hash consisting of keys (values of each category, eg :success, :error) and value being the
|
11
|
+
# constant created for such a value.
|
12
|
+
#
|
13
|
+
# __WARNING__: You are not supposed to instantiate these classes, to be honest. The
|
14
|
+
# "correct" way is via the Facåde +Shippo::API::Category.for(name, value)+.
|
15
|
+
#
|
16
|
+
# == Example
|
17
|
+
#
|
18
|
+
# ```ruby
|
19
|
+
# require 'shippo/api'
|
20
|
+
# class Size < ::Shippo::API::Category::Base
|
21
|
+
# allowed_values :small, :medium, :large, :xlarge, :xxlarge
|
22
|
+
# end
|
23
|
+
# # ⤷ [:small, :medium, :large, :xlarge, :xxlarge]
|
24
|
+
#
|
25
|
+
# my_size = Shippo::API::Category.for('size', 'xlarge')
|
26
|
+
# # ⤷ size:xlarge
|
27
|
+
#
|
28
|
+
# my_size.xlarge?
|
29
|
+
# # ⤷ true
|
30
|
+
# my_size.medium?
|
31
|
+
# # ⤷ false
|
32
|
+
# my_size.name
|
33
|
+
# # ⤷ size
|
34
|
+
# my_size.value
|
35
|
+
# # ⤷ xlarge
|
36
|
+
#
|
37
|
+
# medium_1 = Size.new('medium')
|
38
|
+
# ⤷ size:medium
|
39
|
+
# medium_2 = Size.new('medium')
|
40
|
+
# ⤷ size:medium
|
41
|
+
# medium_3 = Shippo::API::Category.for(:size, :medium)
|
42
|
+
# ⤷ size:medium
|
43
|
+
#
|
44
|
+
# # But keep in mind these instances are all different objects,
|
45
|
+
# # which are +eql?()+ to each other, but not identical.
|
46
|
+
# medium_1.object_id
|
47
|
+
# # ⤷ 70282669124280
|
48
|
+
# medium_2.object_id
|
49
|
+
# # ⤷ 70282669580500
|
50
|
+
# medium_3.object_id
|
51
|
+
# # ⤷ 70282681963740
|
52
|
+
# medium_1.eql?(medium_2)
|
53
|
+
# # ⤷ true
|
54
|
+
# medium_2.eql?(medium_3)
|
55
|
+
# # ⤷ true
|
56
|
+
# ```
|
57
|
+
#
|
58
|
+
class Base
|
59
|
+
|
60
|
+
@categories = Shippo::API::Category.categories
|
61
|
+
class << self
|
62
|
+
attr_accessor :categories
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.inherited(klazz)
|
66
|
+
klazz.instance_eval do
|
67
|
+
@allowed_values = Set.new
|
68
|
+
class << self
|
69
|
+
def categories
|
70
|
+
::Shippo::API::Category::Base.categories
|
71
|
+
end
|
72
|
+
|
73
|
+
def value_transformer(values)
|
74
|
+
values.map(&:downcase).map(&:to_sym)
|
75
|
+
end
|
76
|
+
|
77
|
+
def allowed_values(*values)
|
78
|
+
return @allowed_values if values.nil? || values.empty? || !@allowed_values.empty?
|
79
|
+
|
80
|
+
@allowed_values = self.value_transformer(values)
|
81
|
+
@allowed_values.each do |allowed_value|
|
82
|
+
category_value = Category.key(allowed_value)
|
83
|
+
category_const = category_value.to_s.upcase
|
84
|
+
|
85
|
+
raise ::Shippo::API::Category::DuplicateValueError.new(
|
86
|
+
"Constant #{category_const} is already defined in #{self.name}") if self.const_defined?(category_const)
|
87
|
+
|
88
|
+
new_instance = self.new(category_value)
|
89
|
+
self.const_set(category_const, new_instance)
|
90
|
+
|
91
|
+
define_method "#{category_value}?".to_sym do
|
92
|
+
value.eql?(category_value)
|
93
|
+
end
|
94
|
+
|
95
|
+
categories[new_instance.name] ||= {}
|
96
|
+
categories[new_instance.name][new_instance.value] = new_instance
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
attr_accessor :name, :value
|
104
|
+
|
105
|
+
def initialize(value)
|
106
|
+
raise ::Shippo::Exceptions::AbstractClassInitError.new('Can not instantiate Base!') if self.class.eql?(::Shippo::API::Category::Base)
|
107
|
+
self.name = Category.key(self.class.name.gsub(%r{.*::}, ''))
|
108
|
+
self.value = assign_value(value)
|
109
|
+
end
|
110
|
+
|
111
|
+
def eql?(other)
|
112
|
+
self.class.eql?(other.class) && self.value.eql?(other.value)
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_s
|
116
|
+
"#{self.value.upcase}"
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def value_allowed?(value)
|
122
|
+
self.class.allowed_values.include?(value)
|
123
|
+
end
|
124
|
+
|
125
|
+
def assign_value(value)
|
126
|
+
value = clean(value)
|
127
|
+
|
128
|
+
if value_allowed?(value)
|
129
|
+
@value = value
|
130
|
+
else
|
131
|
+
raise ::Shippo::Exceptions::InvalidCategoryValueError.new(
|
132
|
+
"Value #{value} is not allowed for Category #{self.class.name}, allowed values are: #{self.class.allowed_values})")
|
133
|
+
end
|
134
|
+
@value
|
135
|
+
end
|
136
|
+
|
137
|
+
def clean(value)
|
138
|
+
Category.key(value)
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|