haveapi 0.23.7 → 0.25.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/README.md +3 -3
- data/haveapi.gemspec +4 -4
- data/lib/haveapi/action.rb +5 -5
- data/lib/haveapi/action_state.rb +2 -2
- data/lib/haveapi/actions/paginable.rb +3 -3
- data/lib/haveapi/authentication/oauth2/provider.rb +1 -1
- data/lib/haveapi/authentication/token/provider.rb +8 -8
- data/lib/haveapi/model_adapters/active_record.rb +41 -0
- data/lib/haveapi/params.rb +7 -0
- data/lib/haveapi/resources/action_state.rb +7 -7
- data/lib/haveapi/server.rb +15 -11
- data/lib/haveapi/spec/spec_methods.rb +2 -2
- data/lib/haveapi/version.rb +1 -1
- data/lib/haveapi/views/version_page/resource_body.erb +3 -8
- data/lib/haveapi/views/version_page.erb +0 -28
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e3abf24d477cb53a7654a236f2daf3abadd8b153d3017ea159dbe1dd072fd2b
|
4
|
+
data.tar.gz: 406961707ce35f79c6ee6f2835697143f2b5a4e42e86f433949d08f98b546644
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdddd4eb49bc38b54c799b2cd57668f550a38212f1b735f1aad6238bb93f4a7d3b0b1bc52ff09055d0247afd70fa6fe156b41d7c99bc20317bc470d22ae9f744
|
7
|
+
data.tar.gz: 0120c81aa41cbc7a32d039fb4c645b2fa1ca510d91093c813e4e3b8802e69393e2641af63c99287fbb8b75f56021461e1c2eaf67351874f7ee8865195af7cac6
|
data/README.md
CHANGED
@@ -138,7 +138,7 @@ module MyAPI
|
|
138
138
|
|
139
139
|
# Execute action, return the list
|
140
140
|
def exec
|
141
|
-
query
|
141
|
+
with_pagination(query)
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -178,9 +178,9 @@ module MyAPI
|
|
178
178
|
user = ::User.new(input)
|
179
179
|
|
180
180
|
if user.save
|
181
|
-
ok(user)
|
181
|
+
ok!(user)
|
182
182
|
else
|
183
|
-
error('save failed', user.errors.to_hash)
|
183
|
+
error!('save failed', user.errors.to_hash)
|
184
184
|
end
|
185
185
|
end
|
186
186
|
end
|
data/haveapi.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
|
17
17
|
s.add_dependency 'activesupport', '>= 7.1'
|
18
18
|
s.add_dependency 'github-markdown'
|
19
|
-
s.add_dependency 'haveapi-client', '~> 0.
|
19
|
+
s.add_dependency 'haveapi-client', '~> 0.25.0'
|
20
20
|
s.add_dependency 'json'
|
21
21
|
s.add_dependency 'mail'
|
22
22
|
s.add_dependency 'nesty', '~> 1.0'
|
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_dependency 'rake'
|
25
25
|
s.add_dependency 'redcarpet', '~> 3.6'
|
26
26
|
s.add_dependency 'require_all', '~> 2.0.0'
|
27
|
-
s.add_dependency 'sinatra', '~>
|
28
|
-
s.add_dependency 'sinatra-contrib', '~>
|
29
|
-
s.add_dependency 'tilt', '~> 2.
|
27
|
+
s.add_dependency 'sinatra', '~> 4.0'
|
28
|
+
s.add_dependency 'sinatra-contrib', '~> 4.0'
|
29
|
+
s.add_dependency 'tilt', '~> 2.4'
|
30
30
|
end
|
data/lib/haveapi/action.rb
CHANGED
@@ -323,7 +323,7 @@ module HaveAPI
|
|
323
323
|
def validate!
|
324
324
|
@params = validate
|
325
325
|
rescue ValidationError => e
|
326
|
-
error(e.message, e.to_hash)
|
326
|
+
error!(e.message, e.to_hash)
|
327
327
|
end
|
328
328
|
|
329
329
|
def authorized?(user)
|
@@ -379,11 +379,11 @@ module HaveAPI
|
|
379
379
|
if tmp.empty?
|
380
380
|
p e.message
|
381
381
|
puts e.backtrace
|
382
|
-
error('Server error occurred')
|
382
|
+
error!('Server error occurred')
|
383
383
|
end
|
384
384
|
|
385
385
|
unless tmp[:status]
|
386
|
-
error(tmp[:message], {}, http_status: tmp[:http_status] || 500)
|
386
|
+
error!(tmp[:message], {}, http_status: tmp[:http_status] || 500)
|
387
387
|
end
|
388
388
|
end
|
389
389
|
|
@@ -555,7 +555,7 @@ module HaveAPI
|
|
555
555
|
# @param ret [Hash] response
|
556
556
|
# @param opts [Hash] options
|
557
557
|
# @option opts [Integer] http_status HTTP status code sent to the client
|
558
|
-
def ok(ret = {}, opts = {})
|
558
|
+
def ok!(ret = {}, opts = {})
|
559
559
|
@http_status = opts[:http_status]
|
560
560
|
throw(:return, ret)
|
561
561
|
end
|
@@ -564,7 +564,7 @@ module HaveAPI
|
|
564
564
|
# @param errs [Hash<Array>] parameter errors sent to the client
|
565
565
|
# @param opts [Hash] options
|
566
566
|
# @option opts [Integer] http_status HTTP status code sent to the client
|
567
|
-
def error(msg, errs = {}, opts = {})
|
567
|
+
def error!(msg, errs = {}, opts = {})
|
568
568
|
@message = msg
|
569
569
|
@errors = errs
|
570
570
|
@http_status = opts[:http_status]
|
data/lib/haveapi/action_state.rb
CHANGED
@@ -11,11 +11,11 @@ module HaveAPI
|
|
11
11
|
class ActionState
|
12
12
|
# Return an array of objects representing actions that are pending completion.
|
13
13
|
# @param [Object] user
|
14
|
-
# @param [Integer]
|
14
|
+
# @param [Integer] from_id
|
15
15
|
# @param [Integer] limit
|
16
16
|
# @param [Symbol] order (:newest or :oldest)
|
17
17
|
# @return [Array<ActionState>]
|
18
|
-
def self.list_pending(user,
|
18
|
+
def self.list_pending(user, from_id, limit, order)
|
19
19
|
raise NotImplementedError
|
20
20
|
end
|
21
21
|
|
@@ -2,9 +2,9 @@ module HaveAPI::Actions
|
|
2
2
|
module Paginable
|
3
3
|
def self.included(action)
|
4
4
|
action.input do
|
5
|
-
integer :
|
6
|
-
|
7
|
-
integer :limit, label: 'Limit', desc: '
|
5
|
+
integer :from_id, label: 'From ID', desc: 'List objects with greater/lesser ID',
|
6
|
+
number: { min: 0 }
|
7
|
+
integer :limit, label: 'Limit', desc: 'Number of objects to retrieve',
|
8
8
|
number: { min: 0 }
|
9
9
|
end
|
10
10
|
end
|
@@ -159,7 +159,7 @@ module HaveAPI::Authentication
|
|
159
159
|
# @param request [Sinatra::Request]
|
160
160
|
# @return [String]
|
161
161
|
def token(request)
|
162
|
-
request[config.class.query_parameter] || request.env[header_to_env]
|
162
|
+
request.params[config.class.query_parameter] || request.env[header_to_env]
|
163
163
|
end
|
164
164
|
|
165
165
|
def describe
|
@@ -227,11 +227,11 @@ module HaveAPI::Authentication
|
|
227
227
|
input:
|
228
228
|
), ActionResult.new)
|
229
229
|
rescue HaveAPI::AuthenticationError => e
|
230
|
-
error(e.message)
|
230
|
+
error!(e.message)
|
231
231
|
end
|
232
232
|
|
233
233
|
unless result.ok?
|
234
|
-
error(result.error || 'invalid authentication credentials')
|
234
|
+
error!(result.error || 'invalid authentication credentials')
|
235
235
|
end
|
236
236
|
|
237
237
|
{
|
@@ -260,9 +260,9 @@ module HaveAPI::Authentication
|
|
260
260
|
), ActionResult.new)
|
261
261
|
|
262
262
|
if result.ok?
|
263
|
-
ok
|
263
|
+
ok!
|
264
264
|
else
|
265
|
-
error(result.error || 'revoke failed')
|
265
|
+
error!(result.error || 'revoke failed')
|
266
266
|
end
|
267
267
|
end
|
268
268
|
end
|
@@ -290,7 +290,7 @@ module HaveAPI::Authentication
|
|
290
290
|
if result.ok?
|
291
291
|
{ valid_to: result.valid_to }
|
292
292
|
else
|
293
|
-
error(result.error || 'renew failed')
|
293
|
+
error!(result.error || 'renew failed')
|
294
294
|
end
|
295
295
|
end
|
296
296
|
end
|
@@ -324,11 +324,11 @@ module HaveAPI::Authentication
|
|
324
324
|
token: input[:token]
|
325
325
|
), ActionResult.new)
|
326
326
|
rescue HaveAPI::AuthenticationError => e
|
327
|
-
error(e.message)
|
327
|
+
error!(e.message)
|
328
328
|
end
|
329
329
|
|
330
330
|
unless result.ok?
|
331
|
-
error(result.error || 'authentication failed')
|
331
|
+
error!(result.error || 'authentication failed')
|
332
332
|
end
|
333
333
|
|
334
334
|
{
|
@@ -41,6 +41,47 @@ module HaveAPI::ModelAdapters
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
# Apply pagination on query in ascending order
|
45
|
+
# @param q [ActiveRecord::Relation] query to apply pagination on
|
46
|
+
def with_asc_pagination(q = nil)
|
47
|
+
ar_with_pagination(q, check: true) do |query, from_id|
|
48
|
+
query.where("`#{self.class.model.table_name}`.`#{self.class.model.primary_key}` > ?", from_id)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Apply pagination on query in descending order
|
53
|
+
# @param q [ActiveRecord::Relation] query to apply pagination on
|
54
|
+
def with_desc_pagination(q = nil)
|
55
|
+
ar_with_pagination(q, check: true) do |query, from_id|
|
56
|
+
query.where("`#{self.class.model.table_name}`.`#{self.class.model.primary_key}` < ?", from_id)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
alias with_pagination with_asc_pagination
|
61
|
+
|
62
|
+
# @param q [ActiveRecord::Relation] query to apply pagination on
|
63
|
+
# @param parameter [Symbol] input parameter used for pagination
|
64
|
+
# @param check [Boolean] raise if the model does not have a simple primary key
|
65
|
+
# @yieldparam q [ActiveRecord::Relation] query to apply pagination on
|
66
|
+
# @yieldparam parameter [any] value of the input parameter
|
67
|
+
def ar_with_pagination(q, parameter: :from_id, check: false)
|
68
|
+
pk = self.class.model.primary_key
|
69
|
+
|
70
|
+
if check && !pk.is_a?(String)
|
71
|
+
raise 'only simple primary key is supported, ' \
|
72
|
+
"#{self.class.model} has a composite primary key (#{pk.join(', ')})"
|
73
|
+
end
|
74
|
+
|
75
|
+
q ||= self.class.model.all
|
76
|
+
|
77
|
+
paginable = input[parameter]
|
78
|
+
limit = input[:limit]
|
79
|
+
|
80
|
+
q = yield(q, paginable) if paginable
|
81
|
+
q = q.limit(limit) if limit
|
82
|
+
q
|
83
|
+
end
|
84
|
+
|
44
85
|
# Parse includes sent by the user and return them
|
45
86
|
# in an array of symbols and hashes.
|
46
87
|
def ar_parse_includes(raw)
|
data/lib/haveapi/params.rb
CHANGED
@@ -154,6 +154,13 @@ module HaveAPI
|
|
154
154
|
@params.detect { |p| p.name == name }.patch(changes)
|
155
155
|
end
|
156
156
|
|
157
|
+
def remove(name)
|
158
|
+
i = @params.index { |p| p.name == name }
|
159
|
+
raise "Parameter #{name.inspect} not found" if i.nil?
|
160
|
+
|
161
|
+
@params.delete_at(i)
|
162
|
+
end
|
163
|
+
|
157
164
|
# Action returns custom data.
|
158
165
|
def custom(name, **kwargs, &block)
|
159
166
|
add_param(name, apply(kwargs, type: Custom, clean: block))
|
@@ -63,7 +63,7 @@ module HaveAPI::Resources
|
|
63
63
|
def exec
|
64
64
|
actions = @context.server.action_state.list_pending(
|
65
65
|
current_user,
|
66
|
-
input[:
|
66
|
+
input[:from_id],
|
67
67
|
input[:limit],
|
68
68
|
input[:order].to_sym
|
69
69
|
)
|
@@ -106,7 +106,7 @@ module HaveAPI::Resources
|
|
106
106
|
id: params[:action_state_id]
|
107
107
|
)
|
108
108
|
|
109
|
-
error('action state not found') unless state.valid?
|
109
|
+
error!('action state not found') unless state.valid?
|
110
110
|
|
111
111
|
if state.finished? || (Time.now - t) >= input[:timeout]
|
112
112
|
return state_to_hash(state)
|
@@ -145,7 +145,7 @@ module HaveAPI::Resources
|
|
145
145
|
|
146
146
|
return state_to_hash(state) if state.valid?
|
147
147
|
|
148
|
-
error('action state not found')
|
148
|
+
error!('action state not found')
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
@@ -164,7 +164,7 @@ module HaveAPI::Resources
|
|
164
164
|
id: params[:action_state_id]
|
165
165
|
)
|
166
166
|
|
167
|
-
error('action state not found') unless state.valid?
|
167
|
+
error!('action state not found') unless state.valid?
|
168
168
|
|
169
169
|
ret = state.cancel
|
170
170
|
|
@@ -172,13 +172,13 @@ module HaveAPI::Resources
|
|
172
172
|
@state_id = ret
|
173
173
|
|
174
174
|
elsif ret
|
175
|
-
ok
|
175
|
+
ok!
|
176
176
|
|
177
177
|
else
|
178
|
-
error('cancellation failed')
|
178
|
+
error!('cancellation failed')
|
179
179
|
end
|
180
180
|
rescue RuntimeError, NotImplementedError => e
|
181
|
-
error(e.message)
|
181
|
+
error!(e.message)
|
182
182
|
end
|
183
183
|
|
184
184
|
attr_reader :state_id
|
data/lib/haveapi/server.rb
CHANGED
@@ -74,11 +74,11 @@ module HaveAPI
|
|
74
74
|
return unless request.env['HTTP_ORIGIN'] && request.env['HTTP_ACCESS_CONTROL_REQUEST_METHOD']
|
75
75
|
|
76
76
|
halt 200, {
|
77
|
-
'
|
78
|
-
'
|
79
|
-
'
|
80
|
-
'
|
81
|
-
'
|
77
|
+
'access-control-allow-origin' => '*',
|
78
|
+
'access-control-allow-methods' => 'GET,POST,OPTIONS,PATCH,PUT,DELETE',
|
79
|
+
'access-control-allow-credentials' => 'false',
|
80
|
+
'access-control-allow-headers' => settings.api_server.allowed_headers,
|
81
|
+
'access-control-max-age' => (60 * 60).to_s
|
82
82
|
}, ''
|
83
83
|
end
|
84
84
|
|
@@ -94,7 +94,7 @@ module HaveAPI
|
|
94
94
|
def require_auth!
|
95
95
|
report_error(
|
96
96
|
401,
|
97
|
-
{ '
|
97
|
+
{ 'www-authenticate' => 'Basic realm="Restricted Area"' },
|
98
98
|
'Action requires user to authenticate'
|
99
99
|
)
|
100
100
|
end
|
@@ -166,13 +166,19 @@ module HaveAPI
|
|
166
166
|
ret += "<h5>#{name.to_s.capitalize}</h5>"
|
167
167
|
ret += '<dl>'
|
168
168
|
opts.each do |k, v|
|
169
|
-
ret += "<dt>#{k}</dt><dd>#{v}</dd>"
|
169
|
+
ret += "<dt>#{k}</dt><dd>#{escape_html(v.to_s)}</dd>"
|
170
170
|
end
|
171
171
|
ret += '</dl>'
|
172
172
|
end
|
173
173
|
|
174
174
|
ret
|
175
175
|
end
|
176
|
+
|
177
|
+
def escape_html(v)
|
178
|
+
return '' if v.nil?
|
179
|
+
|
180
|
+
CGI.escapeHTML(v.to_s)
|
181
|
+
end
|
176
182
|
end
|
177
183
|
|
178
184
|
def initialize(module_name = HaveAPI.module_name)
|
@@ -231,8 +237,8 @@ module HaveAPI
|
|
231
237
|
|
232
238
|
before do
|
233
239
|
if request.env['HTTP_ORIGIN']
|
234
|
-
headers '
|
235
|
-
'
|
240
|
+
headers 'access-control-allow-origin' => '*',
|
241
|
+
'access-control-allow-credentials' => 'false'
|
236
242
|
end
|
237
243
|
end
|
238
244
|
|
@@ -468,8 +474,6 @@ module HaveAPI
|
|
468
474
|
authenticated?(v)
|
469
475
|
end
|
470
476
|
|
471
|
-
request.body.rewind
|
472
|
-
|
473
477
|
begin
|
474
478
|
body = request.body.read
|
475
479
|
|
@@ -42,7 +42,7 @@ module HaveAPI::Spec
|
|
42
42
|
method(action.http_method).call(
|
43
43
|
path,
|
44
44
|
params && params.to_json,
|
45
|
-
{ '
|
45
|
+
{ 'content-type' => 'application/json' }
|
46
46
|
)
|
47
47
|
|
48
48
|
else
|
@@ -51,7 +51,7 @@ module HaveAPI::Spec
|
|
51
51
|
method(http_method).call(
|
52
52
|
path,
|
53
53
|
params && params.to_json,
|
54
|
-
{ '
|
54
|
+
{ 'content-type' => 'application/json' }
|
55
55
|
)
|
56
56
|
end
|
57
57
|
end
|
data/lib/haveapi/version.rb
CHANGED
@@ -54,8 +54,8 @@
|
|
54
54
|
<td><%= info[:required] ? 'yes' : 'no' %></td>
|
55
55
|
<td><%= format_param_type(info) %></td>
|
56
56
|
<td><%= format_validators(info[:validators]) %></td>
|
57
|
-
<td><%= info[:default] == :_nil ? '' : info[:default] %></td>
|
58
|
-
<td><%= info[:description] %></td>
|
57
|
+
<td><%= info[:default] == :_nil ? '' : escape_html(info[:default]) %></td>
|
58
|
+
<td><%= escape_html(info[:description]) %></td>
|
59
59
|
</tr>
|
60
60
|
<% end %>
|
61
61
|
</table>
|
@@ -86,18 +86,13 @@
|
|
86
86
|
<td><%= info[:label] %></td>
|
87
87
|
<td><%= param %></td>
|
88
88
|
<td><%= format_param_type(info) %></td>
|
89
|
-
<td><%= info[:description] %></td>
|
89
|
+
<td><%= escape_html(info[:description]) %></td>
|
90
90
|
</tr>
|
91
91
|
<% end %>
|
92
92
|
</table>
|
93
93
|
<% end %>
|
94
94
|
</div>
|
95
95
|
|
96
|
-
<div class="action-self-description">
|
97
|
-
<h4>Self-description</h4>
|
98
|
-
<pre><code><%= JSON.pretty_generate(info) %></code></pre>
|
99
|
-
</div>
|
100
|
-
|
101
96
|
<% unless info[:examples].empty? %>
|
102
97
|
<h4>Examples</h4>
|
103
98
|
<% info[:examples].each_with_index do |example, i| %>
|
@@ -111,33 +111,5 @@ nojsTabs({
|
|
111
111
|
|
112
112
|
event.preventDefault();
|
113
113
|
});
|
114
|
-
|
115
|
-
// Show/hide button for help messages
|
116
|
-
$('.action .action-self-description').each(function(i, el){
|
117
|
-
// replace text by show/hide button
|
118
|
-
var div = $(el);
|
119
|
-
var pre = div.find('pre');
|
120
|
-
var h4 = div.find('h4');
|
121
|
-
h4.text('');
|
122
|
-
|
123
|
-
h4.append(
|
124
|
-
$('<button>')
|
125
|
-
.attr('type', 'button')
|
126
|
-
.addClass('btn btn-primary btn-sm')
|
127
|
-
.text('Show self-description')
|
128
|
-
.click(function(event) {
|
129
|
-
var button = $(this);
|
130
|
-
button.toggleClass('active');
|
131
|
-
pre.toggle('fast');
|
132
|
-
|
133
|
-
if(button.hasClass('active'))
|
134
|
-
button.text('Hide self-description');
|
135
|
-
else
|
136
|
-
button.text('Show self-description');
|
137
|
-
})
|
138
|
-
);
|
139
|
-
|
140
|
-
$(el).find('pre').hide();
|
141
|
-
});
|
142
114
|
});
|
143
115
|
</script>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: haveapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.25.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakub Skokan
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.25.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
54
|
+
version: 0.25.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,42 +156,42 @@ dependencies:
|
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version:
|
159
|
+
version: '4.0'
|
160
160
|
type: :runtime
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
166
|
+
version: '4.0'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: sinatra-contrib
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
171
|
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
173
|
+
version: '4.0'
|
174
174
|
type: :runtime
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version:
|
180
|
+
version: '4.0'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: tilt
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 2.
|
187
|
+
version: '2.4'
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: 2.
|
194
|
+
version: '2.4'
|
195
195
|
description: Framework for creating self-describing APIs
|
196
196
|
email: jakub.skokan@vpsfree.cz
|
197
197
|
executables: []
|