shippo 1.0.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|