praxis 0.15.0 → 0.16.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.
@@ -9,7 +9,7 @@ describe Praxis::ResourceDefinition do
9
9
  its(:version) { should eq('1.0') }
10
10
  its(:version_options) { should eq({using: [:header,:params]}) }
11
11
 
12
- its(:routing_config) { should be_kind_of(Proc) }
12
+ its(:prefix) { should eq('/people') }
13
13
 
14
14
  its(:actions) { should have(2).items }
15
15
  its(:metadata) { should_not have_key(:doc_visibility) }
@@ -22,6 +22,7 @@ describe Praxis::ResourceDefinition do
22
22
 
23
23
  its([:actions]) { should have(2).items }
24
24
  its([:metadata]) { should be_kind_of(Hash) }
25
+ its([:traits]) { should eq [:test] }
25
26
  end
26
27
 
27
28
  context '.action' do
@@ -34,7 +35,7 @@ describe Praxis::ResourceDefinition do
34
35
  expect(index).to be_kind_of(Praxis::ActionDefinition)
35
36
  expect(index.description).to eq("index description")
36
37
  end
37
-
38
+
38
39
  it 'complains if action names are not symbols' do
39
40
  expect do
40
41
  Class.new do
@@ -46,7 +47,43 @@ describe Praxis::ResourceDefinition do
46
47
  end
47
48
  end
48
49
 
50
+ context 'action_defaults' do
51
+ let(:resource_definition) do
52
+ Class.new do
53
+ include Praxis::ResourceDefinition
54
+ media_type Person
55
+
56
+ def self.name
57
+ 'FooBar'
58
+ end
49
59
 
60
+ action_defaults do
61
+ routing do
62
+ prefix '/people/:id'
63
+ end
64
+
65
+ params do
66
+ attribute :id
67
+ end
68
+ end
69
+
70
+ action :show do
71
+ routing do
72
+ get ''
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+
79
+ it 'are applied to actions' do
80
+ action = resource_definition.actions[:show]
81
+ expect(action.params.attributes).to have_key(:id)
82
+ expect(action.routes.first.path.to_s).to eq '/people/:id'
83
+ end
84
+
85
+ end
86
+
50
87
  context 'setting other values' do
51
88
  subject(:resource_definition) { Class.new {include Praxis::ResourceDefinition } }
52
89
 
@@ -64,7 +101,7 @@ describe Praxis::ResourceDefinition do
64
101
  end
65
102
 
66
103
 
67
- context '.use' do
104
+ context '.trait' do
68
105
  subject(:resource_definition) { Class.new {include Praxis::ResourceDefinition } }
69
106
  it 'raises an error for missing traits' do
70
107
  expect { resource_definition.use(:stuff) }.to raise_error(Praxis::Exceptions::InvalidTrait)
@@ -81,9 +118,10 @@ describe Praxis::ResourceDefinition do
81
118
  def self.name
82
119
  'FooBar'
83
120
  end
121
+
84
122
  silence_warnings do
85
123
  payload { attribute :inherited_payload, String }
86
- headers { header "Inherited-Header", String }
124
+ headers { key "Inherited-Header", String }
87
125
  params { attribute :inherited_params, String }
88
126
  response :not_found
89
127
  end
@@ -95,11 +133,7 @@ describe Praxis::ResourceDefinition do
95
133
 
96
134
  let(:action) { resource_definition.actions[:index] }
97
135
 
98
- it 'defers the values to procs in action_defaults' do
99
- expect(resource_definition.action_defaults).to have(4).items
100
- end
101
-
102
- it 'delegates defaults to the action' do
136
+ it 'are applied to the action' do
103
137
  expect(action.payload.attributes).to have_key(:inherited_payload)
104
138
  expect(action.headers.attributes).to have_key("Inherited-Header")
105
139
  expect(action.params.attributes).to have_key(:inherited_params)
@@ -110,7 +144,7 @@ describe Praxis::ResourceDefinition do
110
144
 
111
145
  context 'with nodoc! called' do
112
146
  before do
113
- resource_definition.nodoc!
147
+ resource_definition.nodoc!
114
148
  end
115
149
 
116
150
  it 'has the :doc_visibility option set' do
