tacokit 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +86 -0
- data/.travis.yml +6 -0
- data/Gemfile +16 -25
- data/Guardfile +1 -1
- data/README.md +61 -17
- data/Rakefile +10 -5
- data/lib/tacokit/authorization.rb +14 -13
- data/lib/tacokit/client/actions.rb +68 -28
- data/lib/tacokit/client/boards.rb +92 -85
- data/lib/tacokit/client/cards.rb +285 -92
- data/lib/tacokit/client/checklists.rb +48 -28
- data/lib/tacokit/client/labels.rb +14 -16
- data/lib/tacokit/client/lists.rb +52 -28
- data/lib/tacokit/client/members.rb +56 -46
- data/lib/tacokit/client/notifications.rb +13 -27
- data/lib/tacokit/client/organizations.rb +0 -6
- data/lib/tacokit/client/searches.rb +0 -1
- data/lib/tacokit/client/tokens.rb +0 -6
- data/lib/tacokit/client/types.rb +0 -1
- data/lib/tacokit/client/webhooks.rb +3 -8
- data/lib/tacokit/client.rb +48 -75
- data/lib/tacokit/collection.rb +49 -0
- data/lib/tacokit/configuration.rb +4 -6
- data/lib/tacokit/error.rb +0 -2
- data/lib/tacokit/middleware/boom.rb +6 -7
- data/lib/tacokit/middleware.rb +2 -10
- data/lib/tacokit/resource.rb +84 -57
- data/lib/tacokit/response.rb +3 -3
- data/lib/tacokit/transform.rb +35 -13
- data/lib/tacokit/utils.rb +40 -8
- data/lib/tacokit/version.rb +1 -1
- data/lib/tacokit.rb +0 -2
- data/spec/cassettes/Tacokit_Client_Actions/_action_board/returns_action_board.json +1 -0
- data/spec/cassettes/Tacokit_Client_Actions/_action_card/returns_action_card.json +1 -0
- data/spec/cassettes/Tacokit_Client_Actions/_action_entities/returns_action_entities.json +1 -0
- data/spec/cassettes/Tacokit_Client_Actions/_action_list/returns_action_list.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_add_board_member/adds_invites_member_to_board.json +1 -1
- data/spec/cassettes/Tacokit_Client_Boards/_board_actions/returns_board_actions.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_cards/returns_board_cards.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_checklists/returns_board_checklists.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_labels/returns_board_labels.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_lists/returns_board_lists.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_members/returns_board_members.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_organization/returns_board_organization.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_preferences/returns_preferences_for_a_board.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_board_stars/returns_board_stars.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_member_board_stars/returns_board_stars.json +1 -0
- data/spec/cassettes/Tacokit_Client_Boards/_update_board_member/updates_member.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_add_comment/creates_a_comment.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_add_label/adds_label_to_card.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_add_member_to_card/adds_member_to_card.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_archive_card/archives_card.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_archive_card/restore_card.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_attachments/returns_an_attachment.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_attachments/returns_attachment.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_attachments/returns_attachments.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_card/returns_a_card_by_card_resource.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_card/returns_a_card_by_id.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card/returns_a_card_by_short_link.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card_actions/returns_card_actions.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_card_board/returns_card_board.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_card_field/returns_a_hash.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card_field/returns_a_value.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card_field/returns_an_array.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card_list/returns_a_list.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_card_members/returns_members.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_card_members/returns_members_voted.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_card_resource/returns_card_actions.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card_resource/returns_card_board.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card_resource/returns_card_check_item_states.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_card_stickers/returns_.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_checklists/returns_check_item_states.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_checklists/returns_checklists.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_create_card/creates_a_card.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_create_card_attachment/attaches_external_url.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_create_card_attachment/uploads_local_file.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_delete_card/deletes_a_card.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_delete_card_resource/deletes_resource.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_delete_comment/deletes_comment.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_list/returns_list.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_move_card/moves_card_to_a_new_position.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_move_card/moves_card_to_another_board_list.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_move_card/moves_card_to_board.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_move_card/moves_card_to_list.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_move_card/raises_error_if_missing_options.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_start_checklist/adds_a_checklist_item.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_start_checklist/adds_new_checklist_by_name.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_start_checklist/copies_a_checklist_by_id.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_stickers/returns_stickers.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_update_card/updates_a_card.json +1 -1
- data/spec/cassettes/Tacokit_Client_Cards/_update_checklist_item/updates_checklist_item.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_update_comment/updates_a_comment.json +1 -0
- data/spec/cassettes/Tacokit_Client_Cards/_vote/adds_a_member_s_vote_to_card.json +1 -0
- data/spec/cassettes/Tacokit_Client_Checklists/_check_items/adds_a_checklist_check_item.json +1 -0
- data/spec/cassettes/Tacokit_Client_Checklists/_check_items/retrieves_checklist_check_items.json +1 -0
- data/spec/cassettes/Tacokit_Client_Lists/_archive_list_cards/should_archive_cards_in_list.json +1 -0
- data/spec/cassettes/Tacokit_Client_Lists/_list_actions/returns_list_actions.json +1 -0
- data/spec/cassettes/Tacokit_Client_Lists/_list_board/returns_list_board.json +1 -0
- data/spec/cassettes/Tacokit_Client_Lists/_list_cards/returns_list_cards.json +1 -0
- data/spec/cassettes/Tacokit_Client_Lists/_move_list_cards/should_move_cards_in_list.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_actions/returns_member_actions.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_board_stars/returns_member_board_stars.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_boards/returns_member_boards.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_cards/returns_member_cards.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_notifications/returns_member_notifications.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_organizations/returns_member_organizations.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_tokens/returns_member_organizations.json +1 -0
- data/spec/cassettes/Tacokit_Client_Members/_tokens/returns_member_tokens.json +1 -0
- data/spec/spec_helper.rb +39 -29
- data/spec/tacokit/authorization_spec.rb +11 -11
- data/spec/tacokit/client/actions_spec.rb +56 -19
- data/spec/tacokit/client/boards_spec.rb +81 -78
- data/spec/tacokit/client/cards_spec.rb +322 -68
- data/spec/tacokit/client/checklists_spec.rb +29 -27
- data/spec/tacokit/client/labels_spec.rb +8 -16
- data/spec/tacokit/client/lists_spec.rb +74 -27
- data/spec/tacokit/client/members_spec.rb +55 -41
- data/spec/tacokit/client/notifications_spec.rb +3 -31
- data/spec/tacokit/client/organizations_spec.rb +6 -27
- data/spec/tacokit/client/searches_spec.rb +1 -3
- data/spec/tacokit/client/tokens_spec.rb +2 -18
- data/spec/tacokit/client/types_spec.rb +2 -3
- data/spec/tacokit/client/webhooks_spec.rb +6 -14
- data/spec/tacokit/client_spec.rb +3 -3
- data/spec/tacokit/configuration_spec.rb +30 -31
- data/spec/tacokit/middleware/boom_spec.rb +6 -7
- data/spec/tacokit/resource_spec.rb +142 -17
- data/spec/tacokit/transform_spec.rb +37 -35
- data/spec/tacokit_spec.rb +3 -5
- data/tacokit.gemspec +6 -6
- metadata +132 -15
- data/config.ru +0 -7
- data/lib/tacokit/middleware/debug.rb +0 -22
- data/spec/cassettes/Tacokit_Client_Boards/_update_board_resource/updates_member.json +0 -1
- data/spec/cassettes/Tacokit_Client_Members/_member/raises_error_for_missing_token.json +0 -1
data/lib/tacokit/client.rb
CHANGED
@@ -1,27 +1,30 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
require
|
4
|
-
|
5
|
-
|
6
|
-
require
|
7
|
-
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
|
12
|
-
require
|
13
|
-
require
|
14
|
-
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
require "addressable/uri"
|
4
|
+
|
5
|
+
require "faraday"
|
6
|
+
require "faraday_middleware"
|
7
|
+
|
8
|
+
require "tacokit/authorization"
|
9
|
+
require "tacokit/collection"
|
10
|
+
require "tacokit/configuration"
|
11
|
+
require "tacokit/middleware"
|
12
|
+
require "tacokit/response"
|
13
|
+
require "tacokit/transform"
|
14
|
+
|
15
|
+
require "tacokit/client/actions"
|
16
|
+
require "tacokit/client/boards"
|
17
|
+
require "tacokit/client/cards"
|
18
|
+
require "tacokit/client/checklists"
|
19
|
+
require "tacokit/client/labels"
|
20
|
+
require "tacokit/client/lists"
|
21
|
+
require "tacokit/client/members"
|
22
|
+
require "tacokit/client/notifications"
|
23
|
+
require "tacokit/client/organizations"
|
24
|
+
require "tacokit/client/searches"
|
25
|
+
require "tacokit/client/tokens"
|
26
|
+
require "tacokit/client/types"
|
27
|
+
require "tacokit/client/webhooks"
|
25
28
|
|
26
29
|
module Tacokit
|
27
30
|
class Client
|
@@ -47,10 +50,12 @@ module Tacokit
|
|
47
50
|
def_delegators :configuration, *Configuration.keys
|
48
51
|
def_delegators :configuration, :user_authenticated?, :user_credentials
|
49
52
|
def_delegators :configuration, :app_authenticated?, :app_credentials
|
50
|
-
def_delegators :transform, :serialize, :deserialize
|
53
|
+
def_delegators :transform, :serialize, :deserialize, :serialize_params
|
54
|
+
|
55
|
+
attr_accessor :last_response
|
51
56
|
|
52
57
|
def initialize(options = {})
|
53
|
-
|
58
|
+
configuration.options = options
|
54
59
|
end
|
55
60
|
|
56
61
|
def reset!
|
@@ -81,61 +86,24 @@ module Tacokit
|
|
81
86
|
request :delete, url, options
|
82
87
|
end
|
83
88
|
|
89
|
+
def paginated_get(*args)
|
90
|
+
Collection.new(self, :get, *args)
|
91
|
+
end
|
92
|
+
|
84
93
|
def request(method, url, data = nil, params = nil)
|
85
94
|
if [:get, :body].include?(method)
|
86
95
|
params ||= data
|
87
96
|
data = nil
|
88
97
|
end
|
89
98
|
|
90
|
-
params = normalize_request_params(params || {})
|
91
99
|
response = connection.send method, url do |req|
|
92
|
-
req.params.update params
|
100
|
+
req.params.update serialize_params(params)
|
93
101
|
req.body = serialize(data) if data
|
94
102
|
end
|
95
103
|
|
96
|
-
Response.new(self, response)
|
97
|
-
end
|
98
|
-
|
99
|
-
def transform
|
100
|
-
@transform ||= Transform.new
|
101
|
-
end
|
102
|
-
|
103
|
-
# Prepare ruby-style params for trello request
|
104
|
-
def normalize_request_params(params)
|
105
|
-
{}.tap do |norm|
|
106
|
-
params.each do |key,value|
|
107
|
-
norm[key] = normalize_param_value(value)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
104
|
+
@last_response = last_response = Response.new(self, response)
|
111
105
|
|
112
|
-
|
113
|
-
case value
|
114
|
-
when Array
|
115
|
-
value.map { |v| camp(v) }.join(',')
|
116
|
-
when /\,/
|
117
|
-
normalize_param_value(value.split(','))
|
118
|
-
else
|
119
|
-
camp(value)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def path_join(*paths)
|
124
|
-
paths.join('/')
|
125
|
-
end
|
126
|
-
|
127
|
-
def to_path(*paths)
|
128
|
-
warn "to_path is deprecated"
|
129
|
-
path_join(*paths)
|
130
|
-
end
|
131
|
-
|
132
|
-
def camel_path(path)
|
133
|
-
camelize(path.to_s, :lower)
|
134
|
-
end
|
135
|
-
alias camp camel_path
|
136
|
-
|
137
|
-
def camel_join(*paths)
|
138
|
-
path_join paths.map { |p| camel_path(p) }
|
106
|
+
last_response.data
|
139
107
|
end
|
140
108
|
|
141
109
|
def to_s
|
@@ -143,13 +111,19 @@ module Tacokit
|
|
143
111
|
end
|
144
112
|
alias_method :inspect, :to_s
|
145
113
|
|
114
|
+
private
|
115
|
+
|
116
|
+
def transform
|
117
|
+
@transform ||= Transform.new
|
118
|
+
end
|
119
|
+
|
146
120
|
def connection
|
147
|
-
@connection
|
148
|
-
http.headers[:user_agent] =
|
121
|
+
@connection ||= Faraday.new(url: api_endpoint) do |http|
|
122
|
+
http.headers[:user_agent] = "TacoKit 0.0.1"
|
149
123
|
|
150
124
|
if user_authenticated?
|
151
125
|
http.request :oauth, user_credentials
|
152
|
-
|
126
|
+
elsif app_authenticated?
|
153
127
|
http.params.update app_credentials
|
154
128
|
end
|
155
129
|
|
@@ -159,11 +133,10 @@ module Tacokit
|
|
159
133
|
|
160
134
|
http.response :json, content_type: /\bjson$/
|
161
135
|
http.response :boom
|
162
|
-
http.response :logger if ENV[
|
136
|
+
http.response :logger if ENV["DEBUG"]
|
163
137
|
|
164
138
|
http.adapter Faraday.default_adapter
|
165
139
|
end
|
166
140
|
end
|
167
|
-
|
168
141
|
end
|
169
142
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Tacokit
|
4
|
+
class Collection
|
5
|
+
include Enumerable
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
MAX = 1000
|
9
|
+
|
10
|
+
def_delegators :@collection, :[], :empty?, :size
|
11
|
+
|
12
|
+
def initialize(client, method, path, options)
|
13
|
+
@client, @method, @path, @options = client, method, path, options
|
14
|
+
|
15
|
+
@page = options.fetch(:page, 0)
|
16
|
+
@limit = options.fetch(:limit, 50)
|
17
|
+
|
18
|
+
@collection = []
|
19
|
+
|
20
|
+
fetch_next_page
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(start = 0)
|
24
|
+
return to_enum(:each, start) unless block_given?
|
25
|
+
Array(@collection[start..-1]).each do |element|
|
26
|
+
yield(element)
|
27
|
+
end
|
28
|
+
unless last?
|
29
|
+
start = [@collection.size, start].max
|
30
|
+
fetch_next_page
|
31
|
+
each(start, &Proc.new)
|
32
|
+
end
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def last?
|
39
|
+
@last_response_empty || (@page * @limit) >= MAX
|
40
|
+
end
|
41
|
+
|
42
|
+
def fetch_next_page
|
43
|
+
response = @client.send(@method, @path, @options.merge(page: @page))
|
44
|
+
@last_response_empty = response.empty?
|
45
|
+
@page += 1
|
46
|
+
@collection += response
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Tacokit
|
2
2
|
class Configuration
|
3
|
-
|
4
3
|
API_URL = "https://api.trello.com".freeze
|
5
4
|
WEB_URL = "https://trello.com".freeze
|
6
5
|
|
@@ -41,7 +40,7 @@ module Tacokit
|
|
41
40
|
end
|
42
41
|
|
43
42
|
def app_credentials
|
44
|
-
{ key: app_key, token: app_token }.delete_if { |k,v| v.nil? }
|
43
|
+
{ key: app_key, token: app_token }.delete_if { |k, v| v.nil? }
|
45
44
|
end
|
46
45
|
|
47
46
|
private
|
@@ -50,11 +49,10 @@ module Tacokit
|
|
50
49
|
{
|
51
50
|
api_endpoint: File.join(API_URL, API_VERSION),
|
52
51
|
web_endpoint: File.join(WEB_URL, API_VERSION),
|
53
|
-
app_key: ENV[
|
54
|
-
app_secret: ENV[
|
55
|
-
app_token: ENV[
|
52
|
+
app_key: ENV["TRELLO_APP_KEY"],
|
53
|
+
app_secret: ENV["TRELLO_APP_SECRET"],
|
54
|
+
app_token: ENV["TRELLO_APP_TOKEN"]
|
56
55
|
}
|
57
56
|
end
|
58
|
-
|
59
57
|
end
|
60
58
|
end
|
data/lib/tacokit/error.rb
CHANGED
@@ -1,26 +1,25 @@
|
|
1
1
|
module Tacokit
|
2
2
|
module Middleware
|
3
3
|
class Boom < Faraday::Response::Middleware
|
4
|
-
|
4
|
+
CLIENT_ERROR_STATUSES = 400...600
|
5
5
|
|
6
6
|
def on_complete(env)
|
7
7
|
case env[:status]
|
8
8
|
when 401
|
9
|
-
raise Tacokit::Error::Unauthorized
|
9
|
+
raise Tacokit::Error::Unauthorized, error_message(env)
|
10
10
|
when 404
|
11
|
-
raise Tacokit::Error::ResourceNotFound
|
11
|
+
raise Tacokit::Error::ResourceNotFound, error_message(env)
|
12
12
|
when 407
|
13
13
|
# mimic the behavior that we get with proxy requests with HTTPS
|
14
|
-
raise Tacokit::Error::ConnectionFailed, %
|
15
|
-
when
|
16
|
-
raise Tacokit::Error::ClientError
|
14
|
+
raise Tacokit::Error::ConnectionFailed, %(407 "Proxy Authentication Required ")
|
15
|
+
when CLIENT_ERROR_STATUSES
|
16
|
+
raise Tacokit::Error::ClientError, error_message(env)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
def error_message(env)
|
21
21
|
"Server returned #{env[:status]}: #{env.body}. Headers #{env.response_headers.inspect}"
|
22
22
|
end
|
23
|
-
|
24
23
|
end
|
25
24
|
end
|
26
25
|
end
|
data/lib/tacokit/middleware.rb
CHANGED
@@ -1,15 +1,7 @@
|
|
1
|
-
require
|
2
|
-
# require 'tacokit/middleware/debug'
|
1
|
+
require "tacokit/middleware/boom"
|
3
2
|
|
4
3
|
module Tacokit
|
5
4
|
module Middleware
|
6
|
-
|
7
|
-
# Faraday::Request.register_middleware \
|
8
|
-
# :example => lambda { Tacokit::Middleware::Example }
|
9
|
-
#
|
10
|
-
|
11
|
-
Faraday::Response.register_middleware \
|
12
|
-
:boom => lambda { Tacokit::Middleware::Boom }
|
13
|
-
|
5
|
+
Faraday::Response.register_middleware boom: -> { Tacokit::Middleware::Boom }
|
14
6
|
end
|
15
7
|
end
|
data/lib/tacokit/resource.rb
CHANGED
@@ -1,36 +1,25 @@
|
|
1
|
-
require
|
1
|
+
require "forwardable"
|
2
2
|
|
3
3
|
module Tacokit
|
4
4
|
class Resource
|
5
|
-
SPECIAL_METHODS = Set.new(%w(client fields))
|
6
|
-
attr_reader :_client
|
7
|
-
attr_reader :_fields
|
8
|
-
attr_reader :attrs
|
9
|
-
alias to_hash attrs
|
10
|
-
alias to_h attrs
|
11
5
|
include Enumerable
|
12
6
|
extend Forwardable
|
13
7
|
|
14
|
-
|
8
|
+
SPECIAL_METHODS = Set.new(%w[fields])
|
9
|
+
attr_reader :_fields
|
10
|
+
attr_reader :attrs
|
11
|
+
alias_method :to_hash, :attrs
|
12
|
+
alias_method :to_h, :attrs
|
13
|
+
|
14
|
+
def_delegators :@_fields, :fetch, :keys, :any?
|
15
15
|
|
16
|
-
def initialize(
|
17
|
-
@_client = client
|
16
|
+
def initialize(data = {})
|
18
17
|
@attrs = {}
|
19
|
-
@_metaclass = (class << self; self; end)
|
20
18
|
@_fields = Set.new
|
21
19
|
data.each do |key, value|
|
22
|
-
@_fields << key
|
23
20
|
@attrs[key.to_sym] = process_value(value)
|
24
21
|
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def process_value(value)
|
29
|
-
case value
|
30
|
-
when Hash then self.class.new(@_client, value)
|
31
|
-
when Array then value.map { |v| process_value(v) }
|
32
|
-
else value
|
33
|
-
end
|
22
|
+
new_attrs(*data.keys)
|
34
23
|
end
|
35
24
|
|
36
25
|
def each(&block)
|
@@ -49,42 +38,55 @@ module Tacokit
|
|
49
38
|
nil
|
50
39
|
end
|
51
40
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
41
|
+
def key?(key)
|
42
|
+
@_fields.include?(key)
|
43
|
+
end
|
44
|
+
alias_method :has_key?, :key?
|
45
|
+
alias_method :include?, :key?
|
46
|
+
|
47
|
+
def inspect
|
48
|
+
(to_attrs.respond_to?(:pretty_inspect) ? to_attrs.pretty_inspect : to_attrs.inspect)
|
49
|
+
end
|
58
50
|
|
59
|
-
|
60
|
-
@attrs[attribute.to_sym] = value
|
61
|
-
end
|
51
|
+
alias_method :to_s, :inspect
|
62
52
|
|
63
|
-
|
64
|
-
|
65
|
-
|
53
|
+
def to_attrs
|
54
|
+
hash = attrs.clone
|
55
|
+
hash.keys.each do |k|
|
56
|
+
if hash[k].is_a?(Resource)
|
57
|
+
hash[k] = hash[k].to_attrs
|
58
|
+
elsif hash[k].is_a?(Array) && hash[k].all? { |el| el.is_a?(Resource) }
|
59
|
+
hash[k] = hash[k].collect(&:to_attrs)
|
66
60
|
end
|
67
61
|
end
|
62
|
+
hash
|
63
|
+
end
|
64
|
+
|
65
|
+
def update(attributes)
|
66
|
+
attributes.each do |key, value|
|
67
|
+
send("#{key}=", value)
|
68
|
+
end
|
68
69
|
end
|
69
70
|
|
70
|
-
|
71
|
-
|
71
|
+
private
|
72
|
+
|
73
|
+
def process_value(value)
|
74
|
+
case value
|
75
|
+
when Hash then self.class.new(value)
|
76
|
+
when Array then value.map { |v| process_value(v) }
|
77
|
+
else cast_value_type(value)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
ATTR_SETTER = "=".freeze
|
82
|
+
ATTR_PREDICATE = "?".freeze
|
72
83
|
|
73
|
-
# Provides access to a resource's attributes.
|
74
84
|
def method_missing(method, *args)
|
75
85
|
attr_name, suffix = method.to_s.scan(/([a-z0-9\_]+)(\?|\=)?$/i).first
|
76
86
|
if suffix == ATTR_SETTER
|
77
|
-
|
78
|
-
@_fields << attr_name.to_sym
|
79
|
-
send(method, args.first)
|
87
|
+
setter_missing(attr_name, args.first)
|
80
88
|
elsif attr_name && @_fields.include?(attr_name.to_sym)
|
81
|
-
|
82
|
-
case suffix
|
83
|
-
when nil
|
84
|
-
@_metaclass.send(:attr_accessor, attr_name)
|
85
|
-
value
|
86
|
-
when ATTR_PREDICATE then !!value
|
87
|
-
end
|
89
|
+
getter_missing(attr_name, suffix)
|
88
90
|
elsif suffix.nil? && SPECIAL_METHODS.include?(attr_name)
|
89
91
|
instance_variable_get "@_#{attr_name}"
|
90
92
|
elsif attr_name && !@_fields.include?(attr_name.to_sym)
|
@@ -94,21 +96,46 @@ module Tacokit
|
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
97
|
-
def
|
98
|
-
|
99
|
+
def new_attrs(*names)
|
100
|
+
names.map { |n| new_attr(n) }
|
99
101
|
end
|
100
102
|
|
101
|
-
def
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
103
|
+
def new_attr(name)
|
104
|
+
name = name.to_sym
|
105
|
+
@_fields << name
|
106
|
+
unless respond_to?(name)
|
107
|
+
define_singleton_method(name) { @attrs[name] }
|
108
|
+
define_singleton_method("#{name}=") { |v| @attrs[name] = v }
|
109
|
+
define_singleton_method("#{name}?") { !!@attrs[name] }
|
109
110
|
end
|
110
|
-
|
111
|
+
name
|
112
|
+
end
|
113
|
+
|
114
|
+
def setter_missing(attr_name, value)
|
115
|
+
new_attr(attr_name)
|
116
|
+
send("#{attr_name}=", value)
|
111
117
|
end
|
112
118
|
|
119
|
+
def getter_missing(attr_name, suffix)
|
120
|
+
value = @attrs[attr_name.to_sym]
|
121
|
+
case suffix
|
122
|
+
when nil
|
123
|
+
new_attr(attr_name)
|
124
|
+
value
|
125
|
+
when ATTR_PREDICATE then !!value
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# rubocop:disable Metrics/LineLength
|
130
|
+
ISO8601 = %r{^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$}.freeze
|
131
|
+
# rubocop:enable Metrics/LineLength
|
132
|
+
def cast_value_type(value)
|
133
|
+
case value
|
134
|
+
when ISO8601 then DateTime.parse(value)
|
135
|
+
else value
|
136
|
+
end
|
137
|
+
rescue
|
138
|
+
value
|
139
|
+
end
|
113
140
|
end
|
114
141
|
end
|
data/lib/tacokit/response.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module Tacokit
|
2
2
|
class Response
|
3
|
-
|
4
3
|
attr_reader :client, :status, :headers, :env, :data
|
5
4
|
|
6
5
|
def initialize(client, res, options = {})
|
@@ -11,13 +10,14 @@ module Tacokit
|
|
11
10
|
@data = process_data(@client.deserialize(res.body))
|
12
11
|
end
|
13
12
|
|
13
|
+
private
|
14
|
+
|
14
15
|
def process_data(data)
|
15
16
|
case data
|
16
|
-
when Hash then Resource.new(
|
17
|
+
when Hash then Resource.new(data)
|
17
18
|
when Array then data.map { |value| process_data(value) }
|
18
19
|
else data
|
19
20
|
end
|
20
21
|
end
|
21
|
-
|
22
22
|
end
|
23
23
|
end
|
data/lib/tacokit/transform.rb
CHANGED
@@ -2,6 +2,10 @@ module Tacokit
|
|
2
2
|
class Transform
|
3
3
|
include Tacokit::Utils
|
4
4
|
|
5
|
+
def serialize_params(params)
|
6
|
+
normalize_request_params(params)
|
7
|
+
end
|
8
|
+
|
5
9
|
def serialize(body)
|
6
10
|
serialize_body(body)
|
7
11
|
end
|
@@ -12,6 +16,25 @@ module Tacokit
|
|
12
16
|
|
13
17
|
private
|
14
18
|
|
19
|
+
def normalize_request_params(params)
|
20
|
+
{}.tap do |norm|
|
21
|
+
(params || {}).each do |key, value|
|
22
|
+
norm[key] = normalize_param_value(value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def normalize_param_value(value)
|
28
|
+
case value
|
29
|
+
when Array
|
30
|
+
value.map { |v| camel_path(v) }.join(",")
|
31
|
+
when /\,/
|
32
|
+
normalize_param_value(value.split(","))
|
33
|
+
else
|
34
|
+
camel_path(value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
15
38
|
def serialize_body(body)
|
16
39
|
case body
|
17
40
|
when Hash
|
@@ -31,26 +54,25 @@ module Tacokit
|
|
31
54
|
|
32
55
|
def camelize_key(key)
|
33
56
|
k = key.to_s
|
34
|
-
k = k.gsub(%r{([a-zA-
|
35
|
-
k = k.gsub(%r{(#{camelize_special_cases.keys.join(
|
57
|
+
k = k.gsub(%r{([a-zA-Z_]+?)_id(s\b|\b)?$}, "id_\\1\\2")
|
58
|
+
k = k.gsub(%r{(#{camelize_special_cases.keys.join("|")})}) { |m| camelize_special_cases.fetch(m) }
|
36
59
|
camelize(k, :lower)
|
37
60
|
end
|
38
61
|
|
39
62
|
# Converts
|
40
|
-
#
|
63
|
+
# "prefs" => { "voting" => "members" }
|
41
64
|
# to
|
42
|
-
#
|
65
|
+
# "prefs/voting" => "members
|
43
66
|
#
|
44
67
|
def flatten_nested_keys(body)
|
45
68
|
options = {}
|
46
69
|
body.each do |key, value|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
-
body.delete(key)
|
70
|
+
next unless value.is_a?(Hash)
|
71
|
+
value = flatten_nested_keys(value.dup)
|
72
|
+
value.each do |nested_key, nested_value|
|
73
|
+
options["#{key}/#{nested_key}"] = nested_value
|
53
74
|
end
|
75
|
+
body.delete(key)
|
54
76
|
end
|
55
77
|
body.merge(options)
|
56
78
|
end
|
@@ -78,7 +100,7 @@ module Tacokit
|
|
78
100
|
|
79
101
|
def underscore_key(key)
|
80
102
|
k = key.to_s
|
81
|
-
k = k.gsub(%r{(#{pluralize_special_cases.join(
|
103
|
+
k = k.gsub(%r{(#{pluralize_special_cases.join("|")})}, "\\1s")
|
82
104
|
k = underscore(k)
|
83
105
|
k.gsub(%r{^id_([a-zA-Z_]+?)(s\b|\b)$}, "\\1_id\\2")
|
84
106
|
end
|
@@ -89,9 +111,9 @@ module Tacokit
|
|
89
111
|
|
90
112
|
def camelize_special_cases
|
91
113
|
{
|
92
|
-
|
114
|
+
"callback_url" => "callbackURL",
|
115
|
+
"checklist_source_id" => "idChecklistSource"
|
93
116
|
}
|
94
117
|
end
|
95
|
-
|
96
118
|
end
|
97
119
|
end
|