unleashed 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab9f52896f8b680ac28a67a8716d0e1bafb0213be69e5e3c4ff6ceb1f6898f0e
4
- data.tar.gz: 9facbcd5c5592d277b3cb3220534a38629c7d109556c971fd48f129e73c05331
3
+ metadata.gz: 147bdc99b6e8ce42af1eb564d90374ccaa7ae220b41b3ccc5fed0fee3e23bb6e
4
+ data.tar.gz: b5f3fc37b96ee6c404c95e00b33822f8025015b6e2dbe781ec25711d469a1d5d
5
5
  SHA512:
6
- metadata.gz: e4195bce78819508d81b6ec88b7b166e7a4cb84a7338e26b90bb58e6b5e88e45d2e35a1428af19df4447cab4599e698e78516abc9fa455a1c828c3975ea5b3eb
7
- data.tar.gz: 2f045fc73f056945c9288efb6cf1144ce8f6e29032dbe1a76445614f441e48b32f1d8bd1ec1f42260b1e667147af27d0b1d1a359d903bd3f182f4ad5d3dbb731
6
+ metadata.gz: 334ecfd9f511222c578654b81e2a7054c16a7a2ed9f05b6b670e41119b8527c6cb714a024e5c56efb0a00fc1756f847d4b2285efccc0684ac1d5ae8211c0686a
7
+ data.tar.gz: c9534ae24edb3ec3b933f1cbb5dc47510883583d93f9d20ca197a757542efc6d17085e8bc2cae1863ba14f16fd9846b25e04caa224e3ac517003923ef7c8468d
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.1.4] - 2019-11-11
6
+
7
+ - Add `Customer` resource
8
+ - Add `json` and `faraday` gems
9
+
10
+ ## [0.1.0] - 2019-11-08
11
+
12
+ - Init project
13
+
14
+ ### Added
15
+
16
+ - Added ability to request data.
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -0,0 +1,159 @@
1
+ require_relative 'configurable'
2
+ require_relative 'error'
3
+ require_relative 'models/base_model'
4
+ require_relative 'models/customer'
5
+ require_relative 'resources/base_resource'
6
+ require_relative 'resources/customer_resource'
7
+ require 'json'
8
+ require 'faraday'
9
+
10
+ module Unleashed
11
+ # Client for the Unleashed API
12
+ #
13
+ # @see https://apidocs.unleashedsoftware.com
14
+ class Client
15
+ include Unleashed::Configurable
16
+
17
+ def initialize(options = {})
18
+ # Use options passed in, but fall back to module defaults
19
+ Unleashed::Configurable.keys.each do |key|
20
+ instance_variable_set(
21
+ :"@#{key}", options[key] || Unleashed.instance_variable_get(:"@#{key}")
22
+ )
23
+ end
24
+ end
25
+
26
+ # Create a new Faraday connection
27
+ #
28
+ # @return [Faraday::Connection]
29
+ def connection
30
+ Faraday.new(url: @api_endpoint) do |faraday|
31
+ faraday.adapter :net_http
32
+ end
33
+ end
34
+
35
+ # Create a signature for request
36
+ def signature(params = '')
37
+ hash = OpenSSL::HMAC.digest('sha256', @api_key, params)
38
+ Base64.strict_encode64(hash)
39
+ end
40
+
41
+ def init_default_headers(request)
42
+ request.headers['client-type'] = @client_type_header
43
+ request.headers['Accept'] = 'application/json'
44
+ request.headers['Content-Type'] = 'application/json'
45
+ request.headers['api-auth-id'] = @api_id
46
+ request.headers['api-auth-signature'] = signature(request.params.to_query)
47
+ end
48
+
49
+ # Make a HTTP GET request
50
+ #
51
+ # @param url [String] The path, relative to {api_endpoint}
52
+ # @param parameters [Hash] Query params for request
53
+ # @return [Faraday::Response]
54
+ def get(url, parameters = {}, headers = {}, skip_status_check = false)
55
+ response = connection.get do |request|
56
+ request.url "#{api_endpoint}#{url}"
57
+ request.params = parameters
58
+
59
+ # Set headers
60
+ init_default_headers(request)
61
+
62
+ # Assign more custom headers
63
+ headers.each do |key, value|
64
+ request.headers[key] = value
65
+ end
66
+ end
67
+
68
+ on_complete(response) unless skip_status_check
69
+ response
70
+ end
71
+
72
+ # # Make a HTTP POST request
73
+ # #
74
+ # # @param url [String] The path, relative to {#api_endpoint}
75
+ # # @param parameters [Hash] Query params for request
76
+ # # @return [Faraday::Response]
77
+ # def post(url, parameters = {})
78
+ # response = connection.post do |req|
79
+ # req.url "#{api_endpoint}#{url}"
80
+ # req.headers['Content-Type'] = 'application/json'
81
+ # req.body = parameters.to_json
82
+ # end
83
+ # on_complete(response)
84
+ # response
85
+ # end
86
+
87
+ # # Make a HTTP PATCH request
88
+ # #
89
+ # # @param url [String] The path, relative to {#api_endpoint}
90
+ # # @param parameters [Hash] Query params for request
91
+ # # @return [Faraday::Response]
92
+ # def patch(url, parameters = {})
93
+ # response = connection.patch do |req|
94
+ # req.url "#{api_endpoint}#{url}"
95
+ # req.headers['Content-Type'] = 'application/json'
96
+ # req.body = parameters.to_json
97
+ # end
98
+ # on_complete(response)
99
+ # response
100
+ # end
101
+
102
+ # # Make a HTTP DELETE request
103
+ # #
104
+ # # @param url [String] The path, relative to {#api_endpoint}
105
+ # # @param parameters [Hash] Query params for request
106
+ # # @return [Faraday::Response]
107
+ # def delete(url, parameters = {})
108
+ # response = connection.delete do |req|
109
+ # req.url "#{api_endpoint}#{url}"
110
+ # req.headers['Content-Type'] = 'application/json'
111
+ # req.body = parameters.to_json
112
+ # end
113
+ # on_complete(response)
114
+ # response
115
+ # end
116
+
117
+ # Show details of your Platform.
118
+ #
119
+ # @see https://reference.Unleashed.com/#show-marketplace
120
+ #
121
+ # @return [Hash]
122
+ def marketplace
123
+ JSON.parse(get('marketplace').body)['marketplaces']
124
+ end
125
+
126
+ # Available resources for {Client}
127
+ #
128
+ # @return [Hash]
129
+ def self.resources
130
+ {
131
+ customers: CustomerResource
132
+ }
133
+ end
134
+
135
+ # Catch calls for resources
136
+ #
137
+ def method_missing(name, *args, &block)
138
+ if self.class.resources.keys.include?(name)
139
+ resources[name] ||= self.class.resources[name].new(self)
140
+ resources[name]
141
+ else
142
+ super
143
+ end
144
+ end
145
+
146
+ # Resources being currently used
147
+ #
148
+ # @return [Hash]
149
+ def resources
150
+ @resources ||= {}
151
+ end
152
+
153
+ private
154
+
155
+ def on_complete(response)
156
+ fail Unleashed::Error.from_response(response, @errors_format) unless response.success?
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,40 @@
1
+ module Unleashed
2
+ # Configuration options for {Client}, defaulting to values in {Default}.
3
+ module Configurable
4
+ attr_accessor :api_domain, :api_id, :api_key, :client_type_header, :errors_format
5
+
6
+ class << self
7
+ # List of configurable keys for {Unleashed::Client}.
8
+ #
9
+ # @return [Array] of option keys
10
+ def keys
11
+ @keys ||= [
12
+ :api_domain,
13
+ :api_id,
14
+ :api_key,
15
+ :client_type_header,
16
+ :errors_format
17
+ ]
18
+ end
19
+ end
20
+
21
+ # Reset configuration options to default values.
22
+ def reset!
23
+ Unleashed::Configurable.keys.each do |key|
24
+ instance_variable_set(:"@#{key}", Unleashed::Default.options[key])
25
+ end
26
+
27
+ self
28
+ end
29
+
30
+ alias setup reset!
31
+
32
+ # API endpoint to be used by {Unleashed::Client}.
33
+ # Built from {#api_domain}
34
+ #
35
+ # @return [String]
36
+ def api_endpoint
37
+ "https://#{@api_domain}/"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,53 @@
1
+ module Unleashed
2
+ # Default configuration options for {Client}
3
+ module Default
4
+ # Default API domain
5
+ API_DOMAIN = 'api.unleashedsoftware.com'.freeze
6
+ # Default client_type_header
7
+ CLIENT_TYPE_HEADER = 'API-Sandbox'.freeze
8
+
9
+ class << self
10
+ # Configuration options.
11
+ #
12
+ # @return [Hash]
13
+ def options
14
+ Hash[Unleashed::Configurable.keys.map { |key| [key, send(key)] }]
15
+ end
16
+
17
+ # Default API domain from ENV or {API_DOMAIN}.
18
+ #
19
+ # @return [String]
20
+ def api_domain
21
+ ENV['UNLEASHED_API_DOMAIN'] || API_DOMAIN
22
+ end
23
+
24
+ # Default api_id from ENV.
25
+ #
26
+ # @return [String]
27
+ def api_id
28
+ ENV['UNLEASHED_API_ID']
29
+ end
30
+
31
+ # Default api_key from ENV.
32
+ #
33
+ # @return [String]
34
+ def api_key
35
+ ENV['UNLEASHED_API_KEY']
36
+ end
37
+
38
+ # Default client_type_header from ENV.
39
+ #
40
+ # @return [String]
41
+ def client_type_header
42
+ ENV['UNLEASHED_CLIENT_TYPE_HEADER'] || CLIENT_TYPE_HEADER
43
+ end
44
+
45
+ # Default errors_format from ENV.
46
+ #
47
+ # @return [String]
48
+ def errors_format
49
+ ENV['UNLEASHED_ERRORS_FORMAT'] || 'processed'
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,97 @@
1
+ module Unleashed
2
+ # Custom error class for rescuing from all Unleashed errors
3
+ class Error < StandardError
4
+ # Returns the appropriate Unleashed::Error subclass based on status
5
+ #
6
+ # @param [Faraday::Response] response Faraday HTTP response
7
+ # @return [Unleashed::Error]
8
+ def self.from_response(response, errors_format = nil)
9
+ klass = case response.status
10
+ when 400 then Unleashed::BadRequest
11
+ when 401 then Unleashed::Unauthorized
12
+ when 403 then Unleashed::Forbidden
13
+ when 404 then Unleashed::NotFound
14
+ when 405 then Unleashed::MethodNotAllowed
15
+ when 406 then Unleashed::NotAcceptable
16
+ when 409 then Unleashed::Conflict
17
+ when 422 then Unleashed::UnprocessableEntity
18
+ when 400..499 then Unleashed::ClientError
19
+ when 500 then Unleashed::InternalServerError
20
+ when 501 then Unleashed::NotImplemented
21
+ when 502 then Unleashed::BadGateway
22
+ when 503 then Unleashed::ServiceUnavailable
23
+ when 500..599 then Unleashed::ServerError
24
+ end
25
+ klass ? klass.new(response, errors_format) : new(response, errors_format)
26
+ end
27
+
28
+ def initialize(response = nil, errors_format = nil)
29
+ @response = response
30
+ @errors_format = errors_format
31
+ super(build_error_message)
32
+ end
33
+
34
+ private
35
+
36
+ def build_error_message
37
+ return nil if @response.nil? || @response.body.nil?
38
+
39
+ case @errors_format
40
+ when 'raw'
41
+ @response.body
42
+ else
43
+ json_response = JSON.parse(@response.body)
44
+ message = ''
45
+ message << json_response['message'] if json_response.key?('message')
46
+
47
+ if json_response.key?('errors')
48
+ message << json_response['errors'].map { |attribute, content| "#{attribute}: #{content}" }.join(', ')
49
+ end
50
+
51
+ message
52
+ end
53
+ end
54
+ end
55
+
56
+ # Raised on errors in the 400-499 range
57
+ class ClientError < Error; end
58
+
59
+ # Raised when Unleashed returns a 400 HTTP status code
60
+ class BadRequest < ClientError; end
61
+
62
+ # Raised when Unleashed returns a 401 HTTP status code
63
+ class Unauthorized < ClientError; end
64
+
65
+ # Raised when Unleashed returns a 403 HTTP status code
66
+ class Forbidden < ClientError; end
67
+
68
+ # Raised when Unleashed returns a 404 HTTP status code
69
+ class NotFound < ClientError; end
70
+
71
+ # Raised when Unleashed returns a 405 HTTP status code
72
+ class MethodNotAllowed < ClientError; end
73
+
74
+ # Raised when Unleashed returns a 406 HTTP status code
75
+ class NotAcceptable < ClientError; end
76
+
77
+ # Raised when Unleashed returns a 409 HTTP status code
78
+ class Conflict < ClientError; end
79
+
80
+ # Raised when Unleashed returns a 422 HTTP status code
81
+ class UnprocessableEntity < ClientError; end
82
+
83
+ # Raised on errors in the 500-599 range
84
+ class ServerError < Error; end
85
+
86
+ # Raised when Unleashed returns a 500 HTTP status code
87
+ class InternalServerError < ServerError; end
88
+
89
+ # Raised when Unleashed returns a 501 HTTP status code
90
+ class NotImplemented < ServerError; end
91
+
92
+ # Raised when Unleashed returns a 502 HTTP status code
93
+ class BadGateway < ServerError; end
94
+
95
+ # Raised when Unleashed returns a 503 HTTP status code
96
+ class ServiceUnavailable < ServerError; end
97
+ end
@@ -0,0 +1,23 @@
1
+ module Unleashed
2
+ # Base model for all the other models to inherit from
3
+ class BaseModel
4
+ def initialize(client, attributes = {})
5
+ @client = client
6
+ @attributes = stringify_keys(attributes)
7
+ end
8
+
9
+ def method_missing(name, *args, &block)
10
+ if @attributes.key?(name.to_s)
11
+ @attributes[name.to_s]
12
+ else
13
+ super
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def stringify_keys(hash)
20
+ Hash[hash.map { |key, value| [key.to_s, value] }]
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+
2
+ module Unleashed
3
+ # Manage Customers
4
+ class Customer < BaseModel
5
+ end
6
+ end
@@ -0,0 +1,20 @@
1
+ module Unleashed
2
+ # Base resource for all the other resources to inherit from
3
+ class BaseResource
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ def method_missing(name, *args, &block)
9
+ if instance_methods.include?(model) && respond_to?(name)
10
+ model.new(@client, id: args[0]).send(name, *args[1..-1])
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def respond_to?(name, include_all = false)
17
+ super || model.new(@client).respond_to?(name, include_all)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ module Unleashed
2
+ # Resource for the Customers API
3
+ # The Customers resource allows Customers to be listed, viewed, created, and updated.
4
+ # An individual Customer's details can be viewed, or updated by appending its identifier
5
+ # (a GUID formatted as XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX) to the URI
6
+ #
7
+ # @see https://apidocs.unleashedsoftware.com/Customers
8
+ class CustomerResource < BaseResource
9
+ def model
10
+ Unleashed::Customer
11
+ end
12
+
13
+ # List all customers
14
+ # /Customers - also returns the first 200 customers because page number 1 is the default.
15
+ #
16
+ # @param options [Hash] Optional options.
17
+ # @option options [Integer] :page_size Can ask for up to 200 customers. default: 10
18
+ # @option options [Integer] :page Page index. default: 1
19
+ #
20
+ # @return [Array<Unleashed::Customer>] List all customers.
21
+ def all(options = { page: 1, page_size: 10 })
22
+ response = JSON.parse(@client.get('Customers', options).body)
23
+ customers = response.key?('Items') ? response['Items'] : []
24
+ customers.map { |attributes| Unleashed::Customer.new(@client, attributes) }
25
+ end
26
+
27
+ # Get a single customer
28
+ # /Customers/E6E8163F-6911-40e9-B740-90E5A0A3A996 - returns details of a particular customer.
29
+ #
30
+ # @param id [String] customer ID.
31
+ #
32
+ # @return [Unleashed::Customer]
33
+ def find(id)
34
+ response = JSON.parse(@client.get("Customers/#{id}").body)
35
+ Unleashed::Customer.new(@client, response)
36
+ end
37
+ end
38
+ end
@@ -2,7 +2,7 @@ module Unleashed
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 3
5
+ TINY = 4
6
6
 