@@ -133,7 +167,7 @@ describe Praxis::ResourceDefinition do
133
167
  resource_definition.canonical_path :reset
134
168
  }.to raise_error(/'canonical_path' can only be defined once./)
135
169
  end
136
- end
170
+ end
137
171
  context 'if none specified' do
138
172
  subject(:resource_definition) do
139
173
  Class.new do
@@ -143,7 +177,7 @@ describe Praxis::ResourceDefinition do
143
177
  end
144
178
  end
145
179
  it 'defaults to the :show action' do
146
- expect(subject.canonical_path).to eq(subject.actions[:show])
180
+ expect(subject.canonical_path).to eq(subject.actions[:show])
147
181
  end
148
182
  end
149
183
  context 'with an undefined action' do
@@ -75,9 +75,6 @@ describe Praxis::Router do
75
75
  end
76
76
 
77
77
  context ".add_route" do
78
- before do
79
- expect(router).to receive(:warn).with("other conditions not supported yet")
80
- end
81
78
 
82
79
  let(:route){ double('route', options: [1], version: 1, verb: 'verb', path: 'path')}
83
80
  let(:target){ double('target') }
@@ -93,9 +90,6 @@ describe Praxis::Router do
93
90
  router.add_route(target ,route)
94
91
  end
95
92
 
96
- it "raises warning when options are specified in route" do
97
- expect(router.add_route(proc {'target'},route)).to eq(['path'])
98
- end
99
93
  end
100
94
 
101
95
  context ".call" do
@@ -116,34 +110,34 @@ describe Praxis::Router do
116
110
  router.add_route(double("P"),double("route1", verb: 'POST', path: '/', options: {} , version: request_version))
117
111
  # Hijack the callable block in the routes (since there's no way to point back to the registered route object)
118
112
  router.instance_variable_get( :@routes )['POST'] = post_target_router
119
-
113
+
120
114
  end
121
115
 
122
116
  context 'for routes without wildcards (a single POST route)' do
123
-
117
+
124
118
  context 'and an incoming POST request' do
125
119
  it "finds a match and invokes it the route" do
126
120
  expect(router.call(request)).to eq(router_response_for_post)
127
121
  end
128
122
  end
129
123
  context 'and an incoming PUT request' do
130
- let(:request_verb) { 'PUT' }
124
+ let(:request_verb) { 'PUT' }
131
125
  it "does not find a route" do
132
126
  response_code, _ , _ = router.call(request)
133
127
  expect(response_code).to be(404)
134
128
  end
135
129
  end
136
130
  end
137
-
131
+
138
132
  context 'for routes with wildcards (a POST and a * route)' do
139
133
  before do
140
134
  router.add_route(double("*"),double("route2", verb: 'ANY', path: '/*', options: {} , version: request_version))
141
135
  # 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
136
+ router.instance_variable_get( :@routes )['ANY'] = any_target_router
143
137
  end
144
-
138
+
145
139
  context 'and an incoming PUT request' do
146
- let(:request_verb) { 'PUT' }
140
+ let(:request_verb) { 'PUT' }
147
141
  it "it can successfully find a match using the wildcard target" do
148
142
  expect(router.call(request)).to eq(router_response_for_wildcard)
149
143
  end
@@ -164,7 +158,7 @@ describe Praxis::Router do
164
158
  end
165
159
 
166
160
  context "when not_found is returned" do
167
- let(:request_verb) { 'DELETE' }
161
+ let(:request_verb) { 'DELETE' }
168
162
  let(:router_response){ :not_found }
169
163
 
170
164
 
@@ -175,7 +169,7 @@ describe Praxis::Router do
175
169
  end
176
170
 
177
171
  context 'with X-Cascade disabled' do
178
- let(:config) { Praxis::Application.instance.config.praxis }
172
+ let(:config) { Praxis::Application.instance.config.praxis }
179
173
  before do
180
174
  expect(config).to receive(:x_cascade).and_return(false)
181
175
  end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe Praxis::RoutingConfig do
