praxis 0.11.2 → 0.13.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/lib/api_browser/app/js/controllers/action.js +2 -2
  4. data/lib/api_browser/app/js/controllers/type.js +2 -2
  5. data/lib/praxis/action_definition.rb +11 -0
  6. data/lib/praxis/api_definition.rb +2 -0
  7. data/lib/praxis/bootloader_stages/environment.rb +1 -0
  8. data/lib/praxis/controller.rb +2 -11
  9. data/lib/praxis/media_type.rb +12 -3
  10. data/lib/praxis/media_type_collection.rb +0 -2
  11. data/lib/praxis/plugins/praxis_mapper_plugin.rb +27 -5
  12. data/lib/praxis/request_stages/request_stage.rb +53 -32
  13. data/lib/praxis/request_stages/response.rb +2 -3
  14. data/lib/praxis/resource_definition.rb +11 -1
  15. data/lib/praxis/responses/http.rb +108 -20
  16. data/lib/praxis/responses/internal_server_error.rb +1 -1
  17. data/lib/praxis/responses/validation_error.rb +1 -1
  18. data/lib/praxis/restful_doc_generator.rb +27 -3
  19. data/lib/praxis/router.rb +16 -2
  20. data/lib/praxis/skeletor/restful_routing_config.rb +3 -0
  21. data/lib/praxis/stage.rb +1 -1
  22. data/lib/praxis/tasks/api_docs.rb +1 -1
  23. data/lib/praxis/tasks/console.rb +21 -3
  24. data/lib/praxis/tasks/routes.rb +19 -7
  25. data/lib/praxis/version.rb +1 -1
  26. data/praxis.gemspec +3 -5
  27. data/spec/functional_spec.rb +12 -0
  28. data/spec/praxis/action_definition_spec.rb +17 -0
  29. data/spec/praxis/media_type_spec.rb +22 -2
  30. data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +62 -15
  31. data/spec/praxis/request_stage_spec.rb +147 -67
  32. data/spec/praxis/resource_definition_spec.rb +18 -2
  33. data/spec/praxis/restful_routing_config_spec.rb +1 -1
  34. data/spec/praxis/router_spec.rb +115 -37
  35. data/spec/spec_app/design/resources/instances.rb +1 -1
  36. data/spec/support/spec_media_types.rb +2 -0
  37. metadata +8 -22
@@ -1,93 +1,173 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Praxis::RequestStages::RequestStage do
4
- # Ugly, but clear and easy to test the shortcuts
5
- $before_controller_callback = Proc.new { nil }
6
- $after_controller_callback = Proc.new { nil }
7
- $before_show_controller_callback = Proc.new { Praxis::Responses::Unauthorized.new }
8
-
9
- class MyController
10
- include Praxis::Controller
11
- before( :action , &$before_controller_callback)
12
- after( :action , &$after_controller_callback)
13
- before( actions: [:show], &$before_show_controller_callback)
4
+
5
+ let(:controller_class) do
6
+ Class.new do
7
+ include Praxis::Controller
8
+ end
14
9
  end
15
- class MyStage < Praxis::RequestStages::RequestStage
10
+
11
+ let(:stage_class) { Class.new(Praxis::RequestStages::RequestStage) }
12
+
13
+ let(:request) { instance_double("Praxis::Request") }
14
+ let(:controller){ controller_class.new(request) }
15
+
16
+
17
+ let(:action){ instance_double("Praxis::ActionDefinition") }
18
+ let(:context){ double("context", controller: controller , action: action) }
19
+
20
+ let(:substage_1) { instance_double('Praxis::RequestStage') }
21
+ let(:substage_2) { instance_double('Praxis::RequestStage') }
22
+ let(:substage_3) { instance_double('Praxis::RequestStage') }
23
+
24
+ let(:before_callbacks) { double('before_callbacks') }
25
+ let(:after_callbacks) { double('after_callbacks') }
26
+ let(:controller_before_callbacks) { double('controller_before_callbacks') }
27
+ let(:controller_after_callbacks) { double('controller_after_callbacks') }
28
+
29
+ subject(:stage) { stage_class.new(:action, context) }
30
+
31
+
32
+ before do
33
+ # clear any pre-existing callbacks that may have been added by plugins
34
+ controller_class.before_callbacks = Hash.new
35
+ controller_class.after_callbacks = Hash.new
16
36
  end
