lotus-controller 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +127 -0
- data/{LICENSE.txt → LICENSE.md} +0 -0
- data/README.md +259 -15
- data/lib/lotus/action.rb +20 -0
- data/lib/lotus/action/callbacks.rb +20 -2
- data/lib/lotus/action/configurable.rb +48 -0
- data/lib/lotus/action/cookie_jar.rb +29 -5
- data/lib/lotus/action/exposable.rb +12 -5
- data/lib/lotus/action/mime.rb +215 -32
- data/lib/lotus/action/params.rb +21 -4
- data/lib/lotus/action/rack.rb +81 -0
- data/lib/lotus/action/redirect.rb +6 -1
- data/lib/lotus/action/session.rb +1 -0
- data/lib/lotus/action/throwable.rb +37 -36
- data/lib/lotus/controller.rb +216 -17
- data/lib/lotus/controller/configuration.rb +510 -0
- data/lib/lotus/controller/dsl.rb +6 -4
- data/lib/lotus/controller/version.rb +1 -1
- data/lib/lotus/http/status.rb +5 -62
- data/lib/rack-patch.rb +4 -2
- data/lotus-controller.gemspec +3 -3
- metadata +26 -56
- data/.gitignore +0 -10
- data/.travis.yml +0 -5
- data/.yardopts +0 -4
- data/Gemfile +0 -15
- data/Rakefile +0 -17
- data/test/action/callbacks_test.rb +0 -99
- data/test/action/params_test.rb +0 -29
- data/test/action_test.rb +0 -31
- data/test/controller_test.rb +0 -24
- data/test/cookies_test.rb +0 -36
- data/test/fixtures.rb +0 -501
- data/test/integration/mime_type_test.rb +0 -175
- data/test/integration/routing_test.rb +0 -141
- data/test/integration/sessions_test.rb +0 -63
- data/test/redirect_test.rb +0 -20
- data/test/session_test.rb +0 -19
- data/test/test_helper.rb +0 -24
- data/test/throw_test.rb +0 -93
- data/test/version_test.rb +0 -7
@@ -1,175 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'lotus/router'
|
3
|
-
|
4
|
-
MimeRoutes = Lotus::Router.new do
|
5
|
-
get '/', to: 'mimes#default'
|
6
|
-
get '/custom', to: 'mimes#custom'
|
7
|
-
get '/accept', to: 'mimes#accept'
|
8
|
-
get '/restricted', to: 'mimes#restricted'
|
9
|
-
end
|
10
|
-
|
11
|
-
class MimesController
|
12
|
-
include Lotus::Controller
|
13
|
-
|
14
|
-
action 'Default' do
|
15
|
-
def call(params)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
action 'Custom' do
|
20
|
-
def call(params)
|
21
|
-
self.content_type = 'application/xml'
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
action 'Accept' do
|
26
|
-
def call(params)
|
27
|
-
self.headers.merge!({'X-AcceptDefault' => accept?('application/octet-stream').to_s })
|
28
|
-
self.headers.merge!({'X-AcceptHtml' => accept?('text/html').to_s })
|
29
|
-
self.headers.merge!({'X-AcceptXml' => accept?('application/xml').to_s })
|
30
|
-
self.headers.merge!({'X-AcceptJson' => accept?('text/json').to_s })
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
action 'Restricted' do
|
35
|
-
accept :html, :json
|
36
|
-
|
37
|
-
def call(params)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe 'Content type' do
|
43
|
-
before do
|
44
|
-
@app = Rack::MockRequest.new(MimeRoutes)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'fallbacks to the default "Content-Type" header when the request is lacking of this information' do
|
48
|
-
response = @app.get('/')
|
49
|
-
response.headers['Content-Type'].must_equal 'application/octet-stream'
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'returns the specified "Content-Type" header' do
|
53
|
-
response = @app.get('/custom')
|
54
|
-
response.headers['Content-Type'].must_equal 'application/xml'
|
55
|
-
end
|
56
|
-
|
57
|
-
describe 'when Accept is sent' do
|
58
|
-
it 'sets "Content-Type" header according to "Accept"' do
|
59
|
-
response = @app.get('/', 'HTTP_ACCEPT' => '*/*')
|
60
|
-
response.headers['Content-Type'].must_equal 'application/octet-stream'
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'sets "Content-Type" header according to "Accept"' do
|
64
|
-
response = @app.get('/', 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
|
65
|
-
response.headers['Content-Type'].must_equal 'text/html'
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'sets "Content-Type" header according to "Accept" quality scale' do
|
69
|
-
response = @app.get('/', 'HTTP_ACCEPT' => 'application/json;q=0.6,application/xml;q=0.9,*/*;q=0.8')
|
70
|
-
response.headers['Content-Type'].must_equal 'application/xml'
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
describe 'Accept' do
|
76
|
-
before do
|
77
|
-
@app = Rack::MockRequest.new(MimeRoutes)
|
78
|
-
@response = @app.get('/accept', 'HTTP_ACCEPT' => accept)
|
79
|
-
end
|
80
|
-
|
81
|
-
describe 'when Accept is missing' do
|
82
|
-
let(:accept) { nil }
|
83
|
-
|
84
|
-
it 'accepts all' do
|
85
|
-
@response.headers['X-AcceptDefault'].must_equal 'true'
|
86
|
-
@response.headers['X-AcceptHtml'].must_equal 'true'
|
87
|
-
@response.headers['X-AcceptXml'].must_equal 'true'
|
88
|
-
@response.headers['X-AcceptJson'].must_equal 'true'
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe 'when Accept is sent' do
|
93
|
-
describe 'when "*/*"' do
|
94
|
-
let(:accept) { '*/*' }
|
95
|
-
|
96
|
-
it 'accepts all' do
|
97
|
-
@response.headers['X-AcceptDefault'].must_equal 'true'
|
98
|
-
@response.headers['X-AcceptHtml'].must_equal 'true'
|
99
|
-
@response.headers['X-AcceptXml'].must_equal 'true'
|
100
|
-
@response.headers['X-AcceptJson'].must_equal 'true'
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe 'when "text/html"' do
|
105
|
-
let(:accept) { 'text/html' }
|
106
|
-
|
107
|
-
it 'accepts selected mime types' do
|
108
|
-
@response.headers['X-AcceptDefault'].must_equal 'false'
|
109
|
-
@response.headers['X-AcceptHtml'].must_equal 'true'
|
110
|
-
@response.headers['X-AcceptXml'].must_equal 'false'
|
111
|
-
@response.headers['X-AcceptJson'].must_equal 'false'
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
describe 'when weighted' do
|
116
|
-
let(:accept) { 'text/html,application/xhtml+xml,application/xml;q=0.9' }
|
117
|
-
|
118
|
-
it 'accepts selected mime types' do
|
119
|
-
@response.headers['X-AcceptDefault'].must_equal 'false'
|
120
|
-
@response.headers['X-AcceptHtml'].must_equal 'true'
|
121
|
-
@response.headers['X-AcceptXml'].must_equal 'true'
|
122
|
-
@response.headers['X-AcceptJson'].must_equal 'false'
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
describe 'Restricted Accept' do
|
129
|
-
before do
|
130
|
-
@app = Rack::MockRequest.new(MimeRoutes)
|
131
|
-
@response = @app.get('/restricted', 'HTTP_ACCEPT' => accept)
|
132
|
-
end
|
133
|
-
|
134
|
-
describe 'when Accept is missing' do
|
135
|
-
let(:accept) { nil }
|
136
|
-
|
137
|
-
it 'returns the mime type according to the application defined policy' do
|
138
|
-
@response.status.must_equal 200
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
describe 'when Accept is sent' do
|
143
|
-
describe 'when "*/*"' do
|
144
|
-
let(:accept) { '*/*' }
|
145
|
-
|
146
|
-
it 'returns the mime type according to the application defined policy' do
|
147
|
-
@response.status.must_equal 200
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe 'when accepted' do
|
152
|
-
let(:accept) { 'text/html' }
|
153
|
-
|
154
|
-
it 'accepts selected mime types' do
|
155
|
-
@response.status.must_equal 200
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
describe 'when not accepted' do
|
160
|
-
let(:accept) { 'application/xml' }
|
161
|
-
|
162
|
-
it 'accepts selected mime types' do
|
163
|
-
@response.status.must_equal 406
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
describe 'when weighted' do
|
168
|
-
let(:accept) { 'text/html,application/xhtml+xml,application/xml;q=0.9' }
|
169
|
-
|
170
|
-
it 'accepts selected mime types' do
|
171
|
-
@response.status.must_equal 200
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
@@ -1,141 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'lotus/router'
|
3
|
-
|
4
|
-
Routes = Lotus::Router.new do
|
5
|
-
get '/', to: 'root'
|
6
|
-
get '/team', to: 'about#team'
|
7
|
-
get '/contacts', to: 'about#contacts'
|
8
|
-
|
9
|
-
resource :identity
|
10
|
-
resources :flowers
|
11
|
-
end
|
12
|
-
|
13
|
-
describe 'Lotus::Router integration' do
|
14
|
-
before do
|
15
|
-
@app = Rack::MockRequest.new(Routes)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'calls simple action' do
|
19
|
-
response = @app.get('/')
|
20
|
-
|
21
|
-
response.status.must_equal 200
|
22
|
-
response.body.must_equal '{}'
|
23
|
-
response.headers['X-Test'].must_equal 'test'
|
24
|
-
end
|
25
|
-
|
26
|
-
it "calls a controller's class action" do
|
27
|
-
response = @app.get('/team')
|
28
|
-
|
29
|
-
response.status.must_equal 200
|
30
|
-
response.body.must_equal '{}'
|
31
|
-
response.headers['X-Test'].must_equal 'test'
|
32
|
-
end
|
33
|
-
|
34
|
-
it "calls a controller's action (with DSL)" do
|
35
|
-
response = @app.get('/contacts')
|
36
|
-
|
37
|
-
response.status.must_equal 200
|
38
|
-
response.body.must_equal '{}'
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'returns a 404 for unknown path' do
|
42
|
-
response = @app.get('/unknown')
|
43
|
-
|
44
|
-
response.status.must_equal 404
|
45
|
-
end
|
46
|
-
|
47
|
-
describe 'resource' do
|
48
|
-
it 'calls GET show' do
|
49
|
-
response = @app.get('/identity')
|
50
|
-
|
51
|
-
response.status.must_equal 200
|
52
|
-
response.body.must_equal "{}"
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'calls GET new' do
|
56
|
-
response = @app.get('/identity/new')
|
57
|
-
|
58
|
-
response.status.must_equal 200
|
59
|
-
response.body.must_equal '{}'
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'calls POST create' do
|
63
|
-
response = @app.post('/identity', params: { identity: { avatar: { image: 'jodosha.png' } }})
|
64
|
-
|
65
|
-
response.status.must_equal 200
|
66
|
-
response.body.must_equal "{:identity=>{:avatar=>{:image=>\"jodosha.png\"}}}"
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'calls GET edit' do
|
70
|
-
response = @app.get('/identity/edit')
|
71
|
-
|
72
|
-
response.status.must_equal 200
|
73
|
-
response.body.must_equal "{}"
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'calls PATCH update' do
|
77
|
-
response = @app.request('PATCH', '/identity', params: { identity: { avatar: { image: 'jodosha-2x.png' } }})
|
78
|
-
|
79
|
-
response.status.must_equal 200
|
80
|
-
response.body.must_equal "{:identity=>{:avatar=>{:image=>\"jodosha-2x.png\"}}}"
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'calls DELETE destroy' do
|
84
|
-
response = @app.delete('/identity')
|
85
|
-
|
86
|
-
response.status.must_equal 200
|
87
|
-
response.body.must_equal "{}"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
describe 'resources' do
|
92
|
-
it 'calls GET index' do
|
93
|
-
response = @app.get('/flowers')
|
94
|
-
|
95
|
-
response.status.must_equal 200
|
96
|
-
response.body.must_equal '{}'
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'calls GET show' do
|
100
|
-
response = @app.get('/flowers/23')
|
101
|
-
|
102
|
-
response.status.must_equal 200
|
103
|
-
response.body.must_equal "{:id=>\"23\"}"
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'calls GET new' do
|
107
|
-
response = @app.get('/flowers/new')
|
108
|
-
|
109
|
-
response.status.must_equal 200
|
110
|
-
response.body.must_equal '{}'
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'calls POST create' do
|
114
|
-
response = @app.post('/flowers', params: { flower: { name: 'Lotus' } })
|
115
|
-
|
116
|
-
response.status.must_equal 200
|
117
|
-
response.body.must_equal "{:flower=>{:name=>\"Lotus\"}}"
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'calls GET edit' do
|
121
|
-
response = @app.get('/flowers/23/edit')
|
122
|
-
|
123
|
-
response.status.must_equal 200
|
124
|
-
response.body.must_equal "{:id=>\"23\"}"
|
125
|
-
end
|
126
|
-
|
127
|
-
it 'calls PATCH update' do
|
128
|
-
response = @app.request('PATCH', '/flowers/23', params: { flower: { name: 'Lotus!' } })
|
129
|
-
|
130
|
-
response.status.must_equal 200
|
131
|
-
response.body.must_equal "{:flower=>{:name=>\"Lotus!\"}, :id=>\"23\"}"
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'calls DELETE destroy' do
|
135
|
-
response = @app.delete('/flowers/23')
|
136
|
-
|
137
|
-
response.status.must_equal 200
|
138
|
-
response.body.must_equal "{:id=>\"23\"}"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'rack/test'
|
3
|
-
require 'lotus/router'
|
4
|
-
|
5
|
-
SessionRoutes = Lotus::Router.new do
|
6
|
-
get '/', to: 'dashboard#index'
|
7
|
-
post '/login', to: 'sessions#create'
|
8
|
-
delete '/logout', to: 'sessions#destroy'
|
9
|
-
end
|
10
|
-
|
11
|
-
SessionApplication = Rack::Builder.new do
|
12
|
-
use Rack::Session::Cookie, secret: SecureRandom.hex(16)
|
13
|
-
run SessionRoutes
|
14
|
-
end.to_app
|
15
|
-
|
16
|
-
StandaloneSessionApplication = Rack::Builder.new do
|
17
|
-
use Rack::Session::Cookie, secret: SecureRandom.hex(16)
|
18
|
-
run StandaloneSession.new
|
19
|
-
end
|
20
|
-
|
21
|
-
describe 'Sessions' do
|
22
|
-
include Rack::Test::Methods
|
23
|
-
|
24
|
-
def app
|
25
|
-
SessionApplication
|
26
|
-
end
|
27
|
-
|
28
|
-
it "denies access if user isn't loggedin" do
|
29
|
-
get '/'
|
30
|
-
last_response.status.must_equal 401
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'grant access after login' do
|
34
|
-
post '/login'
|
35
|
-
follow_redirect!
|
36
|
-
last_response.status.must_equal 200
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'logs out' do
|
40
|
-
post '/login'
|
41
|
-
follow_redirect!
|
42
|
-
last_response.status.must_equal 200
|
43
|
-
|
44
|
-
delete '/logout'
|
45
|
-
|
46
|
-
get '/'
|
47
|
-
last_response.status.must_equal 401
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
describe 'Standalone Sessions' do
|
52
|
-
include Rack::Test::Methods
|
53
|
-
|
54
|
-
def app
|
55
|
-
StandaloneSessionApplication
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'sets the session value' do
|
59
|
-
get '/'
|
60
|
-
last_response.status.must_equal 200
|
61
|
-
last_response.headers.fetch('Set-Cookie').must_match(/\Arack\.session/)
|
62
|
-
end
|
63
|
-
end
|
data/test/redirect_test.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
describe Lotus::Action do
|
4
|
-
describe 'redirect' do
|
5
|
-
it 'redirects to the given path' do
|
6
|
-
action = RedirectAction.new
|
7
|
-
response = action.call({})
|
8
|
-
|
9
|
-
response[0].must_equal(302)
|
10
|
-
response[1].must_equal({ 'Content-Type' => 'application/octet-stream', 'Location' => '/destination' })
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'redirects with custom status code' do
|
14
|
-
action = StatusRedirectAction.new
|
15
|
-
response = action.call({})
|
16
|
-
|
17
|
-
response[0].must_equal(301)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/test/session_test.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
describe Lotus::Action do
|
4
|
-
describe 'session' do
|
5
|
-
it 'captures session from Rack env' do
|
6
|
-
action = SessionAction.new
|
7
|
-
action.call({'rack.session' => session = { 'user_id' => '23' }})
|
8
|
-
|
9
|
-
action.send(:session).must_equal(session)
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'returns empty hash when it is missing' do
|
13
|
-
action = SessionAction.new
|
14
|
-
action.call({})
|
15
|
-
|
16
|
-
action.send(:session).must_equal({})
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/test/test_helper.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler/setup'
|
3
|
-
|
4
|
-
if ENV['COVERAGE'] == 'true'
|
5
|
-
require 'simplecov'
|
6
|
-
require 'coveralls'
|
7
|
-
|
8
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
9
|
-
SimpleCov::Formatter::HTMLFormatter,
|
10
|
-
Coveralls::SimpleCov::Formatter
|
11
|
-
]
|
12
|
-
|
13
|
-
SimpleCov.start do
|
14
|
-
command_name 'test'
|
15
|
-
add_filter 'test'
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
require 'minitest/autorun'
|
20
|
-
$:.unshift 'lib'
|
21
|
-
require 'lotus/controller'
|
22
|
-
require 'lotus/action/cookies'
|
23
|
-
require 'lotus/action/session'
|
24
|
-
require 'fixtures'
|