teamsnap_rb 1.3.3 → 2.0.0.beta
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/CHANGELOG.md +6 -0
- data/README.md +131 -29
- data/lib/config/inflecto.rb +13 -0
- data/lib/config/oj.rb +5 -0
- data/lib/teamsnap.rb +36 -376
- data/lib/teamsnap/api.rb +113 -0
- data/lib/teamsnap/auth_middleware.rb +62 -0
- data/lib/teamsnap/client.rb +51 -0
- data/lib/teamsnap/collection.rb +125 -0
- data/lib/teamsnap/item.rb +100 -0
- data/lib/teamsnap/response.rb +101 -0
- data/lib/teamsnap/structure.rb +80 -0
- data/lib/teamsnap/version.rb +1 -1
- data/spec/cassettes/apiv3-init.yml +756 -124
- data/spec/cassettes/client/when_calling_via_s_on_the_client/does_not_raise_an_error_when_the_HTTP_actions_are_called.yml +56 -0
- data/spec/cassettes/structure/_create_collection_class/registers_new_classes_via_introspection_of_the_root_collection.yml +110 -0
- data/spec/cassettes/structure/_create_collection_class/sets_the_href_attribute_on_the_new_class.yml +57 -0
- data/spec/cassettes/structure/_init/has_all_classes_in_schema_loaded_except_for_exceptions_list_endpoints.yml +56 -0
- data/spec/cassettes/structure/has_all_classes_in_schema_loaded_except_for_exceptions_list_endpoints.yml +56 -0
- data/spec/cassettes/teamsnap__client/when_calling_via_s_on_the_client/does_not_raise_an_error_when_the_HTTP_actions_are_called.yml +69 -0
- data/spec/cassettes/teamsnap__client/when_calling_via_s_on_the_client/passes_them_to_the_faraday_client_using_method_missing.yml +69 -0
- data/spec/cassettes/teamsnap__collection/adds_find_if_search_is_available.yml +61 -0
- data/spec/cassettes/teamsnap__collection/adds_href_to_items.yml +62 -0
- data/spec/cassettes/teamsnap__collection/can_follow_plural_links.yml +179 -0
- data/spec/cassettes/teamsnap__collection/can_follow_singular_links.yml +120 -0
- data/spec/cassettes/teamsnap__collection/can_handle_links_with_no_data.yml +107 -0
- data/spec/cassettes/{teamsnap_rb/can_handle_errors_generated_by_command.yml → teamsnap__collection/can_handle_no_argument_errors_generated_by_command.yml} +10 -16
- data/spec/cassettes/teamsnap__collection/handles_executing_an_action_via_commands.yml +64 -0
- data/spec/cassettes/teamsnap__collection/handles_executing_an_action_via_commands_with_multiple_params.yml +70 -0
- data/spec/cassettes/teamsnap__collection/handles_fetching_data_via_queries.yml +61 -0
- data/spec/cassettes/teamsnap__collection/handles_queries_with_no_data.yml +57 -0
- data/spec/cassettes/teamsnap__collection/raises_an_exception_if_find_returns_nothing.yml +57 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_array_of_objects_when_successful.yml +117 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_empty_array_when_no_objects_exist.yml +111 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_nil_if_it_does_NOT_exist.yml +111 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_the_object_if_it_exists.yml +124 -0
- data/spec/cassettes/teamsnap__structure/_create_collection_class/registers_new_classes_via_introspection_of_the_root_collection.yml +57 -0
- data/spec/cassettes/teamsnap__structure/_create_collection_class/sets_the_href_attribute_on_the_new_class.yml +57 -0
- data/spec/cassettes/teamsnap__structure/_init/has_all_classes_in_schema_loaded_except_for_exceptions_list_endpoints.yml +69 -0
- data/spec/cassettes/teamsnap_rb/_bulk_load/can_handle_an_empty_bulk_load.yml +55 -0
- data/spec/cassettes/teamsnap_rb/{can_handle_an_error_with_bulk_load.yml → _bulk_load/can_handle_an_error_with_bulk_load.yml} +11 -23
- data/spec/cassettes/teamsnap_rb/_bulk_load/can_use_bulk_load.yml +121 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_DELETE_on_the_given_client.yml +2405 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_GET_on_the_given_client.yml +69 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_PATCH_on_the_given_client.yml +2404 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_POST_on_the_given_client.yml +2404 -0
- data/spec/cassettes/teamsnap_rb/_run/processes_the_response.yml +267 -0
- data/spec/cassettes/teamsnap_rb/adds_find_if_search_is_available.yml +27 -30
- data/spec/cassettes/teamsnap_rb/adds_href_to_items.yml +31 -19
- data/spec/cassettes/teamsnap_rb/can_follow_plural_links.yml +118 -67
- data/spec/cassettes/teamsnap_rb/can_follow_singular_links.yml +59 -56
- data/spec/cassettes/teamsnap_rb/can_handle_links_with_no_data.yml +48 -38
- data/spec/cassettes/teamsnap_rb/can_handle_no_argument_errors_generated_by_command.yml +42 -0
- data/spec/cassettes/teamsnap_rb/handles_executing_an_action_via_commands.yml +32 -20
- data/spec/cassettes/teamsnap_rb/handles_executing_an_action_via_commands_with_multiple_params.yml +29 -404
- data/spec/cassettes/teamsnap_rb/handles_fetching_data_via_queries.yml +26 -23
- data/spec/cassettes/teamsnap_rb/handles_queries_with_no_data.yml +24 -28
- data/spec/cassettes/teamsnap_rb/raises_an_exception_if_find_returns_nothing.yml +24 -28
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_array_of_objects_when_successful.yml +53 -45
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_empty_array_when_no_objects_exist.yml +50 -54
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_nil_if_it_does_NOT_exist.yml +50 -54
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_the_object_if_it_exists.yml +59 -58
- data/spec/spec_helper.rb +2 -0
- data/spec/teamsnap/client_spec.rb +75 -0
- data/spec/teamsnap/collection_spec.rb +155 -0
- data/spec/teamsnap/item_spec.rb +155 -0
- data/spec/teamsnap/structure_spec.rb +63 -0
- data/spec/teamsnap_spec.rb +169 -157
- data/teamsnap_rb.gemspec +1 -1
- metadata +92 -15
- data/spec/cassettes/teamsnap_rb/can_handle_an_empty_bulk_load.yml +0 -60
- data/spec/cassettes/teamsnap_rb/can_use_bulk_load.yml +0 -74
data/lib/teamsnap/api.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
module TeamSnap
|
2
|
+
class Api
|
3
|
+
|
4
|
+
CRUD_METHODS = [:find, :create, :update, :delete]
|
5
|
+
CRUD_VIAS = [:get, :post, :patch, :delete]
|
6
|
+
|
7
|
+
def self.run(client, method, klass, args = {}, template_args = false)
|
8
|
+
klass = klass.class == Symbol ? get_class(klass) : klass
|
9
|
+
via = via(klass, method)
|
10
|
+
href = href(klass.href, method, args)
|
11
|
+
args = args(method, args)
|
12
|
+
client_send_args = template_args ? template_attributes(args) : args
|
13
|
+
resp = TeamSnap.client_send(client, via, href, client_send_args)
|
14
|
+
TeamSnap::Response.new(
|
15
|
+
:args => args,
|
16
|
+
:client => client,
|
17
|
+
:client_send_args => client_send_args,
|
18
|
+
:href => href,
|
19
|
+
:resp => resp,
|
20
|
+
:status => resp.status,
|
21
|
+
:via => via
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.args(method, sent_args)
|
26
|
+
case method
|
27
|
+
when :update
|
28
|
+
sent_args.except(:id)
|
29
|
+
when :find, :delete
|
30
|
+
{}
|
31
|
+
else
|
32
|
+
sent_args
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.get_class(sym)
|
37
|
+
"TeamSnap::#{sym.to_s.singularize.camelcase}".constantize
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.href(base_href, method, args = {})
|
41
|
+
case method
|
42
|
+
when :find, :delete
|
43
|
+
if [Fixnum, String].include?(args.class)
|
44
|
+
base_href + "/#{args}"
|
45
|
+
elsif args.class == Hash
|
46
|
+
base_href + "/#{args.fetch(:id)}"
|
47
|
+
else
|
48
|
+
raise TeamSnap::Error.new("You must pass in the `id` of the object you would like to :find or :delete")
|
49
|
+
end
|
50
|
+
when :create
|
51
|
+
base_href
|
52
|
+
when :update
|
53
|
+
base_href + "/#{args.fetch(:id)}"
|
54
|
+
else
|
55
|
+
base_href + "/#{method}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.via(klass, method)
|
60
|
+
queries = klass.query_names
|
61
|
+
commands = klass.command_names
|
62
|
+
|
63
|
+
method_map = CRUD_METHODS + queries + commands
|
64
|
+
via_map = CRUD_VIAS + ([:get] * queries.count) + ([:post] * commands.count)
|
65
|
+
|
66
|
+
# SET VIA
|
67
|
+
if method_index = method_map.index(method)
|
68
|
+
return via_map[method_index]
|
69
|
+
else
|
70
|
+
raise TeamSnap::Error.new("Method Missing: `#{method}` for Collection Class: `#{klass}`")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.parse_error(resp)
|
75
|
+
return "Object Not Found (404)" if resp.status == 404
|
76
|
+
begin
|
77
|
+
Oj.load(resp.body)
|
78
|
+
.fetch(:collection)
|
79
|
+
.fetch(:error)
|
80
|
+
.fetch(:message)
|
81
|
+
rescue KeyError
|
82
|
+
resp.body
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.template_args?(method)
|
87
|
+
[:create, :update].include?(method)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.template_attributes(attributes)
|
91
|
+
request_attributes = {
|
92
|
+
:template => {
|
93
|
+
:data => []
|
94
|
+
}
|
95
|
+
}
|
96
|
+
attributes.each do |key, value|
|
97
|
+
request_attributes[:template][:data] << {
|
98
|
+
"name" => key,
|
99
|
+
"value" => value
|
100
|
+
}
|
101
|
+
end
|
102
|
+
return request_attributes
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.untemplate_attributes(request_attributes)
|
106
|
+
attributes = {}
|
107
|
+
request_attributes.fetch(:template).fetch(:data).each do |datum|
|
108
|
+
attributes[datum.fetch(:name).to_sym] = datum.fetch(:value)
|
109
|
+
end
|
110
|
+
return attributes
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module TeamSnap
|
2
|
+
class AuthMiddleware < Faraday::Middleware
|
3
|
+
def initialize(app, options)
|
4
|
+
@options = options
|
5
|
+
super(app)
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
if token
|
10
|
+
env[:request_headers].merge!({"Authorization" => "Bearer #{token}"})
|
11
|
+
elsif client_id && client_secret
|
12
|
+
query_params = Hash[URI.decode_www_form(env.url.query || "")]
|
13
|
+
.merge({
|
14
|
+
hmac_client_id: client_id,
|
15
|
+
hmac_nonce: SecureRandom.uuid,
|
16
|
+
hmac_timestamp: Time.now.to_i
|
17
|
+
})
|
18
|
+
env.url.query = URI.encode_www_form(query_params)
|
19
|
+
|
20
|
+
env.request_headers["X-Teamsnap-Hmac"] = OpenSSL::HMAC.hexdigest(
|
21
|
+
digest, client_secret, message_hash(env)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
@app.call(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
def token
|
29
|
+
@token ||= @options[:token]
|
30
|
+
end
|
31
|
+
|
32
|
+
def client_id
|
33
|
+
@client_id ||= @options[:client_id]
|
34
|
+
end
|
35
|
+
|
36
|
+
def client_secret
|
37
|
+
@client_secret ||= @options[:client_secret]
|
38
|
+
end
|
39
|
+
|
40
|
+
def digest
|
41
|
+
OpenSSL::Digest.new("sha256")
|
42
|
+
end
|
43
|
+
|
44
|
+
def message_hash(env)
|
45
|
+
digest.hexdigest(
|
46
|
+
query_string(env) + message(env)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def query_string(env)
|
51
|
+
"/?" + env.url.query.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def message(env)
|
55
|
+
env.body || ""
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Faraday::Request.register_middleware(
|
61
|
+
:teamsnap_auth_middleware => -> { TeamSnap::AuthMiddleware }
|
62
|
+
)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module TeamSnap
|
2
|
+
class Client
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def set_faraday_client(url, token, client_id, client_secret)
|
6
|
+
Faraday.new(
|
7
|
+
:url => url,
|
8
|
+
:parallel_manager => Typhoeus::Hydra.new
|
9
|
+
) do |c|
|
10
|
+
c.request :teamsnap_auth_middleware, {
|
11
|
+
:token => token,
|
12
|
+
:client_id => client_id,
|
13
|
+
:client_secret => client_secret
|
14
|
+
}
|
15
|
+
c.adapter :typhoeus
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_accessor :faraday_client
|
21
|
+
|
22
|
+
def initialize(opts = {})
|
23
|
+
c_url = opts.fetch(:url) {}
|
24
|
+
c_token = opts.fetch(:token) {}
|
25
|
+
c_id = opts.fetch(:client_id) {}
|
26
|
+
c_secret = opts.fetch(:client_secret) {}
|
27
|
+
|
28
|
+
self.faraday_client = TeamSnap::Client.set_faraday_client(
|
29
|
+
c_url || TeamSnap.url,
|
30
|
+
c_token,
|
31
|
+
c_id || TeamSnap.client_id,
|
32
|
+
c_secret || TeamSnap.client_secret
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(method, *args, &block)
|
37
|
+
self.faraday_client.send(method, *args, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def api(method, klass, sent_args = {})
|
41
|
+
TeamSnap::Api.run(
|
42
|
+
self,
|
43
|
+
method,
|
44
|
+
klass,
|
45
|
+
sent_args,
|
46
|
+
TeamSnap::Api.template_args?(method)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module TeamSnap
|
2
|
+
module Collection
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def apply_endpoints(obj, collection)
|
7
|
+
queries = collection.fetch(:queries) { [] }
|
8
|
+
commands = collection.fetch(:commands) { [] }
|
9
|
+
|
10
|
+
endpoint_creation_set(obj, queries, :get)
|
11
|
+
endpoint_creation_set(obj, commands, :post)
|
12
|
+
end
|
13
|
+
|
14
|
+
def endpoint_creation_set(obj, creation_set, via)
|
15
|
+
creation_set.each{ |endpoint| register_endpoint(obj, endpoint, :via => via) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def register_endpoint(obj, endpoint, opts)
|
19
|
+
rel = endpoint.fetch(:rel)
|
20
|
+
href = endpoint.fetch(:href)
|
21
|
+
valid_args = endpoint.fetch(:data) { [] }
|
22
|
+
.map { |datum| datum.fetch(:name).to_sym }
|
23
|
+
via = opts.fetch(:via)
|
24
|
+
|
25
|
+
obj.define_singleton_method(rel) do |client, *args|
|
26
|
+
args = Hash[*args]
|
27
|
+
|
28
|
+
unless args.all? { |arg, _| valid_args.include?(arg) }
|
29
|
+
raise ArgumentError.new(
|
30
|
+
"Invalid argument(s). Valid argument(s) are #{valid_args.inspect}"
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
resp = TeamSnap.run(client, via, href, args)
|
35
|
+
TeamSnap::Item.load_items(client, resp)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def actions
|
41
|
+
actions = parsed_collection.fetch(:actions) {
|
42
|
+
%w(create read update delete search)
|
43
|
+
}
|
44
|
+
return actions.map(&:to_sym)
|
45
|
+
end
|
46
|
+
|
47
|
+
def queries
|
48
|
+
parsed_collection.fetch(:queries) { [] }
|
49
|
+
end
|
50
|
+
|
51
|
+
def query_names
|
52
|
+
queries.map{ |q| q[:rel].to_sym }
|
53
|
+
end
|
54
|
+
|
55
|
+
def commands
|
56
|
+
parsed_collection.fetch(:commands) { [] }
|
57
|
+
end
|
58
|
+
|
59
|
+
def command_names
|
60
|
+
commands.map{ |q| q[:rel].to_sym }
|
61
|
+
end
|
62
|
+
|
63
|
+
def create(client, attributes = {})
|
64
|
+
post_attributes = TeamSnap::Api.template_attributes(attributes)
|
65
|
+
|
66
|
+
create_resp = TeamSnap.run(client, :post, href, post_attributes)
|
67
|
+
TeamSnap::Item.load_items(client, create_resp).first
|
68
|
+
end
|
69
|
+
|
70
|
+
def update(client, id, attributes = {})
|
71
|
+
patch_attributes = TeamSnap::Api.template_attributes(attributes)
|
72
|
+
|
73
|
+
update_resp = TeamSnap.run(client, :patch, href+"/#{id}", patch_attributes)
|
74
|
+
TeamSnap::Item.load_items(client, update_resp).first
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete(client, id)
|
78
|
+
TeamSnap.run(client, :delete, href+"/#{id}", {})
|
79
|
+
end
|
80
|
+
|
81
|
+
def template_attributes
|
82
|
+
template = parsed_collection.fetch(:template) {}
|
83
|
+
data = template.fetch(:data) { [] }
|
84
|
+
data
|
85
|
+
.reject{ |col| col.fetch(:name) == "type" }
|
86
|
+
.map{ |col| col.fetch(:name) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def href
|
90
|
+
self.instance_variable_get(:@href)
|
91
|
+
end
|
92
|
+
|
93
|
+
def resp
|
94
|
+
self.instance_variable_get(:@resp)
|
95
|
+
end
|
96
|
+
|
97
|
+
def parsed_collection
|
98
|
+
self.instance_variable_get(:@parsed_collection)
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse_collection
|
102
|
+
if resp
|
103
|
+
TeamSnap.response_check(resp, :get)
|
104
|
+
collection = Oj.load(resp.body).fetch(:collection) { [] }
|
105
|
+
elsif parsed_collection
|
106
|
+
collection = parsed_collection
|
107
|
+
end
|
108
|
+
|
109
|
+
TeamSnap::Collection.apply_endpoints(self, collection)
|
110
|
+
enable_find if respond_to?(:search)
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def enable_find
|
116
|
+
define_singleton_method(:find) do |client, id|
|
117
|
+
search(client, :id => id).first.tap do |object|
|
118
|
+
raise TeamSnap::NotFound.new(
|
119
|
+
"Could not find a #{self} with an id of '#{id}'."
|
120
|
+
) unless object
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module TeamSnap
|
2
|
+
module Item
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def load_items(client, collection)
|
6
|
+
collection
|
7
|
+
.fetch(:items) { [] }
|
8
|
+
.map { |item|
|
9
|
+
data = parse_data(item).merge(:href => item[:href])
|
10
|
+
type = type_of(item)
|
11
|
+
cls = load_class(type, data)
|
12
|
+
|
13
|
+
cls.new(data).tap { |obj|
|
14
|
+
obj.send(:load_links, client, item.fetch(:links) { [] })
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_data(item)
|
20
|
+
data = item
|
21
|
+
.fetch(:data)
|
22
|
+
.map { |datum|
|
23
|
+
name = datum.fetch(:name)
|
24
|
+
value = datum.fetch(:value)
|
25
|
+
type = datum.fetch(:type) { :default }
|
26
|
+
|
27
|
+
value = DateTime.parse(value) if value && type == "DateTime"
|
28
|
+
|
29
|
+
[name, value]
|
30
|
+
}
|
31
|
+
hashify(data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def type_of(item)
|
35
|
+
item
|
36
|
+
.fetch(:data)
|
37
|
+
.find { |datum| datum.fetch(:name) == "type" }
|
38
|
+
.fetch(:value)
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_class(type, data)
|
42
|
+
TeamSnap.const_get(Inflecto.camelize(type), false).tap { |cls|
|
43
|
+
unless cls.include?(Virtus::Model::Core)
|
44
|
+
cls.class_eval do
|
45
|
+
include Virtus.value_object
|
46
|
+
|
47
|
+
values do
|
48
|
+
attribute :href, String
|
49
|
+
data.each { |name, value| attribute name, value.class }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def hashify(arr)
|
57
|
+
Hash[*arr.flatten]
|
58
|
+
rescue NoMethodError
|
59
|
+
arr.inject({}) { |hash, (key, value)| hash[key] = value; hash }
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def load_links(client, links)
|
67
|
+
links.each do |link|
|
68
|
+
next if EXCLUDED_RELS.include?(link.fetch(:rel))
|
69
|
+
|
70
|
+
rel = link.fetch(:rel)
|
71
|
+
href = link.fetch(:href)
|
72
|
+
is_singular = rel == Inflecto.singularize(rel)
|
73
|
+
|
74
|
+
define_singleton_method(rel) {
|
75
|
+
instance_variable_get("@#{rel}") || instance_variable_set(
|
76
|
+
"@#{rel}", -> {
|
77
|
+
coll = TeamSnap::Item.load_items(
|
78
|
+
client,
|
79
|
+
TeamSnap.run(client, :get, href)
|
80
|
+
)
|
81
|
+
is_singular ? coll.first : coll
|
82
|
+
}.call
|
83
|
+
)
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
define_singleton_method(:update) { |attributes|
|
88
|
+
patch_attributes = TeamSnap::Api.template_attributes(attributes)
|
89
|
+
|
90
|
+
response = TeamSnap.run(client, :patch, instance_variable_get("@href"), patch_attributes)
|
91
|
+
TeamSnap::Item.load_items(client, response).first
|
92
|
+
}
|
93
|
+
|
94
|
+
define_singleton_method(:delete) {
|
95
|
+
response = TeamSnap.run(client, :delete, instance_variable_get("@href"), {})
|
96
|
+
TeamSnap::Item.load_items(client, response).first
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|