lotus-controller 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +47 -14
- data/lib/lotus/action/cookie_jar.rb +13 -1
- data/lib/lotus/action/cookies.rb +26 -2
- data/lib/lotus/action/head.rb +0 -2
- data/lib/lotus/action/mime.rb +31 -1
- data/lib/lotus/action/redirect.rb +1 -1
- data/lib/lotus/controller.rb +0 -1
- data/lib/lotus/controller/version.rb +1 -1
- metadata +2 -3
- data/lib/rack-patch.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40bc827a76215d889abc5fd33c3b102cb626732e
|
4
|
+
data.tar.gz: 3ea7a9a16a40c1e00e2861684076f1a7c543efa8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ff6ac5d43e155662c2318ba55184260d4ffdebbb6d0b6eec607d3563439bd809bf8dee089fdb342779eaa23c10d1d7bb5074ae11ead2c5c832bd64ee9506272
|
7
|
+
data.tar.gz: 8e6e4c60d239bd321aa0a1aec3aad3120fbef86dc86f33e8c50603f18013650b63ff184572379068fb2f734b7faf593586fcf0c97b9d3f5feb6d6e0167151df2
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
# Lotus::Controller
|
2
2
|
Complete, fast and testable actions for Rack
|
3
3
|
|
4
|
+
## v0.4.1 - 2015-05-15
|
5
|
+
### Fixed
|
6
|
+
- [Luca Guidi] Ensure proper automatic `Content-Type` working well with Internet Explorer.
|
7
|
+
- [Luca Guidi] Ensure `Lotus::Action#redirect_to` to return `::String` for Rack servers compatibility.
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- [Alfonso Uceda Pompa] Prevent `Content-Type` and `Content-Lenght` to be sent when status code requires no body (eg. `204`).
|
11
|
+
This is for compatibility with `Rack::Lint`, not with RFC 2016.
|
12
|
+
- [Luca Guidi] Ensure `Lotus::Action::Params#to_h` to return `::Hash`
|
13
|
+
|
4
14
|
## v0.4.0 - 2015-03-23
|
5
15
|
### Added
|
6
16
|
- [Erol Fornoles] `Action.use` now accepts a block
|
data/README.md
CHANGED
@@ -75,7 +75,7 @@ __An action is an object__. That's important because __you have the full control
|
|
75
75
|
In other words, you have the freedom to instantiate, inject dependencies and test it, both at the unit and integration level.
|
76
76
|
|
77
77
|
In the example below, the default repository is `Article`. During a unit test we can inject a stubbed version, and invoke `#call` with the params.
|
78
|
-
__We're avoiding HTTP calls__, we're
|
78
|
+
__We're avoiding HTTP calls__, we're also going to avoid hitting the database (it depends on the stubbed repository), __we're just dealing with message passing__.
|
79
79
|
Imagine how **fast** the unit test could be.
|
80
80
|
|
81
81
|
```ruby
|
@@ -99,7 +99,7 @@ action.call({ id: 23 })
|
|
99
99
|
|
100
100
|
The request params are passed as an argument to the `#call` method.
|
101
101
|
If routed with *Lotus::Router*, it extracts the relevant bits from the Rack `env` (eg the requested `:id`).
|
102
|
-
Otherwise everything passed as is: the full Rack `env` in production, and the given `Hash` for unit tests.
|
102
|
+
Otherwise everything is passed as is: the full Rack `env` in production, and the given `Hash` for unit tests.
|
103
103
|
|
104
104
|
With Lotus::Router:
|
105
105
|
|
@@ -158,6 +158,12 @@ class Signup
|
|
158
158
|
param :first_name
|
159
159
|
param :last_name
|
160
160
|
param :email
|
161
|
+
|
162
|
+
param :address do
|
163
|
+
param :line_one
|
164
|
+
param :state
|
165
|
+
param :country
|
166
|
+
end
|
161
167
|
end
|
162
168
|
|
163
169
|
def call(params)
|
@@ -168,6 +174,10 @@ class Signup
|
|
168
174
|
# Whitelist :first_name, but not :admin
|
169
175
|
puts params[:first_name] # => "Luca"
|
170
176
|
puts params[:admin] # => nil
|
177
|
+
|
178
|
+
# Whitelist nested params [:address][:line_one], not [:address][:line_two]
|
179
|
+
puts params[:address][:line_one] # => '69 Tender St'
|
180
|
+
puts params[:address][:line_two] # => nil
|
171
181
|
end
|
172
182
|
end
|
173
183
|
```
|
@@ -232,7 +242,7 @@ action = Show.new
|
|
232
242
|
action.call({}) # => [200, {}, [""]]
|
233
243
|
```
|
234
244
|
|
235
|
-
It has private accessors to explicitly set status, headers and body:
|
245
|
+
It has private accessors to explicitly set status, headers, and body:
|
236
246
|
|
237
247
|
```ruby
|
238
248
|
class Show
|
@@ -251,17 +261,17 @@ action.call({}) # => [201, { "X-Custom" => "OK" }, ["Hi!"]]
|
|
251
261
|
|
252
262
|
### Exposures
|
253
263
|
|
254
|
-
We know that actions are objects and Lotus::Action respects one of the pillars of OOP: __encapsulation__.
|
264
|
+
We know that actions are objects and `Lotus::Action` respects one of the pillars of OOP: __encapsulation__.
|
255
265
|
Other frameworks extract instance variables (`@ivar`) and make them available to the view context.
|
256
266
|
|
257
|
-
Lotus::Action's solution is the simple and powerful DSL: `expose`.
|
267
|
+
`Lotus::Action`'s solution is the simple and powerful DSL: `expose`.
|
258
268
|
It's a thin layer on top of `attr_reader`.
|
259
269
|
|
260
270
|
Using `expose` creates a getter for the given attribute, and adds it to the _exposures_.
|
261
271
|
Exposures (`#exposures`) are a set of attributes exposed to the view.
|
262
272
|
That is to say the variables necessary for rendering a view.
|
263
273
|
|
264
|
-
By default, all Lotus::
|
274
|
+
By default, all `Lotus::Action` objects expose `#params` and `#errors`.
|
265
275
|
|
266
276
|
```ruby
|
267
277
|
class Show
|
@@ -526,10 +536,34 @@ class RemoveCookies
|
|
526
536
|
end
|
527
537
|
end
|
528
538
|
|
529
|
-
action =
|
539
|
+
action = RemoveCookies.new
|
530
540
|
action.call({}) # => [200, {'Set-Cookie' => "foo=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000"}, '...']
|
531
541
|
```
|
532
542
|
|
543
|
+
Default values can be set in configuration, but overriden case by case.
|
544
|
+
|
545
|
+
```ruby
|
546
|
+
require 'lotus/controller'
|
547
|
+
require 'lotus/action/cookies'
|
548
|
+
|
549
|
+
Lotus::Controller.configure do
|
550
|
+
cookies max_age: 300 # 5 minutes
|
551
|
+
end
|
552
|
+
|
553
|
+
class SetCookies
|
554
|
+
include Lotus::Action
|
555
|
+
include Lotus::Action::Cookies
|
556
|
+
|
557
|
+
def call(params)
|
558
|
+
# ...
|
559
|
+
cookies[:foo] = { value: 'bar', max_age: 100 }
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
action = SetCookies.new
|
564
|
+
action.call({}) # => [200, {'Set-Cookie' => "foo=bar; max-age=100;"}, '...']
|
565
|
+
```
|
566
|
+
|
533
567
|
### Sessions
|
534
568
|
|
535
569
|
It has builtin support for Rack sessions:
|
@@ -722,7 +756,7 @@ action.call({ article: { title: 'Hello' }}) # => [301, {'Location' => '/articles
|
|
722
756
|
|
723
757
|
### Mime Types
|
724
758
|
|
725
|
-
Lotus::Action automatically sets the `Content-Type` header, according to the request.
|
759
|
+
`Lotus::Action` automatically sets the `Content-Type` header, according to the request.
|
726
760
|
|
727
761
|
```ruby
|
728
762
|
class Show
|
@@ -872,7 +906,7 @@ Articles::Index.new.call({})
|
|
872
906
|
### Lotus::Router integration
|
873
907
|
|
874
908
|
While Lotus::Router works great with this framework, Lotus::Controller doesn't depend on it.
|
875
|
-
You,
|
909
|
+
You, the developer, are free to choose your own routing system.
|
876
910
|
|
877
911
|
But, if you use them together, the **only constraint is that an action must support _arity 0_ in its constructor**.
|
878
912
|
The following examples are valid constructors:
|
@@ -908,9 +942,8 @@ While a Lotus application's architecture is more web oriented, this framework is
|
|
908
942
|
|
909
943
|
### Rack middleware
|
910
944
|
|
911
|
-
Rack middleware can be configured globally in `config.ru
|
912
|
-
unnecessary overhead for all
|
913
|
-
certain middleware.
|
945
|
+
Rack middleware can be configured globally in `config.ru`. However, consider that they often add
|
946
|
+
unnecessary overhead for *all* endpoints that aren't direct users of all the configured middleware.
|
914
947
|
|
915
948
|
Think about a middleware to create sessions, where only `SessionsController::Create` needs that middleware, but every other action pays the performance price for that middleware.
|
916
949
|
|
@@ -1067,8 +1100,8 @@ end
|
|
1067
1100
|
run Action
|
1068
1101
|
```
|
1069
1102
|
|
1070
|
-
Lotus::Controller heavely depends on class configuration
|
1071
|
-
in deployment environments,
|
1103
|
+
Lotus::Controller heavely depends on class configuration. To ensure immutability
|
1104
|
+
in deployment environments, use `Lotus::Controller.load!`.
|
1072
1105
|
|
1073
1106
|
## Versioning
|
1074
1107
|
|
@@ -68,11 +68,22 @@ module Lotus
|
|
68
68
|
# Associate the given value with the given key and store them
|
69
69
|
#
|
70
70
|
# @param key [Symbol] the key
|
71
|
-
# @param value [
|
71
|
+
# @param value [#to_s,Hash] value that can be serialized as a string or
|
72
|
+
# expressed as a Hash
|
73
|
+
# @option value [String] :domain - The domain
|
74
|
+
# @option value [String] :path - The path
|
75
|
+
# @option value [Integer] :max_age - Duration expressed in seconds
|
76
|
+
# @option value [Time] :expires - Expiration time
|
77
|
+
# @option value [TrueClass,FalseClass] :secure - Restrict cookie to secure
|
78
|
+
# connections
|
79
|
+
# @option value [TrueClass,FalseClass] :httponly - Restrict JavaScript
|
80
|
+
# access
|
72
81
|
#
|
73
82
|
# @return [void]
|
74
83
|
#
|
75
84
|
# @since 0.2.0
|
85
|
+
#
|
86
|
+
# @see http://en.wikipedia.org/wiki/HTTP_cookie
|
76
87
|
def []=(key, value)
|
77
88
|
@cookies[key] = value
|
78
89
|
end
|
@@ -93,6 +104,7 @@ module Lotus
|
|
93
104
|
end
|
94
105
|
@default_options.merge cookies_options
|
95
106
|
end
|
107
|
+
|
96
108
|
# Extract the cookies from the raw Rack env.
|
97
109
|
#
|
98
110
|
# This implementation is borrowed from Rack::Request#cookies.
|
data/lib/lotus/action/cookies.rb
CHANGED
@@ -14,12 +14,21 @@ module Lotus
|
|
14
14
|
|
15
15
|
# Gets the cookies from the request and expose them as an Hash
|
16
16
|
#
|
17
|
-
#
|
17
|
+
# It automatically sets options from global configuration, but it allows to
|
18
|
+
# override values case by case.
|
19
|
+
#
|
20
|
+
# For a list of options please have a look at <tt>Lotus::Controller::Configuration</tt>,
|
21
|
+
# and <tt>Lotus::Action::CookieJar</tt>.
|
22
|
+
#
|
23
|
+
# @return [Lotus::Action::CookieJar] cookies
|
18
24
|
#
|
19
25
|
# @since 0.1.0
|
20
26
|
# @api public
|
21
27
|
#
|
22
|
-
# @
|
28
|
+
# @see Lotus::Controller::Configuration#cookies
|
29
|
+
# @see Lotus::Action::CookieJar#[]=
|
30
|
+
#
|
31
|
+
# @example Basic Usage
|
23
32
|
# require 'lotus/controller'
|
24
33
|
# require 'lotus/action/cookies'
|
25
34
|
#
|
@@ -40,6 +49,21 @@ module Lotus
|
|
40
49
|
# cookies[:bax] = nil
|
41
50
|
# end
|
42
51
|
# end
|
52
|
+
#
|
53
|
+
# @example Cookies Options
|
54
|
+
# require 'lotus/controller'
|
55
|
+
# require 'lotus/action/cookies'
|
56
|
+
#
|
57
|
+
# class Show
|
58
|
+
# include Lotus::Action
|
59
|
+
# include Lotus::Action::Cookies
|
60
|
+
#
|
61
|
+
# def call(params)
|
62
|
+
# # ...
|
63
|
+
# # set a value
|
64
|
+
# cookies[:foo] = { value: 'bar', max_age: 300, path: '/dashboard' }
|
65
|
+
# end
|
66
|
+
# end
|
43
67
|
def cookies
|
44
68
|
@cookies ||= CookieJar.new(@_env.dup, headers, configuration.cookies)
|
45
69
|
end
|
data/lib/lotus/action/head.rb
CHANGED
@@ -30,11 +30,9 @@ module Lotus
|
|
30
30
|
'Allow' => true,
|
31
31
|
'Content-Encoding' => true,
|
32
32
|
'Content-Language' => true,
|
33
|
-
'Content-Length' => true,
|
34
33
|
'Content-Location' => true,
|
35
34
|
'Content-MD5' => true,
|
36
35
|
'Content-Range' => true,
|
37
|
-
'Content-Type' => true,
|
38
36
|
'Expires' => true,
|
39
37
|
'Last-Modified' => true,
|
40
38
|
'extension-header' => true
|
data/lib/lotus/action/mime.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
require 'lotus/utils'
|
1
3
|
require 'lotus/utils/kernel'
|
2
4
|
|
3
5
|
module Lotus
|
@@ -415,7 +417,7 @@ module Lotus
|
|
415
417
|
# @api private
|
416
418
|
def accepts
|
417
419
|
unless accept == DEFAULT_ACCEPT
|
418
|
-
|
420
|
+
best_q_match(accept, ::Rack::Mime::MIME_TYPES.values)
|
419
421
|
end
|
420
422
|
end
|
421
423
|
|
@@ -446,6 +448,34 @@ module Lotus
|
|
446
448
|
"#{content_type}; charset=#{charset}"
|
447
449
|
end
|
448
450
|
|
451
|
+
# Patched version of <tt>Rack::Utils.best_q_match</tt>.
|
452
|
+
#
|
453
|
+
# @since x.x.x
|
454
|
+
# @api private
|
455
|
+
#
|
456
|
+
# @see http://www.rubydoc.info/gems/rack/Rack/Utils#best_q_match-class_method
|
457
|
+
# @see https://github.com/rack/rack/pull/659
|
458
|
+
# @see https://github.com/lotus/controller/issues/59
|
459
|
+
# @see https://github.com/lotus/controller/issues/104
|
460
|
+
def best_q_match(q_value_header, available_mimes)
|
461
|
+
values = ::Rack::Utils.q_values(q_value_header)
|
462
|
+
|
463
|
+
values = values.map do |req_mime, quality|
|
464
|
+
match = available_mimes.find { |am| ::Rack::Mime.match?(am, req_mime) }
|
465
|
+
next unless match
|
466
|
+
[match, quality]
|
467
|
+
end.compact
|
468
|
+
|
469
|
+
# See https://github.com/lotus/controller/issues/59
|
470
|
+
# See https://github.com/lotus/controller/issues/104
|
471
|
+
values = values.reverse unless Lotus::Utils.jruby?
|
472
|
+
|
473
|
+
value = values.sort_by do |match, quality|
|
474
|
+
(match.split('/', 2).count('*') * -10) + quality
|
475
|
+
end.last
|
476
|
+
|
477
|
+
value.first if value
|
478
|
+
end
|
449
479
|
end
|
450
480
|
end
|
451
481
|
end
|
data/lib/lotus/controller.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lotus-controller
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-05-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -149,7 +149,6 @@ files:
|
|
149
149
|
- lib/lotus/controller/configuration.rb
|
150
150
|
- lib/lotus/controller/version.rb
|
151
151
|
- lib/lotus/http/status.rb
|
152
|
-
- lib/rack-patch.rb
|
153
152
|
- lotus-controller.gemspec
|
154
153
|
homepage: http://lotusrb.org
|
155
154
|
licenses:
|
data/lib/rack-patch.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# see https://github.com/rack/rack/pull/659
|
2
|
-
require 'rack'
|
3
|
-
require 'lotus/utils'
|
4
|
-
|
5
|
-
if Rack.release <= '1.5'
|
6
|
-
require 'rack/utils'
|
7
|
-
|
8
|
-
Rack::Utils.class_eval do
|
9
|
-
def self.best_q_match(q_value_header, available_mimes)
|
10
|
-
values = q_values(q_value_header)
|
11
|
-
|
12
|
-
values = values.map do |req_mime, quality|
|
13
|
-
match = available_mimes.find { |am| Rack::Mime.match?(am, req_mime) }
|
14
|
-
next unless match
|
15
|
-
[match, quality]
|
16
|
-
end.compact
|
17
|
-
|
18
|
-
# See https://github.com/lotus/controller/issues/59
|
19
|
-
values = values.reverse if RUBY_VERSION >= '2.2.0' || Lotus::Utils.rubinius?
|
20
|
-
|
21
|
-
value = values.sort_by do |match, quality|
|
22
|
-
(match.split('/', 2).count('*') * -10) + quality
|
23
|
-
end.last
|
24
|
-
|
25
|
-
value.first if value
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|