tacokit 0.1.0 → 0.2.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 +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
|