apidiesel 0.12 → 0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/apidiesel.gemspec +6 -0
- data/bin/console +2 -2
- data/examples/github/actions/get_user_repos.rb +102 -0
- data/examples/github/api.rb +15 -0
- data/lib/apidiesel.rb +2 -2
- data/lib/apidiesel/action.rb +114 -44
- data/lib/apidiesel/api.rb +3 -2
- data/lib/apidiesel/dsl.rb +121 -82
- data/lib/apidiesel/request.rb +7 -15
- data/lib/apidiesel/version.rb +1 -1
- metadata +90 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9da8479808b1cfc506569b246e5dc7901d51d8be
|
4
|
+
data.tar.gz: 853d657cf6fbb75d6b0518900aa1375813b5e035
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb0cbe4ab97aa00a61c4dba87f93a9238060bc3847a82226cf16ab3aeb5e3cd2dc8b1bdfab89b094e79fe0077553955b5a4e85b6e17d8274adedaca4740bf785
|
7
|
+
data.tar.gz: af20d68bf9143dee06a5686f4c7092310e4f09b5a76ce2b10321310a6a97ae1cb79cd97034cf72b6466d795de0ddf1461d263a14bc0c42e0dc2e50bb5961034d
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup=markdown
|
data/apidiesel.gemspec
CHANGED
@@ -25,4 +25,10 @@ Gem::Specification.new do |spec|
|
|
25
25
|
|
26
26
|
spec.add_development_dependency "bundler", "~> 1.10"
|
27
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "redcarpet", "~> 3.3"
|
29
|
+
spec.add_development_dependency "yard", "~> 0.8"
|
30
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
31
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.2.0'
|
32
|
+
spec.add_development_dependency 'pry-rescue', '~> 1.4'
|
33
|
+
spec.add_development_dependency 'pry-stack_explorer', '~> 0.4.9'
|
28
34
|
end
|
data/bin/console
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
module Github
|
2
|
+
module Actions
|
3
|
+
class GetUserRepos < Apidiesel::Action
|
4
|
+
url path: '/users/%{username}/repos'
|
5
|
+
|
6
|
+
expects do
|
7
|
+
string :username, submit: false
|
8
|
+
end
|
9
|
+
|
10
|
+
responds_with do
|
11
|
+
array do
|
12
|
+
integer :id
|
13
|
+
string :name
|
14
|
+
string :full_name
|
15
|
+
hash :owner do
|
16
|
+
string :login
|
17
|
+
integer :id
|
18
|
+
string :avatar_url
|
19
|
+
string :gravatar_id
|
20
|
+
string :url
|
21
|
+
string :html_url
|
22
|
+
string :followers_url
|
23
|
+
string :following_url
|
24
|
+
string :gists_url
|
25
|
+
string :starred_url
|
26
|
+
string :subscriptions_url
|
27
|
+
string :organizations_url
|
28
|
+
string :repos_url
|
29
|
+
string :events_url
|
30
|
+
string :received_events_url
|
31
|
+
string :type
|
32
|
+
string :site_admin
|
33
|
+
end
|
34
|
+
boolean :private
|
35
|
+
string :html_url
|
36
|
+
string :description
|
37
|
+
string :fork
|
38
|
+
string :url
|
39
|
+
string :forks_url
|
40
|
+
string :keys_url
|
41
|
+
string :collaborators_url
|
42
|
+
string :teams_url
|
43
|
+
string :hooks_url
|
44
|
+
string :issue_events_url
|
45
|
+
string :events_url
|
46
|
+
string :assignees_url
|
47
|
+
string :branches_url
|
48
|
+
string :tags_url
|
49
|
+
string :blobs_url
|
50
|
+
string :git_tags_url
|
51
|
+
string :git_refs_url
|
52
|
+
string :trees_url
|
53
|
+
string :statuses_url
|
54
|
+
string :languages_url
|
55
|
+
string :stargazers_url
|
56
|
+
string :contributors_url
|
57
|
+
string :subscribers_url
|
58
|
+
string :subscription_url
|
59
|
+
string :commits_url
|
60
|
+
string :git_commits_url
|
61
|
+
string :comments_url
|
62
|
+
string :issue_comment_url
|
63
|
+
string :contents_url
|
64
|
+
string :compare_url
|
65
|
+
string :merges_url
|
66
|
+
string :archive_url
|
67
|
+
string :downloads_url
|
68
|
+
string :issues_url
|
69
|
+
string :pulls_url
|
70
|
+
string :milestones_url
|
71
|
+
string :notifications_url
|
72
|
+
string :labels_url
|
73
|
+
string :releases_url
|
74
|
+
string :deployments_url
|
75
|
+
datetime :created_at
|
76
|
+
datetime :updated_at
|
77
|
+
datetime :pushed_at
|
78
|
+
string :git_url
|
79
|
+
string :ssh_url
|
80
|
+
string :clone_url
|
81
|
+
string :svn_url
|
82
|
+
string :homepage
|
83
|
+
integer :size
|
84
|
+
integer :stargazers_count
|
85
|
+
integer :watchers_count
|
86
|
+
string :language
|
87
|
+
boolean :has_issues
|
88
|
+
boolean :has_downloads
|
89
|
+
boolean :has_wiki
|
90
|
+
boolean :has_pages
|
91
|
+
integer :forks_count
|
92
|
+
string :mirror_url
|
93
|
+
integer :open_issues_count
|
94
|
+
integer :forks
|
95
|
+
integer :open_issues
|
96
|
+
integer :watchers
|
97
|
+
string :default_branch
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "apidiesel"
|
2
|
+
|
3
|
+
Dir[ File.join(__dir__, 'actions', '*.rb') ].each do |file|
|
4
|
+
require file
|
5
|
+
end
|
6
|
+
|
7
|
+
module Github
|
8
|
+
class Api < Apidiesel::Api
|
9
|
+
use Apidiesel::Handlers::JSON
|
10
|
+
|
11
|
+
url 'https://api.github.com'
|
12
|
+
|
13
|
+
register_actions
|
14
|
+
end
|
15
|
+
end
|
data/lib/apidiesel.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'httpi'
|
3
|
+
require 'active_support/all'
|
3
4
|
|
4
5
|
HTTPI.log = false
|
5
6
|
|
@@ -13,5 +14,4 @@ require 'apidiesel/request'
|
|
13
14
|
require 'apidiesel/action'
|
14
15
|
require 'apidiesel/handlers/action_response_processor'
|
15
16
|
require 'apidiesel/handlers/http_request_helper'
|
16
|
-
require 'apidiesel/handlers/json'
|
17
|
-
|
17
|
+
require 'apidiesel/handlers/json'
|
data/lib/apidiesel/action.rb
CHANGED
@@ -9,15 +9,20 @@ module Apidiesel
|
|
9
9
|
class << self
|
10
10
|
include Handlers
|
11
11
|
|
12
|
-
attr_reader :url_args
|
12
|
+
attr_reader :url_value, :url_args
|
13
13
|
|
14
|
-
#
|
14
|
+
# Array for storing parameter validation closures. These closures are called with the request
|
15
15
|
# parameters before the request is made and have the opportunity to check and modify them.
|
16
16
|
def parameter_validations
|
17
17
|
@parameter_validations ||= []
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
20
|
+
# Array for storing action argument names which are not to be submitted as parameters
|
21
|
+
def parameters_to_filter
|
22
|
+
@parameters_to_filter ||= []
|
23
|
+
end
|
24
|
+
|
25
|
+
# Array for storing filter closures. These closures are called with the received data
|
21
26
|
# after a request is made and have the opportunity to modify or check it before the
|
22
27
|
# data is returned
|
23
28
|
def response_filters
|
@@ -47,21 +52,78 @@ module Apidiesel
|
|
47
52
|
end
|
48
53
|
end
|
49
54
|
|
50
|
-
#
|
55
|
+
# Defines this Actions URL, or modifies the base URL set on `Api`
|
51
56
|
#
|
52
|
-
#
|
57
|
+
# Given keyword arguments such as `path:` will be applied to
|
58
|
+
# the `URI` object supplied to `Api.url`.
|
53
59
|
#
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
60
|
+
# Accepts a `Proc`, which will be called at request time with
|
61
|
+
# the URL constructed so far and the current `Request` object.
|
62
|
+
#
|
63
|
+
# A string value and all keyword arguments can contain
|
64
|
+
# placeholders for all arguments supplied to the action in
|
65
|
+
# Rubys standard `String.%` syntax.
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# class Api < Apidiesel::Api
|
69
|
+
# url 'https://foo.example'
|
70
|
+
#
|
71
|
+
# register_actions
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# module Actions
|
75
|
+
# # modify the base URL set on `Api`
|
76
|
+
# class ActionA < Apidiesel::Action
|
77
|
+
# url path: '/action_a'
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# # replace the base URL set on `Api`
|
81
|
+
# class ActionB < Apidiesel::Action
|
82
|
+
# url 'https://subdomain.foo.example'
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# # modify the base URL set on `Api` with a
|
86
|
+
# # 'username' argument placeholder
|
87
|
+
# class ActionC < Apidiesel::Action
|
88
|
+
# url path: '/action_c/%{username}'
|
89
|
+
#
|
90
|
+
# expects do
|
91
|
+
# string :username, submit: false
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# # dynamically determine the URL with a
|
96
|
+
# # `Proc` object
|
97
|
+
# class ActionD < Apidiesel::Action
|
98
|
+
# url ->(url, request) {
|
99
|
+
# url.path = '/' + request.action_arguments[:username]
|
100
|
+
# .downcase
|
101
|
+
# url
|
102
|
+
# }
|
103
|
+
#
|
104
|
+
# expects do
|
105
|
+
# string :username, submit: false
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# @overload url(value)
|
111
|
+
# @param [String, URI] value a complete URL string or `URI`
|
112
|
+
#
|
113
|
+
# @overload url(**kargs)
|
114
|
+
# @option **kargs [String] any method name valid on Rubys `URI::Generic`
|
115
|
+
#
|
116
|
+
# @overload url(value)
|
117
|
+
# @param [Proc] value a callback that returns a URL string at request time.
|
118
|
+
# Receives the URL contructed so far and the current
|
119
|
+
# `Request` instance.
|
120
|
+
def url(value = nil, **kargs)
|
121
|
+
if value && kargs.any?
|
122
|
+
raise ArgumentError, "you cannot supply both argument and keyword args"
|
64
123
|
end
|
124
|
+
|
125
|
+
@url_value = value
|
126
|
+
@url_args = kargs
|
65
127
|
end
|
66
128
|
|
67
129
|
# Combined getter/setter for the HTTP method used
|
@@ -128,42 +190,17 @@ module Apidiesel
|
|
128
190
|
self.class.endpoint
|
129
191
|
end
|
130
192
|
|
131
|
-
def base_url
|
132
|
-
if self.class.url.nil? || self.class.url.is_a?(Proc)
|
133
|
-
@api.class.url.dup
|
134
|
-
else
|
135
|
-
self.class.url.dup
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def url
|
140
|
-
if self.class.url.is_a?(Proc)
|
141
|
-
url = self.class.url
|
142
|
-
|
143
|
-
elsif self.class.url_args
|
144
|
-
url = base_url
|
145
|
-
|
146
|
-
self.class.url_args.each do |key, value|
|
147
|
-
url.send("#{key}=", value)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
url
|
152
|
-
end
|
153
|
-
|
154
193
|
def http_method
|
155
|
-
self.class.http_method || @api.class.http_method
|
194
|
+
self.class.http_method || @api.class.http_method || :get
|
156
195
|
end
|
157
196
|
|
158
197
|
# Performs the action-specific input validations on `*args` according to the actions
|
159
198
|
# `expects` block, executes the API request and prepares the data according to the
|
160
199
|
# actions `responds_with` block.
|
161
200
|
#
|
162
|
-
# @
|
201
|
+
# @option **args see specific, non-abstract `Apidiesel::Action`
|
163
202
|
# @return [Apidiesel::Request]
|
164
|
-
def build_request(
|
165
|
-
args = args && args.first.is_a?(Hash) ? args.first : {}
|
166
|
-
|
203
|
+
def build_request(**args)
|
167
204
|
params = {}
|
168
205
|
|
169
206
|
self.class.parameter_validations.each do |validation|
|
@@ -172,9 +209,14 @@ module Apidiesel
|
|
172
209
|
|
173
210
|
if self.class.parameter_formatter
|
174
211
|
params = self.class.parameter_formatter.call(params)
|
212
|
+
else
|
213
|
+
params.except!(*self.class.parameters_to_filter)
|
175
214
|
end
|
176
215
|
|
177
|
-
Apidiesel::Request.new
|
216
|
+
request = Apidiesel::Request.new(action: self, action_arguments: args, parameters: params)
|
217
|
+
request.url = build_url(args, request)
|
218
|
+
|
219
|
+
request
|
178
220
|
end
|
179
221
|
|
180
222
|
def process_response(response_data)
|
@@ -208,6 +250,34 @@ module Apidiesel
|
|
208
250
|
|
209
251
|
protected
|
210
252
|
|
253
|
+
# @return [URI]
|
254
|
+
def build_url(action_arguments, request)
|
255
|
+
url = case self.class.url_value
|
256
|
+
when String
|
257
|
+
URI( self.class.url_value % action_arguments )
|
258
|
+
when URI
|
259
|
+
self.class.url_value
|
260
|
+
when Proc
|
261
|
+
self.class.url_value.call(base_url, request)
|
262
|
+
when nil
|
263
|
+
base_url
|
264
|
+
end
|
265
|
+
|
266
|
+
url_args = self.class.url_args.transform_values do |value|
|
267
|
+
value % action_arguments
|
268
|
+
end
|
269
|
+
|
270
|
+
url_args.each do |name, value|
|
271
|
+
url.send("#{name}=", value)
|
272
|
+
end
|
273
|
+
|
274
|
+
url
|
275
|
+
end
|
276
|
+
|
277
|
+
def base_url
|
278
|
+
@api.class.url.nil? ? URI('http://') : @api.class.url.dup
|
279
|
+
end
|
280
|
+
|
211
281
|
# @return [Hash] Apidiesel configuration options
|
212
282
|
def config
|
213
283
|
Apidiesel::CONFIG[environment]
|
data/lib/apidiesel/api.rb
CHANGED
@@ -42,7 +42,7 @@ module Apidiesel
|
|
42
42
|
#
|
43
43
|
# Falls back to the Api setting if blank.
|
44
44
|
#
|
45
|
-
# @param [String]
|
45
|
+
# @param [String] base_url
|
46
46
|
def url(base_url = nil)
|
47
47
|
if base_url
|
48
48
|
config[:url] = URI.parse(base_url)
|
@@ -68,7 +68,8 @@ module Apidiesel
|
|
68
68
|
#
|
69
69
|
# Falls back to the Api setting if blank.
|
70
70
|
#
|
71
|
-
# @param [String]
|
71
|
+
# @param [String] username
|
72
|
+
# @param [String] password
|
72
73
|
def http_basic_auth(username = nil, password = nil)
|
73
74
|
if username && password
|
74
75
|
config[:http_basic_username] = username
|
data/lib/apidiesel/dsl.rb
CHANGED
@@ -17,6 +17,7 @@ module Apidiesel
|
|
17
17
|
builder = ExpectationBuilder.new
|
18
18
|
builder.instance_eval(&block)
|
19
19
|
parameter_validations.concat builder.parameter_validations
|
20
|
+
parameters_to_filter.concat builder.parameters_to_filter
|
20
21
|
end
|
21
22
|
|
22
23
|
# Defines the expected content and format of the response for this API action.
|
@@ -53,10 +54,13 @@ module Apidiesel
|
|
53
54
|
# ExpectationBuilder defines the methods available within an `expects` block
|
54
55
|
# when defining an API action.
|
55
56
|
class ExpectationBuilder
|
56
|
-
|
57
|
+
# @!visibility private
|
58
|
+
attr_accessor :parameter_validations, :parameters_to_filter
|
57
59
|
|
60
|
+
# @!visibility private
|
58
61
|
def initialize
|
59
62
|
@parameter_validations = []
|
63
|
+
@parameters_to_filter = []
|
60
64
|
end
|
61
65
|
|
62
66
|
# Defines a string parameter.
|
@@ -71,19 +75,23 @@ module Apidiesel
|
|
71
75
|
# # This action expects to be given an 'email', which is sent to the API as 'username',
|
72
76
|
# # and requires either a 'value1', a 'value2' or both to be present.
|
73
77
|
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
|
86
|
-
|
78
|
+
# @!macro [new] expectation_types
|
79
|
+
# @param param_name [Symbol] name of the parameter
|
80
|
+
# @option args [Boolean] :optional (false) defines whether this parameter may be omitted
|
81
|
+
# @option args [Symbol] :optional_if_present param_name is optional, if the parameter given here is present instead
|
82
|
+
# @option args [Symbol] :required_if_present param_name is required if param_name is also present
|
83
|
+
# @option args [Symbol] :submitted_as submit param_name to the API under the name given here
|
84
|
+
# @option args [Object] :default a default parameter to be set when no value is specified
|
85
|
+
# @option args [true, false] :submit (true) set to `false` for arguments that should not be submitted
|
86
|
+
# as API parameters
|
87
|
+
# @option args [Enumerable] :allowed_values only accept the values in this Enumerable.
|
88
|
+
# If Enumerable is a Hash, use the hash values to define what is actually
|
89
|
+
# sent to the server. Example: `:allowed_values => {:foo => "f"}` allows
|
90
|
+
# the value ':foo', but sends it as 'f'
|
91
|
+
# @return [nil]
|
92
|
+
def string(param_name, **args)
|
93
|
+
validation_builder(:to_s, param_name, **args)
|
94
|
+
parameters_to_filter << param_name if args[:submit] == false
|
87
95
|
end
|
88
96
|
|
89
97
|
# Defines an integer parameter.
|
@@ -93,10 +101,10 @@ module Apidiesel
|
|
93
101
|
# integer :per_page, :optional => true
|
94
102
|
# end
|
95
103
|
#
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
104
|
+
# @!macro expectation_types
|
105
|
+
def integer(param_name, **args)
|
106
|
+
validation_builder(:to_i, param_name, **args)
|
107
|
+
parameters_to_filter << param_name if args[:submit] == false
|
100
108
|
end
|
101
109
|
|
102
110
|
# Defines a boolean parameter.
|
@@ -108,10 +116,10 @@ module Apidiesel
|
|
108
116
|
# boolean :per_page, :optional => true
|
109
117
|
# end
|
110
118
|
#
|
111
|
-
#
|
112
|
-
|
113
|
-
|
114
|
-
|
119
|
+
# @!macro expectation_types
|
120
|
+
def boolean(param_name, **args)
|
121
|
+
validation_builder(:to_s, param_name, **args)
|
122
|
+
parameters_to_filter << param_name if args[:submit] == false
|
115
123
|
end
|
116
124
|
|
117
125
|
# Defines a date, time or datetime parameter.
|
@@ -122,15 +130,15 @@ module Apidiesel
|
|
122
130
|
# datetime :starts_at, format: '%d-%m-%Y'
|
123
131
|
# end
|
124
132
|
#
|
125
|
-
#
|
126
|
-
# @option
|
127
|
-
# @option (see #string)
|
133
|
+
# @!macro expectation_types
|
134
|
+
# @option args [String] :format a format string as supported by Rubys `#strftime`
|
128
135
|
def datetime(param_name, **args)
|
129
136
|
if args[:format]
|
130
137
|
args[:processor] = ->(value) { value.try(:strftime, args[:format]) }
|
131
138
|
end
|
132
139
|
|
133
140
|
validation_builder(:strftime, param_name, **args)
|
141
|
+
parameters_to_filter << param_name if args[:submit] == false
|
134
142
|
end
|
135
143
|
|
136
144
|
alias_method :time, :datetime
|
@@ -144,9 +152,8 @@ module Apidiesel
|
|
144
152
|
# object :contract, klass: Contract
|
145
153
|
# end
|
146
154
|
#
|
147
|
-
#
|
148
|
-
# @option
|
149
|
-
# @option (see #string)
|
155
|
+
# @!macro expectation_types
|
156
|
+
# @option args [Class] :klass the expected class of the value
|
150
157
|
def object(param_name, **args)
|
151
158
|
type_check = ->(value, param_name) {
|
152
159
|
unless value.is_a?(args[:klass])
|
@@ -155,12 +162,13 @@ module Apidiesel
|
|
155
162
|
}
|
156
163
|
|
157
164
|
validation_builder(type_check, param_name, **args)
|
165
|
+
parameters_to_filter << param_name if args[:submit] == false
|
158
166
|
end
|
159
167
|
|
160
168
|
protected
|
161
169
|
|
162
|
-
def validation_builder(duck_typing_check, param_name,
|
163
|
-
options = args
|
170
|
+
def validation_builder(duck_typing_check, param_name, **args)
|
171
|
+
options = args
|
164
172
|
|
165
173
|
parameter_validations << lambda do |given_params, processed_params|
|
166
174
|
if options[:default]
|
@@ -211,13 +219,38 @@ module Apidiesel
|
|
211
219
|
# FilterBuilder defines the methods available within an `responds_with` block
|
212
220
|
# when defining an API action.
|
213
221
|
class FilterBuilder
|
222
|
+
# @!visibility private
|
214
223
|
attr_accessor :response_filters, :response_formatters
|
215
224
|
|
225
|
+
# @!visibility private
|
216
226
|
def initialize
|
217
227
|
@response_filters = []
|
218
228
|
@response_formatters = []
|
219
229
|
end
|
220
230
|
|
231
|
+
# @!macro [new] filter_types
|
232
|
+
# Returns a $0 from the API response hash
|
233
|
+
#
|
234
|
+
# @overload $0(key, **kargs)
|
235
|
+
# Get the $0 named `key` from the response hash and name it `key` in the result hash
|
236
|
+
#
|
237
|
+
# @param key [String, Symbol]
|
238
|
+
# @option kargs [Proc] :prefilter callback for modifying the value before typecasting
|
239
|
+
# @option kargs [Proc] :postfilter callback for modifying the value after typecasting
|
240
|
+
# @option kargs [Proc] :filter alias for :postfilter
|
241
|
+
# @option kargs [Hash] :map a hash map for replacing the value
|
242
|
+
#
|
243
|
+
# @overload $0(at:, as:, **kargs)
|
244
|
+
# Get the $0 named `at:` from the response hash and name it `as:` in the result hash
|
245
|
+
#
|
246
|
+
# @param at [String, Symbol, Array<Symbol>] response hash key name or key path to lookup
|
247
|
+
# @param as [String, Symbol] result hash key name to return the value as
|
248
|
+
# @option kargs [Proc] :prefilter callback for modifying the value before typecasting
|
249
|
+
# @option kargs [Proc] :postfilter callback for modifying the value after typecasting
|
250
|
+
# @option kargs [Proc] :filter alias for :postfilter
|
251
|
+
# @option kargs [Hash] :map a hash map for replacing the value
|
252
|
+
#
|
253
|
+
# @return [nil]
|
221
254
|
def value(*args, **kargs)
|
222
255
|
args = normalize_arguments(args, kargs)
|
223
256
|
|
@@ -236,43 +269,65 @@ module Apidiesel
|
|
236
269
|
end
|
237
270
|
end
|
238
271
|
|
239
|
-
#
|
272
|
+
# @!macro filter_types
|
240
273
|
#
|
241
|
-
#
|
242
|
-
#
|
243
|
-
#
|
274
|
+
# Please note that response value is typecasted to `String` for comparison, so that
|
275
|
+
# for absent values to be considered false, you have to include an empty string.
|
276
|
+
#
|
277
|
+
# @option kargs [Array<#to_s>, #to_s] :truthy ('true') values to be considered true
|
278
|
+
# @option kargs [Array<#to_s>, #to_s] :falsy ('false') values to be considered false
|
279
|
+
def boolean(*args, **kargs)
|
280
|
+
args = normalize_arguments(args, kargs)
|
281
|
+
|
282
|
+
args.reverse_merge!(truthy: 'true', falsy: 'false')
|
283
|
+
|
284
|
+
args[:truthy] = Array(args[:truthy]).map(&:to_s)
|
285
|
+
args[:falsy] = Array(args[:falsy]).map(&:to_s)
|
286
|
+
|
287
|
+
response_formatters << lambda do |data, processed_data|
|
288
|
+
value = get_value(data, args[:at])
|
289
|
+
|
290
|
+
value = apply_filter(args[:prefilter], value)
|
291
|
+
|
292
|
+
value = if args[:truthy].include?(value.to_s)
|
293
|
+
true
|
294
|
+
elsif args[:falsy].include?(value.to_s)
|
295
|
+
false
|
296
|
+
else
|
297
|
+
nil
|
298
|
+
end
|
299
|
+
|
300
|
+
value = apply_filter(args[:postfilter] || args[:filter], value)
|
301
|
+
|
302
|
+
value = args[:map][value] if args[:map]
|
303
|
+
|
304
|
+
processed_data[ args[:as] ] = value
|
305
|
+
|
306
|
+
processed_data
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
# @!macro filter_types
|
244
311
|
def string(*args, **kargs)
|
245
312
|
create_primitive_formatter(:to_s, *args, **kargs)
|
246
313
|
end
|
247
314
|
|
248
|
-
#
|
249
|
-
#
|
250
|
-
# @param (see #string)
|
251
|
-
# @option (see #string)
|
315
|
+
# @!macro filter_types
|
252
316
|
def integer(*args, **kargs)
|
253
317
|
create_primitive_formatter(:to_i, *args, **kargs)
|
254
318
|
end
|
255
319
|
|
256
|
-
#
|
257
|
-
#
|
258
|
-
# @param (see #string)
|
259
|
-
# @option (see #string)
|
320
|
+
# @!macro filter_types
|
260
321
|
def float(*args, **kargs)
|
261
322
|
create_primitive_formatter(:to_f, *args, **kargs)
|
262
323
|
end
|
263
324
|
|
264
|
-
#
|
265
|
-
#
|
266
|
-
# @param (see #string)
|
267
|
-
# @option (see #string)
|
325
|
+
# @!macro filter_types
|
268
326
|
def symbol(*args, **kargs)
|
269
327
|
create_primitive_formatter(:to_sym, *args, **kargs)
|
270
328
|
end
|
271
329
|
|
272
|
-
#
|
273
|
-
#
|
274
|
-
# @param (see #string)
|
275
|
-
# @option (see #string)
|
330
|
+
# @!macro filter_types
|
276
331
|
def datetime(*args, **kargs)
|
277
332
|
args = normalize_arguments(args, kargs)
|
278
333
|
args.reverse_merge!(format: '%Y-%m-%d')
|
@@ -296,10 +351,7 @@ module Apidiesel
|
|
296
351
|
end
|
297
352
|
end
|
298
353
|
|
299
|
-
#
|
300
|
-
#
|
301
|
-
# @param (see #string)
|
302
|
-
# @option (see #string)
|
354
|
+
# @!macro filter_types
|
303
355
|
def date(*args, **kargs)
|
304
356
|
args = normalize_arguments(args, kargs)
|
305
357
|
args.reverse_merge!(format: '%Y-%m-%d')
|
@@ -323,10 +375,7 @@ module Apidiesel
|
|
323
375
|
end
|
324
376
|
end
|
325
377
|
|
326
|
-
#
|
327
|
-
#
|
328
|
-
# @param (see #string)
|
329
|
-
# @option (see #string)
|
378
|
+
# @!macro filter_types
|
330
379
|
def time(*args, **kargs)
|
331
380
|
args = normalize_arguments(args, kargs)
|
332
381
|
args.reverse_merge!(format: '%Y-%m-%d')
|
@@ -350,8 +399,7 @@ module Apidiesel
|
|
350
399
|
end
|
351
400
|
end
|
352
401
|
|
353
|
-
#
|
354
|
-
#
|
402
|
+
# @!macro filter_types
|
355
403
|
# @example
|
356
404
|
#
|
357
405
|
# # Given an API response:
|
@@ -375,6 +423,7 @@ module Apidiesel
|
|
375
423
|
# end
|
376
424
|
# end
|
377
425
|
#
|
426
|
+
# @example
|
378
427
|
# # Given an API response:
|
379
428
|
# #
|
380
429
|
# # [
|
@@ -388,19 +437,12 @@ module Apidiesel
|
|
388
437
|
# # },
|
389
438
|
# # ]
|
390
439
|
#
|
391
|
-
# @example
|
392
440
|
# expects do
|
393
441
|
# array do
|
394
442
|
# string :name
|
395
443
|
# integer :order_id
|
396
444
|
# end
|
397
445
|
# end
|
398
|
-
#
|
399
|
-
# @option *args [Symbol] the key for finding and returning the array
|
400
|
-
# (sets both :as and :at)
|
401
|
-
# @option **kargs [Symbol] :at which key to find the hash at in the
|
402
|
-
# response
|
403
|
-
# @option **kargs [Symbol] :as which key to return the result under
|
404
446
|
def array(*args, **kargs, &block)
|
405
447
|
unless block.present?
|
406
448
|
create_primitive_formatter(:to_a, *args, **kargs)
|
@@ -447,10 +489,7 @@ module Apidiesel
|
|
447
489
|
end
|
448
490
|
end
|
449
491
|
|
450
|
-
#
|
451
|
-
#
|
452
|
-
# @param (see #string)
|
453
|
-
# @option (see #string)
|
492
|
+
# @!macro filter_types
|
454
493
|
def hash(*args, **kargs, &block)
|
455
494
|
unless block.present?
|
456
495
|
create_primitive_formatter(:to_hash, *args, **kargs)
|
@@ -483,24 +522,24 @@ module Apidiesel
|
|
483
522
|
end
|
484
523
|
end
|
485
524
|
|
486
|
-
# Returns the API response processed or wrapped in wrapper objects.
|
487
|
-
#
|
488
525
|
# @example
|
489
526
|
# responds_with do
|
490
|
-
# object :issues,
|
527
|
+
# object :issues,
|
528
|
+
# processed_with: ->(data) {
|
529
|
+
# data.delete_if { |k,v| k == 'www_id' }
|
530
|
+
# }
|
491
531
|
# end
|
492
532
|
#
|
493
533
|
# @example
|
494
534
|
#
|
495
535
|
# responds_with do
|
496
|
-
# object :issues,
|
536
|
+
# object :issues,
|
537
|
+
# wrapped_in: Apidiesel::ResponseObjects::Topic
|
497
538
|
# end
|
498
539
|
#
|
499
|
-
#
|
500
|
-
# @option
|
501
|
-
# @option
|
502
|
-
# @option *args [Class] :wrapped_in wrapper object, will be called as `Object.create(data)`
|
503
|
-
# @option *args [Symbol] :as key name to save the result as
|
540
|
+
# @!macro filter_types
|
541
|
+
# @option kargs [Proc] :processed_with yield the data to this Proc for processing
|
542
|
+
# @option kargs [Class] :wrapped_in wrapper object, will be called as `Object.create(data)`
|
504
543
|
def objects(*args, **kargs)
|
505
544
|
args = normalize_arguments(args, kargs)
|
506
545
|
|
@@ -530,7 +569,7 @@ module Apidiesel
|
|
530
569
|
# @param [Symbol, Array] key
|
531
570
|
def set_scope(key)
|
532
571
|
response_filters << lambda do |data|
|
533
|
-
|
572
|
+
fetch_path(data, *key)
|
534
573
|
end
|
535
574
|
end
|
536
575
|
|
@@ -543,7 +582,7 @@ module Apidiesel
|
|
543
582
|
#
|
544
583
|
# @param [Lambda, Proc] callable
|
545
584
|
# @param [String, Lambda, Proc] message
|
546
|
-
# @
|
585
|
+
# @raise [Apidiesel::ResponseError]
|
547
586
|
def response_error_if(callable, message:)
|
548
587
|
response_formatters << lambda do |data, processed_data|
|
549
588
|
return processed_data unless callable.call(data)
|
data/lib/apidiesel/request.rb
CHANGED
@@ -2,25 +2,17 @@ module Apidiesel
|
|
2
2
|
|
3
3
|
# Wrapper for API requests
|
4
4
|
class Request
|
5
|
-
attr_accessor :action, :parameters, :response_body, :http_request, :http_response, :metadata, :result
|
5
|
+
attr_accessor :action, :action_arguments, :parameters, :url, :response_body, :http_request, :http_response, :metadata, :result
|
6
6
|
|
7
7
|
# @param [Apidiesel::Action] action
|
8
|
+
# @param [Hash] action_arguments
|
8
9
|
# @param [Hash] parameters
|
9
10
|
# @param [Hash] metadata
|
10
|
-
def initialize(action:, parameters:, metadata: {})
|
11
|
-
@action
|
12
|
-
@
|
13
|
-
@
|
14
|
-
|
15
|
-
|
16
|
-
def url
|
17
|
-
@url ||=
|
18
|
-
case action.url
|
19
|
-
when Proc
|
20
|
-
action.url.call(action.base_url, self)
|
21
|
-
when URI
|
22
|
-
action.url
|
23
|
-
end
|
11
|
+
def initialize(action:, action_arguments:, parameters:, metadata: {})
|
12
|
+
@action = action
|
13
|
+
@action_arguments = action_arguments
|
14
|
+
@parameters = parameters
|
15
|
+
@metadata = metadata
|
24
16
|
end
|
25
17
|
|
26
18
|
def response_body
|
data/lib/apidiesel/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apidiesel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.13'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan-Christian Foeh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -66,6 +66,90 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: redcarpet
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.10'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.10'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry-byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 3.2.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 3.2.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry-rescue
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.4'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.4'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry-stack_explorer
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.4.9
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.4.9
|
69
153
|
description:
|
70
154
|
email:
|
71
155
|
- jan@programmanstalt.de
|
@@ -76,6 +160,7 @@ files:
|
|
76
160
|
- ".gitignore"
|
77
161
|
- ".ruby-gemset"
|
78
162
|
- ".ruby-version"
|
163
|
+
- ".yardopts"
|
79
164
|
- Gemfile
|
80
165
|
- LICENSE
|
81
166
|
- README.md
|
@@ -83,6 +168,8 @@ files:
|
|
83
168
|
- apidiesel.gemspec
|
84
169
|
- bin/console
|
85
170
|
- bin/setup
|
171
|
+
- examples/github/actions/get_user_repos.rb
|
172
|
+
- examples/github/api.rb
|
86
173
|
- lib/apidiesel.rb
|
87
174
|
- lib/apidiesel/action.rb
|
88
175
|
- lib/apidiesel/api.rb
|
@@ -120,3 +207,4 @@ signing_key:
|
|
120
207
|
specification_version: 4
|
121
208
|
summary: Build API clients through an expressive DSL
|
122
209
|
test_files: []
|
210
|
+
has_rdoc:
|