apidiesel 0.12 → 0.13
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/.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:
|