lotus-controller 0.1.0 → 0.2.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.
- 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'
|