17
-
18
- let(:controller){ MyController.new( double("request") ) }
19
- let(:action_name) { :unknown }
20
- let(:action){ double("action", name: action_name )}
21
- let(:context){ double("context", controller: controller , action: action )}
22
- subject(:stage) { MyStage.new(:action, context) }
23
-
24
- context ".run" do
25
- context 'for an abstract stage' do
26
- subject(:stage) {Praxis::RequestStages::RequestStage.new(:action, context)}
27
- it 'complains about having to implement execute' do
28
- expect{stage.run}.to raise_error(NotImplementedError,/Subclass must implement Stage#execute/)
29
- end
37
+
38
+ context 'for an abstract stage' do
39
+ subject(:stage) { Praxis::RequestStages::RequestStage.new(:action, context) }
40
+ it 'raises NotImplementedError for undefined #execute' do
41
+ expect {
42
+ stage.execute
43
+ }.to raise_error(NotImplementedError,/Subclass must implement Stage#execute/)
30
44
  end
31
-
32
- it "sets up and execute callbacks" do
33
- expect(stage).to receive(:setup!)
34
- expect(stage).to receive(:setup_deferred_callbacks!)
35
- expect(stage).to receive(:execute)
36
- expect(stage).to receive(:execute_callbacks).twice
37
- expect(stage).to receive(:execute_controller_callbacks).twice
38
- stage.run
45
+ end
46
+
47
+ context 'execute_controller_callbacks' do
48
+ end
49
+
50
+ context 'execute_with_around' do
51
+ end
52
+
53
+ context "#execute" do
54
+ before do
55
+ stage.stages.push(substage_1, substage_2, substage_3)
39
56
  end
40
-
41
-
42
- context 'when before controller callbacks return a Response' do
43
- let(:action_name) { :show }
44
-
45
- after do
46
- stage.run
47
- end
48
- it 'only calls the before callbacks' do
49
- expect(stage).to receive(:execute_callbacks).once.and_call_original
50
- expect(stage).to receive(:execute_controller_callbacks).once.and_call_original
57
+
58
+ context 'when all stages succeed' do
59
+ it "runs them all and returns nil" do
60
+ expect(substage_1).to receive(:run).once
61
+ expect(substage_2).to receive(:run).once
62
+ expect(substage_3).to receive(:run).once
63
+ expect(stage.execute).to be(nil)
51
64
  end
52
- it 'stops executing any other ones in the before chain' do
53
- expect($before_controller_callback).to receive(:call).once
65
+ end
66
+
67
+ context 'when one stage returns a Response' do
68
+ let(:response) { Praxis::Responses::Ok.new }
69
+ before do
70
+ expect(substage_1).to receive(:run).once
71
+ expect(substage_2).to receive(:run).once.and_return(response)
54
72
  end
55
- it 'does not call "execute"' do
56
- expect(stage).to_not receive(:execute)
73
+
74
+ it "runs no further stages after that" do
75
+ expect(substage_3).to_not receive(:run)
76
+ stage.execute
57
77
  end
58
- it 'does not execute any "after" callbacks either' do
59
- expect($after_controller_callback).to_not receive(:call)
78
+
79
+ it 'assigns the response to controller.response' do
80
+ stage.execute
81
+
82
+ expect(controller.response).to be(response)
60
83
  end
84
+
61
85
  end
62
86
  end
63
87
 
64
- context ".execute" do
65
- let(:double_stage_ok){ double("ok stage") }
88
+ context "#run" do
66
89
 
67
- context 'when all stages suceed' do
90
+ let(:before_callbacks) { double('before_callbacks') }
91
+ let(:after_callbacks) { double('after_callbacks') }
92
+
93
+ let(:controller_before_callbacks) { double('controller_before_callbacks') }
94
+ let(:controller_after_callbacks) { double('controller_after_callbacks') }
95
+
96
+ after do
97
+ stage.run
98
+ end
99
+
100
+ context 'callback execution' do
68
101
  before do
69
- expect(double_stage_ok).to receive(:run).twice
70
- stage.instance_variable_set(:@stages, [double_stage_ok, double_stage_ok])
71
- end
72
-
73
- it "runs them all" do
74
- stage.execute
102
+ allow(stage).to receive(:before_callbacks).once.and_return(before_callbacks)
103
+ allow(stage).to receive(:after_callbacks).once.and_return(after_callbacks)
104
+
105
+ allow(controller_class).to receive(:before_callbacks).once.and_return(controller_before_callbacks)
106
+ allow(controller_class).to receive(:after_callbacks).once.and_return(controller_after_callbacks)
75
107
  end
76
- it 'returns nil' do
77
- expect( stage.execute ).to be(nil)
108
+
109
+ it "sets up and executes callbacks" do
110
+ expect(stage).to receive(:setup!)
111
+ expect(stage).to receive(:setup_deferred_callbacks!)
112
+ expect(stage).to receive(:execute)
113
+ expect(stage).to receive(:execute_callbacks).once.with(before_callbacks)
114
+ expect(stage).to receive(:execute_callbacks).once.with(after_callbacks)
115
+ expect(stage).to receive(:execute_controller_callbacks).once.with(controller_before_callbacks)
116
+ expect(stage).to receive(:execute_controller_callbacks).once.with(controller_after_callbacks)
78
117
  end
118
+
79
119
  end
80
- context 'when one stage returns a Response' do
81
- it "runs no further stages after that" do
82
- double_stage_fail = double("fail stage")
83
- expect(double_stage_ok).to receive(:run).once
84
- expect(double_stage_fail).to receive(:run).once.and_return(Praxis::Responses::Ok.new)
85
- stage.instance_variable_set(:@stages, [double_stage_ok, double_stage_fail, double_stage_ok])
86
- stage.execute
120
+
121
+ context 'when the before execute_controller_callbacks return a Response' do
122
+ let(:action_name) { :show }
123
+ let(:response) { Praxis::Responses::Unauthorized.new }
124
+
125
+ before do
126
+ expect(stage).to receive(:execute_controller_callbacks).once.and_return(response)
127
+ end
128
+
129
+
130
+ it 'does not call "execute"' do
131
+ expect(stage).to_not receive(:execute)
87
132
  end
133
+
134
+ it 'does not execute any "after" callbacks' do
135
+ expect(stage).to_not receive(:after_callbacks)
136
+ expect(controller_class).to_not receive(:after_callbacks)
137
+ end
138
+
88
139
  end
89
140
 
141
+ context 'with substages' do
142
+ before do
143
+ stage.stages.push(substage_1, substage_2, substage_3)
144
+ end
145
+
146
+
147
+ context 'when one returns a Response' do
148
+ let(:response) { Praxis::Responses::Unauthorized.new }
149
+
150
+ before do
151
+ expect(substage_1).to receive(:run).once
152
+ expect(substage_2).to receive(:run).once.and_return(response)
153
+ expect(substage_3).to_not receive(:run)
154
+ end
155
+
156
+ it 'runs no after callbacks (including from the controller) ' do
157
+ expect(stage).to_not receive(:after_callbacks)
158
+ expect(controller_class).to_not receive(:after_callbacks)
159
+ end
160
+
161
+ it 'assigns controller.response' do
162
+ # twice, because we do it once in #execute, and again in #run...
163
+ expect(controller).to receive(:response=).
164
+ with(response).twice.and_call_original
165
+ end
166
+
167
+ end
168
+ end
90
169
  end
91
170
 
92
171
 
172
+
93
173
  end
@@ -12,8 +12,7 @@ describe Praxis::ResourceDefinition do
12
12
  its(:routing_config) { should be_kind_of(Proc) }
13
13
 
14
14
  its(:actions) { should have(2).items }
15
-
16
-
15
+ its(:metadata) { should_not have_key(:doc_visibility) }
17
16
 
18
17
  context '.describe' do
19
18
  subject(:describe) { resource_definition.describe }
@@ -22,6 +21,7 @@ describe Praxis::ResourceDefinition do
22
21
  its([:media_type]) { should eq(resource_definition.media_type.name) }
23
22
 
24
23
  its([:actions]) { should have(2).items }
24
+ its([:metadata]) { should be_kind_of(Hash) }
25
25
  end
26
26
 
27
27
  context '.action' do
@@ -97,4 +97,20 @@ describe Praxis::ResourceDefinition do
97
97
  end
98
98
 
99
99
  end
100
+
101
+ context 'with nodoc! called' do
102
+ before do
103
+ resource_definition.nodoc!
104
+ end
105
+
106
+ it 'has the :doc_visibility option set' do
107
+ expect(resource_definition.metadata[:doc_visibility]).to be(:none)
108
+ end
109
+
110
+ it 'is exposed in the describe' do
111
+ expect(resource_definition.describe[:metadata][:doc_visibility]).to be(:none)
112
+ end
113
+
114
+ end
115
+
100
116
  end
@@ -88,7 +88,7 @@ describe Praxis::Skeletor::RestfulRoutingConfig do
88
88
  let(:route_prefix) { nil }
89
89
 
90
90
  it 'call the add_route with the correct parameters' do
91
- helper_verbs = [:get, :put, :post, :delete, :head, :options, :patch ]
91
+ helper_verbs = [:get, :put, :post, :delete, :head, :options, :patch, :any]
92
92
  helper_verbs.each do |verb|
93
93
  path = "/path_for_#{verb}"
94
94
  options = {option: verb}
@@ -14,11 +14,11 @@ describe Praxis::Router do
14
14
  expect( matcher.instance_variable_get(:@version) ).to eq("n/a")
15
15
  end
16
16
  end
17
-
17
+
18
18
  context '.call' do
19
19
  let(:env){ {"HTTP_X_API_VERSION" => request_version } }
20
20
  let(:request) {Praxis::Request.new(env)}
21
-
21
+
22
22
  #let(:request){ double("request", version: request_version, env: env ) }
23
23
  context 'with matching versions' do
24
24
  let(:request_version) { "1.0" }
@@ -42,13 +42,14 @@ describe Praxis::Router do
42
42
 
43
43
  end
44
44
  end
45
+
45
46
  describe Praxis::Router::RequestRouter do
46
47
 
47
48
  let(:request) {double("request", route_params: '', path: 'path')}
48
49
  let(:callback) {double("callback")}
49
-
50
+
50
51
  subject(:request_router) {Praxis::Router::RequestRouter.new}
51
-
52
+
52
53
  context ".invoke" do
53
54
  it "update request and call request for callback" do
54
55
  allow(request).to receive(:route_params=)
@@ -91,64 +92,141 @@ describe Praxis::Router do
91
92
  end
92
93
  router.add_route(target ,route)
93
94
  end
94
-
95
+
95
96
  it "raises warning when options are specified in route" do
96
97
  expect(router.add_route(proc {'target'},route)).to eq(['path'])
97
98
  end
98
99
  end
99
100
 
100
101
  context ".call" do
101
- let(:env){ {"PATH_INFO"=>"/"} }
102
+ let(:env){ {"PATH_INFO"=>request_path_info, "REQUEST_METHOD"=>request_verb} }
103
+ let(:request_verb) { 'POST' }
104
+ let(:request_path_info) { '/' }
102
105
  let(:request_version){ nil }
103
106
  let(:request) {Praxis::Request.new(env)}
104
107
  let(:router_response){ 1 }
105
-
108
+ let(:router_response_for_post){ "POST result" }
109
+ let(:router_response_for_wildcard){ "* result" }
110
+ let(:post_target_router){ double("POST target", call: router_response_for_post) }
111
+ let(:any_target_router){ double("ANY target", call: router_response_for_wildcard) }
106
112
  before do
107
113
  env['HTTP_X_API_VERSION'] = request_version if request_version
108
114
  allow_any_instance_of(Praxis::Router::RequestRouter).
109
115
  to receive(:call).with(request).and_return(router_response)
116
+ router.add_route(double("P"),double("route1", verb: 'POST', path: '/', options: {} , version: request_version))
117
+ # Hijack the callable block in the routes (since there's no way to point back to the registered route object)
118
+ router.instance_variable_get( :@routes )['POST'] = post_target_router
119
+
110
120
  end
111
-
112
- it "calls the route with params request" do
113
- expect(router.call(request)).to eq(router_response)
121
+
122
+ context 'for routes without wildcards (a single POST route)' do
123
+
124
+ context 'and an incoming POST request' do
125
+ it "finds a match and invokes it the route" do
126
+ expect(router.call(request)).to eq(router_response_for_post)
127
+ end
128
+ end
129
+ context 'and an incoming PUT request' do
130
+ let(:request_verb) { 'PUT' }
131
+ it "does not find a route" do
132
+ response_code, _ , _ = router.call(request)
133
+ expect(response_code).to be(404)
134
+ end
135
+ end
114
136
  end
115
137
 
138
+ context 'for routes with wildcards (a POST and a * route)' do
139
+ before do
140
+ router.add_route(double("*"),double("route2", verb: 'ANY', path: '/*', options: {} , version: request_version))
141
+ # Hijack the callable block in the routes (since there's no way to point back to the registered route object)
142
+ router.instance_variable_get( :@routes )['ANY'] = any_target_router
143
+ end
144
+
145
+ context 'and an incoming PUT request' do
146
+ let(:request_verb) { 'PUT' }
147
+ it "it can successfully find a match using the wildcard target" do
148
+ expect(router.call(request)).to eq(router_response_for_wildcard)
149
+ end
150
+ end
151
+ context 'and an incoming POST request' do
152
+ it 'matches the most specific POST route, rather than the wildcard'do
153
+ expect(router.call(request)).to eq(router_response_for_post)
154
+ end
155
+ end
156
+ context 'and an incoming POST request (but that does not match other route conditions)' do
157
+ let(:router_response_for_post){ :not_found }
158
+ it 'still matches wildcard verb if that was route conditions-compatible' do
159
+ expect(post_target_router).to receive(:call).once # try the match cause it's a POST
160
+ expect(any_target_router).to receive(:call).once # fallback to wildcard upon a not_found
161
+ expect(router.call(request)).to eq(router_response_for_wildcard)
162
+ end
163
+ end
164
+ end
165
+
116
166
  context "when not_found is returned" do
167
+ let(:request_verb) { 'DELETE' }
117
168
  let(:router_response){ :not_found }
118
- before{ request.instance_variable_set(:@unmatched_versions, unmatched_versions) }
119
169
 
120
- context "having passed no version in the request" do
121
-
122
- context 'and no controllers matching the path' do
123
- let(:unmatched_versions){ Set.new([]) }
124
- it 'returns a basic "NotFound" response: 404 status, text/plain content and "NotFound" body' do
125
- expect( router.call(request) ).to eq([404, {"Content-Type" => "text/plain", }, ["NotFound"]])
126
- end
170
+
171
+ it 'sets X-Cascade: pass by default' do
172
+ _, headers, _ = router.call(request)
173
+ expect(headers).to have_key('X-Cascade')
174
+ expect(headers['X-Cascade']).to eq('pass')
175
+ end
176
+
177
+ context 'with X-Cascade disabled' do
178
+ let(:config) { Praxis::Application.instance.config.praxis }
179
+ before do
180
+ expect(config).to receive(:x_cascade).and_return(false)
127
181
  end
128
-
129
- context 'and some controllers matching the path' do
130
- let(:unmatched_versions){ Set.new(["1.0"]) }
131
- it 'returns a specific body response noting which request versions would matched if passed in' do
132
- _, _, body = router.call(request)
133
- expect( body.first ).to eq('NotFound. Your request did not specify an API version. Available versions = "1.0".')
134
- end
182
+
183
+ it 'does not set X-Cascade: pass' do
184
+ _, headers, _ = router.call(request)
185
+ expect(headers).to_not have_key("X-Cascade")
135
186
  end
187
+
136
188
  end
137
-
138
- context "having passed a version in the request" do
139
-
140
- context 'but having no controllers matching the path part' do
141
- let(:request_version){ "50.0" }
142
- let(:unmatched_versions){ Set.new(["1.0","2.0"]) }
143
-
144
- it 'returns a specific body response noting that the version might be wrong (and which could be right)' do
145
- code, headers, body = router.call(request)
146
- expect(code).to eq(404)
147
- expect(headers['Content-Type']).to eq('text/plain')
148
- expect(body.first).to eq("NotFound. Your request speficied API version = \"#{request_version}\". Available versions = \"1.0\", \"2.0\".")
189
+
190
+ context 'with versioning' do
191
+ before do
192
+ request.instance_variable_set(:@unmatched_versions, unmatched_versions)
193
+ end
194
+
195
+ context "having passed no version in the request" do
196
+ context 'and no controllers matching the path' do
197
+ let(:unmatched_versions) { Set.new([]) }
198
+
199
+ it 'returns a basic "NotFound" response: 404 status, text/plain content and "NotFound" body' do
200
+ expect( router.call(request) ).to eq([404, {"Content-Type" => "text/plain","X-Cascade"=>"pass"}, ["NotFound"]])
201
+ end
202
+ end
203
+
204
+ context 'and some controllers matching the path' do
205
+ let(:unmatched_versions) { Set.new(["1.0"]) }
206
+ it 'returns a specific body response noting which request versions would matched if passed in' do
207
+ _, _, body = router.call(request)
208
+ expect( body.first ).to eq('NotFound. Your request did not specify an API version. Available versions = "1.0".')
209
+ end
210
+ end
211
+ end
212
+
213
+ context "having passed a version in the request" do
214
+
215
+ context 'but having no controllers matching the path part' do
216
+ let(:request_version) { "50.0" }
217
+ let(:unmatched_versions) { Set.new(["1.0","2.0"]) }
218
+
219
+ it 'returns a specific body response noting that the version might be wrong (and which could be right)' do
220
+ code, headers, body = router.call(request)
221
+ expect(code).to eq(404)
222
+ expect(headers['Content-Type']).to eq('text/plain')
223
+ expect(body.first).to eq("NotFound. Your request speficied API version = \"#{request_version}\". Available versions = \"1.0\", \"2.0\".")
224
+ end
149
225
  end
150
226
  end
151
227
  end
228
+
229
+
152
230
  end
153
231
  end
154
232
  end
@@ -130,7 +130,7 @@ module ApiResources
130
130
 
131
131
  action :terminate do
132
132
  routing do
133
- post '/:id/terminate'
133
+ any '/:id/terminate'
134
134
  end
135
135
 
136
136
  requires_ability :terminate
@@ -3,11 +3,13 @@ class Person < Praxis::MediaType
3
3
  attribute :id, Integer
4
4
  attribute :name, String, example: /[:name:]/
5
5
  attribute :href, String, example: proc { |person| "/people/#{person.id}" }
6
+ attribute :links, Praxis::Collection.of(String)
6
7
  end
7
8
 
8
9
  view :default do
9
10
  attribute :id
10
11
  attribute :name
12
+ attribute :links
11
13
  end
12
14
 
13
15
  view :link do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: praxis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.2
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep M. Blanquer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-08-19 00:00:00.000000000 Z
12
+ date: 2015-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -53,20 +53,6 @@ dependencies:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '3'
56
- - !ruby/object:Gem::Dependency
57
- name: ruport
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - "~>"
61
- - !ruby/object:Gem::Version
62
- version: '1'
63
- type: :runtime
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - "~>"
68
- - !ruby/object:Gem::Version
69
- version: '1'
70
56
  - !ruby/object:Gem::Dependency
71
57
  name: mime
72
58
  requirement: !ruby/object:Gem::Requirement
@@ -87,42 +73,42 @@ dependencies:
87
73
  requirements:
88
74
  - - "~>"
89
75
  - !ruby/object:Gem::Version
90
- version: '3.1'
76
+ version: '3.3'
91
77
  type: :runtime
92
78
  prerelease: false
93
79
  version_requirements: !ruby/object:Gem::Requirement
94
80
  requirements:
95
81
  - - "~>"
96
82
  - !ruby/object:Gem::Version
97
- version: '3.1'
83
+ version: '3.3'
98
84
  - !ruby/object:Gem::Dependency
99
85
  name: praxis-blueprints
100
86
  requirement: !ruby/object:Gem::Requirement
101
87
  requirements:
102
88
  - - "~>"
103
89
  - !ruby/object:Gem::Version
104
- version: '1.1'
90
+ version: '1.2'
105
91
  type: :runtime
106
92
  prerelease: false
107
93
  version_requirements: !ruby/object:Gem::Requirement
108
94
  requirements:
109
95
  - - "~>"
110
96
  - !ruby/object:Gem::Version
111
- version: '1.1'
97
+ version: '1.2'
112
98
  - !ruby/object:Gem::Dependency
113
99
  name: attributor
114
100
  requirement: !ruby/object:Gem::Requirement
115
101
  requirements:
116
102
  - - "~>"
117
103
  - !ruby/object:Gem::Version
118
- version: 2.4.0
104
+ version: 2.5.0
119
105
  type: :runtime
120
106
  prerelease: false
121
107
  version_requirements: !ruby/object:Gem::Requirement
122
108
  requirements:
123
109
  - - "~>"
124
110
  - !ruby/object:Gem::Version
125
- version: 2.4.0
111
+ version: 2.5.0
126
112
  - !ruby/object:Gem::Dependency
127
113
  name: thor
128
114
  requirement: !ruby/object:Gem::Requirement