datmachine 1.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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/datmachine.gemspec +28 -0
- data/lib/datmachine.rb +86 -0
- data/lib/datmachine/client.rb +103 -0
- data/lib/datmachine/error.rb +117 -0
- data/lib/datmachine/pager.rb +250 -0
- data/lib/datmachine/resources.rb +8 -0
- data/lib/datmachine/resources/api_key.rb +0 -0
- data/lib/datmachine/resources/customer.rb +36 -0
- data/lib/datmachine/resources/hypermedia.rb +0 -0
- data/lib/datmachine/resources/plan.rb +10 -0
- data/lib/datmachine/resources/resource.rb +293 -0
- data/lib/datmachine/resources/subscription.rb +14 -0
- data/lib/datmachine/response/datmachine_exception_middleware.rb +34 -0
- data/lib/datmachine/utils.rb +92 -0
- data/lib/datmachine/version.rb +3 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5f9877e5465d31b48b8255af5d4d9bc72ef5fd8f
|
4
|
+
data.tar.gz: db1372df41dac0720874f24ed636c14af37dfab3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3db6b97ac3164ff78742a172bc03725740b67e85e917b225194825e0716f1b813dedf8914632849956e6691e498217195a68a93a341637341e7cf006cc9219b5
|
7
|
+
data.tar.gz: bdca6cc1f10de491dc2112695dea9e7ff09f619df12a7a2857d9304e12b24075c771ffaf803704ef47d49dcdb33bc16f4612b1a17523cae3993a76e39d3a76e4
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 efremov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Datmachine
|
2
|
+
|
3
|
+
Easy to use business intelligence solution specifically designed to improve the performance of Internet companies.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'datmachine'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install datmachine
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/datmachine.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env gem build
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
require "base64"
|
5
|
+
require File.expand_path('../lib/datmachine/version', __FILE__)
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "datmachine"
|
9
|
+
spec.version = Datmachine::VERSION
|
10
|
+
spec.authors = ["efremov"]
|
11
|
+
spec.email = ["efremov@datmachine.co"]
|
12
|
+
spec.description = %q{Datmachine is a business intelligence solution for Internet companies.}
|
13
|
+
spec.summary = %q{https://datmachine.co/guides}
|
14
|
+
spec.homepage = "https://datmachine.co"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_dependency("faraday", ['>= 0.8.6', '<= 0.9.0'])
|
25
|
+
spec.add_dependency("faraday_middleware", '~> 0.9.0')
|
26
|
+
spec.add_dependency("addressable", '~> 2.3.5')
|
27
|
+
|
28
|
+
end
|
data/lib/datmachine.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "datmachine", "resources")
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__), "datmachine", "response")
|
3
|
+
|
4
|
+
require 'uri'
|
5
|
+
require 'datmachine/version' unless defined? Datmachine::VERSION
|
6
|
+
require 'datmachine/client'
|
7
|
+
require 'datmachine/utils'
|
8
|
+
require 'datmachine/error'
|
9
|
+
|
10
|
+
module Datmachine
|
11
|
+
|
12
|
+
@client = nil
|
13
|
+
@config = {
|
14
|
+
:scheme => 'http',
|
15
|
+
:host => 'api.datmachine.co',
|
16
|
+
:port => 80,
|
17
|
+
:version => '1.1'
|
18
|
+
}
|
19
|
+
|
20
|
+
@hypermedia_registry = {}
|
21
|
+
|
22
|
+
class << self
|
23
|
+
|
24
|
+
attr_accessor :client
|
25
|
+
attr_accessor :config
|
26
|
+
attr_accessor :hypermedia_registry
|
27
|
+
|
28
|
+
def configure(api_key=nil, site_id=nil, options={})
|
29
|
+
@config = @config.merge(options)
|
30
|
+
@client = Datmachine::Client.new(api_key, site_id, @config)
|
31
|
+
end
|
32
|
+
|
33
|
+
def is_configured_with_api_key?
|
34
|
+
!@client.api_key.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def split_the_href(href)
|
38
|
+
URI.parse(href).path.sub(/\/$/, '').split('/')
|
39
|
+
end
|
40
|
+
|
41
|
+
def from_hypermedia_registry(resource_name)
|
42
|
+
cls = Datmachine.hypermedia_registry[resource_name]
|
43
|
+
if cls.nil?
|
44
|
+
raise 'OH SHIT'
|
45
|
+
end
|
46
|
+
cls
|
47
|
+
end
|
48
|
+
|
49
|
+
def from_href(href)
|
50
|
+
split_uri = split_the_href(href)
|
51
|
+
split_uri.reverse!.each do |resource|
|
52
|
+
cls = Datmachine.hypermedia_registry[resource]
|
53
|
+
return cls unless cls.nil?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def is_collection(href)
|
58
|
+
split_uri = split_the_href(href)
|
59
|
+
split_uri.last.to_i == 0
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def get(*args, &block)
|
64
|
+
self.client.get *args
|
65
|
+
end
|
66
|
+
|
67
|
+
def post(*args, &block)
|
68
|
+
self.client.post *args
|
69
|
+
end
|
70
|
+
|
71
|
+
def put(*args, &block)
|
72
|
+
self.client.put *args
|
73
|
+
end
|
74
|
+
|
75
|
+
def unstore(*args, &block)
|
76
|
+
self.client.unstore *args
|
77
|
+
end
|
78
|
+
alias_method :delete, :unstore
|
79
|
+
end
|
80
|
+
|
81
|
+
# configure on import so we don't have to configure for creating
|
82
|
+
# an api key
|
83
|
+
configure
|
84
|
+
end
|
85
|
+
|
86
|
+
require 'datmachine/resources'
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'uri'
|
3
|
+
require 'faraday'
|
4
|
+
require 'faraday_middleware'
|
5
|
+
require 'datmachine_exception_middleware'
|
6
|
+
|
7
|
+
module Datmachine
|
8
|
+
class Client
|
9
|
+
|
10
|
+
DEFAULTS = {
|
11
|
+
:scheme => 'http',
|
12
|
+
:host => 'api.datmachine.co/',
|
13
|
+
:port => 80,
|
14
|
+
:version => '1',
|
15
|
+
:logging_level => 'WARN',
|
16
|
+
:connection_timeout => 60,
|
17
|
+
:read_timeout => 60,
|
18
|
+
:logger => nil,
|
19
|
+
:ssl_verify => false,
|
20
|
+
:faraday_adapter => Faraday.default_adapter,
|
21
|
+
:accept_type => 'application/json'
|
22
|
+
}
|
23
|
+
|
24
|
+
attr_reader :conn
|
25
|
+
attr_accessor :api_key, :config
|
26
|
+
|
27
|
+
def initialize(api_key, site_id, options={})
|
28
|
+
@api_key = api_key.nil? ? api_key : api_key.strip
|
29
|
+
@config = DEFAULTS.merge options
|
30
|
+
@config[:site_id] = site_id
|
31
|
+
build_conn
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_conn
|
35
|
+
if config[:logger]
|
36
|
+
logger = config[:logger]
|
37
|
+
else
|
38
|
+
logger = Logger.new(STDOUT)
|
39
|
+
logger.level = Logger.const_get(config[:logging_level].to_s)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
options = {
|
45
|
+
:request => {
|
46
|
+
:open_timeout => config[:connection_timeout],
|
47
|
+
:timeout => config[:read_timeout]
|
48
|
+
},
|
49
|
+
:ssl => {
|
50
|
+
:verify => @config[:ssl_verify] # Only set this to false for testing
|
51
|
+
}
|
52
|
+
}
|
53
|
+
@conn = Faraday.new(url, options) do |cxn|
|
54
|
+
cxn.request :json
|
55
|
+
|
56
|
+
cxn.response :logger, logger
|
57
|
+
cxn.response :json
|
58
|
+
cxn.response :raise_error # raise exceptions on 40x, 50x responses
|
59
|
+
cxn.adapter config[:faraday_adapter]
|
60
|
+
end
|
61
|
+
conn.path_prefix = '/'
|
62
|
+
conn.headers['User-Agent'] = "datmachine-ruby/1"
|
63
|
+
conn.headers['Content-Type'] = "application/json"
|
64
|
+
conn.headers['Accept'] = "#{@config[:accept_type]}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def url
|
68
|
+
builder = (config[:scheme] == 'http') ? URI::HTTP : URI::HTTPS
|
69
|
+
|
70
|
+
builder.build({:host => config[:host],
|
71
|
+
:port => config[:port],
|
72
|
+
:scheme => config[:scheme]})
|
73
|
+
end
|
74
|
+
|
75
|
+
def unstore(*args, &block)
|
76
|
+
delete(*args, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def method_missing(method, *args, &block)
|
80
|
+
if is_http_method? method
|
81
|
+
conn.token_auth(api_key) unless api_key.nil?
|
82
|
+
args[0] = "/sites/#{config[:site_id]}/" + args[0]
|
83
|
+
conn.send method, *args
|
84
|
+
else
|
85
|
+
super method, *args, &block
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def is_http_method? method
|
92
|
+
[:get, :post, :put, :delete].include? method
|
93
|
+
end
|
94
|
+
|
95
|
+
def respond_to?(method, include_private = false)
|
96
|
+
if is_http_method? method
|
97
|
+
true
|
98
|
+
else
|
99
|
+
super method, include_private
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Datmachine
|
2
|
+
|
3
|
+
# Custom error class for rescuing from all API response-related Balanced errors
|
4
|
+
class Error < ::StandardError
|
5
|
+
attr_reader :response
|
6
|
+
|
7
|
+
# @param [Hash] response the decoded json response body
|
8
|
+
def initialize(response=nil)
|
9
|
+
@response = response
|
10
|
+
unless response.nil?
|
11
|
+
super error_message
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Hash]
|
16
|
+
def body
|
17
|
+
@body ||= begin
|
18
|
+
return {} unless response[:body]
|
19
|
+
Utils.indifferent_read_access(response[:body])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def error_message
|
24
|
+
set_attrs
|
25
|
+
errors = body.fetch('errors', nil)
|
26
|
+
unless errors.nil?
|
27
|
+
error = body[:errors][0]
|
28
|
+
extra = error[:additional] ? " -- #{error[:additional]}" : ""
|
29
|
+
"#{self.class.name}(#{response[:status]})::#{error[:status]}:: "\
|
30
|
+
"#{response[:method].to_s.upcase} #{response[:url].to_s}: "\
|
31
|
+
"#{error[:category_code]}: #{error[:description]} #{extra}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def set_attrs
|
37
|
+
errors = body.fetch('errors', nil)
|
38
|
+
unless errors.nil?
|
39
|
+
error = errors[0]
|
40
|
+
error.keys.each do |name|
|
41
|
+
self.class.instance_eval {
|
42
|
+
define_method(name) { error[name] } # Get.
|
43
|
+
define_method("#{name}?") { !!error[name] } # Present.
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# General error class for non API response exceptions
|
51
|
+
class StandardError < Error
|
52
|
+
attr_reader :message
|
53
|
+
alias :error_message :message
|
54
|
+
|
55
|
+
# @param [String, nil] message a description of the exception
|
56
|
+
def initialize(message = nil)
|
57
|
+
@message = message
|
58
|
+
super(message)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
class MoreInformationRequired < Error
|
65
|
+
def redirect_uri
|
66
|
+
response.headers['Location']
|
67
|
+
end
|
68
|
+
|
69
|
+
def error_message
|
70
|
+
set_attrs
|
71
|
+
"#{self.class.name} :: #{response[:method].to_s.upcase} #{response[:url].to_s}: "\
|
72
|
+
"#{response[:status]}: \n#{body[:friendly_html]}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Raised when Balanced returns a 400 HTTP status code
|
77
|
+
class BadRequest < Error; end
|
78
|
+
|
79
|
+
# Raised when Balanced returns a 401 HTTP status code
|
80
|
+
class Unauthorized < Error; end
|
81
|
+
|
82
|
+
# Raised when Balanced returns a 402 HTTP status code
|
83
|
+
class PaymentRequired < Error; end
|
84
|
+
|
85
|
+
# Raised when Balanced returns a 403 HTTP status code
|
86
|
+
class Forbidden < Error; end
|
87
|
+
|
88
|
+
# Raised when Balanced returns a 404 HTTP status code
|
89
|
+
class NotFound < Error; end
|
90
|
+
|
91
|
+
# Raised when Balanced returns a 405 HTTP status code
|
92
|
+
class MethodNotAllowed < Error; end
|
93
|
+
|
94
|
+
# Raised when Balanced returns a 409 HTTP status code
|
95
|
+
class Conflict < Error; end
|
96
|
+
|
97
|
+
# Raised when Balanced returns a 410 HTTP status code
|
98
|
+
class Gone < Error; end
|
99
|
+
|
100
|
+
# Raised when Balanced returns a 500 HTTP status code
|
101
|
+
class InternalServerError < Error; end
|
102
|
+
|
103
|
+
# Raised when Balanced returns a 501 HTTP status code
|
104
|
+
class NotImplemented < Error; end
|
105
|
+
|
106
|
+
# Raised when Balanced returns a 502 HTTP status code
|
107
|
+
class BadGateway < Error; end
|
108
|
+
|
109
|
+
# Raised when Balanced returns a 503 HTTP status code
|
110
|
+
class ServiceUnavailable < Error; end
|
111
|
+
|
112
|
+
# Raised when Balanced returns a 504 HTTP status code
|
113
|
+
class GatewayTimeout < Error; end
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
3
|
+
module Datmachine
|
4
|
+
class Pager
|
5
|
+
DEFAULT_SEP = /[&;] */n
|
6
|
+
DEFAULT_LIMIT = 10
|
7
|
+
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
attr_accessor :href
|
11
|
+
attr_accessor :options
|
12
|
+
|
13
|
+
# A pager for paginating through resource records.
|
14
|
+
#
|
15
|
+
# @param [String] uri the uri of the resource
|
16
|
+
# @param [Hash] options
|
17
|
+
# @option options [Integer] limit
|
18
|
+
# @option options [Integer] offset
|
19
|
+
# @option options [Integer] per an alias for the :limit option
|
20
|
+
def initialize(href, options = {})
|
21
|
+
@href = href
|
22
|
+
@options = options
|
23
|
+
@page = nil
|
24
|
+
@resource_class = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def resource_class
|
28
|
+
return @resource_class unless @resource_class.nil?
|
29
|
+
load! unless @page
|
30
|
+
@resource_class
|
31
|
+
end
|
32
|
+
|
33
|
+
def first
|
34
|
+
load! unless @page
|
35
|
+
if items.first.nil?
|
36
|
+
nil
|
37
|
+
else
|
38
|
+
envelope = {
|
39
|
+
:meta => @page[:meta],
|
40
|
+
:links => @page[:links],
|
41
|
+
@resource_class.collection_name.to_sym => [items.first]
|
42
|
+
}
|
43
|
+
resource_class.construct_from_response(envelope)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def total
|
48
|
+
load! unless @page
|
49
|
+
@page[:meta][:total]
|
50
|
+
end
|
51
|
+
|
52
|
+
def limit
|
53
|
+
load! unless @page
|
54
|
+
@page[:meta][:limit]
|
55
|
+
end
|
56
|
+
alias limit_value limit
|
57
|
+
|
58
|
+
def offset
|
59
|
+
load! unless @page
|
60
|
+
@page[:meta][:offset]
|
61
|
+
end
|
62
|
+
alias offset_value offset
|
63
|
+
|
64
|
+
def items
|
65
|
+
load! unless @page
|
66
|
+
if @resource_class.nil?
|
67
|
+
[]
|
68
|
+
else
|
69
|
+
@page[@resource_class.collection_name]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def current_page
|
74
|
+
(offset / limit) + 1
|
75
|
+
end
|
76
|
+
|
77
|
+
def num_pages
|
78
|
+
num = total / limit
|
79
|
+
num += 1 if total % limit > 0
|
80
|
+
num
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Array] Iterates through the current page of records.
|
84
|
+
# @yield [record]
|
85
|
+
def each
|
86
|
+
return enum_for :each unless block_given?
|
87
|
+
|
88
|
+
load! unless @page
|
89
|
+
loop do
|
90
|
+
items.each do |r|
|
91
|
+
envelope = {
|
92
|
+
:meta => @page[:meta],
|
93
|
+
:links => @page[:links],
|
94
|
+
@resource_class.collection_name.to_sym => [r]
|
95
|
+
}
|
96
|
+
yield resource_class.construct_from_response(envelope)
|
97
|
+
end
|
98
|
+
raise StopIteration if @page[:meta].nil?
|
99
|
+
#raise StopIteration if @page[:meta][:next].nil?
|
100
|
+
self.next
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# @return [nil]
|
105
|
+
# @see Resource.fetch_each
|
106
|
+
# @yield [record]
|
107
|
+
def fetch_each
|
108
|
+
return enum_for :fetch_each unless block_given?
|
109
|
+
begin
|
110
|
+
each { |record| yield record }
|
111
|
+
end while self.next
|
112
|
+
end
|
113
|
+
|
114
|
+
# @return [Array, nil] Refreshes the pager's collection of records with
|
115
|
+
# the next page.
|
116
|
+
def next
|
117
|
+
load! unless @page
|
118
|
+
next_uri = @page[:meta][:next]
|
119
|
+
load_from next_uri, nil unless next_uri.nil?
|
120
|
+
end
|
121
|
+
|
122
|
+
# @return [Array, nil] Refreshes the pager's collection of records with
|
123
|
+
# the previous page.
|
124
|
+
def prev
|
125
|
+
load! unless @page
|
126
|
+
prev_uri = @page[:meta][:prev]
|
127
|
+
load_from prev_uri, nil unless prev_uri.nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [Array, nil] Refreshes the pager's collection of records with
|
131
|
+
# the first page.
|
132
|
+
def start
|
133
|
+
load! unless @page
|
134
|
+
first_page = @page[:meta][:first]
|
135
|
+
load_from first_page, nil unless first_page.nil?
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [Array, nil] Load (or reload) the pager's collection from the
|
139
|
+
# original, supplied options.
|
140
|
+
def load!
|
141
|
+
load_from @href, @options
|
142
|
+
end
|
143
|
+
alias reload load!
|
144
|
+
|
145
|
+
# @return [Pager] Duplicates the pager, updating it with the options
|
146
|
+
# supplied. Useful for resource scopes.
|
147
|
+
# @see #initialize
|
148
|
+
def paginate(options = {})
|
149
|
+
dup.instance_eval {
|
150
|
+
@page = nil
|
151
|
+
@options.update options and self
|
152
|
+
}
|
153
|
+
end
|
154
|
+
alias scoped paginate
|
155
|
+
alias where paginate
|
156
|
+
|
157
|
+
def all(options = {})
|
158
|
+
paginate(options).to_a
|
159
|
+
end
|
160
|
+
|
161
|
+
def fetch(uri)
|
162
|
+
if resource_class.respond_to? :find
|
163
|
+
raise NoMethodError,
|
164
|
+
"#find must be called on #{resource_class} directly"
|
165
|
+
end
|
166
|
+
|
167
|
+
resource_class.fetch uri
|
168
|
+
end
|
169
|
+
|
170
|
+
def create(options={})
|
171
|
+
opts = Datmachine::Utils.indifferent_read_access options
|
172
|
+
opts[:href] = @href
|
173
|
+
# if we don't have a media type for the href,
|
174
|
+
# let's try to inspect the url to look it up from the
|
175
|
+
# registry
|
176
|
+
if @resource_class.nil?
|
177
|
+
@resource_class = Datmachine.from_href(@href)
|
178
|
+
end
|
179
|
+
@resource_class.new(opts).save
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def load_from(uri, params)
|
186
|
+
parsed_uri = URI.parse(uri)
|
187
|
+
|
188
|
+
params ||= {}
|
189
|
+
params = adjust_pagination_params(params)
|
190
|
+
|
191
|
+
unless parsed_uri.query.nil?
|
192
|
+
# The reason we don't use CGI::parse here is because
|
193
|
+
# the Datmachine api currently can't handle variable[]=value.
|
194
|
+
# Faraday ends up encoding a simple query string like:
|
195
|
+
# {"limit"=>["10"], "offset"=>["0"]}
|
196
|
+
# to limit[]=10&offset[]=0 and that's cool, but
|
197
|
+
# we have to make sure Datmachine supports it.
|
198
|
+
query_params = parse_query(parsed_uri.query)
|
199
|
+
params.merge! query_params
|
200
|
+
parsed_uri.query = nil
|
201
|
+
end
|
202
|
+
|
203
|
+
response = Datmachine.get parsed_uri.to_s, params
|
204
|
+
@page = Datmachine::Utils.indifferent_read_access response.body
|
205
|
+
|
206
|
+
#@href = @page[:meta][:href]
|
207
|
+
# resource_class?
|
208
|
+
hypermedia_key = (@page.keys.map{|k| k.to_sym } - [:meta, :links]).first
|
209
|
+
|
210
|
+
unless hypermedia_key.nil?
|
211
|
+
@resource_class = ("Datmachine::" + Datmachine::Utils.classify(hypermedia_key)).constantize
|
212
|
+
end
|
213
|
+
|
214
|
+
@page
|
215
|
+
end
|
216
|
+
|
217
|
+
def adjust_pagination_params(original)
|
218
|
+
adjusted = original.dup
|
219
|
+
per = adjusted.delete(:per)
|
220
|
+
adjusted[:limit] = per unless per.nil?
|
221
|
+
page = adjusted.delete(:page)
|
222
|
+
adjusted[:offset] = (adjusted[:limit] || DEFAULT_LIMIT) * ([page, 1].max - 1) unless page.nil?
|
223
|
+
adjusted
|
224
|
+
end
|
225
|
+
|
226
|
+
# Stolen from Mongrel, with some small modifications:
|
227
|
+
# Parses a query string by breaking it up at the '&'
|
228
|
+
# and ';' characters. You can also use this to parse
|
229
|
+
# cookies by changing the characters used in the second
|
230
|
+
# parameter (which defaults to '&;').
|
231
|
+
def parse_query(qs, d = nil)
|
232
|
+
params = {}
|
233
|
+
|
234
|
+
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
235
|
+
k, v = p.split('=', 2).map { |x| CGI::unescape(x) }
|
236
|
+
if (cur = params[k])
|
237
|
+
if cur.class == Array
|
238
|
+
params[k] << v
|
239
|
+
else
|
240
|
+
params[k] = [cur, v]
|
241
|
+
end
|
242
|
+
else
|
243
|
+
params[k] = v
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
params
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Datmachine
|
2
|
+
# A customer represents a business or person within your Marketplace. A
|
3
|
+
# customer can have many funding instruments such as cards and bank accounts
|
4
|
+
# associated to them.
|
5
|
+
#
|
6
|
+
class Customer
|
7
|
+
|
8
|
+
include Datmachine::Resource
|
9
|
+
|
10
|
+
def create_subscription(options = {})
|
11
|
+
options[:href] = self.subscriptions.href
|
12
|
+
subscription = Datmachine::Subscription.new(options)
|
13
|
+
subscription.save
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(options = {})
|
17
|
+
options.each do |key, value|
|
18
|
+
attributes[key] = value
|
19
|
+
end
|
20
|
+
save
|
21
|
+
end
|
22
|
+
|
23
|
+
def all_subscriptions
|
24
|
+
subscriptions.to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
def last_subscription
|
28
|
+
all_subscriptions.last
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.find_by_id(id)
|
32
|
+
Datmachine::Customer.fetch("/customers/#{id}")
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
File without changes
|
@@ -0,0 +1,293 @@
|
|
1
|
+
require File.expand_path('../../pager', __FILE__)
|
2
|
+
require File.expand_path('../../utils', __FILE__)
|
3
|
+
require 'addressable/template'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
|
7
|
+
module Datmachine
|
8
|
+
|
9
|
+
module Resource
|
10
|
+
|
11
|
+
attr_accessor :attributes
|
12
|
+
attr_accessor :hyperlinks
|
13
|
+
|
14
|
+
attr_accessor :id
|
15
|
+
attr_accessor :href
|
16
|
+
attr_accessor :links
|
17
|
+
|
18
|
+
def initialize(attributes = {})
|
19
|
+
@attributes = Utils.indifferent_read_access attributes
|
20
|
+
@hyperlinks = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def id
|
24
|
+
(attributes[:id] ||= nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
def id=(value)
|
28
|
+
attributes[:id] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def href
|
32
|
+
(attributes[:href] ||= self.class.collection_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def links
|
36
|
+
(attributes[:links] ||= {})
|
37
|
+
end
|
38
|
+
|
39
|
+
def links=(value)
|
40
|
+
attributes[:links] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
def hydrate(links, meta)
|
44
|
+
# links here is 'marketplaces.events'
|
45
|
+
links.each do |key, uri|
|
46
|
+
# key is 'marketplaces.events'
|
47
|
+
property = key.sub(/.*?\./, '')
|
48
|
+
# property here is events
|
49
|
+
# if marketplace.links is a hash
|
50
|
+
# for each property and uri, we want to set them on the instance
|
51
|
+
# as pagers.
|
52
|
+
#
|
53
|
+
# right?
|
54
|
+
if self.links.include? property
|
55
|
+
link_value = self.links[property]
|
56
|
+
# expands /customers/{marketplaces.owner_customer} to /customers/ACxxxxx
|
57
|
+
template = Addressable::Template.new(uri)
|
58
|
+
uri = template.expand("#{key}" => link_value).to_s
|
59
|
+
@hyperlinks[property] = Datmachine::Utils.callable(
|
60
|
+
link_value.nil? ? link_value : lambda { self.class.find(uri) }
|
61
|
+
)
|
62
|
+
else
|
63
|
+
unless uri.nil? || uri.is_a?(Hash)
|
64
|
+
# matches something like '/blah/{class.attribute}/bliakdf'
|
65
|
+
begin
|
66
|
+
match_data = /\{(#{self.class.collection_name}\.(\w+))\}/.match(uri)
|
67
|
+
rescue TypeError => ex
|
68
|
+
puts 'what the fuck'
|
69
|
+
raise ex
|
70
|
+
end
|
71
|
+
unless match_data.nil?
|
72
|
+
attribute_path = match_data[1]
|
73
|
+
attribute_name = match_data[2]
|
74
|
+
template = Addressable::Template.new(uri)
|
75
|
+
uri = template.expand("#{attribute_path}" => @attributes[attribute_name]).to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@hyperlinks[property] = Datmachine::Utils.callable(Datmachine::Pager.new(uri, {}))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# delegate the query to the pager module
|
84
|
+
|
85
|
+
def fetch(*arguments)
|
86
|
+
self.class.find *arguments
|
87
|
+
end
|
88
|
+
|
89
|
+
alias find fetch
|
90
|
+
|
91
|
+
def save
|
92
|
+
href = @attributes.delete('href')
|
93
|
+
method = :post
|
94
|
+
if href.nil?
|
95
|
+
href = self.class.collection_path
|
96
|
+
elsif !Datmachine.is_collection(href)
|
97
|
+
method = :put
|
98
|
+
end
|
99
|
+
|
100
|
+
attributes_to_submit = self.sanitize
|
101
|
+
@response = Datmachine.send(method, href, attributes_to_submit)
|
102
|
+
@attributes['href'] = href
|
103
|
+
|
104
|
+
reload @response
|
105
|
+
end
|
106
|
+
|
107
|
+
def sanitize
|
108
|
+
to_submit = {}
|
109
|
+
@attributes.each do |key, value|
|
110
|
+
unless value.is_a? Datmachine::Resource
|
111
|
+
to_submit[key] = value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
to_submit
|
115
|
+
end
|
116
|
+
|
117
|
+
def response
|
118
|
+
@response
|
119
|
+
end
|
120
|
+
|
121
|
+
private :response
|
122
|
+
|
123
|
+
def unstore
|
124
|
+
Datmachine.unstore @attributes[:href]
|
125
|
+
end
|
126
|
+
alias_method :destroy, :unstore
|
127
|
+
|
128
|
+
def reload(the_response = nil)
|
129
|
+
if the_response
|
130
|
+
return if the_response.body.to_s.length.zero?
|
131
|
+
fresh = self.class.construct_from_response the_response.body
|
132
|
+
else
|
133
|
+
fresh = self.find(@attributes[:href])
|
134
|
+
end
|
135
|
+
fresh and copy_from fresh
|
136
|
+
return fresh
|
137
|
+
end
|
138
|
+
|
139
|
+
def copy_from(other)
|
140
|
+
other.instance_variables.each do |ivar|
|
141
|
+
instance_variable_set ivar, other.instance_variable_get(ivar)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def method_missing(method, *args, &block)
|
146
|
+
if @attributes.has_key?(method.to_s)
|
147
|
+
return @attributes[method.to_s]
|
148
|
+
end
|
149
|
+
|
150
|
+
case method.to_s
|
151
|
+
when /(.+)=$/
|
152
|
+
attr = method.to_s.chop
|
153
|
+
@attributes[attr] = args[0]
|
154
|
+
else
|
155
|
+
# This piece of code is a bit disgusting. We will clean it up soon,
|
156
|
+
# but basically, we were creating closures using this code snippet
|
157
|
+
# but those closures were transferred to the actual classes themselves
|
158
|
+
# so you would have something like BankAccount.new.account and this
|
159
|
+
# will give the last closure added for a BankAccount even if it has
|
160
|
+
# nothing to do with the actual class itself.
|
161
|
+
#
|
162
|
+
# This caused some weird errors, so the best thing to do was to just
|
163
|
+
# move this piece of code and "dynamically" enable it for all
|
164
|
+
# method requests that are essentially #{method}_uri.
|
165
|
+
#
|
166
|
+
# This solves the acute problem, for now.
|
167
|
+
if @hyperlinks.has_key? "#{method}"
|
168
|
+
value = @hyperlinks["#{method}"]
|
169
|
+
result = value.call
|
170
|
+
return result
|
171
|
+
else
|
172
|
+
super
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
if RUBY_VERSION < '1.9'
|
178
|
+
def respond_to?(method_name, include_private=false)
|
179
|
+
does_resource_respond_to?(method_name) || super
|
180
|
+
end
|
181
|
+
else
|
182
|
+
def respond_to_missing?(method_name, include_private=false)
|
183
|
+
does_resource_respond_to?(method_name) || super
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def does_resource_respond_to?(method_name)
|
188
|
+
@attributes.has_key?(method_name.to_s) or @hyperlinks.has_key?(method_name.to_s)
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.included(base)
|
192
|
+
base.extend ClassMethods
|
193
|
+
end
|
194
|
+
|
195
|
+
module ClassMethods
|
196
|
+
|
197
|
+
def resource_name
|
198
|
+
Utils.demodulize name
|
199
|
+
end
|
200
|
+
|
201
|
+
def collection_name
|
202
|
+
Utils.pluralize Utils.underscore(resource_name)
|
203
|
+
end
|
204
|
+
|
205
|
+
def collection_path
|
206
|
+
# this is to just support version1 stuff, but in reality, if we get here
|
207
|
+
# we should throw an exception since we do not want to use v1 ever.
|
208
|
+
if Datmachine.config[:version] == '1'
|
209
|
+
# XXX: we should raise an exception if we get here.
|
210
|
+
["/v#{Datmachine.config[:version]}", collection_name].compact.join '/'
|
211
|
+
else
|
212
|
+
collection_name
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def href
|
217
|
+
collection_path
|
218
|
+
end
|
219
|
+
|
220
|
+
def member_name
|
221
|
+
Utils.underscore resource_name
|
222
|
+
end
|
223
|
+
|
224
|
+
def construct_from_response(payload)
|
225
|
+
payload = Datmachine::Utils.indifferent_read_access payload
|
226
|
+
|
227
|
+
links = payload.delete('links') || {}
|
228
|
+
meta = payload.delete('meta') || {}
|
229
|
+
|
230
|
+
if payload.length > 1
|
231
|
+
raise 'NOT SUPPORTED YET'
|
232
|
+
end
|
233
|
+
|
234
|
+
instance = nil
|
235
|
+
# the remaining keys here are just hypermedia resources
|
236
|
+
payload.each do |key, value|
|
237
|
+
# > If the length of an array at a resource key is greater than one,
|
238
|
+
# the value represents a list of documents.
|
239
|
+
if value.length > 1
|
240
|
+
# key is a collection, this should never happen
|
241
|
+
resource_body = value
|
242
|
+
else
|
243
|
+
resource_body = value.first
|
244
|
+
end
|
245
|
+
# > Singular resources are represented as JSON objects. However,
|
246
|
+
# they are still wrapped inside an array:
|
247
|
+
#resource_body = value.first
|
248
|
+
cls = ("Datmachine::" + Datmachine::Utils.classify(key)).constantize
|
249
|
+
instance = cls.new resource_body
|
250
|
+
instance.hydrate(links, meta)
|
251
|
+
end
|
252
|
+
instance
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
def fetch(*arguments)
|
257
|
+
if arguments.nil? ||
|
258
|
+
arguments.empty? ||
|
259
|
+
arguments[0].nil? ||
|
260
|
+
arguments[0].empty?
|
261
|
+
|
262
|
+
end
|
263
|
+
scope = arguments.slice!(0)
|
264
|
+
options = arguments.slice!(0) || {}
|
265
|
+
case scope
|
266
|
+
when :all then
|
267
|
+
all(options)
|
268
|
+
when :first then
|
269
|
+
paginate(options).first
|
270
|
+
else
|
271
|
+
response = Datmachine.get scope, options
|
272
|
+
construct_from_response response.body
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
alias find fetch
|
277
|
+
|
278
|
+
def paginate(options = {})
|
279
|
+
Datmachine::Pager.new href, options
|
280
|
+
end
|
281
|
+
|
282
|
+
alias scoped paginate
|
283
|
+
alias where paginate
|
284
|
+
|
285
|
+
def all(options = {})
|
286
|
+
pager = paginate(options)
|
287
|
+
pager.to_a
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
293
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'datmachine/error'
|
3
|
+
|
4
|
+
# @api private
|
5
|
+
module Faraday
|
6
|
+
|
7
|
+
class Response::RaiseDatmachineError < Response::Middleware
|
8
|
+
|
9
|
+
HTTP_STATUS_CODES = {
|
10
|
+
300 => Datmachine::MoreInformationRequired,
|
11
|
+
400 => Datmachine::BadRequest,
|
12
|
+
401 => Datmachine::Unauthorized,
|
13
|
+
402 => Datmachine::PaymentRequired,
|
14
|
+
403 => Datmachine::Forbidden,
|
15
|
+
404 => Datmachine::NotFound,
|
16
|
+
405 => Datmachine::MethodNotAllowed,
|
17
|
+
409 => Datmachine::Conflict,
|
18
|
+
410 => Datmachine::Gone,
|
19
|
+
500 => Datmachine::InternalServerError,
|
20
|
+
501 => Datmachine::NotImplemented,
|
21
|
+
502 => Datmachine::BadGateway,
|
22
|
+
503 => Datmachine::ServiceUnavailable,
|
23
|
+
504 => Datmachine::GatewayTimeout,
|
24
|
+
}
|
25
|
+
|
26
|
+
def on_complete(response)
|
27
|
+
status_code = response[:status].to_i
|
28
|
+
error_class = CATEGORY_CODE_MAP[category_code] || HTTP_STATUS_CODES[status_code]
|
29
|
+
raise error_class.new(response) if error_class
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Datmachine
|
2
|
+
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
def callable( callable_or_not )
|
6
|
+
callable_or_not.respond_to?(:call) ? callable_or_not : lambda { callable_or_not }
|
7
|
+
end
|
8
|
+
|
9
|
+
def camelize(underscored_word)
|
10
|
+
underscored_word.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }
|
11
|
+
end
|
12
|
+
|
13
|
+
def classify(table_name)
|
14
|
+
camelize singularize(table_name.to_s.sub(/.*\./, ''))
|
15
|
+
end
|
16
|
+
|
17
|
+
def demodulize(class_name_in_module)
|
18
|
+
class_name_in_module.to_s.sub(/^.*::/, '')
|
19
|
+
end
|
20
|
+
|
21
|
+
def pluralize(word)
|
22
|
+
word.to_s.sub(/([^s])$/, '\1s')
|
23
|
+
end
|
24
|
+
|
25
|
+
def singularize(word)
|
26
|
+
word.to_s.sub(/s$/, '').sub(/ie$/, 'y')
|
27
|
+
end
|
28
|
+
|
29
|
+
def underscore(camel_cased_word)
|
30
|
+
word = camel_cased_word.to_s.dup
|
31
|
+
word.gsub!(/::/, '/')
|
32
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
33
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
34
|
+
word.tr! '-', '_'
|
35
|
+
word.downcase!
|
36
|
+
word
|
37
|
+
end
|
38
|
+
|
39
|
+
def extract_href_from_object(object)
|
40
|
+
object.respond_to?(:href) ? object.href : object
|
41
|
+
end
|
42
|
+
|
43
|
+
def indifferent_read_access(base = {})
|
44
|
+
indifferent = Hash.new do |hash, key|
|
45
|
+
hash[key.to_s] if key.is_a? Symbol
|
46
|
+
end
|
47
|
+
base.each_pair do |key, value|
|
48
|
+
if value.is_a? Hash
|
49
|
+
value = indifferent_read_access value
|
50
|
+
elsif value.respond_to? :each
|
51
|
+
if value.respond_to? :map!
|
52
|
+
value.map! do |v|
|
53
|
+
if v.is_a? Hash
|
54
|
+
v = indifferent_read_access v
|
55
|
+
end
|
56
|
+
v
|
57
|
+
end
|
58
|
+
else
|
59
|
+
value.map do |v|
|
60
|
+
if v.is_a? Hash
|
61
|
+
v = indifferent_read_access v
|
62
|
+
end
|
63
|
+
v
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
indifferent[key.to_s] = value
|
68
|
+
end
|
69
|
+
indifferent
|
70
|
+
end
|
71
|
+
|
72
|
+
def stringify_keys!(hash)
|
73
|
+
hash.keys.each do |key|
|
74
|
+
stringify_keys! hash[key] if hash[key].is_a? Hash
|
75
|
+
hash[key.to_s] = hash.delete key if key.is_a? Symbol
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def assert_valid_keys(hash, *valid_keys)
|
80
|
+
unknown_keys = hash.keys - [valid_keys].flatten
|
81
|
+
raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(', ')}") unless unknown_keys.empty?
|
82
|
+
end
|
83
|
+
|
84
|
+
def assert_required_keys(hash, params)
|
85
|
+
params[:required] ||= []
|
86
|
+
pending_keys = params[:required] - hash.keys
|
87
|
+
raise(ArgumentError, "Required key(s) not present: #{pending_keys.join(', ')}") unless pending_keys.empty?
|
88
|
+
end
|
89
|
+
extend self
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: datmachine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- efremov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.6
|
48
|
+
- - <=
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 0.9.0
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 0.8.6
|
58
|
+
- - <=
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.9.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: faraday_middleware
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.9.0
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ~>
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 0.9.0
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: addressable
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ~>
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 2.3.5
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ~>
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 2.3.5
|
89
|
+
description: Datmachine is a business intelligence solution for Internet companies.
|
90
|
+
email:
|
91
|
+
- efremov@datmachine.co
|
92
|
+
executables: []
|
93
|
+
extensions: []
|
94
|
+
extra_rdoc_files: []
|
95
|
+
files:
|
96
|
+
- .gitignore
|
97
|
+
- Gemfile
|
98
|
+
- LICENSE.txt
|
99
|
+
- README.md
|
100
|
+
- Rakefile
|
101
|
+
- datmachine.gemspec
|
102
|
+
- lib/datmachine.rb
|
103
|
+
- lib/datmachine/client.rb
|
104
|
+
- lib/datmachine/error.rb
|
105
|
+
- lib/datmachine/pager.rb
|
106
|
+
- lib/datmachine/resources.rb
|
107
|
+
- lib/datmachine/resources/api_key.rb
|
108
|
+
- lib/datmachine/resources/customer.rb
|
109
|
+
- lib/datmachine/resources/hypermedia.rb
|
110
|
+
- lib/datmachine/resources/plan.rb
|
111
|
+
- lib/datmachine/resources/resource.rb
|
112
|
+
- lib/datmachine/resources/subscription.rb
|
113
|
+
- lib/datmachine/response/datmachine_exception_middleware.rb
|
114
|
+
- lib/datmachine/utils.rb
|
115
|
+
- lib/datmachine/version.rb
|
116
|
+
homepage: https://datmachine.co
|
117
|
+
licenses:
|
118
|
+
- MIT
|
119
|
+
metadata: {}
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 2.0.3
|
137
|
+
signing_key:
|
138
|
+
specification_version: 4
|
139
|
+
summary: https://datmachine.co/guides
|
140
|
+
test_files: []
|