7
7
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}".freeze
8
8
  end
data/lib/unleashed.rb CHANGED
@@ -1,5 +1,12 @@
1
- require 'unleashed/version'
1
+ require_relative 'unleashed/client'
2
+ require_relative 'unleashed/default'
3
+ require_relative 'unleashed/error'
4
+ require_relative 'unleashed/version'
2
5
 
3
6
  module Unleashed
4
- # Your code goes here...
7
+ class << self
8
+ include Unleashed::Configurable
9
+ end
5
10
  end
11
+
12
+ Unleashed.setup
data/unleashed.gemspec CHANGED
@@ -40,6 +40,8 @@ Gem::Specification.new do |spec|
40
40
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
41
41
  spec.require_paths = ['lib']
42
42
 
43
+ spec.add_dependency 'faraday'
44
+ spec.add_dependency 'json'
43
45
  spec.add_development_dependency 'bundler', '~> 1.16', '>= 1.16.1'
44
46
  spec.add_development_dependency 'rake', '~> 10.0'
45
47
  spec.add_development_dependency 'rspec', '~> 3.0'
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unleashed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nhan Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-10 00:00:00.000000000 Z
11
+ date: 2019-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -69,6 +97,7 @@ files:
69
97
  - ".rspec"
70
98
  - ".ruby-version"
71
99
  - ".travis.yml"
100
+ - CHANGELOG.md
72
101
  - CODE_OF_CONDUCT.md
73
102
  - Gemfile
74
103
  - LICENSE
@@ -78,6 +107,14 @@ files:
78
107
  - bin/console
79
108
  - bin/setup
80
109
  - lib/unleashed.rb
110
+ - lib/unleashed/client.rb
111
+ - lib/unleashed/configurable.rb
112
+ - lib/unleashed/default.rb
113
+ - lib/unleashed/error.rb
114
+ - lib/unleashed/models/base_model.rb
115
+ - lib/unleashed/models/customer.rb
116
+ - lib/unleashed/resources/base_resource.rb
117
+ - lib/unleashed/resources/customer_resource.rb
81
118
  - lib/unleashed/version.rb
82
119
  - unleashed.gemspec
83
120
  homepage: https://github.com/nnhansg/unleashed-ruby