hanami 2.0.0.alpha6 → 2.0.0.alpha8
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 +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
|