hanami-controller 1.3.3 → 2.0.0.alpha1
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 +46 -7
- data/README.md +295 -537
- data/hanami-controller.gemspec +3 -3
- data/lib/hanami/action.rb +653 -38
- data/lib/hanami/action/base_params.rb +2 -2
- data/lib/hanami/action/cache.rb +1 -139
- data/lib/hanami/action/cache/cache_control.rb +4 -4
- data/lib/hanami/action/cache/conditional_get.rb +4 -5
- data/lib/hanami/action/cache/directives.rb +1 -1
- data/lib/hanami/action/cache/expires.rb +3 -3
- data/lib/hanami/action/cookie_jar.rb +3 -3
- data/lib/hanami/action/cookies.rb +3 -62
- data/lib/hanami/action/flash.rb +2 -2
- data/lib/hanami/action/glue.rb +5 -31
- data/lib/hanami/action/halt.rb +12 -0
- data/lib/hanami/action/mime.rb +77 -491
- data/lib/hanami/action/params.rb +3 -3
- data/lib/hanami/action/rack/file.rb +1 -1
- data/lib/hanami/action/request.rb +30 -20
- data/lib/hanami/action/response.rb +174 -0
- data/lib/hanami/action/session.rb +8 -117
- data/lib/hanami/action/validatable.rb +2 -2
- data/lib/hanami/controller.rb +0 -210
- data/lib/hanami/controller/configuration.rb +51 -506
- data/lib/hanami/controller/version.rb +1 -1
- metadata +12 -21
- data/lib/hanami/action/callable.rb +0 -92
- data/lib/hanami/action/callbacks.rb +0 -214
- data/lib/hanami/action/configurable.rb +0 -50
- data/lib/hanami/action/exposable.rb +0 -126
- data/lib/hanami/action/exposable/guard.rb +0 -104
- data/lib/hanami/action/head.rb +0 -121
- data/lib/hanami/action/rack.rb +0 -411
- data/lib/hanami/action/rack/callable.rb +0 -47
- data/lib/hanami/action/rack/errors.rb +0 -53
- data/lib/hanami/action/redirect.rb +0 -59
- data/lib/hanami/action/throwable.rb +0 -169
@@ -2,7 +2,7 @@ require 'rack/request'
|
|
2
2
|
require 'hanami/utils/hash'
|
3
3
|
|
4
4
|
module Hanami
|
5
|
-
|
5
|
+
class Action
|
6
6
|
class BaseParams
|
7
7
|
# The key that returns raw input from the Rack env
|
8
8
|
#
|
@@ -173,7 +173,7 @@ module Hanami
|
|
173
173
|
def _router_params(fallback = {})
|
174
174
|
env.fetch(ROUTER_PARAMS) do
|
175
175
|
if session = fallback.delete(RACK_SESSION) # rubocop:disable Lint/AssignmentInCondition
|
176
|
-
fallback[RACK_SESSION] = Utils::Hash.
|
176
|
+
fallback[RACK_SESSION] = Utils::Hash.deep_symbolize(session)
|
177
177
|
end
|
178
178
|
|
179
179
|
fallback
|
data/lib/hanami/action/cache.rb
CHANGED
@@ -3,7 +3,7 @@ require 'hanami/action/cache/expires'
|
|
3
3
|
require 'hanami/action/cache/conditional_get'
|
4
4
|
|
5
5
|
module Hanami
|
6
|
-
|
6
|
+
class Action
|
7
7
|
# Cache type API
|
8
8
|
#
|
9
9
|
# @since 0.3.0
|
@@ -26,144 +26,6 @@ module Hanami
|
|
26
26
|
include CacheControl, Expires
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
|
-
protected
|
31
|
-
|
32
|
-
# Specify response freshness policy for HTTP caches (Cache-Control header).
|
33
|
-
# Any number of non-value directives (:public, :private, :no_cache,
|
34
|
-
# :no_store, :must_revalidate, :proxy_revalidate) may be passed along with
|
35
|
-
# a Hash of value directives (:max_age, :min_stale, :s_max_age).
|
36
|
-
#
|
37
|
-
# See RFC 2616 / 14.9 for more on standard cache control directives:
|
38
|
-
# http://tools.ietf.org/html/rfc2616#section-14.9.1
|
39
|
-
#
|
40
|
-
# @param values [Array<Symbols, Hash>] mapped to cache_control directives
|
41
|
-
# @option values [Symbol] :public
|
42
|
-
# @option values [Symbol] :private
|
43
|
-
# @option values [Symbol] :no_cache
|
44
|
-
# @option values [Symbol] :no_store
|
45
|
-
# @option values [Symbol] :must_validate
|
46
|
-
# @option values [Symbol] :proxy_revalidate
|
47
|
-
# @option values [Hash] :max_age
|
48
|
-
# @option values [Hash] :min_stale
|
49
|
-
# @option values [Hash] :s_max_age
|
50
|
-
#
|
51
|
-
# @return void
|
52
|
-
#
|
53
|
-
# @since 0.3.0
|
54
|
-
#
|
55
|
-
# @example
|
56
|
-
# require 'hanami/controller'
|
57
|
-
# require 'hanami/action/cache'
|
58
|
-
#
|
59
|
-
# class Show
|
60
|
-
# include Hanami::Action
|
61
|
-
# include Hanami::Action::Cache
|
62
|
-
#
|
63
|
-
# def call(params)
|
64
|
-
# # ...
|
65
|
-
#
|
66
|
-
# # set Cache-Control directives
|
67
|
-
# cache_control :public, max_age: 900, s_maxage: 86400
|
68
|
-
#
|
69
|
-
# # overwrite previous Cache-Control directives
|
70
|
-
# cache_control :private, :no_cache, :no_store
|
71
|
-
#
|
72
|
-
# => Cache-Control: private, no-store, max-age=900
|
73
|
-
#
|
74
|
-
# end
|
75
|
-
# end
|
76
|
-
def cache_control(*values)
|
77
|
-
cache_control = CacheControl::Directives.new(*values)
|
78
|
-
headers.merge!(cache_control.headers)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Set the Expires header and Cache-Control/max-age directive. Amount
|
82
|
-
# can be an integer number of seconds in the future or a Time object
|
83
|
-
# indicating when the response should be considered "stale". The remaining
|
84
|
-
# "values" arguments are passed to the #cache_control helper:
|
85
|
-
#
|
86
|
-
# @param amount [Integer,Time] number of seconds or point in time
|
87
|
-
# @param values [Array<Symbols>] mapped to cache_control directives
|
88
|
-
#
|
89
|
-
# @return void
|
90
|
-
#
|
91
|
-
# @since 0.3.0
|
92
|
-
#
|
93
|
-
# @example
|
94
|
-
# require 'hanami/controller'
|
95
|
-
# require 'hanami/action/cache'
|
96
|
-
#
|
97
|
-
# class Show
|
98
|
-
# include Hanami::Action
|
99
|
-
# include Hanami::Action::Cache
|
100
|
-
#
|
101
|
-
# def call(params)
|
102
|
-
# # ...
|
103
|
-
#
|
104
|
-
# # set Cache-Control directives and Expires
|
105
|
-
# expires 900, :public
|
106
|
-
#
|
107
|
-
# # overwrite Cache-Control directives and Expires
|
108
|
-
# expires 300, :private, :no_cache, :no_store
|
109
|
-
#
|
110
|
-
# => Expires: Thu, 26 Jun 2014 12:00:00 GMT
|
111
|
-
# => Cache-Control: private, no-cache, no-store max-age=300
|
112
|
-
#
|
113
|
-
# end
|
114
|
-
# end
|
115
|
-
def expires(amount, *values)
|
116
|
-
expires = Expires::Directives.new(amount, *values)
|
117
|
-
headers.merge!(expires.headers)
|
118
|
-
end
|
119
|
-
|
120
|
-
# Set the etag, last_modified, or both headers on the response
|
121
|
-
# and halts a 304 Not Modified if the request is still fresh
|
122
|
-
# respecting IfNoneMatch and IfModifiedSince request headers
|
123
|
-
#
|
124
|
-
# @param options [Hash]
|
125
|
-
# @option options [Integer] :etag for testing IfNoneMatch conditions
|
126
|
-
# @option options [Date] :last_modified for testing IfModifiedSince conditions
|
127
|
-
#
|
128
|
-
# @return void
|
129
|
-
#
|
130
|
-
# @since 0.3.0
|
131
|
-
#
|
132
|
-
# @example
|
133
|
-
# require 'hanami/controller'
|
134
|
-
# require 'hanami/action/cache'
|
135
|
-
#
|
136
|
-
# class Show
|
137
|
-
# include Hanami::Action
|
138
|
-
# include Hanami::Action::Cache
|
139
|
-
#
|
140
|
-
# def call(params)
|
141
|
-
# # ...
|
142
|
-
#
|
143
|
-
# # set etag response header and halt 304
|
144
|
-
# # if request matches IF_NONE_MATCH header
|
145
|
-
# fresh etag: @resource.updated_at.to_i
|
146
|
-
#
|
147
|
-
# # set last_modified response header and halt 304
|
148
|
-
# # if request matches IF_MODIFIED_SINCE
|
149
|
-
# fresh last_modified: @resource.updated_at
|
150
|
-
#
|
151
|
-
# # set etag and last_modified response header,
|
152
|
-
# # halt 304 if request matches IF_MODIFIED_SINCE
|
153
|
-
# # and IF_NONE_MATCH
|
154
|
-
# fresh last_modified: @resource.updated_at
|
155
|
-
#
|
156
|
-
# end
|
157
|
-
# end
|
158
|
-
def fresh(options)
|
159
|
-
conditional_get = ConditionalGet.new(@_env, options)
|
160
|
-
|
161
|
-
headers.merge!(conditional_get.headers)
|
162
|
-
|
163
|
-
conditional_get.fresh? do
|
164
|
-
halt 304
|
165
|
-
end
|
166
|
-
end
|
167
29
|
end
|
168
30
|
end
|
169
31
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'hanami/action/cache/directives'
|
2
2
|
|
3
3
|
module Hanami
|
4
|
-
|
4
|
+
class Action
|
5
5
|
module Cache
|
6
6
|
# Module with Cache-Control logic
|
7
7
|
#
|
@@ -37,7 +37,7 @@ module Hanami
|
|
37
37
|
def cache_control_directives
|
38
38
|
@cache_control_directives || Object.new.tap do |null_object|
|
39
39
|
def null_object.headers
|
40
|
-
Hash.new
|
40
|
+
::Hash.new
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -49,9 +49,9 @@ module Hanami
|
|
49
49
|
# @api private
|
50
50
|
#
|
51
51
|
# @see Hanami::Action#finish
|
52
|
-
def finish
|
52
|
+
def finish(_, res, _)
|
53
|
+
res.headers.merge!(self.class.cache_control_directives.headers) unless res.headers.include? HEADER
|
53
54
|
super
|
54
|
-
headers.merge!(self.class.cache_control_directives.headers) unless headers.include? HEADER
|
55
55
|
end
|
56
56
|
|
57
57
|
# Class which stores CacheControl values
|
@@ -1,5 +1,7 @@
|
|
1
|
+
require "hanami/utils/blank"
|
2
|
+
|
1
3
|
module Hanami
|
2
|
-
|
4
|
+
class Action
|
3
5
|
module Cache
|
4
6
|
# @since 0.3.0
|
5
7
|
# @api private
|
@@ -67,10 +69,7 @@ module Hanami
|
|
67
69
|
# @since 0.3.0
|
68
70
|
# @api private
|
69
71
|
def fresh?
|
70
|
-
|
71
|
-
return false if Hanami::Utils::Blank.blank?(@value)
|
72
|
-
|
73
|
-
Time.httpdate(modified_since).to_i >= @value.to_time.to_i
|
72
|
+
!Hanami::Utils::Blank.blank?(modified_since) && Time.httpdate(modified_since).to_i >= @value.to_time.to_i
|
74
73
|
end
|
75
74
|
|
76
75
|
# @since 0.3.0
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'hanami/action/cache/cache_control'
|
2
2
|
|
3
3
|
module Hanami
|
4
|
-
|
4
|
+
class Action
|
5
5
|
module Cache
|
6
6
|
# Module with Expires logic
|
7
7
|
#
|
@@ -49,9 +49,9 @@ module Hanami
|
|
49
49
|
# @api private
|
50
50
|
#
|
51
51
|
# @see Hanami::Action#finish
|
52
|
-
def finish
|
52
|
+
def finish(_, res, _)
|
53
|
+
res.headers.merge!(self.class.expires_directives.headers) unless res.headers.include? HEADER
|
53
54
|
super
|
54
|
-
headers.merge!(self.class.expires_directives.headers) unless headers.include? HEADER
|
55
55
|
end
|
56
56
|
|
57
57
|
# Class which stores Expires directives
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'hanami/utils/hash'
|
2
2
|
|
3
3
|
module Hanami
|
4
|
-
|
4
|
+
class Action
|
5
5
|
# A set of HTTP Cookies
|
6
6
|
#
|
7
7
|
# It acts as an Hash
|
@@ -55,7 +55,7 @@ module Hanami
|
|
55
55
|
# @since 0.1.0
|
56
56
|
def initialize(env, headers, default_options)
|
57
57
|
@_headers = headers
|
58
|
-
@cookies = Utils::Hash.
|
58
|
+
@cookies = Utils::Hash.deep_symbolize(extract(env))
|
59
59
|
@default_options = default_options
|
60
60
|
end
|
61
61
|
|
@@ -166,7 +166,7 @@ module Hanami
|
|
166
166
|
# @since 0.4.0
|
167
167
|
# @api private
|
168
168
|
def _merge_default_values(value)
|
169
|
-
cookies_options = if value.is_a?
|
169
|
+
cookies_options = if value.is_a?(::Hash)
|
170
170
|
value.merge! _add_expires_option(value)
|
171
171
|
else
|
172
172
|
{ value: value }
|
@@ -1,7 +1,5 @@
|
|
1
|
-
require 'hanami/action/cookie_jar'
|
2
|
-
|
3
1
|
module Hanami
|
4
|
-
|
2
|
+
class Action
|
5
3
|
# Cookies API
|
6
4
|
#
|
7
5
|
# This module isn't included by default.
|
@@ -10,63 +8,6 @@ module Hanami
|
|
10
8
|
#
|
11
9
|
# @see Hanami::Action::Cookies#cookies
|
12
10
|
module Cookies
|
13
|
-
protected
|
14
|
-
|
15
|
-
# Gets the cookies from the request and expose them as an Hash
|
16
|
-
#
|
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>Hanami::Controller::Configuration</tt>,
|
21
|
-
# and <tt>Hanami::Action::CookieJar</tt>.
|
22
|
-
#
|
23
|
-
# @return [Hanami::Action::CookieJar] cookies
|
24
|
-
#
|
25
|
-
# @since 0.1.0
|
26
|
-
#
|
27
|
-
# @see Hanami::Controller::Configuration#cookies
|
28
|
-
# @see Hanami::Action::CookieJar#[]=
|
29
|
-
#
|
30
|
-
# @example Basic Usage
|
31
|
-
# require 'hanami/controller'
|
32
|
-
# require 'hanami/action/cookies'
|
33
|
-
#
|
34
|
-
# class Show
|
35
|
-
# include Hanami::Action
|
36
|
-
# include Hanami::Action::Cookies
|
37
|
-
#
|
38
|
-
# def call(params)
|
39
|
-
# # ...
|
40
|
-
#
|
41
|
-
# # get a value
|
42
|
-
# cookies[:user_id] # => '23'
|
43
|
-
#
|
44
|
-
# # set a value
|
45
|
-
# cookies[:foo] = 'bar'
|
46
|
-
#
|
47
|
-
# # remove a value
|
48
|
-
# cookies[:bax] = nil
|
49
|
-
# end
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# @example Cookies Options
|
53
|
-
# require 'hanami/controller'
|
54
|
-
# require 'hanami/action/cookies'
|
55
|
-
#
|
56
|
-
# class Show
|
57
|
-
# include Hanami::Action
|
58
|
-
# include Hanami::Action::Cookies
|
59
|
-
#
|
60
|
-
# def call(params)
|
61
|
-
# # ...
|
62
|
-
# # set a value
|
63
|
-
# cookies[:foo] = { value: 'bar', max_age: 300, path: '/dashboard' }
|
64
|
-
# end
|
65
|
-
# end
|
66
|
-
def cookies
|
67
|
-
@cookies ||= CookieJar.new(@_env.dup, headers, configuration.cookies)
|
68
|
-
end
|
69
|
-
|
70
11
|
private
|
71
12
|
|
72
13
|
# Finalize the response by flushing cookies into the response
|
@@ -75,9 +16,9 @@ module Hanami
|
|
75
16
|
# @api private
|
76
17
|
#
|
77
18
|
# @see Hanami::Action#finish
|
78
|
-
def finish
|
19
|
+
def finish(req, res, *)
|
20
|
+
res.cookies.finish
|
79
21
|
super
|
80
|
-
cookies.finish
|
81
22
|
end
|
82
23
|
end
|
83
24
|
end
|
data/lib/hanami/action/flash.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'hanami/utils/json'
|
2
2
|
|
3
3
|
module Hanami
|
4
|
-
|
4
|
+
class Action
|
5
5
|
# Container useful to transport data with the HTTP session
|
6
6
|
# It has a life span of one HTTP request or redirect.
|
7
7
|
#
|
@@ -263,7 +263,7 @@ module Hanami
|
|
263
263
|
# @since 1.3.0
|
264
264
|
# @api private
|
265
265
|
def is_hash?(data)
|
266
|
-
data && data.is_a?(Hash)
|
266
|
+
data && data.is_a?(::Hash)
|
267
267
|
end
|
268
268
|
end
|
269
269
|
end
|
data/lib/hanami/action/glue.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Hanami
|
2
|
-
|
2
|
+
class Action
|
3
3
|
# Glue code for full stack Hanami applications
|
4
4
|
#
|
5
5
|
# This includes missing rendering logic that it makes sense to include
|
@@ -14,43 +14,17 @@ module Hanami
|
|
14
14
|
# @since 0.3.0
|
15
15
|
ENV_KEY = 'hanami.action'.freeze
|
16
16
|
|
17
|
-
# @api private
|
18
|
-
# @since 0.3.2
|
19
|
-
ADDITIONAL_HTTP_STATUSES_WITHOUT_BODY = Set.new([301, 302]).freeze
|
20
|
-
|
21
|
-
# Override Ruby's Module#included
|
22
|
-
#
|
23
|
-
# @api private
|
24
|
-
# @since 0.3.0
|
25
|
-
def self.included(base)
|
26
|
-
base.class_eval { _expose(:format) if respond_to?(:_expose) }
|
27
|
-
end
|
28
|
-
|
29
|
-
# Check if the current HTTP request is renderable.
|
30
|
-
#
|
31
|
-
# It verifies if the verb isn't HEAD, if the status demands to omit
|
32
|
-
# the body and if it isn't sending a file.
|
33
|
-
#
|
34
|
-
# @return [TrueClass,FalseClass] the result of the check
|
35
|
-
#
|
36
|
-
# @api private
|
37
|
-
# @since 0.3.2
|
38
|
-
def renderable?
|
39
|
-
!_requires_no_body? &&
|
40
|
-
!sending_file? &&
|
41
|
-
!ADDITIONAL_HTTP_STATUSES_WITHOUT_BODY.include?(@_status)
|
42
|
-
end
|
43
|
-
|
44
17
|
protected
|
18
|
+
|
45
19
|
# Put the current instance into the Rack environment
|
46
20
|
#
|
47
21
|
# @api private
|
48
22
|
# @since 0.3.0
|
49
23
|
#
|
50
24
|
# @see Hanami::Action#finish
|
51
|
-
def finish
|
25
|
+
def finish(req, *)
|
26
|
+
req.env[ENV_KEY] = self
|
52
27
|
super
|
53
|
-
@_env[ENV_KEY] = self
|
54
28
|
end
|
55
29
|
|
56
30
|
# Check if the request's body is a file
|
@@ -59,7 +33,7 @@ module Hanami
|
|
59
33
|
#
|
60
34
|
# @since 0.4.3
|
61
35
|
def sending_file?
|
62
|
-
|
36
|
+
response.body.is_a?(::Rack::File::Iterator)
|
63
37
|
end
|
64
38
|
end
|
65
39
|
end
|