dyndrop 0.0.1 → 0.0.2
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.
- data/LICENSE +1277 -0
- data/lib/dyndrop.rb +2 -0
- data/lib/dyndrop/auth_token.rb +63 -0
- data/lib/dyndrop/baseclient.rb +178 -0
- data/lib/dyndrop/client.rb +18 -0
- data/lib/dyndrop/errors.rb +152 -0
- data/lib/dyndrop/rest_client.rb +299 -0
- data/lib/dyndrop/trace_helpers.rb +40 -0
- data/lib/dyndrop/v1/base.rb +28 -0
- data/lib/dyndrop/v1/client.rb +114 -0
- data/lib/dyndrop/v1/model_magic.rb +129 -0
- data/lib/dyndrop/validator.rb +39 -0
- data/lib/dyndrop/version.rb +1 -1
- metadata +13 -1
@@ -0,0 +1,40 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "multi_json"
|
3
|
+
|
4
|
+
module Dyndrop
|
5
|
+
module TraceHelpers
|
6
|
+
|
7
|
+
def request_trace(request)
|
8
|
+
return nil unless request
|
9
|
+
info = ["REQUEST: #{request[:method]} #{request[:url]}"]
|
10
|
+
info << "REQUEST_HEADERS:"
|
11
|
+
info << header_trace(request[:headers])
|
12
|
+
info << "REQUEST_BODY: #{request[:body]}" if request[:body]
|
13
|
+
info.join("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def response_trace(response)
|
18
|
+
return nil unless response
|
19
|
+
info = ["RESPONSE: [#{response[:status]}]"]
|
20
|
+
info << "RESPONSE_HEADERS:"
|
21
|
+
info << header_trace(response[:headers])
|
22
|
+
info << "RESPONSE_BODY:"
|
23
|
+
begin
|
24
|
+
parsed_body = MultiJson.load(response[:body])
|
25
|
+
info << MultiJson.dump(parsed_body, :pretty => true)
|
26
|
+
rescue
|
27
|
+
info << "#{response[:body]}"
|
28
|
+
end
|
29
|
+
info.join("\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def header_trace(headers)
|
35
|
+
headers.sort.map do |key, value|
|
36
|
+
" #{key} : #{value}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "multi_json"
|
2
|
+
require "tmpdir"
|
3
|
+
|
4
|
+
require "dyndrop/baseclient"
|
5
|
+
|
6
|
+
require "dyndrop/errors"
|
7
|
+
|
8
|
+
module Dyndrop::V1
|
9
|
+
class Base < Dyndrop::BaseClient
|
10
|
+
|
11
|
+
def get_token(email, payload)
|
12
|
+
post("1", "users", email, "tokens", :content => :json, :accept => :json, :payload => payload)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Users
|
16
|
+
def create_user(payload)
|
17
|
+
# no JSON response
|
18
|
+
post("users", :content => :json, :payload => payload)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Applications
|
22
|
+
def instances(name)
|
23
|
+
get("apps", name, "instances", :accept => :json)[:instances]
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Dyndrop::V1
|
2
|
+
# The primary API entrypoint. Wraps a BaseClient to provide nicer return
|
3
|
+
# values. Initialize with the target and, optionally, an auth token. These
|
4
|
+
# are the only two internal states.
|
5
|
+
class Client
|
6
|
+
|
7
|
+
attr_reader :base
|
8
|
+
|
9
|
+
# Create a new Client for interfacing with the given target.
|
10
|
+
#
|
11
|
+
# A token may also be provided to skip the login step.
|
12
|
+
def initialize(target = "http://api.dyndrop.com", token = nil)
|
13
|
+
@base = Base.new(target, token)
|
14
|
+
end
|
15
|
+
|
16
|
+
def version
|
17
|
+
1
|
18
|
+
end
|
19
|
+
|
20
|
+
# The current target URL of the client.
|
21
|
+
def target
|
22
|
+
@base.target
|
23
|
+
end
|
24
|
+
|
25
|
+
# Current authentication token.
|
26
|
+
def token
|
27
|
+
@base.token
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set the authentication token.
|
31
|
+
def token=(token)
|
32
|
+
@base.token = token
|
33
|
+
end
|
34
|
+
|
35
|
+
# Current proxy user. Usually nil.
|
36
|
+
def proxy
|
37
|
+
@base.proxy
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the proxy user for the client. Must be authorized as an
|
41
|
+
# administrator for this to have any effect.
|
42
|
+
def proxy=(email)
|
43
|
+
@base.proxy = email
|
44
|
+
end
|
45
|
+
|
46
|
+
# Is the client tracing API requests?
|
47
|
+
def trace
|
48
|
+
@base.trace
|
49
|
+
end
|
50
|
+
|
51
|
+
# Set the tracing flag; if true, API requests and responses will be
|
52
|
+
# printed out.
|
53
|
+
def trace=(bool)
|
54
|
+
@base.trace = bool
|
55
|
+
end
|
56
|
+
|
57
|
+
# The current log. See +log=+.
|
58
|
+
def log
|
59
|
+
@base.log
|
60
|
+
end
|
61
|
+
|
62
|
+
# Set the logging mode. Mode can be one of:
|
63
|
+
#
|
64
|
+
# [+String+] Name of a file to log the last 10 requests to.
|
65
|
+
# [+Array+] Array to append with log data (a Hash).
|
66
|
+
# [+IO+] An IO object to write to.
|
67
|
+
# [+false+] No logging.
|
68
|
+
def log=(mode)
|
69
|
+
@base.log = mode
|
70
|
+
end
|
71
|
+
|
72
|
+
# The currently authenticated user.
|
73
|
+
def current_user
|
74
|
+
if user = info[:user]
|
75
|
+
user(user)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def current_space
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_org
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
# Retrieve target metadata.
|
89
|
+
def info
|
90
|
+
@base.info
|
91
|
+
end
|
92
|
+
|
93
|
+
def login(username, password)
|
94
|
+
@base.token = Dyndrop::AuthToken.from_token_info(@base.get_token(username, {:password => password}))
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# Create a user on the target and return a User object representing them.
|
99
|
+
def register(email, password)
|
100
|
+
@base.create_user(:email => email, :password => password)
|
101
|
+
user(email)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Clear client token. No requests are made for this.
|
105
|
+
def logout
|
106
|
+
@base.token = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
# Is an authentication token set on the client?
|
110
|
+
def logged_in?
|
111
|
+
!!@base.token
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require "dyndrop/validator"
|
2
|
+
|
3
|
+
module Dyndrop::V1
|
4
|
+
module BaseClientMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClientMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ModelMagic
|
11
|
+
attr_accessor :guid_name
|
12
|
+
|
13
|
+
def read_locations
|
14
|
+
@read_locations ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_locations
|
18
|
+
@write_locations ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_only_attributes
|
22
|
+
@read_only_attributes ||= []
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_client(&blk)
|
26
|
+
ClientMethods.module_eval(&blk)
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_base_client(&blk)
|
30
|
+
BaseClientMethods.module_eval(&blk)
|
31
|
+
end
|
32
|
+
|
33
|
+
def define_client_methods(klass = self)
|
34
|
+
singular = klass.object_name
|
35
|
+
plural = klass.plural_object_name
|
36
|
+
|
37
|
+
base_singular = klass.base_object_name
|
38
|
+
base_plural = klass.plural_base_object_name
|
39
|
+
|
40
|
+
on_base_client do
|
41
|
+
define_method(base_singular) do |guid|
|
42
|
+
get(base_plural, guid, :accept => :json)
|
43
|
+
end
|
44
|
+
|
45
|
+
define_method(:"create_#{base_singular}") do |payload|
|
46
|
+
post(base_plural, :content => :json, :accept => :json, :payload => payload)
|
47
|
+
end
|
48
|
+
|
49
|
+
define_method(:"delete_#{base_singular}") do |guid|
|
50
|
+
delete(base_plural, guid)
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
define_method(:"update_#{base_singular}") do |guid, payload|
|
55
|
+
put(base_plural, guid, :content => :json, :payload => payload)
|
56
|
+
end
|
57
|
+
|
58
|
+
define_method(base_plural) do |*args|
|
59
|
+
get(base_plural, :accept => :json)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
on_client do
|
64
|
+
if klass.guid_name
|
65
|
+
define_method(:"#{singular}_by_#{klass.guid_name}") do |guid|
|
66
|
+
obj = send(singular, guid)
|
67
|
+
obj if obj.exists?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
define_method(singular) do |*args|
|
72
|
+
guid, _ = args
|
73
|
+
klass.new(guid, self)
|
74
|
+
end
|
75
|
+
|
76
|
+
define_method(plural) do |*args|
|
77
|
+
options, _ = args
|
78
|
+
options ||= {}
|
79
|
+
|
80
|
+
@base.send(base_plural).collect do |json|
|
81
|
+
klass.new(json[klass.guid_name], self, json)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def attribute(name, type, opts = {})
|
88
|
+
default = opts[:default]
|
89
|
+
is_guid = opts[:guid]
|
90
|
+
read_only = opts[:read_only]
|
91
|
+
write_only = opts[:write_only]
|
92
|
+
has_default = opts.key?(:default)
|
93
|
+
|
94
|
+
read_locations[name] = Array(opts[:read] || opts[:at] || name) unless write_only
|
95
|
+
write_locations[name] = Array(opts[:write] || opts[:at] || name) unless read_only
|
96
|
+
|
97
|
+
read_only_attributes << name if read_only
|
98
|
+
|
99
|
+
self.guid_name = name if is_guid
|
100
|
+
|
101
|
+
define_method(name) do
|
102
|
+
return @guid if @guid && is_guid
|
103
|
+
|
104
|
+
read = read_manifest
|
105
|
+
read.key?(name) ? read[name] : default
|
106
|
+
end
|
107
|
+
|
108
|
+
define_method(:"#{name}=") do |val|
|
109
|
+
unless has_default && val == default
|
110
|
+
Dyndrop::Validator.validate_type(val, type)
|
111
|
+
end
|
112
|
+
|
113
|
+
@guid = val if is_guid
|
114
|
+
|
115
|
+
@manifest ||= {}
|
116
|
+
|
117
|
+
old = read_manifest[name]
|
118
|
+
@changes[name] = [old, val] if old != val
|
119
|
+
|
120
|
+
write_to = read_only ? self.class.read_locations : self.class.write_locations
|
121
|
+
|
122
|
+
put(val, @manifest, write_to[name])
|
123
|
+
end
|
124
|
+
|
125
|
+
private name if write_only
|
126
|
+
private :"#{name}=" if read_only
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Dyndrop
|
2
|
+
module Validator
|
3
|
+
class << self
|
4
|
+
def value_matches?(val, type)
|
5
|
+
case type
|
6
|
+
when Class
|
7
|
+
val.is_a?(type)
|
8
|
+
when Regexp
|
9
|
+
val.is_a?(String) && val =~ type
|
10
|
+
when :url
|
11
|
+
value_matches?(val, URI::regexp(%w(http https)))
|
12
|
+
when :https_url
|
13
|
+
value_matches?(val, URI::regexp("https"))
|
14
|
+
when :boolean
|
15
|
+
val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
16
|
+
when Array
|
17
|
+
val.all? do |x|
|
18
|
+
value_matches?(x, type.first)
|
19
|
+
end
|
20
|
+
when Hash
|
21
|
+
val.is_a?(Hash) &&
|
22
|
+
type.all? { |name, subtype|
|
23
|
+
val.key?(name) && value_matches?(val[name], subtype)
|
24
|
+
}
|
25
|
+
when nil
|
26
|
+
true
|
27
|
+
else
|
28
|
+
val.is_a?(Object.const_get(type.to_s.capitalize))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_type(val, type)
|
33
|
+
unless value_matches?(val, type)
|
34
|
+
raise Dyndrop::Mismatch.new(type, val)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/dyndrop/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dyndrop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -19,7 +19,19 @@ executables: []
|
|
19
19
|
extensions: []
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
|
+
- LICENSE
|
23
|
+
- lib/dyndrop.rb
|
24
|
+
- lib/dyndrop/baseclient.rb
|
22
25
|
- lib/dyndrop/version.rb
|
26
|
+
- lib/dyndrop/client.rb
|
27
|
+
- lib/dyndrop/auth_token.rb
|
28
|
+
- lib/dyndrop/errors.rb
|
29
|
+
- lib/dyndrop/rest_client.rb
|
30
|
+
- lib/dyndrop/validator.rb
|
31
|
+
- lib/dyndrop/trace_helpers.rb
|
32
|
+
- lib/dyndrop/v1/client.rb
|
33
|
+
- lib/dyndrop/v1/model_magic.rb
|
34
|
+
- lib/dyndrop/v1/base.rb
|
23
35
|
homepage: http://github.com/dyndrop/dyndrop
|
24
36
|
licenses: []
|
25
37
|
post_install_message:
|