hanami 2.0.0.alpha6 → 2.0.0.alpha8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +79 -0
- data/lib/hanami/application/action/slice_configured_action.rb +103 -0
- data/lib/hanami/application/action.rb +72 -0
- data/lib/hanami/application/routing/router.rb +36 -0
- data/lib/hanami/application/slice_registrar.rb +106 -0
- data/lib/hanami/application/view/context.rb +95 -0
- data/lib/hanami/application/view/slice_configured_context.rb +71 -0
- data/lib/hanami/application/view/slice_configured_view.rb +101 -0
- data/lib/hanami/application/view.rb +24 -0
- data/lib/hanami/application/view_name_inferrer.rb +63 -0
- data/lib/hanami/application.rb +64 -147
- data/lib/hanami/configuration/actions/content_security_policy.rb +118 -0
- data/lib/hanami/configuration/actions/cookies.rb +29 -0
- data/lib/hanami/configuration/actions/sessions.rb +46 -0
- data/lib/hanami/configuration/actions.rb +95 -0
- data/lib/hanami/configuration/logger.rb +11 -8
- data/lib/hanami/configuration/views.rb +81 -0
- data/lib/hanami/configuration.rb +28 -62
- data/lib/hanami/constants.rb +29 -0
- data/lib/hanami/errors.rb +15 -0
- data/lib/hanami/slice.rb +157 -99
- data/lib/hanami/slice_configurable.rb +75 -0
- data/lib/hanami/slice_name.rb +111 -0
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami.rb +13 -5
- metadata +21 -3
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/view"
|
4
|
+
require_relative "../slice_configurable"
|
5
|
+
require_relative "view/slice_configured_view"
|
6
|
+
|
7
|
+
module Hanami
|
8
|
+
class Application
|
9
|
+
# Superclass for views intended for use within an Hanami application.
|
10
|
+
#
|
11
|
+
# @see Hanami::View
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
# @since 2.0.0
|
15
|
+
class View < Hanami::View
|
16
|
+
extend Hanami::SliceConfigurable
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def self.configure_for_slice(slice)
|
20
|
+
extend SliceConfiguredView.new(slice)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../constants"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
7
|
+
# Infers a view name for automatically rendering within actions.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
# @since 2.0.0
|
11
|
+
class ViewNameInferrer
|
12
|
+
ALTERNATIVE_NAMES = {
|
13
|
+
"create" => "new",
|
14
|
+
"update" => "edit"
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Returns an array of container keys for views matching the given action.
|
19
|
+
#
|
20
|
+
# Also provides alternative view keys for common RESTful actions.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# ViewNameInferrer.call(action_name: "Main::Actions::Posts::Create", slice: Main::Slice)
|
24
|
+
# # => ["views.posts.create", "views.posts.new"]
|
25
|
+
#
|
26
|
+
# @param action_name [String] action class name
|
27
|
+
# @param slice [Hanami::Slice, Hanami::Application] Hanami slice containing the action
|
28
|
+
#
|
29
|
+
# @return [Array<string>] array of paired view container keys
|
30
|
+
def call(action_class_name:, slice:)
|
31
|
+
action_key_base = slice.application.config.actions.name_inference_base
|
32
|
+
view_key_base = slice.application.config.actions.view_name_inference_base
|
33
|
+
|
34
|
+
action_name_key = action_name_key(action_class_name, slice, action_key_base)
|
35
|
+
|
36
|
+
view_key = [view_key_base, action_name_key].compact.join(CONTAINER_KEY_DELIMITER)
|
37
|
+
|
38
|
+
[view_key, alternative_view_key(view_key)].compact
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def action_name_key(action_name, slice, key_base)
|
44
|
+
slice
|
45
|
+
.inflector
|
46
|
+
.underscore(action_name)
|
47
|
+
.sub(%r{^#{slice.slice_name.path}#{PATH_DELIMITER}}, "")
|
48
|
+
.sub(%r{^#{key_base}#{PATH_DELIMITER}}, "")
|
49
|
+
.gsub("/", CONTAINER_KEY_DELIMITER)
|
50
|
+
end
|
51
|
+
|
52
|
+
def alternative_view_key(view_key)
|
53
|
+
parts = view_key.split(CONTAINER_KEY_DELIMITER)
|
54
|
+
|
55
|
+
alternative_name = ALTERNATIVE_NAMES[parts.last]
|
56
|
+
return unless alternative_name
|
57
|
+
|
58
|
+
[parts[0..-2], alternative_name].join(CONTAINER_KEY_DELIMITER)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/hanami/application.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "dry/system/container"
|
4
|
-
require "dry/system/loader/autoloading"
|
5
4
|
require "hanami/configuration"
|
6
5
|
require "pathname"
|
7
6
|
require "rack"
|
8
7
|
require "zeitwerk"
|
8
|
+
require_relative "constants"
|
9
9
|
require_relative "slice"
|
10
|
+
require_relative "slice_name"
|
11
|
+
require_relative "application/slice_registrar"
|
10
12
|
|
11
13
|
module Hanami
|
12
14
|
# Hanami application class
|
@@ -16,19 +18,25 @@ module Hanami
|
|
16
18
|
@_mutex = Mutex.new
|
17
19
|
|
18
20
|
class << self
|
19
|
-
def inherited(
|
21
|
+
def inherited(subclass)
|
20
22
|
super
|
23
|
+
|
21
24
|
@_mutex.synchronize do
|
22
|
-
|
23
|
-
@_mutex
|
24
|
-
@
|
25
|
+
subclass.class_eval do
|
26
|
+
@_mutex = Mutex.new
|
27
|
+
@application_name = SliceName.new(subclass, inflector: -> { subclass.inflector })
|
28
|
+
@configuration = Hanami::Configuration.new(application_name: @application_name, env: Hanami.env)
|
29
|
+
@autoloader = Zeitwerk::Loader.new
|
30
|
+
@container = Class.new(Dry::System::Container)
|
31
|
+
|
32
|
+
@prepared = @booted = false
|
25
33
|
|
26
34
|
extend ClassMethods
|
27
35
|
end
|
28
36
|
|
29
|
-
|
37
|
+
subclass.send :prepare_base_load_path
|
30
38
|
|
31
|
-
Hanami.application =
|
39
|
+
Hanami.application = subclass
|
32
40
|
end
|
33
41
|
end
|
34
42
|
end
|
@@ -37,39 +45,24 @@ module Hanami
|
|
37
45
|
#
|
38
46
|
# rubocop:disable Metrics/ModuleLength
|
39
47
|
module ClassMethods
|
40
|
-
|
41
|
-
klass.class_eval do
|
42
|
-
@prepared = @booted = false
|
43
|
-
end
|
44
|
-
end
|
48
|
+
attr_reader :application_name, :configuration, :autoloader, :container
|
45
49
|
|
46
|
-
|
47
|
-
@_configuration
|
48
|
-
end
|
50
|
+
alias_method :slice_name, :application_name
|
49
51
|
|
50
52
|
alias_method :config, :configuration
|
51
53
|
|
54
|
+
def application
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
52
58
|
def prepare(provider_name = nil)
|
53
|
-
if provider_name
|
54
|
-
container.prepare(provider_name)
|
55
|
-
return self
|
56
|
-
end
|
59
|
+
container.prepare(provider_name) and return self if provider_name
|
57
60
|
|
58
61
|
return self if prepared?
|
59
62
|
|
60
63
|
configuration.finalize!
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
@autoloader = Zeitwerk::Loader.new
|
65
|
-
@container = prepare_container
|
66
|
-
@deps_module = prepare_deps_module
|
67
|
-
|
68
|
-
load_slices
|
69
|
-
slices.each_value(&:prepare)
|
70
|
-
slices.freeze
|
71
|
-
|
72
|
-
@autoloader.setup
|
65
|
+
prepare_all
|
73
66
|
|
74
67
|
@prepared = true
|
75
68
|
self
|
@@ -82,40 +75,24 @@ module Hanami
|
|
82
75
|
|
83
76
|
container.finalize!(&block)
|
84
77
|
|
85
|
-
slices.
|
78
|
+
slices.each(&:boot)
|
86
79
|
|
87
80
|
@booted = true
|
88
81
|
self
|
89
82
|
end
|
90
83
|
|
91
84
|
def shutdown
|
85
|
+
slices.each(&:shutdown)
|
92
86
|
container.shutdown!
|
87
|
+
self
|
93
88
|
end
|
94
89
|
|
95
90
|
def prepared?
|
96
|
-
|
91
|
+
!!@prepared
|
97
92
|
end
|
98
93
|
|
99
94
|
def booted?
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
def autoloader
|
104
|
-
raise "Application not yet prepared" unless defined?(@autoloader)
|
105
|
-
|
106
|
-
@autoloader
|
107
|
-
end
|
108
|
-
|
109
|
-
def container
|
110
|
-
raise "Application not yet prepared" unless defined?(@container)
|
111
|
-
|
112
|
-
@container
|
113
|
-
end
|
114
|
-
|
115
|
-
def deps
|
116
|
-
raise "Application not yet prepared" unless defined?(@deps_module)
|
117
|
-
|
118
|
-
@deps_module
|
95
|
+
!!@booted
|
119
96
|
end
|
120
97
|
|
121
98
|
def router
|
@@ -131,15 +108,11 @@ module Hanami
|
|
131
108
|
end
|
132
109
|
|
133
110
|
def slices
|
134
|
-
@slices ||=
|
111
|
+
@slices ||= SliceRegistrar.new(self)
|
135
112
|
end
|
136
113
|
|
137
|
-
def register_slice(
|
138
|
-
|
139
|
-
|
140
|
-
slice = Slice.new(self, name: name, **slice_args)
|
141
|
-
slice.namespace.const_set :Slice, slice if slice.namespace # rubocop:disable Style/SafeNavigation
|
142
|
-
slices[name.to_sym] = slice
|
114
|
+
def register_slice(...)
|
115
|
+
slices.register(...)
|
143
116
|
end
|
144
117
|
|
145
118
|
def register(...)
|
@@ -175,19 +148,7 @@ module Hanami
|
|
175
148
|
end
|
176
149
|
|
177
150
|
def namespace
|
178
|
-
|
179
|
-
end
|
180
|
-
|
181
|
-
def namespace_name
|
182
|
-
namespace.name
|
183
|
-
end
|
184
|
-
|
185
|
-
def namespace_path
|
186
|
-
inflector.underscore(namespace)
|
187
|
-
end
|
188
|
-
|
189
|
-
def application_name
|
190
|
-
configuration.application_name
|
151
|
+
application_name.namespace
|
191
152
|
end
|
192
153
|
|
193
154
|
def root
|
@@ -198,21 +159,6 @@ module Hanami
|
|
198
159
|
configuration.inflector
|
199
160
|
end
|
200
161
|
|
201
|
-
# @api private
|
202
|
-
def component_provider(component)
|
203
|
-
raise "Hanami.application must be prepared before detecting providers" unless prepared?
|
204
|
-
|
205
|
-
# [Admin, Main, MyApp] or [MyApp::Admin, MyApp::Main, MyApp]
|
206
|
-
providers = slices.values + [self]
|
207
|
-
|
208
|
-
component_class = component.is_a?(Class) ? component : component.class
|
209
|
-
component_name = component_class.name
|
210
|
-
|
211
|
-
return unless component_name
|
212
|
-
|
213
|
-
providers.detect { |provider| component_name.include?(provider.namespace.to_s) }
|
214
|
-
end
|
215
|
-
|
216
162
|
private
|
217
163
|
|
218
164
|
def prepare_base_load_path
|
@@ -220,20 +166,25 @@ module Hanami
|
|
220
166
|
$LOAD_PATH.unshift base_path unless $LOAD_PATH.include?(base_path)
|
221
167
|
end
|
222
168
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
169
|
+
def prepare_all
|
170
|
+
load_settings
|
171
|
+
prepare_container_plugins
|
172
|
+
prepare_container_base_config
|
173
|
+
prepare_container_consts
|
174
|
+
container.configured!
|
175
|
+
prepare_slices
|
176
|
+
# For the application, the autoloader must be prepared after the slices, since
|
177
|
+
# they'll be configuring the autoloader with their own dirs
|
178
|
+
prepare_autoloader
|
179
|
+
end
|
232
180
|
|
233
|
-
|
234
|
-
container.use
|
235
|
-
container.use :
|
181
|
+
def prepare_container_plugins
|
182
|
+
container.use(:env, inferrer: -> { Hanami.env })
|
183
|
+
container.use(:zeitwerk, loader: autoloader, run_setup: false, eager_load: false)
|
184
|
+
container.use(:notifications)
|
185
|
+
end
|
236
186
|
|
187
|
+
def prepare_container_base_config
|
237
188
|
container.config.root = configuration.root
|
238
189
|
container.config.inflector = configuration.inflector
|
239
190
|
|
@@ -241,63 +192,32 @@ module Hanami
|
|
241
192
|
"config/providers",
|
242
193
|
Pathname(__dir__).join("application/container/providers").realpath,
|
243
194
|
]
|
195
|
+
end
|
244
196
|
|
197
|
+
def prepare_autoload_paths
|
245
198
|
# Autoload classes defined in lib/[app_namespace]/
|
246
|
-
if root.join("lib",
|
247
|
-
|
199
|
+
if root.join("lib", application_name.name).directory?
|
200
|
+
autoloader.push_dir(root.join("lib", application_name.name), namespace: namespace)
|
248
201
|
end
|
249
|
-
|
250
|
-
# Add lib/ to to the $LOAD_PATH so any files there (outside the app namespace) can
|
251
|
-
# be required
|
252
|
-
container.add_to_load_path!("lib") if root.join("lib").directory?
|
253
|
-
|
254
|
-
container.configured!
|
255
|
-
|
256
|
-
container
|
257
202
|
end
|
258
|
-
# rubocop:enable Metrics/AbcSize
|
259
203
|
|
260
|
-
def
|
261
|
-
|
262
|
-
end
|
263
|
-
|
264
|
-
def define_deps_module
|
265
|
-
require "#{application_name}/deps"
|
266
|
-
namespace.const_get :Deps
|
267
|
-
rescue LoadError, NameError
|
204
|
+
def prepare_container_consts
|
205
|
+
namespace.const_set :Container, container
|
268
206
|
namespace.const_set :Deps, container.injector
|
269
207
|
end
|
270
208
|
|
271
|
-
def
|
272
|
-
|
273
|
-
|
274
|
-
.each(&method(:load_slice))
|
275
|
-
end
|
276
|
-
|
277
|
-
def slices_path
|
278
|
-
File.join(root, config.slices_dir)
|
209
|
+
def prepare_slices
|
210
|
+
slices.load_slices.each(&:prepare)
|
211
|
+
slices.freeze
|
279
212
|
end
|
280
213
|
|
281
|
-
def
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
slice_const_name = inflector.camelize(slice_name)
|
286
|
-
|
287
|
-
if config.slices_namespace.const_defined?(slice_const_name)
|
288
|
-
slice_module = config.slices_namespace.const_get(slice_const_name)
|
289
|
-
|
290
|
-
raise "Cannot use slice +#{slice_const_name}+ since it is not a module" unless slice_module.is_a?(Module)
|
291
|
-
else
|
292
|
-
slice_module = Module.new
|
293
|
-
config.slices_namespace.const_set inflector.camelize(slice_name), slice_module
|
214
|
+
def prepare_autoloader
|
215
|
+
# Autoload classes defined in lib/[app_namespace]/
|
216
|
+
if root.join("lib", application_name.name).directory?
|
217
|
+
autoloader.push_dir(root.join("lib", application_name.name), namespace: namespace)
|
294
218
|
end
|
295
219
|
|
296
|
-
|
297
|
-
slice_name,
|
298
|
-
namespace: slice_module,
|
299
|
-
root: slice_path.realpath
|
300
|
-
)
|
220
|
+
autoloader.setup
|
301
221
|
end
|
302
222
|
|
303
223
|
def load_settings
|
@@ -311,11 +231,8 @@ module Hanami
|
|
311
231
|
Settings.new
|
312
232
|
end
|
313
233
|
|
314
|
-
MODULE_DELIMITER = "::"
|
315
|
-
private_constant :MODULE_DELIMITER
|
316
|
-
|
317
234
|
def autodiscover_application_constant(constants)
|
318
|
-
inflector.constantize([namespace_name, *constants].join(MODULE_DELIMITER))
|
235
|
+
inflector.constantize([application_name.namespace_name, *constants].join(MODULE_DELIMITER))
|
319
236
|
end
|
320
237
|
|
321
238
|
def load_router
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Configuration
|
5
|
+
class Actions
|
6
|
+
# Configuration for Content Security Policy in Hanami applications
|
7
|
+
#
|
8
|
+
# @since 2.0.0
|
9
|
+
class ContentSecurityPolicy
|
10
|
+
# @since 2.0.0
|
11
|
+
# @api private
|
12
|
+
def initialize(&blk)
|
13
|
+
@policy = {
|
14
|
+
base_uri: "'self'",
|
15
|
+
child_src: "'self'",
|
16
|
+
connect_src: "'self'",
|
17
|
+
default_src: "'none'",
|
18
|
+
font_src: "'self'",
|
19
|
+
form_action: "'self'",
|
20
|
+
frame_ancestors: "'self'",
|
21
|
+
frame_src: "'self'",
|
22
|
+
img_src: "'self' https: data:",
|
23
|
+
media_src: "'self'",
|
24
|
+
object_src: "'none'",
|
25
|
+
plugin_types: "application/pdf",
|
26
|
+
script_src: "'self'",
|
27
|
+
style_src: "'self' 'unsafe-inline' https:"
|
28
|
+
}
|
29
|
+
|
30
|
+
blk&.(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @since 2.0.0
|
34
|
+
# @api private
|
35
|
+
def initialize_copy(original_object)
|
36
|
+
@policy = original_object.instance_variable_get(:@policy).dup
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get a CSP setting
|
41
|
+
#
|
42
|
+
# @param key [Symbol] the underscored name of the CPS setting
|
43
|
+
# @return [String,NilClass] the CSP setting, if any
|
44
|
+
#
|
45
|
+
# @since 2.0.0
|
46
|
+
# @api public
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# module MyApp
|
50
|
+
# class Application < Hanami::Application
|
51
|
+
# config.actions.content_security_policy[:base_uri] # => "'self'"
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
def [](key)
|
55
|
+
@policy[key]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Set a CSP setting
|
59
|
+
#
|
60
|
+
# @param key [Symbol] the underscored name of the CPS setting
|
61
|
+
# @param value [String] the CSP setting value
|
62
|
+
#
|
63
|
+
# @since 2.0.0
|
64
|
+
# @api public
|
65
|
+
#
|
66
|
+
# @example Replace a default value
|
67
|
+
# module MyApp
|
68
|
+
# class Application < Hanami::Application
|
69
|
+
# config.actions.content_security_policy[:plugin_types] = nil
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# @example Append to a default value
|
74
|
+
# module MyApp
|
75
|
+
# class Application < Hanami::Application
|
76
|
+
# config.actions.content_security_policy[:script_src] += " https://my.cdn.test"
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
def []=(key, value)
|
80
|
+
@policy[key] = value
|
81
|
+
end
|
82
|
+
|
83
|
+
# Deletes a CSP key
|
84
|
+
#
|
85
|
+
# @param key [Symbol] the underscored name of the CPS setting
|
86
|
+
#
|
87
|
+
# @since 2.0.0
|
88
|
+
# @api public
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# module MyApp
|
92
|
+
# class Application < Hanami::Application
|
93
|
+
# config.actions.content_security_policy.delete(:object_src)
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
def delete(key)
|
97
|
+
@policy.delete(key)
|
98
|
+
end
|
99
|
+
|
100
|
+
# @since 2.0.0
|
101
|
+
# @api private
|
102
|
+
def to_str
|
103
|
+
@policy.map do |key, value|
|
104
|
+
"#{dasherize(key)} #{value}"
|
105
|
+
end.join(";\n")
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# @since 2.0.0
|
111
|
+
# @api private
|
112
|
+
def dasherize(key)
|
113
|
+
key.to_s.gsub("_", "-")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Configuration
|
5
|
+
class Actions
|
6
|
+
# Wrapper for application-level configuration of HTTP cookies for Hanami actions.
|
7
|
+
# This decorates the hash of cookie options that is otherwise directly configurable
|
8
|
+
# on actions, and adds the `enabled?` method to allow `ApplicationAction` to
|
9
|
+
# determine whether to include the `Action::Cookies` module.
|
10
|
+
#
|
11
|
+
# @since 2.0.0
|
12
|
+
class Cookies
|
13
|
+
attr_reader :options
|
14
|
+
|
15
|
+
def initialize(options)
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def enabled?
|
20
|
+
!options.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_h
|
24
|
+
options.to_h
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/constants"
|
4
|
+
require "hanami/utils/string"
|
5
|
+
require "hanami/utils/class"
|
6
|
+
|
7
|
+
module Hanami
|
8
|
+
class Configuration
|
9
|
+
class Actions
|
10
|
+
# Configuration for HTTP sessions in Hanami actions
|
11
|
+
#
|
12
|
+
# @since 2.0.0
|
13
|
+
class Sessions
|
14
|
+
attr_reader :storage, :options
|
15
|
+
|
16
|
+
def initialize(storage = nil, *options)
|
17
|
+
@storage = storage
|
18
|
+
@options = options
|
19
|
+
end
|
20
|
+
|
21
|
+
def enabled?
|
22
|
+
!storage.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def middleware
|
26
|
+
return [] if !enabled?
|
27
|
+
|
28
|
+
[[storage_middleware, options]]
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def storage_middleware
|
34
|
+
require_storage
|
35
|
+
|
36
|
+
name = Utils::String.classify(storage)
|
37
|
+
Utils::Class.load!(name, ::Rack::Session)
|
38
|
+
end
|
39
|
+
|
40
|
+
def require_storage
|
41
|
+
require "rack/session/#{storage}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|