hanami-controller 2.0.0.alpha1 → 2.0.0.alpha2
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 +29 -0
- data/LICENSE.md +1 -1
- data/README.md +5 -5
- data/hanami-controller.gemspec +4 -3
- data/lib/hanami/action.rb +14 -573
- data/lib/hanami/action/application_action.rb +111 -0
- data/lib/hanami/action/application_configuration.rb +92 -0
- data/lib/hanami/action/application_configuration/cookies.rb +29 -0
- data/lib/hanami/action/application_configuration/sessions.rb +46 -0
- data/lib/hanami/action/cache/conditional_get.rb +4 -1
- data/lib/hanami/action/configuration.rb +430 -0
- data/lib/hanami/action/csrf_protection.rb +214 -0
- data/lib/hanami/action/flash.rb +101 -206
- data/lib/hanami/action/mime.rb +8 -1
- data/lib/hanami/action/params.rb +1 -1
- data/lib/hanami/action/response.rb +43 -24
- data/lib/hanami/action/session.rb +6 -14
- data/lib/hanami/action/standalone_action.rb +581 -0
- data/lib/hanami/action/validatable.rb +1 -1
- data/lib/hanami/action/view_name_inferrer.rb +46 -0
- data/lib/hanami/controller.rb +0 -17
- data/lib/hanami/controller/version.rb +1 -1
- data/lib/hanami/http/status.rb +2 -2
- metadata +33 -13
- data/lib/hanami-controller.rb +0 -1
- data/lib/hanami/controller/configuration.rb +0 -308
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Action
|
5
|
+
class ApplicationAction < Module
|
6
|
+
attr_reader :provider
|
7
|
+
attr_reader :application
|
8
|
+
|
9
|
+
def initialize(provider)
|
10
|
+
@provider = provider
|
11
|
+
@application = provider.respond_to?(:application) ? provider.application : Hanami.application
|
12
|
+
end
|
13
|
+
|
14
|
+
def included(action_class)
|
15
|
+
action_class.include InstanceMethods
|
16
|
+
|
17
|
+
define_initialize action_class
|
18
|
+
configure_action action_class
|
19
|
+
extend_behavior action_class
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"#<#{self.class.name}[#{provider.name}]>"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def define_initialize(action_class)
|
29
|
+
resolve_view = method(:resolve_paired_view)
|
30
|
+
resolve_context = method(:resolve_view_context)
|
31
|
+
|
32
|
+
define_method :initialize do |**deps|
|
33
|
+
# Conditionally assign these to repsect any explictly auto-injected
|
34
|
+
# dependencies provided by the class
|
35
|
+
@view ||= deps[:view] || resolve_view.(self.class)
|
36
|
+
@view_context ||= deps[:view_context] || resolve_context.()
|
37
|
+
|
38
|
+
super(**deps)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def resolve_view_context
|
43
|
+
identifier = application.config.actions.view_context_identifier
|
44
|
+
|
45
|
+
if provider.key?(identifier)
|
46
|
+
provider[identifier]
|
47
|
+
elsif application.key?(identifier)
|
48
|
+
application[identifier]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def resolve_paired_view(action_class)
|
53
|
+
view_identifiers = application.config.actions.view_name_inferrer.(
|
54
|
+
action_name: action_class.name,
|
55
|
+
provider: provider
|
56
|
+
)
|
57
|
+
|
58
|
+
view_identifiers.detect { |identifier|
|
59
|
+
break provider[identifier] if provider.key?(identifier)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def configure_action(action_class)
|
64
|
+
action_class.config.settings.each do |setting|
|
65
|
+
application_value = application.config.actions.public_send(:"#{setting}")
|
66
|
+
action_class.config.public_send :"#{setting}=", application_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def extend_behavior(action_class)
|
71
|
+
if application.config.actions.csrf_protection
|
72
|
+
require "hanami/action/csrf_protection"
|
73
|
+
action_class.include Hanami::Action::CSRFProtection
|
74
|
+
end
|
75
|
+
|
76
|
+
if application.config.actions.cookies.enabled?
|
77
|
+
require "hanami/action/cookies"
|
78
|
+
action_class.include Hanami::Action::Cookies
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module InstanceMethods
|
83
|
+
attr_reader :view
|
84
|
+
attr_reader :view_context
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def handle(request, response)
|
89
|
+
if view
|
90
|
+
response.render view, **request.params
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def build_response(**options)
|
97
|
+
options = options.merge(view_options: method(:view_options))
|
98
|
+
super(**options)
|
99
|
+
end
|
100
|
+
|
101
|
+
def view_options(req, res)
|
102
|
+
{context: view_context&.with(**view_context_options(req, res))}.compact
|
103
|
+
end
|
104
|
+
|
105
|
+
def view_context_options(req, res)
|
106
|
+
{request: req, response: res}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "application_configuration/cookies"
|
4
|
+
require_relative "application_configuration/sessions"
|
5
|
+
require_relative "configuration"
|
6
|
+
require_relative "view_name_inferrer"
|
7
|
+
|
8
|
+
module Hanami
|
9
|
+
class Action
|
10
|
+
class ApplicationConfiguration
|
11
|
+
include Dry::Configurable
|
12
|
+
|
13
|
+
setting(:cookies, {}) { |options| Cookies.new(options) }
|
14
|
+
setting(:sessions) { |storage, *options| Sessions.new(storage, *options) }
|
15
|
+
setting :csrf_protection
|
16
|
+
|
17
|
+
setting :name_inference_base, "actions"
|
18
|
+
setting :view_context_identifier, "view.context"
|
19
|
+
setting :view_name_inferrer, ViewNameInferrer
|
20
|
+
setting :view_name_inference_base, "views"
|
21
|
+
|
22
|
+
def initialize(*)
|
23
|
+
super
|
24
|
+
|
25
|
+
@base_configuration = Configuration.new
|
26
|
+
|
27
|
+
configure_defaults
|
28
|
+
end
|
29
|
+
|
30
|
+
def finalize!
|
31
|
+
# A nil value for `csrf_protection` means it has not been explicitly configured
|
32
|
+
# (neither true nor false), so we can default it to whether sessions are enabled
|
33
|
+
self.csrf_protection = sessions.enabled? if csrf_protection.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the list of available settings
|
37
|
+
#
|
38
|
+
# @return [Set]
|
39
|
+
#
|
40
|
+
# @since 2.0.0
|
41
|
+
# @api private
|
42
|
+
def settings
|
43
|
+
base_configuration.settings + self.class.settings
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :base_configuration
|
49
|
+
|
50
|
+
# Apply defaults for base configuration settings
|
51
|
+
def configure_defaults
|
52
|
+
self.default_request_format = :html
|
53
|
+
self.default_response_format = :html
|
54
|
+
|
55
|
+
self.default_headers = {
|
56
|
+
"X-Frame-Options" => "DENY",
|
57
|
+
"X-Content-Type-Options" => "nosniff",
|
58
|
+
"X-XSS-Protection" => "1; mode=block",
|
59
|
+
"Content-Security-Policy" => \
|
60
|
+
"base-uri 'self'; " \
|
61
|
+
"child-src 'self'; " \
|
62
|
+
"connect-src 'self'; " \
|
63
|
+
"default-src 'none'; " \
|
64
|
+
"font-src 'self'; " \
|
65
|
+
"form-action 'self'; " \
|
66
|
+
"frame-ancestors 'self'; " \
|
67
|
+
"frame-src 'self'; " \
|
68
|
+
"img-src 'self' https: data:; " \
|
69
|
+
"media-src 'self'; " \
|
70
|
+
"object-src 'none'; " \
|
71
|
+
"plugin-types application/pdf; " \
|
72
|
+
"script-src 'self'; " \
|
73
|
+
"style-src 'self' 'unsafe-inline' https:"
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing(name, *args, &block)
|
78
|
+
if config.respond_to?(name)
|
79
|
+
config.public_send(name, *args, &block)
|
80
|
+
elsif base_configuration.respond_to?(name)
|
81
|
+
base_configuration.public_send(name, *args, &block)
|
82
|
+
else
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def respond_to_missing?(name, _incude_all = false)
|
88
|
+
config.respond_to?(name) || base_configuration.respond_to?(name) || super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Action
|
5
|
+
class ApplicationConfiguration
|
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 Action
|
9
|
+
class ApplicationConfiguration
|
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
|
@@ -69,7 +69,10 @@ module Hanami
|
|
69
69
|
# @since 0.3.0
|
70
70
|
# @api private
|
71
71
|
def fresh?
|
72
|
-
|
72
|
+
return false if Hanami::Utils::Blank.blank?(modified_since)
|
73
|
+
return false if Hanami::Utils::Blank.blank?(@value)
|
74
|
+
|
75
|
+
Time.httpdate(modified_since).to_i >= @value.to_time.to_i
|
73
76
|
end
|
74
77
|
|
75
78
|
# @since 0.3.0
|
@@ -0,0 +1,430 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "hanami/utils/kernel"
|
5
|
+
require "pathname"
|
6
|
+
require_relative "mime"
|
7
|
+
|
8
|
+
module Hanami
|
9
|
+
class Action
|
10
|
+
class Configuration
|
11
|
+
include Dry::Configurable
|
12
|
+
|
13
|
+
# Initialize the Configuration
|
14
|
+
#
|
15
|
+
# @yield [config] the configuration object
|
16
|
+
#
|
17
|
+
# @return [Configuration]
|
18
|
+
#
|
19
|
+
# @since 2.0.0
|
20
|
+
# @api private
|
21
|
+
def initialize(*)
|
22
|
+
super
|
23
|
+
yield self if block_given?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the list of available settings
|
27
|
+
#
|
28
|
+
# @return [Set]
|
29
|
+
#
|
30
|
+
# @since 2.0.0
|
31
|
+
# @api private
|
32
|
+
def settings
|
33
|
+
self.class.settings
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!method handled_exceptions=(exceptions)
|
37
|
+
#
|
38
|
+
# Specifies how to handle exceptions with an HTTP status
|
39
|
+
#
|
40
|
+
# Raised exceptions will return the corresponding HTTP status
|
41
|
+
#
|
42
|
+
# @param exceptions [Hash{Exception=>Integer}] exception classes as
|
43
|
+
# keys and HTTP statuses as values
|
44
|
+
#
|
45
|
+
# @return [void]
|
46
|
+
#
|
47
|
+
# @since 0.2.0
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# configuration.handled_exceptions = {ArgumentError => 400}
|
51
|
+
#
|
52
|
+
# @!method handled_exceptions
|
53
|
+
#
|
54
|
+
# Returns the configured handled exceptions
|
55
|
+
#
|
56
|
+
# @return [Hash{Exception=>Integer}]
|
57
|
+
#
|
58
|
+
# @see handled_exceptions=
|
59
|
+
#
|
60
|
+
# @since 0.2.0
|
61
|
+
setting :handled_exceptions, {}
|
62
|
+
|
63
|
+
# Specifies how to handle exceptions with an HTTP status
|
64
|
+
#
|
65
|
+
# Raised exceptions will return the corresponding HTTP status
|
66
|
+
#
|
67
|
+
# The specified exceptions will be merged with any previously configured
|
68
|
+
# exceptions
|
69
|
+
#
|
70
|
+
# @param exceptions [Hash{Exception=>Integer}] exception classes as keys
|
71
|
+
# and HTTP statuses as values
|
72
|
+
#
|
73
|
+
# @return [void]
|
74
|
+
#
|
75
|
+
# @since 0.2.0
|
76
|
+
#
|
77
|
+
# @see handled_exceptions=
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# configuration.handle_exceptions(ArgumentError => 400}
|
81
|
+
def handle_exception(exceptions)
|
82
|
+
self.handled_exceptions = handled_exceptions
|
83
|
+
.merge(exceptions)
|
84
|
+
.sort { |(ex1, _), (ex2, _)| ex1.ancestors.include?(ex2) ? -1 : 1 }
|
85
|
+
.to_h
|
86
|
+
end
|
87
|
+
|
88
|
+
# Default MIME type to format mapping
|
89
|
+
#
|
90
|
+
# @since 0.2.0
|
91
|
+
# @api private
|
92
|
+
DEFAULT_FORMATS = {
|
93
|
+
'application/octet-stream' => :all,
|
94
|
+
'*/*' => :all,
|
95
|
+
'text/html' => :html
|
96
|
+
}.freeze
|
97
|
+
|
98
|
+
# @!method formats=(formats)
|
99
|
+
#
|
100
|
+
# Specifies the MIME type to format mapping
|
101
|
+
#
|
102
|
+
# @param formats [Hash{String=>Symbol}] MIME type strings as keys and
|
103
|
+
# format symbols as values
|
104
|
+
#
|
105
|
+
# @return [void]
|
106
|
+
#
|
107
|
+
# @since 0.2.0
|
108
|
+
#
|
109
|
+
# @see format
|
110
|
+
# @see Hanami::Action::Mime
|
111
|
+
#
|
112
|
+
# @example
|
113
|
+
# configuration.formats = {"text/html" => :html}
|
114
|
+
#
|
115
|
+
# @!method formats
|
116
|
+
#
|
117
|
+
# Returns the configured MIME type to format mapping
|
118
|
+
#
|
119
|
+
# @return [Symbol,nil] the corresponding format, if present
|
120
|
+
#
|
121
|
+
# @see format
|
122
|
+
# @see formats=
|
123
|
+
#
|
124
|
+
# @since 0.2.0
|
125
|
+
setting :formats, DEFAULT_FORMATS.dup
|
126
|
+
|
127
|
+
# Registers a MIME type to format mapping
|
128
|
+
#
|
129
|
+
# @param hash [Hash{Symbol=>String}] format symbols as keys and the MIME
|
130
|
+
# type strings must as values
|
131
|
+
#
|
132
|
+
# @return [void]
|
133
|
+
#
|
134
|
+
# @since 0.2.0
|
135
|
+
#
|
136
|
+
# @see Hanami::Action::Mime
|
137
|
+
#
|
138
|
+
# @example configuration.format html: "text/html"
|
139
|
+
def format(hash)
|
140
|
+
symbol, mime_type = *Utils::Kernel.Array(hash)
|
141
|
+
formats[Utils::Kernel.String(mime_type)] = Utils::Kernel.Symbol(symbol)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns the configured format for the given MIME type
|
145
|
+
#
|
146
|
+
# @param mime_type [#to_s,#to_str] A mime type
|
147
|
+
#
|
148
|
+
# @return [Symbol,nil] the corresponding format, nil if not found
|
149
|
+
#
|
150
|
+
# @see format
|
151
|
+
#
|
152
|
+
# @since 0.2.0
|
153
|
+
# @api private
|
154
|
+
def format_for(mime_type)
|
155
|
+
formats[mime_type]
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns the configured format's MIME types
|
159
|
+
#
|
160
|
+
# @return [Array<String>] the format's MIME types
|
161
|
+
#
|
162
|
+
# @see formats=
|
163
|
+
# @see format
|
164
|
+
#
|
165
|
+
# @since 0.8.0
|
166
|
+
#
|
167
|
+
# @api private
|
168
|
+
def mime_types
|
169
|
+
# FIXME: this isn't efficient. speed it up!
|
170
|
+
((formats.keys - DEFAULT_FORMATS.keys) +
|
171
|
+
Hanami::Action::Mime::TYPES.values).freeze
|
172
|
+
end
|
173
|
+
|
174
|
+
# Returns a MIME type for the given format
|
175
|
+
#
|
176
|
+
# @param format [#to_sym] a format
|
177
|
+
#
|
178
|
+
# @return [String,nil] the corresponding MIME type, if present
|
179
|
+
#
|
180
|
+
# @since 0.2.0
|
181
|
+
# @api private
|
182
|
+
def mime_type_for(format)
|
183
|
+
formats.key(format)
|
184
|
+
end
|
185
|
+
|
186
|
+
# @!method default_request_format=(format)
|
187
|
+
#
|
188
|
+
# Sets a format as default fallback for all the requests without a strict
|
189
|
+
# requirement for the MIME type.
|
190
|
+
#
|
191
|
+
# The given format must be coercible to a symbol, and be a valid MIME
|
192
|
+
# type alias. If it isn't, at runtime the framework will raise an
|
193
|
+
# `Hanami::Controller::UnknownFormatError`.
|
194
|
+
#
|
195
|
+
# By default, this value is nil.
|
196
|
+
#
|
197
|
+
# @param format [Symbol]
|
198
|
+
#
|
199
|
+
# @return [void]
|
200
|
+
#
|
201
|
+
# @since 0.5.0
|
202
|
+
#
|
203
|
+
# @see Hanami::Action::Mime
|
204
|
+
#
|
205
|
+
# @!method default_request_format
|
206
|
+
#
|
207
|
+
# Returns the configured default request format
|
208
|
+
#
|
209
|
+
# @return [Symbol] format
|
210
|
+
#
|
211
|
+
# @see default_request_format=
|
212
|
+
#
|
213
|
+
# @since 0.5.0
|
214
|
+
setting :default_request_format do |format|
|
215
|
+
Utils::Kernel.Symbol(format) unless format.nil?
|
216
|
+
end
|
217
|
+
|
218
|
+
# @!method default_response_format=(format)
|
219
|
+
#
|
220
|
+
# Sets a format to be used for all responses regardless of the request
|
221
|
+
# type.
|
222
|
+
#
|
223
|
+
# The given format must be coercible to a symbol, and be a valid MIME
|
224
|
+
# type alias. If it isn't, at the runtime the framework will raise an
|
225
|
+
# `Hanami::Controller::UnknownFormatError`.
|
226
|
+
#
|
227
|
+
# By default, this value is nil.
|
228
|
+
#
|
229
|
+
# @param format [Symbol]
|
230
|
+
#
|
231
|
+
# @return [void]
|
232
|
+
#
|
233
|
+
# @since 0.5.0
|
234
|
+
#
|
235
|
+
# @see Hanami::Action::Mime
|
236
|
+
#
|
237
|
+
# @!method default_response_format
|
238
|
+
#
|
239
|
+
# Returns the configured default response format
|
240
|
+
#
|
241
|
+
# @return [Symbol] format
|
242
|
+
#
|
243
|
+
# @see default_request_format=
|
244
|
+
#
|
245
|
+
# @since 0.5.0
|
246
|
+
setting :default_response_format do |format|
|
247
|
+
Utils::Kernel.Symbol(format) unless format.nil?
|
248
|
+
end
|
249
|
+
|
250
|
+
# @!method default_charset=(charset)
|
251
|
+
#
|
252
|
+
# Sets a charset (character set) as default fallback for all the requests
|
253
|
+
# without a strict requirement for the charset.
|
254
|
+
#
|
255
|
+
# By default, this value is nil.
|
256
|
+
#
|
257
|
+
# @param charset [String]
|
258
|
+
#
|
259
|
+
# @return [void]
|
260
|
+
#
|
261
|
+
# @since 0.3.0
|
262
|
+
#
|
263
|
+
# @see Hanami::Action::Mime
|
264
|
+
#
|
265
|
+
# @!method default_charset
|
266
|
+
#
|
267
|
+
# Returns the configured default charset.
|
268
|
+
#
|
269
|
+
# @return [String,nil] the charset, if present
|
270
|
+
#
|
271
|
+
# @see default_charset=
|
272
|
+
#
|
273
|
+
# @since 0.3.0
|
274
|
+
setting :default_charset
|
275
|
+
|
276
|
+
# @!method default_headers=(headers)
|
277
|
+
#
|
278
|
+
# Sets default headers for all responses.
|
279
|
+
#
|
280
|
+
# By default, this is an empty hash.
|
281
|
+
#
|
282
|
+
# @param headers [Hash{String=>String}] the headers
|
283
|
+
#
|
284
|
+
# @return [void]
|
285
|
+
#
|
286
|
+
# @since 0.4.0
|
287
|
+
#
|
288
|
+
# @see default_headers
|
289
|
+
#
|
290
|
+
# @example
|
291
|
+
# configuration.default_headers = {'X-Frame-Options' => 'DENY'}
|
292
|
+
#
|
293
|
+
# @!method default_headers
|
294
|
+
#
|
295
|
+
# Returns the configured headers
|
296
|
+
#
|
297
|
+
# @return [Hash{String=>String}] the headers
|
298
|
+
#
|
299
|
+
# @since 0.4.0
|
300
|
+
#
|
301
|
+
# @see default_headers=
|
302
|
+
setting :default_headers, {} do |headers|
|
303
|
+
headers.compact
|
304
|
+
end
|
305
|
+
|
306
|
+
# @!method cookies=(cookie_options)
|
307
|
+
#
|
308
|
+
# Sets default cookie options for all responses.
|
309
|
+
#
|
310
|
+
# By default this, is an empty hash.
|
311
|
+
#
|
312
|
+
# @param cookie_options [Hash{Symbol=>String}] the cookie options
|
313
|
+
#
|
314
|
+
# @return [void]
|
315
|
+
#
|
316
|
+
# @since 0.4.0
|
317
|
+
#
|
318
|
+
# @example
|
319
|
+
# configuration.cookies = {
|
320
|
+
# domain: 'hanamirb.org',
|
321
|
+
# path: '/controller',
|
322
|
+
# secure: true,
|
323
|
+
# httponly: true
|
324
|
+
# }
|
325
|
+
#
|
326
|
+
# @!method cookies
|
327
|
+
#
|
328
|
+
# Returns the configured cookie options
|
329
|
+
#
|
330
|
+
# @return [Hash{Symbol=>String}]
|
331
|
+
#
|
332
|
+
# @since 0.4.0
|
333
|
+
#
|
334
|
+
# @see cookies=
|
335
|
+
setting :cookies, {} do |cookie_options|
|
336
|
+
# Call `to_h` here to permit `ApplicationConfiguration::Cookies` object to be
|
337
|
+
# provided when application actions are configured
|
338
|
+
cookie_options.to_h.compact
|
339
|
+
end
|
340
|
+
|
341
|
+
# @!method root_directory=(dir)
|
342
|
+
#
|
343
|
+
# Sets the the for the public directory, which is used for file downloads.
|
344
|
+
# This must be an existent directory.
|
345
|
+
#
|
346
|
+
# Defaults to the current working directory.
|
347
|
+
#
|
348
|
+
# @param dir [String] the directory path
|
349
|
+
#
|
350
|
+
# @return [void]
|
351
|
+
#
|
352
|
+
# @since 1.0.0
|
353
|
+
#
|
354
|
+
# @api private
|
355
|
+
#
|
356
|
+
# @!method root_directory
|
357
|
+
#
|
358
|
+
# Returns the configured root directory
|
359
|
+
#
|
360
|
+
# @return [String] the directory path
|
361
|
+
#
|
362
|
+
# @see root_directory=
|
363
|
+
#
|
364
|
+
# @since 1.0.0
|
365
|
+
#
|
366
|
+
# @api private
|
367
|
+
setting :root_directory do |dir|
|
368
|
+
dir ||= Dir.pwd
|
369
|
+
|
370
|
+
Pathname(dir).realpath
|
371
|
+
end
|
372
|
+
|
373
|
+
# Default public directory
|
374
|
+
#
|
375
|
+
# This serves as the root directory for file downloads
|
376
|
+
#
|
377
|
+
# @since 1.0.0
|
378
|
+
#
|
379
|
+
# @api private
|
380
|
+
DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
|
381
|
+
|
382
|
+
# @!method public_directory=(directory)
|
383
|
+
#
|
384
|
+
# Sets the path to public directory. This directory is used for file downloads.
|
385
|
+
#
|
386
|
+
# This given directory will be appended onto the root directory.
|
387
|
+
#
|
388
|
+
# By default, the public directory is "public".
|
389
|
+
#
|
390
|
+
# @param directory [String] the public directory path
|
391
|
+
#
|
392
|
+
# @return [void]
|
393
|
+
#
|
394
|
+
# @see root_directory
|
395
|
+
# @see public_directory
|
396
|
+
setting :public_directory, DEFAULT_PUBLIC_DIRECTORY
|
397
|
+
|
398
|
+
# Returns the configured public directory, appended onto the root directory.
|
399
|
+
#
|
400
|
+
# @return [String] the fill directory path
|
401
|
+
#
|
402
|
+
# @example
|
403
|
+
# configuration.public_directory = "public"
|
404
|
+
#
|
405
|
+
# configuration.public_directory
|
406
|
+
# # => "/path/to/root/public"
|
407
|
+
#
|
408
|
+
# @see public_directory=
|
409
|
+
# @see root_directory=
|
410
|
+
def public_directory
|
411
|
+
# This must be a string, for Rack compatibility
|
412
|
+
root_directory.join(super).to_s
|
413
|
+
end
|
414
|
+
|
415
|
+
private
|
416
|
+
|
417
|
+
def method_missing(name, *args, &block)
|
418
|
+
if config.respond_to?(name)
|
419
|
+
config.public_send(name, *args, &block)
|
420
|
+
else
|
421
|
+
super
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
def respond_to_missing?(name, _incude_all = false)
|
426
|
+
config.respond_to?(name) || super
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|