4
+
5
+ let(:resource_definition) do
6
+ Class.new do
7
+ include Praxis::ResourceDefinition
8
+ def self.name; 'MyResource'; end
9
+ end
10
+ end
11
+
12
+ let(:routing_block) { Proc.new{} }
13
+ let(:default_route_prefix) { "/" + resource_definition.name.split("::").last.underscore }
14
+
15
+ subject(:routing_config){ Praxis::RoutingConfig.new(&routing_block) }
16
+
17
+ its(:version) { should eq('n/a') }
18
+ its(:prefix ) { should eq('') }
19
+
20
+ context '#prefix' do
21
+ it 'sets the prefix' do
22
+ routing_config.prefix '/'
23
+ expect(routing_config.prefix).to eq('/')
24
+ end
25
+
26
+ it 'is additive' do
27
+ routing_config.prefix '/people/:id'
28
+ routing_config.prefix '/address'
29
+ expect(routing_config.prefix).to eq('/people/:id/address')
30
+ end
31
+
32
+ it 'strips duplicated /s' do
33
+ routing_config.prefix '/'
34
+ routing_config.prefix '/people'
35
+ expect(routing_config.prefix).to eq('/people')
36
+ end
37
+
38
+ end
39
+
40
+ context '#add_route' do
41
+ let(:path) { '/people' }
42
+ let(:options) { {} }
43
+ let(:route) { routing_config.add_route 'GET', path, **options}
44
+
45
+ it 'returns a corresponding Praxis::Route' do
46
+ expect(route).to be_kind_of(Praxis::Route)
47
+ end
48
+
49
+ it 'appends the Route to the set of routes' do
50
+ expect(routing_config.routes).to include(route)
51
+ end
52
+
53
+ context 'passing options' do
54
+ let(:options){ {name: 'alternative', except: '/special' } }
55
+
56
+ it 'uses :name to name the route' do
57
+ expect(route.name).to eq('alternative')
58
+ end
59
+
60
+ it 'does NOT pass the name option down to mustermann' do
61
+ expect(Mustermann).to receive(:new).with(path, hash_excluding({name: 'alternative'}))
62
+ expect(route.name).to eq('alternative')
63
+ end
64
+
65
+ it 'passes them through the underlying mustermann object (telling it to ignore unknown ones)' do
66
+ expect(Mustermann).to receive(:new).with(path, hash_including(ignore_unknown_options: true, except: '/special'))
67
+ expect(route.options).to eq( { except: '/special' })
68
+ end
69
+ end
70
+
71
+ context 'with prefix defined' do
72
+ before do
73
+ routing_config.prefix '/parents/:parent_id'
74
+ end
75
+
76
+ it 'includes the prefix in the route path' do
77
+ expect(route.path.to_s).to eq '/parents/:parent_id/people'
78
+ end
79
+
80
+ context 'for paths beginning with //' do
81
+ let(:path) { '//people' }
82
+ it 'does not include the prefix in the route path' do
83
+ expect(route.path.to_s).to eq '/people'
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,38 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Praxis::Trait do
4
+
5
+ subject(:trait) do
6
+ Praxis::Trait.new do
7
+ description 'my awesome trait'
8
+
9
+ routing do
10
+ prefix '/:app_name'
11
+ end
12
+
13
+ response :something
14
+ response :nothing
15
+
16
+ params do
17
+ attribute :app_name, String
18
+ attribute :order, String,
19
+ description: "Field to sort by."
20
+ end
21
+
22
+ end
23
+ end
24
+
25
+ context 'describe' do
26
+ subject(:describe) { trait.describe }
27
+
28
+ its([:description]) { should eq('my awesome trait') }
29
+
30
+ its([:responses, :something]) { should eq Hash.new }
31
+ its([:responses, :nothing]) { should eq Hash.new }
32
+
33
+ its([:params, :app_name, :type, :name]) { should eq 'String' }
34
+ its([:params, :order, :type, :name]) { should eq 'String' }
35
+ its([:routing, :prefix]) { should eq '/:app_name'}
36
+ end
37
+
38
+ end
@@ -3,7 +3,7 @@ class Instances < BaseClass
3
3
 
4
4
  implements ApiResources::Instances
5
5
  include Concerns::BasicApi
6
-
6
+
7
7
  before :validate, actions: [:index] do |controller|
8
8
  #p [:before, :validate, :params_and_headers, controller.request.action.name]
