praxis 0.11.2 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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