praxis 2.0.pre.13 → 2.0.pre.17
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/CHANGELOG.md +19 -0
- data/bin/praxis +6 -0
- data/lib/praxis/api_definition.rb +8 -4
- data/lib/praxis/collection.rb +11 -0
- data/lib/praxis/docs/open_api/response_object.rb +21 -6
- data/lib/praxis/extensions/attribute_filtering.rb +14 -1
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +81 -23
- data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +1 -1
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +3 -4
- data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +52 -12
- data/lib/praxis/mapper/resource.rb +2 -2
- data/lib/praxis/media_type_identifier.rb +11 -1
- data/lib/praxis/response_definition.rb +46 -66
- data/lib/praxis/responses/http.rb +3 -1
- data/lib/praxis/tasks/routes.rb +6 -6
- data/lib/praxis/version.rb +1 -1
- data/spec/praxis/action_definition_spec.rb +3 -1
- data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +110 -35
- data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +25 -3
- data/spec/praxis/extensions/attribute_filtering/filters_parser_spec.rb +13 -5
- data/spec/praxis/extensions/support/spec_resources_active_model.rb +2 -0
- data/spec/praxis/mapper/resource_spec.rb +3 -3
- data/spec/praxis/media_type_identifier_spec.rb +15 -1
- data/spec/praxis/response_definition_spec.rb +37 -129
- data/spec/spec_helper.rb +1 -0
- data/tasks/thor/templates/generator/example_app/app/v1/concerns/href.rb +33 -0
- data/tasks/thor/templates/generator/example_app/app/v1/resources/base.rb +4 -0
- data/tasks/thor/templates/generator/example_app/config/environment.rb +1 -1
- data/tasks/thor/templates/generator/scaffold/implementation/resources/item.rb +2 -2
- metadata +7 -6
@@ -29,7 +29,14 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams do
|
|
29
29
|
{ name: :two, op: '>', value: 'normal'},
|
30
30
|
]
|
31
31
|
expect(described_class.load(str).parsed_array.map{|i| i.slice(:name,:op,:value)}).to eq(parsed)
|
32
|
-
|
32
|
+
end
|
33
|
+
it 'does not handle badly escaped values that contain reserved chars ()|&,' do
|
34
|
+
badly_escaped = 'val('
|
35
|
+
str = "one=#{badly_escaped}&(two>normal|three!)"
|
36
|
+
expect{
|
37
|
+
described_class.load(str)
|
38
|
+
}.to raise_error(Parslet::ParseFailed)
|
39
|
+
end
|
33
40
|
end
|
34
41
|
context 'parses for operator' do
|
35
42
|
described_class::VALUE_OPERATORS.each do |op|
|
@@ -154,9 +161,9 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams do
|
|
154
161
|
# construct it propertly by applying the block. Seems easier than creating the type alone, and
|
155
162
|
# then manually apply the block
|
156
163
|
Attributor::Attribute.new(described_class.for(Post)) do
|
157
|
-
filter 'id', using: ['=', '!=']
|
164
|
+
filter 'id', using: ['=', '!=', '!']
|
158
165
|
filter 'title', using: ['=', '!='], fuzzy: true
|
159
|
-
filter 'content', using: ['=', '!=']
|
166
|
+
filter 'content', using: ['=', '!=', '!']
|
160
167
|
end.type
|
161
168
|
end
|
162
169
|
let(:loaded_params) { filtering_params_type.load(filters_string) }
|
@@ -187,6 +194,21 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams do
|
|
187
194
|
end
|
188
195
|
end
|
189
196
|
end
|
197
|
+
|
198
|
+
context 'non-valued operators' do
|
199
|
+
context 'for string typed fields' do
|
200
|
+
let(:filters_string) { 'content!'}
|
201
|
+
it 'validates properly' do
|
202
|
+
expect(subject).to be_empty
|
203
|
+
end
|
204
|
+
end
|
205
|
+
context 'for non-string typed fields' do
|
206
|
+
let(:filters_string) { 'id!'}
|
207
|
+
it 'validates properly' do
|
208
|
+
expect(subject).to be_empty
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
190
212
|
context 'fuzzy matches' do
|
191
213
|
context 'when allowed' do
|
192
214
|
context 'given a fuzzy string' do
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'praxis/extensions/attribute_filtering/filters_parser'
|
2
2
|
|
3
|
-
|
4
3
|
describe Praxis::Extensions::AttributeFiltering::FilteringParams::Condition do
|
5
4
|
end
|
6
5
|
|
@@ -121,17 +120,26 @@ describe Praxis::Extensions::AttributeFiltering::FilteringParams::Parser do
|
|
121
120
|
context 'supports everything (except &|(),) for values (even without encoding..not allowed, but just to ensure the parser does not bomb)' do
|
122
121
|
it_behaves_like 'round-trip-properly', {
|
123
122
|
'v=1123' => 'v=1123',
|
124
|
-
'v=*foo*' => 'v
|
125
|
-
'v=*^%$#@!foo' => 'v
|
123
|
+
'v=*foo*' => 'v={*}foo{*}',
|
124
|
+
'v=*^%$#@!foo' => 'v={*}^%$#@!foo',
|
126
125
|
'v=_-=\{}"?:><' => 'v=_-=\{}"?:><',
|
127
126
|
'v=_-=\{}"?:><,another_value!' => 'v=[_-=\{}"?:><,another_value!]',
|
128
127
|
}
|
129
128
|
end
|
129
|
+
context 'properly detects and handles fuzzy matching encoded as {*} in the dump' do
|
130
|
+
it_behaves_like 'round-trip-properly', {
|
131
|
+
'v=*foo' => 'v={*}foo',
|
132
|
+
'v=*foo*' => 'v={*}foo{*}',
|
133
|
+
'v=foo*' => 'v=foo{*}',
|
134
|
+
'v=*start,end*,*both*' => 'v=[{*}start,end{*},{*}both{*}]',
|
135
|
+
"v=*#{CGI.escape('***')},#{CGI.escape('*')}" => 'v=[{*}***,*]', # Simple exact match on 2nd
|
136
|
+
}
|
137
|
+
end
|
130
138
|
context 'properly handles url-encoded values' do
|
131
139
|
it_behaves_like 'round-trip-properly', {
|
132
140
|
"v=#{CGI.escape('1123')}" => 'v=1123',
|
133
|
-
"v
|
134
|
-
"v
|
141
|
+
"v=*#{CGI.escape('foo')}*" => 'v={*}foo{*}',
|
142
|
+
"v=*#{CGI.escape('^%$#@!foo')}" => 'v={*}^%$#@!foo',
|
135
143
|
"v=#{CGI.escape('~!@#$%^&*()_+-={}|[]\:";\'<>?,./`')}" => 'v=~!@#$%^&*()_+-={}|[]\:";\'<>?,./`',
|
136
144
|
"v=#{CGI.escape('_-+=\{}"?:><')},#{CGI.escape('another_value!')}" => 'v=[_-+=\{}"?:><,another_value!]',
|
137
145
|
}
|
@@ -120,6 +120,8 @@ class ActiveBookResource < ActiveBaseResource
|
|
120
120
|
'category.books.name': 'category.books.simple_name',
|
121
121
|
'category.books.taggings.tag_id': 'category.books.taggings.tag_id',
|
122
122
|
'category.books.taggings.label': 'category.books.taggings.label',
|
123
|
+
'primary_tags': 'primary_tags',
|
124
|
+
'category.books.taggings': 'category.books.taggings',
|
123
125
|
)
|
124
126
|
# Forces to add an extra column (added_column)...and yet another (author_id) that will serve
|
125
127
|
# to check that if that's already automatically added due to an association, it won't interfere or duplicate
|
@@ -14,15 +14,15 @@ describe Praxis::Mapper::Resource do
|
|
14
14
|
subject(:properties) { resource.properties }
|
15
15
|
|
16
16
|
it 'includes directly-set properties' do
|
17
|
-
expect(properties[:other_resource]).to eq(dependencies: [:other_model])
|
17
|
+
expect(properties[:other_resource]).to eq(dependencies: [:other_model], through: nil)
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'inherits from a superclass' do
|
21
|
-
expect(properties[:href]).to eq(dependencies: [:id])
|
21
|
+
expect(properties[:href]).to eq(dependencies: [:id], through: nil)
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'properly overrides a property from the parent' do
|
25
|
-
expect(properties[:name]).to eq(dependencies: [:simple_name])
|
25
|
+
expect(properties[:name]).to eq(dependencies: [:simple_name], through: nil)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -218,7 +218,21 @@ describe Praxis::MediaTypeIdentifier do
|
|
218
218
|
|
219
219
|
it 'replaces suffix and parameters and adds new ones' do
|
220
220
|
expect(complex_subject + 'json; nuts=false; cherry=true').to \
|
221
|
-
|
221
|
+
eq(described_class.new('application/vnd.icecream+json; cherry=true; nuts=false'))
|
222
|
+
end
|
223
|
+
|
224
|
+
context 'does not add json for an already json identifier' do
|
225
|
+
it 'non-parameterized mediatypes simply ignore adding the suffix' do
|
226
|
+
plain_application_json = described_class.new('application/json')
|
227
|
+
|
228
|
+
expect(plain_application_json + 'json').to \
|
229
|
+
eq(plain_application_json)
|
230
|
+
end
|
231
|
+
it 'parameterized mediatypes still keeps them' do
|
232
|
+
parameterized_application_json = described_class.new('application/json; cherry=true; nuts=false')
|
233
|
+
expect(parameterized_application_json + 'json').to \
|
234
|
+
eq(parameterized_application_json)
|
235
|
+
end
|
222
236
|
end
|
223
237
|
end
|
224
238
|
end
|
@@ -8,7 +8,8 @@ describe Praxis::ResponseDefinition do
|
|
8
8
|
Proc.new do
|
9
9
|
status 200
|
10
10
|
description 'test description'
|
11
|
-
|
11
|
+
header( "X-Header", "value", description: 'Very nais header')
|
12
|
+
header( "Content-Type", "application/some-type" )
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
@@ -17,7 +18,7 @@ describe Praxis::ResponseDefinition do
|
|
17
18
|
its(:parts) { should be(nil) }
|
18
19
|
let(:response_status) { 200 }
|
19
20
|
let(:response_content_type) { "application/some-type" }
|
20
|
-
let(:response_headers) { { "X-Header" => "value", "Content-Type" => response_content_type} }
|
21
|
+
let(:response_headers) { { "X-Header" => "value", "Content-Type" => response_content_type, "Location" => '/somewhere/over/the/rainbow'} }
|
21
22
|
|
22
23
|
let(:response) { instance_double("Praxis::Response", status: response_status , headers: response_headers, content_type: response_content_type ) }
|
23
24
|
|
@@ -105,29 +106,6 @@ describe Praxis::ResponseDefinition do
|
|
105
106
|
end
|
106
107
|
end
|
107
108
|
|
108
|
-
context '#headers' do
|
109
|
-
it 'accepts a Hash' do
|
110
|
-
response_definition.headers Hash["X-Header" => "value", "Content-Type" => "application/some-type"]
|
111
|
-
expect(response_definition.headers).to be_a(Hash)
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'accepts an Array' do
|
115
|
-
response_definition.headers ["X-Header: value", "Content-Type: application/some-type"]
|
116
|
-
expect(response_definition.headers).to be_a(Hash)
|
117
|
-
expect(response_definition.headers.keys).to include("X-Header: value", "Content-Type: application/some-type")
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'accepts a String' do
|
121
|
-
response_definition.headers "X-Header: value"
|
122
|
-
expect(response_definition.headers).to be_a(Hash)
|
123
|
-
expect(response_definition.headers.keys).to include("X-Header: value")
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'should return an error when headers are not a Hash, Array or String object' do
|
127
|
-
expect{ response_definition.headers Object.new }. to raise_error(Praxis::Exceptions::InvalidConfiguration)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
109
|
context '#parts' do
|
132
110
|
context 'with a :like argument (and no block)' do
|
133
111
|
before do
|
@@ -242,7 +220,6 @@ describe Praxis::ResponseDefinition do
|
|
242
220
|
|
243
221
|
it "calls all the validation sub-functions" do
|
244
222
|
expect(response_definition).to receive(:validate_status!).once
|
245
|
-
expect(response_definition).to receive(:validate_location!).once
|
246
223
|
expect(response_definition).to receive(:validate_headers!).once
|
247
224
|
expect(response_definition).to receive(:validate_content_type!).once
|
248
225
|
response_definition.validate(response)
|
@@ -272,112 +249,39 @@ describe Praxis::ResponseDefinition do
|
|
272
249
|
|
273
250
|
end
|
274
251
|
|
275
|
-
describe "#
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
let(:location) { /no_match/ }
|
283
|
-
|
284
|
-
it 'should raise an error' do
|
285
|
-
expect {
|
286
|
-
response_definition.validate_location!(response)
|
287
|
-
}.to raise_error(Praxis::Exceptions::Validation)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
context 'for String' do
|
292
|
-
let(:location) { "no_match" }
|
293
|
-
it 'should raise error' do
|
294
|
-
expect {
|
295
|
-
response_definition.validate_location!(response)
|
296
|
-
}.to raise_error(Praxis::Exceptions::Validation)
|
297
|
-
end
|
252
|
+
describe "#validate_headers!" do
|
253
|
+
context 'when there are missing headers' do
|
254
|
+
it 'should raise error' do
|
255
|
+
response_definition.header('X-Unknown', 'test')
|
256
|
+
expect {
|
257
|
+
response_definition.validate_headers!(response)
|
258
|
+
}.to raise_error(Praxis::Exceptions::Validation)
|
298
259
|
end
|
299
|
-
|
300
260
|
end
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
let (:headers) { { 'X-some' => 'test' } }
|
308
|
-
it 'should raise error' do
|
309
|
-
expect {
|
310
|
-
response_definition.validate_headers!(response)
|
311
|
-
}.to raise_error(Praxis::Exceptions::Validation)
|
312
|
-
end
|
261
|
+
context 'when headers with same names are returned' do
|
262
|
+
it 'a simply required header should not raise error just by being there' do
|
263
|
+
response_definition.header('X-Header', nil)
|
264
|
+
expect {
|
265
|
+
response_definition.validate_headers!(response)
|
266
|
+
}.to_not raise_error
|
313
267
|
end
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
expect {
|
320
|
-
response_definition.validate_headers!(response)
|
321
|
-
}.to raise_error(Praxis::Exceptions::Validation)
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
context "and is not missing" do
|
326
|
-
let (:headers) { [ "X-Header" ] }
|
327
|
-
it 'should not raise error' do
|
328
|
-
expect {
|
329
|
-
response_definition.validate_headers!(response)
|
330
|
-
}.not_to raise_error
|
331
|
-
end
|
332
|
-
end
|
268
|
+
it 'an exact string header should not raise error if it fully matches' do
|
269
|
+
response_definition.header('X-Header', 'value')
|
270
|
+
expect {
|
271
|
+
response_definition.validate_headers!(response)
|
272
|
+
}.to_not raise_error
|
333
273
|
end
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
}
|
340
|
-
it 'should raise error' do
|
341
|
-
expect {
|
342
|
-
response_definition.validate_headers!(response)
|
343
|
-
}.to raise_error(Praxis::Exceptions::Validation)
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
context "and is not missing" do
|
348
|
-
let (:headers) {
|
349
|
-
[ { "X-Header" => "value" } ]
|
350
|
-
}
|
351
|
-
it 'should not raise error' do
|
352
|
-
expect {
|
353
|
-
response_definition.validate_headers!(response)
|
354
|
-
}.not_to raise_error
|
355
|
-
end
|
356
|
-
end
|
274
|
+
it 'a regexp header should not raise error if it matches the regexp' do
|
275
|
+
response_definition.header('X-Header', /value/)
|
276
|
+
expect {
|
277
|
+
response_definition.validate_headers!(response)
|
278
|
+
}.to_not raise_error
|
357
279
|
end
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
}
|
364
|
-
it 'should raise error' do
|
365
|
-
expect {
|
366
|
-
response_definition.validate_headers!(response)
|
367
|
-
}.to raise_error(Praxis::Exceptions::Validation)
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
context "and is not missing" do
|
372
|
-
let (:headers) {
|
373
|
-
[ { "X-Header" => "value" }, "Content-Type" ]
|
374
|
-
}
|
375
|
-
it 'should not raise error' do
|
376
|
-
expect {
|
377
|
-
response_definition.validate_headers!(response)
|
378
|
-
}.not_to raise_error
|
379
|
-
end
|
380
|
-
end
|
280
|
+
it 'a regexp header should raise error if it does not match the regexp' do
|
281
|
+
response_definition.header('X-Header', /anotherthing/)
|
282
|
+
expect {
|
283
|
+
response_definition.validate_headers!(response)
|
284
|
+
}.to raise_error(Praxis::Exceptions::Validation)
|
381
285
|
end
|
382
286
|
end
|
383
287
|
end
|
@@ -478,7 +382,10 @@ describe Praxis::ResponseDefinition do
|
|
478
382
|
if parts || parts_block
|
479
383
|
parts ? response.parts(nil, **parts, &parts_block) : response.parts(nil, &parts_block)
|
480
384
|
end
|
481
|
-
|
385
|
+
|
386
|
+
headers&.each do |(name, value)|
|
387
|
+
response.header(name, value)
|
388
|
+
end
|
482
389
|
end
|
483
390
|
|
484
391
|
context 'for a definition with a media type' do
|
@@ -520,8 +427,9 @@ describe Praxis::ResponseDefinition do
|
|
520
427
|
its([:location]){ should == {value: location.inspect ,type: :regexp} }
|
521
428
|
|
522
429
|
it 'should have a header defined with value and type keys' do
|
523
|
-
expect( output[:headers] ).to have(
|
430
|
+
expect( output[:headers] ).to have(2).keys
|
524
431
|
expect( output[:headers]['Header1'] ).to eq({value: 'Value1' ,type: :string })
|
432
|
+
expect( output[:headers]['Location'] ).to eq({value: "/\\/my\\/url\\//" ,type: :regexp })
|
525
433
|
end
|
526
434
|
end
|
527
435
|
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module V1
|
4
|
+
module Resources
|
5
|
+
module Concerns
|
6
|
+
module Href
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
# Base module where the href concern will grab constants from
|
10
|
+
included do
|
11
|
+
def self.base_module
|
12
|
+
::V1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def endpoint_path_template
|
18
|
+
# memoize a templated path for an endpoint, like
|
19
|
+
# /im/contacts/%{id}
|
20
|
+
return @endpoint_path_template if @endpoint_path_template
|
21
|
+
|
22
|
+
path = self.base_module.const_get(:Endpoints).const_get(model.name.split(':').last.pluralize).canonical_path.route.path
|
23
|
+
@endpoint_path_template = path.names.inject(path.to_s) { |p, name| p.sub(':' + name, "%{#{name}}") }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def href
|
28
|
+
format(self.class.endpoint_path_template, id: id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,8 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../concerns/href'
|
4
|
+
|
3
5
|
module V1
|
4
6
|
module Resources
|
5
7
|
class Base < Praxis::Mapper::Resource
|
8
|
+
include Resources::Concerns::Href
|
9
|
+
|
6
10
|
# Base for all V1 resources.
|
7
11
|
# Resources withing a single version should have resource mappings separate from other versions
|
8
12
|
# and the Mapper::Resource will appropriately maintain different model_maps for each Base classes
|
@@ -4,7 +4,7 @@ Praxis::Application.configure do |application|
|
|
4
4
|
# Configure the Mapper plugin (if we want to use all the filtering/field_selection extensions)
|
5
5
|
application.bootloader.use Praxis::Plugins::MapperPlugin
|
6
6
|
# Configure the Pagination plugin (if we want to use all the pagination/ordering extensions)
|
7
|
-
application.bootloader.use Praxis::Plugins::PaginationPlugin, {
|
7
|
+
application.bootloader.use Praxis::Plugins::PaginationPlugin, **{
|
8
8
|
# max_items: 500, # Unlimited by default,
|
9
9
|
# default_page_size: 100,
|
10
10
|
# paging_default_mode: {by: :id},
|
@@ -18,7 +18,7 @@ module <%= version_module %>
|
|
18
18
|
<%- if action_enabled?(:create) -%>
|
19
19
|
def self.create(payload)
|
20
20
|
# Assuming the API field names directly map the the model attributes. Massage if appropriate.
|
21
|
-
self.new(model.create(
|
21
|
+
self.new(model.create(**payload.to_h))
|
22
22
|
end
|
23
23
|
<%- end -%>
|
24
24
|
|
@@ -27,7 +27,7 @@ module <%= version_module %>
|
|
27
27
|
record = model.find_by(id: id)
|
28
28
|
return nil unless record
|
29
29
|
# Assuming the API field names directly map the the model attributes. Massage if appropriate.
|
30
|
-
record.update(
|
30
|
+
record.update(**payload.to_h)
|
31
31
|
self.new(record)
|
32
32
|
end
|
33
33
|
<%- end -%>
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: praxis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.pre.
|
4
|
+
version: 2.0.pre.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josep M. Blanquer
|
8
8
|
- Dane Jensen
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-
|
12
|
+
date: 2021-08-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -367,7 +367,7 @@ dependencies:
|
|
367
367
|
- - ">"
|
368
368
|
- !ruby/object:Gem::Version
|
369
369
|
version: '4'
|
370
|
-
description:
|
370
|
+
description:
|
371
371
|
email:
|
372
372
|
- blanquer@gmail.com
|
373
373
|
- dane.jensen@gmail.com
|
@@ -647,6 +647,7 @@ files:
|
|
647
647
|
- tasks/thor/templates/generator/example_app/Rakefile
|
648
648
|
- tasks/thor/templates/generator/example_app/app/models/user.rb
|
649
649
|
- tasks/thor/templates/generator/example_app/app/v1/concerns/controller_base.rb
|
650
|
+
- tasks/thor/templates/generator/example_app/app/v1/concerns/href.rb
|
650
651
|
- tasks/thor/templates/generator/example_app/app/v1/controllers/users.rb
|
651
652
|
- tasks/thor/templates/generator/example_app/app/v1/resources/base.rb
|
652
653
|
- tasks/thor/templates/generator/example_app/app/v1/resources/user.rb
|
@@ -671,7 +672,7 @@ homepage: https://github.com/praxis/praxis
|
|
671
672
|
licenses:
|
672
673
|
- MIT
|
673
674
|
metadata: {}
|
674
|
-
post_install_message:
|
675
|
+
post_install_message:
|
675
676
|
rdoc_options: []
|
676
677
|
require_paths:
|
677
678
|
- lib
|
@@ -687,7 +688,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
687
688
|
version: 1.3.1
|
688
689
|
requirements: []
|
689
690
|
rubygems_version: 3.1.2
|
690
|
-
signing_key:
|
691
|
+
signing_key:
|
691
692
|
specification_version: 4
|
692
693
|
summary: Building APIs the way you want it.
|
693
694
|
test_files: []
|