9
9
  end
@@ -32,7 +32,7 @@ class Instances < BaseClass
32
32
  blk.call
33
33
  #puts "Decorator two end"
34
34
  end
35
-
35
+
36
36
  around :action, actions: [:index] do |controller, blk|
37
37
  #puts "Decorator three (index action) start"
38
38
  blk.call
@@ -104,4 +104,8 @@ class Instances < BaseClass
104
104
  response
105
105
  end
106
106
 
107
+ def exceptional(cloud_id:, splat:)
108
+ response.headers['Content-Type'] = 'application/vnd.acme.instance'
109
+ response
110
+ end
107
111
  end
@@ -4,18 +4,16 @@ module ApiResources
4
4
 
5
5
  media_type Instance
6
6
  version '1.0'
7
-
7
+
8
8
  # :show action is the canonical path for this resource.
9
9
  # Note that the following is redundant, since :show is the default canonical path if none is defined.
10
10
  canonical_path :show
11
-
12
- routing do
13
- prefix '/clouds/:cloud_id/instances'
14
- end
15
11
 
16
- action_defaults do
17
- use :authenticated
12
+ prefix '/clouds/:cloud_id/instances'
13
+
14
+ trait :authenticated
18
15
 
16
+ action_defaults do
19
17
  requires_ability :read
20
18
 
21
19
  params do
@@ -31,7 +29,7 @@ module ApiResources
31
29
  params do
32
30
  attribute :response_content_type, String, default: 'application/vnd.acme.instance;type=collection'
33
31
  end
34
-
32
+
35
33
  headers do
36
34
  # BOTH ARE EQUIVALENT
37
35
  #key "FOO", String, required: true
@@ -130,14 +128,14 @@ module ApiResources
130
128
  routing do
131
129
  any '/:id/terminate'
132
130
  end
133
-
131
+
134
132
  requires_ability :terminate
135
133
 
136
134
  params do
137
135
  attribute :id
138
136
  end
139
137
 
140
- payload do
138
+ payload do
141
139
  attribute :when, DateTime
142
140
  end
143
141
 
@@ -175,6 +173,17 @@ module ApiResources
175
173
  response :ok
176
174
  end
177
175
 
176
+
177
+ action :exceptional do
178
+ routing do
179
+ prefix '//clouds/:cloud_id/otherinstances'
180
+ get '/_action/*', except: '*/_action/exceptional'
181
+ end
182
+ params do
183
+ attribute :splat, Attributor::Collection.of(String), required: true
184
+ end
185
+ response :ok
186
+ end
178
187
  # OTHER USAGES:
179
188
  # note: these are all hypothetical, pending, brainstorming usages.
180
189
 
@@ -5,10 +5,10 @@ module ApiResources
5
5
  media_type Volume
6
6
  version '1.0', using: :path
7
7
 
8
- action_defaults do
9
- use :authenticated
10
- end
8
+ prefix '/volumes'
11
9
 
10
+ trait :authenticated
11
+
12
12
  action :index do
13
13
  routing do
14
14
  get ''
@@ -1,5 +1,11 @@
1
1
  require_relative 'spec_media_types'
2
2
 
3
+ Praxis::ApiDefinition.define do
4
+ trait :test do
5
+ description 'testing trait'
6
+ end
7
+ end
8
+
3
9
  class PeopleResource
4
10
  include Praxis::ResourceDefinition
5
11
 
@@ -11,9 +17,9 @@ class PeopleResource
11
17
 
12
18
  canonical_path :show
13
19
 
14
- routing do
15
- prefix "/people"
16
- end
20
+ trait :test
21
+
22
+ prefix '/people'
17
23
 
18
24
  action :index do
19
25
  description 'index description'
@@ -34,6 +40,7 @@ class PeopleResource
34
40
 
35
41
  end
36
42
 
43
+
37
44
  class AddressResource
38
45
  include Praxis::ResourceDefinition
39
46
 
@@ -43,9 +50,7 @@ class AddressResource
43
50
 
44
51
  version '1.0'
45
52
 
46
- routing do
47
- prefix "/addresses"
48
- end
53
+ prefix '/addresses'
49
54
 
50
55
  action :index do
51
56
  description 'index description'