hanami-controller 0.0.0 → 0.6.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 +155 -0
- data/LICENSE.md +22 -0
- data/README.md +1180 -9
- data/hanami-controller.gemspec +19 -12
- data/lib/hanami-controller.rb +1 -0
- data/lib/hanami/action.rb +85 -0
- data/lib/hanami/action/cache.rb +174 -0
- data/lib/hanami/action/cache/cache_control.rb +70 -0
- data/lib/hanami/action/cache/conditional_get.rb +93 -0
- data/lib/hanami/action/cache/directives.rb +99 -0
- data/lib/hanami/action/cache/expires.rb +73 -0
- data/lib/hanami/action/callable.rb +94 -0
- data/lib/hanami/action/callbacks.rb +210 -0
- data/lib/hanami/action/configurable.rb +49 -0
- data/lib/hanami/action/cookie_jar.rb +181 -0
- data/lib/hanami/action/cookies.rb +85 -0
- data/lib/hanami/action/exposable.rb +115 -0
- data/lib/hanami/action/flash.rb +182 -0
- data/lib/hanami/action/glue.rb +66 -0
- data/lib/hanami/action/head.rb +122 -0
- data/lib/hanami/action/mime.rb +493 -0
- data/lib/hanami/action/params.rb +285 -0
- data/lib/hanami/action/rack.rb +270 -0
- data/lib/hanami/action/rack/callable.rb +47 -0
- data/lib/hanami/action/rack/file.rb +33 -0
- data/lib/hanami/action/redirect.rb +59 -0
- data/lib/hanami/action/request.rb +86 -0
- data/lib/hanami/action/session.rb +154 -0
- data/lib/hanami/action/throwable.rb +194 -0
- data/lib/hanami/action/validatable.rb +128 -0
- data/lib/hanami/controller.rb +250 -2
- data/lib/hanami/controller/configuration.rb +705 -0
- data/lib/hanami/controller/error.rb +7 -0
- data/lib/hanami/controller/version.rb +4 -1
- data/lib/hanami/http/status.rb +62 -0
- metadata +124 -16
- data/.gitignore +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -2
- data/bin/console +0 -14
- data/bin/setup +0 -8
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'hanami/utils/class_attribute'
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Action
|
5
|
+
# Configuration API
|
6
|
+
#
|
7
|
+
# @since 0.2.0
|
8
|
+
#
|
9
|
+
# @see Hanami::Controller::Configuration
|
10
|
+
module Configurable
|
11
|
+
# Override Ruby's hook for modules.
|
12
|
+
# It includes configuration logic
|
13
|
+
#
|
14
|
+
# @param base [Class] the target action
|
15
|
+
#
|
16
|
+
# @since 0.2.0
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
# @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# require 'hanami/controller'
|
23
|
+
#
|
24
|
+
# class Show
|
25
|
+
# include Hanami::Action
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# Show.configuration
|
29
|
+
def self.included(base)
|
30
|
+
config = Hanami::Controller::Configuration.for(base)
|
31
|
+
|
32
|
+
base.class_eval do
|
33
|
+
include Utils::ClassAttribute
|
34
|
+
|
35
|
+
class_attribute :configuration
|
36
|
+
self.configuration = config
|
37
|
+
end
|
38
|
+
|
39
|
+
config.copy!(base)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def configuration
|
45
|
+
self.class.configuration
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'hanami/utils/hash'
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Action
|
5
|
+
# A set of HTTP Cookies
|
6
|
+
#
|
7
|
+
# It acts as an Hash
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
#
|
11
|
+
# @see Hanami::Action::Cookies#cookies
|
12
|
+
class CookieJar
|
13
|
+
# The key that returns raw cookies from the Rack env
|
14
|
+
#
|
15
|
+
# @since 0.1.0
|
16
|
+
# @api private
|
17
|
+
HTTP_HEADER = 'HTTP_COOKIE'.freeze
|
18
|
+
|
19
|
+
# The key used by Rack to set the session cookie
|
20
|
+
#
|
21
|
+
# We let CookieJar to NOT take care of this cookie, but it leaves the
|
22
|
+
# responsibility to the Rack middleware that handle sessions.
|
23
|
+
#
|
24
|
+
# This prevents <tt>Set-Cookie</tt> to be sent twice.
|
25
|
+
#
|
26
|
+
# @since 0.5.1
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
# @see https://github.com/hanami/controller/issues/138
|
30
|
+
RACK_SESSION_KEY = :'rack.session'
|
31
|
+
|
32
|
+
# The key used by Rack to set the cookies as an Hash in the env
|
33
|
+
#
|
34
|
+
# @since 0.1.0
|
35
|
+
# @api private
|
36
|
+
COOKIE_HASH_KEY = 'rack.request.cookie_hash'.freeze
|
37
|
+
|
38
|
+
# The key used by Rack to set the cookies as a String in the env
|
39
|
+
#
|
40
|
+
# @since 0.1.0
|
41
|
+
# @api private
|
42
|
+
COOKIE_STRING_KEY = 'rack.request.cookie_string'.freeze
|
43
|
+
|
44
|
+
# @since 0.4.5
|
45
|
+
# @api private
|
46
|
+
COOKIE_SEPARATOR = ';,'.freeze
|
47
|
+
|
48
|
+
# Initialize the CookieJar
|
49
|
+
#
|
50
|
+
# @param env [Hash] a raw Rack env
|
51
|
+
# @param headers [Hash] the response headers
|
52
|
+
#
|
53
|
+
# @return [CookieJar]
|
54
|
+
#
|
55
|
+
# @since 0.1.0
|
56
|
+
def initialize(env, headers, default_options)
|
57
|
+
@_headers = headers
|
58
|
+
@cookies = Utils::Hash.new(extract(env)).symbolize!
|
59
|
+
@default_options = default_options
|
60
|
+
end
|
61
|
+
|
62
|
+
# Finalize itself, by setting the proper headers to add and remove
|
63
|
+
# cookies, before the response is returned to the webserver.
|
64
|
+
#
|
65
|
+
# @return [void]
|
66
|
+
#
|
67
|
+
# @since 0.1.0
|
68
|
+
#
|
69
|
+
# @see Hanami::Action::Cookies#finish
|
70
|
+
def finish
|
71
|
+
@cookies.delete(RACK_SESSION_KEY)
|
72
|
+
@cookies.each { |k,v| v.nil? ? delete_cookie(k) : set_cookie(k, _merge_default_values(v)) }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the object associated with the given key
|
76
|
+
#
|
77
|
+
# @param key [Symbol] the key
|
78
|
+
#
|
79
|
+
# @return [Object,nil] return the associated object, if found
|
80
|
+
#
|
81
|
+
# @since 0.2.0
|
82
|
+
def [](key)
|
83
|
+
@cookies[key]
|
84
|
+
end
|
85
|
+
|
86
|
+
# Associate the given value with the given key and store them
|
87
|
+
#
|
88
|
+
# @param key [Symbol] the key
|
89
|
+
# @param value [#to_s,Hash] value that can be serialized as a string or
|
90
|
+
# expressed as a Hash
|
91
|
+
# @option value [String] :domain - The domain
|
92
|
+
# @option value [String] :path - The path
|
93
|
+
# @option value [Integer] :max_age - Duration expressed in seconds
|
94
|
+
# @option value [Time] :expires - Expiration time
|
95
|
+
# @option value [TrueClass,FalseClass] :secure - Restrict cookie to secure
|
96
|
+
# connections
|
97
|
+
# @option value [TrueClass,FalseClass] :httponly - Restrict JavaScript
|
98
|
+
# access
|
99
|
+
#
|
100
|
+
# @return [void]
|
101
|
+
#
|
102
|
+
# @since 0.2.0
|
103
|
+
#
|
104
|
+
# @see http://en.wikipedia.org/wiki/HTTP_cookie
|
105
|
+
def []=(key, value)
|
106
|
+
@cookies[key] = value
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# Merge default cookies options with values provided by user
|
112
|
+
#
|
113
|
+
# Cookies values provided by user are respected
|
114
|
+
#
|
115
|
+
# @since 0.4.0
|
116
|
+
# @api private
|
117
|
+
def _merge_default_values(value)
|
118
|
+
cookies_options = if value.is_a? Hash
|
119
|
+
value.merge! _add_expires_option(value)
|
120
|
+
else
|
121
|
+
{ value: value }
|
122
|
+
end
|
123
|
+
@default_options.merge cookies_options
|
124
|
+
end
|
125
|
+
|
126
|
+
# Add expires option to cookies if :max_age presents
|
127
|
+
#
|
128
|
+
# @since 0.4.3
|
129
|
+
# @api private
|
130
|
+
def _add_expires_option(value)
|
131
|
+
if value.has_key?(:max_age) && !value.has_key?(:expires)
|
132
|
+
{ expires: (Time.now + value[:max_age]) }
|
133
|
+
else
|
134
|
+
{}
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Extract the cookies from the raw Rack env.
|
139
|
+
#
|
140
|
+
# This implementation is borrowed from Rack::Request#cookies.
|
141
|
+
#
|
142
|
+
# @since 0.1.0
|
143
|
+
# @api private
|
144
|
+
def extract(env)
|
145
|
+
hash = env[COOKIE_HASH_KEY] ||= {}
|
146
|
+
string = env[HTTP_HEADER]
|
147
|
+
|
148
|
+
return hash if string == env[COOKIE_STRING_KEY]
|
149
|
+
# TODO Next Rack 1.7.x ?? version will have ::Rack::Utils.parse_cookies
|
150
|
+
# We can then replace the following lines.
|
151
|
+
hash.clear
|
152
|
+
|
153
|
+
# According to RFC 2109:
|
154
|
+
# If multiple cookies satisfy the criteria above, they are ordered in
|
155
|
+
# the Cookie header such that those with more specific Path attributes
|
156
|
+
# precede those with less specific. Ordering with respect to other
|
157
|
+
# attributes (e.g., Domain) is unspecified.
|
158
|
+
cookies = ::Rack::Utils.parse_query(string, COOKIE_SEPARATOR) { |s| ::Rack::Utils.unescape(s) rescue s }
|
159
|
+
cookies.each { |k,v| hash[k] = Array === v ? v.first : v }
|
160
|
+
env[COOKIE_STRING_KEY] = string
|
161
|
+
hash
|
162
|
+
end
|
163
|
+
|
164
|
+
# Set a cookie in the headers
|
165
|
+
#
|
166
|
+
# @since 0.1.0
|
167
|
+
# @api private
|
168
|
+
def set_cookie(key, value)
|
169
|
+
::Rack::Utils.set_cookie_header!(@_headers, key, value)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Remove a cookie from the headers
|
173
|
+
#
|
174
|
+
# @since 0.1.0
|
175
|
+
# @api private
|
176
|
+
def delete_cookie(key)
|
177
|
+
::Rack::Utils.delete_cookie_header!(@_headers, key, {})
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'hanami/action/cookie_jar'
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Action
|
5
|
+
# Cookies API
|
6
|
+
#
|
7
|
+
# This module isn't included by default.
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
#
|
11
|
+
# @see Hanami::Action::Cookies#cookies
|
12
|
+
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
|
+
# @api public
|
27
|
+
#
|
28
|
+
# @see Hanami::Controller::Configuration#cookies
|
29
|
+
# @see Hanami::Action::CookieJar#[]=
|
30
|
+
#
|
31
|
+
# @example Basic Usage
|
32
|
+
# require 'hanami/controller'
|
33
|
+
# require 'hanami/action/cookies'
|
34
|
+
#
|
35
|
+
# class Show
|
36
|
+
# include Hanami::Action
|
37
|
+
# include Hanami::Action::Cookies
|
38
|
+
#
|
39
|
+
# def call(params)
|
40
|
+
# # ...
|
41
|
+
#
|
42
|
+
# # get a value
|
43
|
+
# cookies[:user_id] # => '23'
|
44
|
+
#
|
45
|
+
# # set a value
|
46
|
+
# cookies[:foo] = 'bar'
|
47
|
+
#
|
48
|
+
# # remove a value
|
49
|
+
# cookies[:bax] = nil
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# @example Cookies Options
|
54
|
+
# require 'hanami/controller'
|
55
|
+
# require 'hanami/action/cookies'
|
56
|
+
#
|
57
|
+
# class Show
|
58
|
+
# include Hanami::Action
|
59
|
+
# include Hanami::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
|
67
|
+
def cookies
|
68
|
+
@cookies ||= CookieJar.new(@_env.dup, headers, configuration.cookies)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Finalize the response by flushing cookies into the response
|
74
|
+
#
|
75
|
+
# @since 0.1.0
|
76
|
+
# @api private
|
77
|
+
#
|
78
|
+
# @see Hanami::Action#finish
|
79
|
+
def finish
|
80
|
+
super
|
81
|
+
cookies.finish
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Hanami
|
2
|
+
module Action
|
3
|
+
# Exposures API
|
4
|
+
#
|
5
|
+
# @since 0.1.0
|
6
|
+
#
|
7
|
+
# @see Hanami::Action::Exposable::ClassMethods#expose
|
8
|
+
module Exposable
|
9
|
+
# Override Ruby's hook for modules.
|
10
|
+
# It includes exposures logic
|
11
|
+
#
|
12
|
+
# @param base [Class] the target action
|
13
|
+
#
|
14
|
+
# @since 0.1.0
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
# @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
|
18
|
+
def self.included(base)
|
19
|
+
base.extend ClassMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
# Exposures API class methods
|
23
|
+
#
|
24
|
+
# @since 0.1.0
|
25
|
+
# @api private
|
26
|
+
module ClassMethods
|
27
|
+
# Expose the given attributes on the outside of the object with
|
28
|
+
# a getter and a special method called #exposures.
|
29
|
+
#
|
30
|
+
# @param names [Array<Symbol>] the name(s) of the attribute(s) to be
|
31
|
+
# exposed
|
32
|
+
#
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @since 0.1.0
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# require 'hanami/controller'
|
39
|
+
#
|
40
|
+
# class Show
|
41
|
+
# include Hanami::Action
|
42
|
+
#
|
43
|
+
# expose :article, :tags
|
44
|
+
#
|
45
|
+
# def call(params)
|
46
|
+
# @article = Article.find params[:id]
|
47
|
+
# @tags = Tag.for(article)
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# action = Show.new
|
52
|
+
# action.call({id: 23})
|
53
|
+
#
|
54
|
+
# action.article # => #<Article ...>
|
55
|
+
# action.tags # => [#<Tag ...>, #<Tag ...>]
|
56
|
+
#
|
57
|
+
# action.exposures # => { :article => #<Article ...>, :tags => [ ... ] }
|
58
|
+
def expose(*names)
|
59
|
+
class_eval do
|
60
|
+
names.each do |name|
|
61
|
+
attr_reader(name) unless attr_reader?(name)
|
62
|
+
end
|
63
|
+
|
64
|
+
exposures.push(*names)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Set of exposures attribute names
|
69
|
+
#
|
70
|
+
# @return [Array] the exposures attribute names
|
71
|
+
#
|
72
|
+
# @since 0.1.0
|
73
|
+
# @api private
|
74
|
+
def exposures
|
75
|
+
@exposures ||= []
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
# Check if the attr_reader is already defined
|
80
|
+
#
|
81
|
+
# @since 0.3.0
|
82
|
+
# @api private
|
83
|
+
def attr_reader?(name)
|
84
|
+
(instance_methods | private_instance_methods).include?(name)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Set of exposures
|
89
|
+
#
|
90
|
+
# @return [Hash] the exposures
|
91
|
+
#
|
92
|
+
# @since 0.1.0
|
93
|
+
#
|
94
|
+
# @see Hanami::Action::Exposable::ClassMethods.expose
|
95
|
+
def exposures
|
96
|
+
@exposures ||= {}.tap do |result|
|
97
|
+
self.class.exposures.each do |name|
|
98
|
+
result[name] = send(name)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Finalize the response
|
104
|
+
#
|
105
|
+
# @since 0.3.0
|
106
|
+
# @api private
|
107
|
+
#
|
108
|
+
# @see Hanami::Action#finish
|
109
|
+
def finish
|
110
|
+
super
|
111
|
+
exposures
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module Hanami
|
2
|
+
module Action
|
3
|
+
# Container useful to transport data with the HTTP session
|
4
|
+
# It has a life span of one HTTP request or redirect.
|
5
|
+
#
|
6
|
+
# @since 0.3.0
|
7
|
+
# @api private
|
8
|
+
class Flash
|
9
|
+
# Session key where the data is stored
|
10
|
+
#
|
11
|
+
# @since 0.3.0
|
12
|
+
# @api private
|
13
|
+
SESSION_KEY = :__flash
|
14
|
+
|
15
|
+
# Session key where the last request_id is stored
|
16
|
+
#
|
17
|
+
# @since 0.4.0
|
18
|
+
# @api private
|
19
|
+
LAST_REQUEST_KEY = :__last_request_id
|
20
|
+
|
21
|
+
# Initialize a new Flash instance
|
22
|
+
#
|
23
|
+
# @param session [Rack::Session::Abstract::SessionHash] the session
|
24
|
+
# @param request_id [String] the HTTP Request ID
|
25
|
+
#
|
26
|
+
# @return [Hanami::Action::Flash] the flash
|
27
|
+
#
|
28
|
+
# @see http://www.rubydoc.info/gems/rack/Rack/Session/Abstract/SessionHash
|
29
|
+
# @see Hanami::Action::Rack#session_id
|
30
|
+
def initialize(session, request_id)
|
31
|
+
@session = session
|
32
|
+
@request_id = request_id
|
33
|
+
@last_request_id = session[LAST_REQUEST_KEY]
|
34
|
+
|
35
|
+
session[SESSION_KEY] ||= {}
|
36
|
+
session[SESSION_KEY][request_id] ||= {}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set the given value for the given key
|
40
|
+
#
|
41
|
+
# @param key [#to_s] the key
|
42
|
+
# @param value [Object] the value
|
43
|
+
#
|
44
|
+
# @since 0.3.0
|
45
|
+
# @api private
|
46
|
+
def []=(key, value)
|
47
|
+
data[key] = value
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get the value associated to the given key, if any
|
51
|
+
#
|
52
|
+
# @return [Object,NilClass] the value
|
53
|
+
#
|
54
|
+
# @since 0.3.0
|
55
|
+
# @api private
|
56
|
+
def [](key)
|
57
|
+
last_request_flash.merge(data).fetch(key) do
|
58
|
+
_values.find {|data| !data[key].nil? }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Removes entirely the flash from the session if it has stale contents
|
63
|
+
# or if empty.
|
64
|
+
#
|
65
|
+
# @return [void]
|
66
|
+
#
|
67
|
+
# @since 0.3.0
|
68
|
+
# @api private
|
69
|
+
def clear
|
70
|
+
# FIXME we're just before a release and I can't find a proper way to reproduce
|
71
|
+
# this bug that I've found via a browser.
|
72
|
+
#
|
73
|
+
# It may happen that `#flash` is nil, and those two methods will fail
|
74
|
+
unless flash.nil?
|
75
|
+
expire_stale!
|
76
|
+
set_last_request_id!
|
77
|
+
remove!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Check if there are contents stored in the flash from the current or the
|
82
|
+
# previous request.
|
83
|
+
#
|
84
|
+
# @return [TrueClass,FalseClass] the result of the check
|
85
|
+
#
|
86
|
+
# @since 0.3.0
|
87
|
+
# @api private
|
88
|
+
def empty?
|
89
|
+
_values.all?(&:empty?)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# The flash registry that holds the data for **all** the recent requests
|
95
|
+
#
|
96
|
+
# @return [Hash] the flash
|
97
|
+
#
|
98
|
+
# @since 0.3.0
|
99
|
+
# @api private
|
100
|
+
def flash
|
101
|
+
@session[SESSION_KEY] || {}
|
102
|
+
end
|
103
|
+
|
104
|
+
# The flash registry that holds the data **only for** the current request
|
105
|
+
#
|
106
|
+
# @return [Hash] the flash for the current request
|
107
|
+
#
|
108
|
+
# @since 0.3.0
|
109
|
+
# @api private
|
110
|
+
def data
|
111
|
+
flash[@request_id] || {}
|
112
|
+
end
|
113
|
+
|
114
|
+
# Expire the stale data from the previous request.
|
115
|
+
#
|
116
|
+
# @return [void]
|
117
|
+
#
|
118
|
+
# @since 0.3.0
|
119
|
+
# @api private
|
120
|
+
def expire_stale!
|
121
|
+
flash.each do |request_id, _|
|
122
|
+
flash.delete(request_id) if delete?(request_id)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Remove the flash entirely from the session if empty.
|
127
|
+
#
|
128
|
+
# @return [void]
|
129
|
+
#
|
130
|
+
# @since 0.3.0
|
131
|
+
# @api private
|
132
|
+
#
|
133
|
+
# @see Hanami::Action::Flash#empty?
|
134
|
+
def remove!
|
135
|
+
@session.delete(SESSION_KEY) if empty?
|
136
|
+
end
|
137
|
+
|
138
|
+
# Values from all the stored requests
|
139
|
+
#
|
140
|
+
# @return [Array]
|
141
|
+
#
|
142
|
+
# @since 0.3.0
|
143
|
+
# @api private
|
144
|
+
def _values
|
145
|
+
flash.values
|
146
|
+
end
|
147
|
+
|
148
|
+
# Determine if delete data from flash for the given Request ID
|
149
|
+
#
|
150
|
+
# @return [TrueClass,FalseClass] the result of the check
|
151
|
+
#
|
152
|
+
# @since 0.4.0
|
153
|
+
# @api private
|
154
|
+
#
|
155
|
+
# @see Hanami::Action::Flash#expire_stale!
|
156
|
+
def delete?(request_id)
|
157
|
+
![@request_id, @session[LAST_REQUEST_KEY]].include?(request_id)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Get the last request session flash
|
161
|
+
#
|
162
|
+
# @return [Hash] the flash of last request
|
163
|
+
#
|
164
|
+
# @since 0.4.0
|
165
|
+
# @api private
|
166
|
+
def last_request_flash
|
167
|
+
flash[@last_request_id] || {}
|
168
|
+
end
|
169
|
+
|
170
|
+
# Store the last request_id to create the next flash with its values
|
171
|
+
# is current flash is not empty.
|
172
|
+
#
|
173
|
+
# @return [void]
|
174
|
+
# @since 0.4.0
|
175
|
+
# @api private
|
176
|
+
def set_last_request_id!
|
177
|
+
@session[LAST_REQUEST_KEY] = @request_id if !empty?
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|