hanami-controller 1.3.0 → 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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +83 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +297 -538
  5. data/hanami-controller.gemspec +6 -5
  6. data/lib/hanami/action.rb +129 -73
  7. data/lib/hanami/action/application_action.rb +111 -0
  8. data/lib/hanami/action/application_configuration.rb +92 -0
  9. data/lib/hanami/action/application_configuration/cookies.rb +29 -0
  10. data/lib/hanami/action/application_configuration/sessions.rb +46 -0
  11. data/lib/hanami/action/base_params.rb +2 -2
  12. data/lib/hanami/action/cache.rb +1 -139
  13. data/lib/hanami/action/cache/cache_control.rb +4 -4
  14. data/lib/hanami/action/cache/conditional_get.rb +7 -2
  15. data/lib/hanami/action/cache/directives.rb +1 -1
  16. data/lib/hanami/action/cache/expires.rb +3 -3
  17. data/lib/hanami/action/configuration.rb +430 -0
  18. data/lib/hanami/action/cookie_jar.rb +3 -3
  19. data/lib/hanami/action/cookies.rb +3 -62
  20. data/lib/hanami/action/csrf_protection.rb +214 -0
  21. data/lib/hanami/action/flash.rb +102 -207
  22. data/lib/hanami/action/glue.rb +5 -31
  23. data/lib/hanami/action/halt.rb +12 -0
  24. data/lib/hanami/action/mime.rb +78 -485
  25. data/lib/hanami/action/params.rb +3 -3
  26. data/lib/hanami/action/rack/file.rb +1 -1
  27. data/lib/hanami/action/request.rb +30 -20
  28. data/lib/hanami/action/response.rb +193 -0
  29. data/lib/hanami/action/session.rb +11 -128
  30. data/lib/hanami/action/standalone_action.rb +581 -0
  31. data/lib/hanami/action/validatable.rb +2 -2
  32. data/lib/hanami/action/view_name_inferrer.rb +46 -0
  33. data/lib/hanami/controller.rb +0 -227
  34. data/lib/hanami/controller/version.rb +1 -1
  35. data/lib/hanami/http/status.rb +2 -2
  36. metadata +47 -30
  37. data/lib/hanami-controller.rb +0 -1
  38. data/lib/hanami/action/callable.rb +0 -92
  39. data/lib/hanami/action/callbacks.rb +0 -214
  40. data/lib/hanami/action/configurable.rb +0 -50
  41. data/lib/hanami/action/exposable.rb +0 -126
  42. data/lib/hanami/action/exposable/guard.rb +0 -104
  43. data/lib/hanami/action/head.rb +0 -121
  44. data/lib/hanami/action/rack.rb +0 -399
  45. data/lib/hanami/action/rack/callable.rb +0 -47
  46. data/lib/hanami/action/redirect.rb +0 -59
  47. data/lib/hanami/action/throwable.rb +0 -196
  48. data/lib/hanami/controller/configuration.rb +0 -763
@@ -1,47 +0,0 @@
1
- module Hanami
2
- module Action
3
- module Rack
4
- module Callable
5
- # Callable module for actions. With this module, actions with middlewares
6
- # will be able to work with rack builder.
7
- #
8
- # @param env [Hash] the full Rack env or the params. This value may vary,
9
- # see the examples below.
10
- #
11
- # @since 0.4.0
12
- # @api private
13
- #
14
- # @see Hanami::Action::Rack::ClassMethods#rack_builder
15
- # @see Hanami::Action::Rack::ClassMethods#use
16
- #
17
- # @example
18
- # require 'hanami/controller'
19
- #
20
- # class MyMiddleware
21
- # def initialize(app)
22
- # @app = app
23
- # end
24
- #
25
- # def call(env)
26
- # #...
27
- # end
28
- # end
29
- #
30
- # class Show
31
- # include Hanami::Action
32
- # use MyMiddleware
33
- #
34
- # def call(params)
35
- # # ...
36
- # puts params # => { id: 23 } extracted from Rack env
37
- # end
38
- # end
39
- #
40
- # Show.respond_to?(:call) # => true
41
- def call(env)
42
- rack_builder.call(env)
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,59 +0,0 @@
1
- module Hanami
2
- module Action
3
- # HTTP redirect API
4
- #
5
- # @since 0.1.0
6
- module Redirect
7
- # The HTTP header for redirects
8
- #
9
- # @since 0.2.0
10
- # @api private
11
- LOCATION = 'Location'.freeze
12
-
13
- private
14
-
15
- # Redirect to the given URL and halt the request
16
- #
17
- # @param url [String] the destination URL
18
- # @param status [Fixnum] the http code
19
- #
20
- # @since 0.1.0
21
- #
22
- # @see Hanami::Action::Throwable#halt
23
- #
24
- # @example With default status code (302)
25
- # require 'hanami/controller'
26
- #
27
- # class Create
28
- # include Hanami::Action
29
- #
30
- # def call(params)
31
- # # ...
32
- # redirect_to 'http://example.com/articles/23'
33
- # end
34
- # end
35
- #
36
- # action = Create.new
37
- # action.call({}) # => [302, {'Location' => '/articles/23'}, '']
38
- #
39
- # @example With custom status code
40
- # require 'hanami/controller'
41
- #
42
- # class Create
43
- # include Hanami::Action
44
- #
45
- # def call(params)
46
- # # ...
47
- # redirect_to 'http://example.com/articles/23', status: 301
48
- # end
49
- # end
50
- #
51
- # action = Create.new
52
- # action.call({}) # => [301, {'Location' => '/articles/23'}, '']
53
- def redirect_to(url, status: 302)
54
- headers[LOCATION] = ::String.new(url)
55
- halt(status)
56
- end
57
- end
58
- end
59
- end
@@ -1,196 +0,0 @@
1
- require 'hanami/utils/class_attribute'
2
- require 'hanami/http/status'
3
-
4
- module Hanami
5
- module Action
6
- # Throw API
7
- #
8
- # @since 0.1.0
9
- #
10
- # @see Hanami::Action::Throwable::ClassMethods#handle_exception
11
- # @see Hanami::Action::Throwable#halt
12
- # @see Hanami::Action::Throwable#status
13
- module Throwable
14
- # @since 0.2.0
15
- # @api private
16
- RACK_ERRORS = 'rack.errors'.freeze
17
-
18
- # This isn't part of Rack SPEC
19
- #
20
- # Exception notifiers use <tt>rack.exception</tt> instead of
21
- # <tt>rack.errors</tt>, so we need to support it.
22
- #
23
- # @since 0.5.0
24
- # @api private
25
- #
26
- # @see Hanami::Action::Throwable::RACK_ERRORS
27
- # @see http://www.rubydoc.info/github/rack/rack/file/SPEC#The_Error_Stream
28
- # @see https://github.com/hanami/controller/issues/133
29
- RACK_EXCEPTION = 'rack.exception'.freeze
30
-
31
- # @since 0.1.0
32
- # @api private
33
- def self.included(base)
34
- base.extend ClassMethods
35
- end
36
-
37
- # Throw API class methods
38
- #
39
- # @since 0.1.0
40
- # @api private
41
- module ClassMethods
42
- private
43
-
44
- # Handle the given exception with an HTTP status code.
45
- #
46
- # When the exception is raise during #call execution, it will be
47
- # translated into the associated HTTP status.
48
- #
49
- # This is a fine grained control, for a global configuration see
50
- # Hanami::Action.handled_exceptions
51
- #
52
- # @param exception [Hash] the exception class must be the key and the
53
- # HTTP status the value of the hash
54
- #
55
- # @since 0.1.0
56
- #
57
- # @see Hanami::Action.handled_exceptions
58
- #
59
- # @example
60
- # require 'hanami/controller'
61
- #
62
- # class Show
63
- # include Hanami::Action
64
- # handle_exception RecordNotFound => 404
65
- #
66
- # def call(params)
67
- # # ...
68
- # raise RecordNotFound.new
69
- # end
70
- # end
71
- #
72
- # Show.new.call({id: 1}) # => [404, {}, ['Not Found']]
73
- def handle_exception(exception)
74
- configuration.handle_exception(exception)
75
- end
76
- end
77
-
78
- protected
79
-
80
- # Halt the action execution with the given HTTP status code and message.
81
- #
82
- # When used, the execution of a callback or of an action is interrupted
83
- # and the control returns to the framework, that decides how to handle
84
- # the event.
85
- #
86
- # If a message is provided, it sets the response body with the message.
87
- # Otherwise, it sets the response body with the default message associated
88
- # to the code (eg 404 will set `"Not Found"`).
89
- #
90
- # @param code [Fixnum] a valid HTTP status code
91
- # @param message [String] the response body
92
- #
93
- # @since 0.2.0
94
- #
95
- # @see Hanami::Controller#handled_exceptions
96
- # @see Hanami::Action::Throwable#handle_exception
97
- # @see Hanami::Http::Status:ALL
98
- #
99
- # @example Basic usage
100
- # require 'hanami/controller'
101
- #
102
- # class Show
103
- # def call(params)
104
- # halt 404
105
- # end
106
- # end
107
- #
108
- # # => [404, {}, ["Not Found"]]
109
- #
110
- # @example Custom message
111
- # require 'hanami/controller'
112
- #
113
- # class Show
114
- # def call(params)
115
- # halt 404, "This is not the droid you're looking for."
116
- # end
117
- # end
118
- #
119
- # # => [404, {}, ["This is not the droid you're looking for."]]
120
- def halt(code, message = nil)
121
- message ||= Http::Status.message_for(code)
122
- status(code, message)
123
-
124
- throw :halt
125
- end
126
-
127
- # Sets the given code and message for the response
128
- #
129
- # @param code [Fixnum] a valid HTTP status code
130
- # @param message [String] the response body
131
- #
132
- # @since 0.1.0
133
- # @see Hanami::Http::Status:ALL
134
- def status(code, message)
135
- self.status = code
136
- self.body = message
137
- end
138
-
139
- private
140
- # @since 0.1.0
141
- # @api private
142
- def _rescue
143
- catch :halt do
144
- begin
145
- yield
146
- rescue => exception
147
- _reference_in_rack_errors(exception)
148
- _handle_exception(exception)
149
- end
150
- end
151
- end
152
-
153
- # @since 0.2.0
154
- # @api private
155
- def _reference_in_rack_errors(exception)
156
- return if configuration.handled_exception?(exception)
157
-
158
- @_env[RACK_EXCEPTION] = exception
159
-
160
- if errors = @_env[RACK_ERRORS]
161
- errors.write(_dump_exception(exception))
162
- errors.flush
163
- end
164
- end
165
-
166
- # @since 0.2.0
167
- # @api private
168
- def _dump_exception(exception)
169
- [[exception.class, exception.message].compact.join(": "), *exception.backtrace].join("\n\t")
170
- end
171
-
172
- # @since 0.1.0
173
- # @api private
174
- def _handle_exception(exception)
175
- raise unless configuration.handle_exceptions
176
-
177
- instance_exec(
178
- exception,
179
- &_exception_handler(exception)
180
- )
181
- end
182
-
183
- # @since 0.3.0
184
- # @api private
185
- def _exception_handler(exception)
186
- handler = configuration.exception_handler(exception)
187
-
188
- if respond_to?(handler.to_s, true)
189
- method(handler)
190
- else
191
- ->(ex) { halt handler }
192
- end
193
- end
194
- end
195
- end
196
- end
@@ -1,763 +0,0 @@
1
- require 'hanami/utils/class'
2
- require 'hanami/utils/kernel'
3
- require 'hanami/utils/string'
4
-
5
- module Hanami
6
- module Controller
7
- # Configuration for the framework, controllers and actions.
8
- #
9
- # Hanami::Controller has its own global configuration that can be manipulated
10
- # via `Hanami::Controller.configure`.
11
- #
12
- # Every time that `Hanami::Controller` and `Hanami::Action` are included, that
13
- # global configuration is being copied to the recipient. The copy will
14
- # inherit all the settings from the original, but all the subsequent changes
15
- # aren't reflected from the parent to the children, and viceversa.
16
- #
17
- # This architecture allows to have a global configuration that capture the
18
- # most common cases for an application, and let controllers and single
19
- # actions to specify exceptions.
20
- #
21
- # @since 0.2.0
22
- class Configuration
23
- # Default HTTP code for server side errors
24
- #
25
- # @since 0.2.0
26
- # @api private
27
- DEFAULT_ERROR_CODE = 500
28
-
29
- # Default public directory
30
- #
31
- # It serves as base root for file downloads
32
- #
33
- # @since 1.0.0
34
- # @api private
35
- DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
36
-
37
- # Default Mime type to format mapping
38
- #
39
- # @since 0.2.0
40
- # @api private
41
- DEFAULT_FORMATS = {
42
- 'application/octet-stream' => :all,
43
- '*/*' => :all,
44
- 'text/html' => :html
45
- }.freeze
46
-
47
- # Return a copy of the configuration of the framework instance associated
48
- # with the given class.
49
- #
50
- # When multiple instances of Hanami::Controller are used in the same
51
- # application, we want to make sure that a controller or an action will
52
- # receive the expected configuration.
53
- #
54
- # @param base [Class, Module] a controller or an action
55
- #
56
- # @return [Hanami::Controller::Configuration] the configuration associated
57
- # to the given class.
58
- #
59
- # @since 0.2.0
60
- # @api private
61
- #
62
- # @example Direct usage of the framework
63
- # require 'hanami/controller'
64
- #
65
- # class Show
66
- # include Hanami::Action
67
- # end
68
- #
69
- # Hanami::Controller::Configuration.for(Show)
70
- # # => will duplicate from Hanami::Controller
71
- #
72
- # @example Multiple instances of the framework
73
- # require 'hanami/controller'
74
- #
75
- # module MyApp
76
- # Controller = Hanami::Controller.duplicate(self)
77
- #
78
- # module Controllers::Dashboard
79
- # class Index
80
- # include MyApp::Action
81
- #
82
- # def call(params)
83
- # # ...
84
- # end
85
- # end
86
- # end
87
- # end
88
- #
89
- # class Show
90
- # include Hanami::Action
91
- # end
92
- #
93
- # Hanami::Controller::Configuration.for(Show)
94
- # # => will duplicate from Hanami::Controller
95
- #
96
- # Hanami::Controller::Configuration.for(MyApp::Controllers::Dashboard)
97
- # # => will duplicate from MyApp::Controller
98
- def self.for(base)
99
- namespace = Utils::String.namespace(base.name)
100
- framework = Utils::Class.load("#{namespace}::Controller") || Utils::Class.load!('Hanami::Controller')
101
- framework.configuration.duplicate
102
- end
103
-
104
- # Initialize a configuration instance
105
- #
106
- # @return [Hanami::Controller::Configuration] a new configuration's
107
- # instance
108
- #
109
- # @since 0.2.0
110
- def initialize
111
- reset!
112
- end
113
-
114
- # @attr_writer handle_exceptions [TrueClass,FalseClass] Handle exceptions
115
- # with an HTTP status or leave them uncaught
116
- #
117
- # @since 0.2.0
118
- #
119
- # @return void
120
- #
121
- # @see Hanami::Controller::Configuration#handle_exceptions
122
- attr_writer :handle_exceptions
123
-
124
- # Handle exceptions with an HTTP status or let them uncaught
125
- #
126
- # If this value is set to `true`, the configured exceptions will return
127
- # the specified HTTP status, the rest of them with `500`.
128
- #
129
- # If this value is set to `false`, the exceptions won't be caught.
130
- #
131
- # This is part of a DSL, for this reason when this method is called with
132
- # an argument, it will set the corresponding instance variable. When
133
- # called without, it will return the already set value, or the default.
134
- #
135
- # @overload handle_exceptions(value)
136
- # Sets the given value
137
- # @param value [TrueClass, FalseClass] true or false, default to true
138
- #
139
- # @overload handle_exceptions
140
- # Gets the value
141
- # @return [TrueClass, FalseClass]
142
- #
143
- # @since 0.2.0
144
- #
145
- # @see Hanami::Controller::Configuration#handle_exception
146
- # @see Hanami::Controller#configure
147
- # @see Hanami::Action::Throwable
148
- # @see http://httpstatus.es/500
149
- #
150
- # @example Getting the value
151
- # require 'hanami/controller'
152
- #
153
- # Hanami::Controller.configuration.handle_exceptions # => true
154
- #
155
- # @example Setting the value
156
- # require 'hanami/controller'
157
- #
158
- # Hanami::Controller.configure do
159
- # handle_exceptions false
160
- # end
161
- def handle_exceptions(value = nil)
162
- if value.nil?
163
- @handle_exceptions
164
- else
165
- @handle_exceptions = value
166
- end
167
- end
168
-
169
- # Specify how to handle an exception with an HTTP status
170
- #
171
- # Raised exceptions will return the configured HTTP status, only if
172
- # `handled_exceptions` is set on `true`.
173
- #
174
- # @param exception [Hash] the exception class must be the key and the HTTP
175
- # status the value
176
- #
177
- # @since 0.2.0
178
- #
179
- # @see Hanami::Controller::Configuration#handle_exceptions
180
- # @see Hanami::Controller#configure
181
- # @see Hanami::Action::Throwable
182
- #
183
- # @example
184
- # require 'hanami/controller'
185
- #
186
- # Hanami::Controller.configure do
187
- # handle_exception ArgumentError => 400
188
- # end
189
- def handle_exception(exception)
190
- @handled_exceptions.merge!(exception)
191
- _sort_handled_exceptions!
192
- end
193
-
194
- # Return a callable handler for the given exception
195
- #
196
- # @param exception [Exception] an exception
197
- #
198
- # @since 0.3.0
199
- # @api private
200
- #
201
- # @see Hanami::Controller::Configuration#handle_exception
202
- def exception_handler(exception)
203
- exception_handler_for(exception) || DEFAULT_ERROR_CODE
204
- end
205
-
206
- # Check if the given exception is handled.
207
- #
208
- # @param exception [Exception] an exception
209
- #
210
- # @since 0.3.2
211
- # @api private
212
- #
213
- # @see Hanami::Controller::Configuration#handle_exception
214
- def handled_exception?(exception)
215
- handled_exceptions &&
216
- !exception_handler_for(exception).nil?
217
- end
218
-
219
- # Finds configured handler for given exception, or nil if not found.
220
- #
221
- # @param exception [Exception] an exception
222
- #
223
- # @since 1.0.0
224
- # @api private
225
- #
226
- # @see Hanami::Controller::Configuration#handle_exception
227
- def exception_handler_for(exception)
228
- @handled_exceptions.each do |exception_class, handler|
229
- return handler if exception.kind_of?(exception_class)
230
- end
231
-
232
- nil
233
- end
234
-
235
- # Specify which is the default action module to be included when we use
236
- # the `Hanami::Controller.action` method.
237
- #
238
- # This setting is useful when we use multiple instances of the framework
239
- # in the same process, so we want to ensure that the actions will include
240
- # `MyApp::Action`, rather than `AnotherApp::Action`.
241
- #
242
- # If not set, the default value is `Hanami::Action`
243
- #
244
- # This is part of a DSL, for this reason when this method is called with
245
- # an argument, it will set the corresponding instance variable. When
246
- # called without, it will return the already set value, or the default.
247
- #
248
- # @overload action_module(value)
249
- # Sets the given value
250
- # @param value [Module] the module to be included in all the actions
251
- #
252
- # @overload action_module
253
- # Gets the value
254
- # @return [Module]
255
- #
256
- # @since 0.2.0
257
- #
258
- # @see Hanami::Controller::Dsl#action
259
- # @see Hanami::Controller#duplicate
260
- #
261
- # @example Getting the value
262
- # require 'hanami/controller'
263
- #
264
- # Hanami::Controller.configuration.action_module # => Hanami::Action
265
- #
266
- # @example Setting the value
267
- # require 'hanami/controller'
268
- #
269
- # module MyAction
270
- # end
271
- #
272
- # Hanami::Controller.configure do
273
- # action_module MyAction
274
- # end
275
- #
276
- # module Dashboard
277
- # # It includes MyAction, instead of Hanami::Action
278
- # class Index
279
- # include MyAction
280
- #
281
- # def call(params)
282
- # # ...
283
- # end
284
- # end
285
- # end
286
- #
287
- # @example Duplicated framework
288
- # require 'hanami/controller'
289
- #
290
- # module MyApp
291
- # Controller = Hanami::Controller.duplicate(self)
292
- #
293
- # module Controllers::Dashboard
294
- # include MyApp::Controller
295
- #
296
- # # It includes MyApp::Action, instead of Hanami::Action
297
- # class Index
298
- # include MyApp::Action
299
- #
300
- # def call(params)
301
- # # ...
302
- # end
303
- # end
304
- # end
305
- # end
306
- def action_module(value = nil)
307
- if value.nil?
308
- @action_module
309
- else
310
- @action_module = value
311
- end
312
- end
313
-
314
- # Configure the logic to be executed when Hanami::Action is included
315
- # This is useful to DRY code by having a single place where to configure
316
- # shared behaviors like authentication, sessions, cookies etc.
317
- #
318
- # This method can be called multiple times.
319
- #
320
- # @param blk [Proc] the code block
321
- #
322
- # @return [void]
323
- #
324
- # @raise [ArgumentError] if called without passing a block
325
- #
326
- # @since 0.3.0
327
- #
328
- # @see Hanami::Controller.configure
329
- # @see Hanami::Controller.duplicate
330
- #
331
- # @example Configure shared logic.
332
- # require 'hanami/controller'
333
- #
334
- # Hanami::Controller.configure do
335
- # prepare do
336
- # include Hanami::Action::Session
337
- # include MyAuthentication
338
- # use SomeMiddleWare
339
- #
340
- # before { authenticate! }
341
- # end
342
- # end
343
- #
344
- # module Dashboard
345
- # class Index
346
- # # When Hanami::Action is included, it will:
347
- # # * Include `Hanami::Action::Session` and `MyAuthentication`
348
- # # * Configure to use `SomeMiddleWare`
349
- # # * Configure a `before` callback that triggers `#authenticate!`
350
- # include Hanami::Action
351
- #
352
- # def call(params)
353
- # # ...
354
- # end
355
- # end
356
- # end
357
- def prepare(&blk)
358
- if block_given?
359
- @modules.push(blk)
360
- else
361
- raise ArgumentError.new('Please provide a block')
362
- end
363
- end
364
-
365
- # Register a format
366
- #
367
- # @param hash [Hash] the symbol format must be the key and the mime type
368
- # string must be the value of the hash
369
- #
370
- # @since 0.2.0
371
- #
372
- # @see Hanami::Action::Mime
373
- #
374
- # @example
375
- # require 'hanami/controller'
376
- #
377
- # Hanami::Controller.configure do
378
- # format custom: 'application/custom'
379
- # end
380
- #
381
- # module Articles
382
- # class Index
383
- # include Hanami::Action
384
- #
385
- # def call(params)
386
- # # ...
387
- # end
388
- # end
389
- #
390
- # class Show
391
- # include Hanami::Action
392
- #
393
- # def call(params)
394
- # # ...
395
- # self.format = :custom
396
- # end
397
- # end
398
- # end
399
- #
400
- # action = Articles::Index.new
401
- #
402
- # action.call({ 'HTTP_ACCEPT' => 'text/html' })
403
- # # => Content-Type "text/html"
404
- # action.format # => :html
405
- #
406
- # action.call({ 'HTTP_ACCEPT' => 'application/custom' })
407
- # # => Content-Type "application/custom"
408
- # action.format # => :custom
409
- #
410
- #
411
- #
412
- # action = Articles::Show.new
413
- #
414
- # action.call({ 'HTTP_ACCEPT' => 'text/html' })
415
- # # => Content-Type "application/custom"
416
- # action.format # => :custom
417
- def format(hash)
418
- symbol, mime_type = *Utils::Kernel.Array(hash)
419
-
420
- @formats[Utils::Kernel.String(mime_type)] = Utils::Kernel.Symbol(symbol)
421
- @mime_types = nil
422
- end
423
-
424
- # Return the configured format's MIME types
425
- #
426
- # @since 0.8.0
427
- # @api private
428
- #
429
- # @see Hanami::Controller::Configuration#format
430
- # @see Hanami::Action::Mime::MIME_TYPES
431
- def mime_types
432
- @mime_types ||= begin
433
- ((@formats.keys - DEFAULT_FORMATS.keys) +
434
- Hanami::Action::Mime::MIME_TYPES.values).freeze
435
- end
436
- end
437
-
438
- # Restrict the MIME types set only to the given set
439
- #
440
- # @param mime_types [Array] the set of MIME types
441
- #
442
- # @since 1.0.0
443
- # @api private
444
- #
445
- # @see Hanami::Action::Mime::ClassMethods#accept
446
- def restrict_mime_types!(mime_types)
447
- @mime_types = self.mime_types & mime_types
448
- end
449
-
450
- # Set a format as default fallback for all the requests without a strict
451
- # requirement for the mime type.
452
- #
453
- # The given format must be coercible to a symbol, and be a valid mime type
454
- # alias. If it isn't, at the runtime the framework will raise a
455
- # `Hanami::Controller::UnknownFormatError`.
456
- #
457
- # By default this value is nil.
458
- #
459
- # This is part of a DSL, for this reason when this method is called with
460
- # an argument, it will set the corresponding instance variable. When
461
- # called without, it will return the already set value, or the default.
462
- #
463
- # @overload default_request_format(format)
464
- # Sets the given value
465
- # @param format [#to_sym] the symbol format
466
- # @raise [TypeError] if it cannot be coerced to a symbol
467
- #
468
- # @overload default_request_format
469
- # Gets the value
470
- # @return [Symbol,nil]
471
- #
472
- # @since 0.5.0
473
- #
474
- # @see Hanami::Action::Mime
475
- #
476
- # @example Getting the value
477
- # require 'hanami/controller'
478
- #
479
- # Hanami::Controller.configuration.default_request_format # => nil
480
- #
481
- # @example Setting the value
482
- # require 'hanami/controller'
483
- #
484
- # Hanami::Controller.configure do
485
- # default_request_format :html
486
- # end
487
- def default_request_format(format = nil)
488
- if format
489
- @default_request_format = Utils::Kernel.Symbol(format)
490
- else
491
- @default_request_format
492
- end
493
- end
494
-
495
- # Set a format to be used for all responses regardless of the request type.
496
- #
497
- # The given format must be coercible to a symbol, and be a valid mime type
498
- # alias. If it isn't, at the runtime the framework will raise a
499
- # `Hanami::Controller::UnknownFormatError`.
500
- #
501
- # By default this value is nil.
502
- #
503
- # This is part of a DSL, for this reason when this method is called with
504
- # an argument, it will set the corresponding instance variable. When
505
- # called without, it will return the already set value, or the default.
506
- #
507
- # @overload default_response_format(format)
508
- # Sets the given value
509
- # @param format [#to_sym] the symbol format
510
- # @raise [TypeError] if it cannot be coerced to a symbol
511
- #
512
- # @overload default_response_format
513
- # Gets the value
514
- # @return [Symbol,nil]
515
- #
516
- # @since 0.5.0
517
- #
518
- # @see Hanami::Action::Mime
519
- #
520
- # @example Getting the value
521
- # require 'hanami/controller'
522
- #
523
- # Hanami::Controller.configuration.default_response_format # => nil
524
- #
525
- # @example Setting the value
526
- # require 'hanami/controller'
527
- #
528
- # Hanami::Controller.configure do
529
- # default_response_format :json
530
- # end
531
- def default_response_format(format = nil)
532
- if format
533
- @default_response_format = Utils::Kernel.Symbol(format)
534
- else
535
- @default_response_format
536
- end
537
- end
538
-
539
- # Set a charset as default fallback for all the requests without a strict
540
- # requirement for the charset.
541
- #
542
- # By default this value is nil.
543
- #
544
- # @since 0.3.0
545
- #
546
- # @see Hanami::Action::Mime
547
- #
548
- # @example Getting the value
549
- # require 'hanami/controller'
550
- #
551
- # Hanami::Controller.configuration.default_charset # => nil
552
- #
553
- # @example Setting the value
554
- # require 'hanami/controller'
555
- #
556
- # Hanami::Controller.configure do
557
- # default_charset 'koi8-r'
558
- # end
559
- def default_charset(charset = nil)
560
- if charset
561
- @default_charset = charset
562
- else
563
- @default_charset
564
- end
565
- end
566
-
567
- # Set default headers for all responses
568
- #
569
- # By default this value is an empty hash.
570
- #
571
- # @since 0.4.0
572
- #
573
- # @example Getting the value
574
- # require 'hanami/controller'
575
- #
576
- # Hanami::Controller.configuration.default_headers # => {}
577
- #
578
- # @example Setting the value
579
- # require 'hanami/controller'
580
- #
581
- # Hanami::Controller.configure do
582
- # default_headers({
583
- # 'X-Frame-Options' => 'DENY'
584
- # })
585
- # end
586
- def default_headers(headers = nil)
587
- if headers
588
- @default_headers.merge!(
589
- headers.reject {|_,v| v.nil? }
590
- )
591
- else
592
- @default_headers
593
- end
594
- end
595
-
596
- # Set default cookies options for all responses
597
- #
598
- # By default this value is an empty hash.
599
- #
600
- # @since 0.4.0
601
- #
602
- # @example Getting the value
603
- # require 'hanami/controller'
604
- #
605
- # Hanami::Controller.configuration.cookies # => {}
606
- #
607
- # @example Setting the value
608
- # require 'hanami/controller'
609
- #
610
- # Hanami::Controller.configure do
611
- # cookies({
612
- # domain: 'hanamirb.org',
613
- # path: '/controller',
614
- # secure: true,
615
- # httponly: true
616
- # })
617
- # end
618
- def cookies(options = nil)
619
- if options
620
- @cookies.merge!(
621
- options.reject { |_, v| v.nil? }
622
- )
623
- else
624
- @cookies
625
- end
626
- end
627
-
628
- # Returns a format for the given mime type
629
- #
630
- # @param mime_type [#to_s,#to_str] A mime type
631
- #
632
- # @return [Symbol,nil] the corresponding format, if present
633
- #
634
- # @see Hanami::Controller::Configuration#format
635
- #
636
- # @since 0.2.0
637
- # @api private
638
- def format_for(mime_type)
639
- @formats[mime_type]
640
- end
641
-
642
- # Returns a mime type for the given format
643
- #
644
- # @param format [#to_sym] a format
645
- #
646
- # @return [String,nil] the corresponding mime type, if present
647
- #
648
- # @since 0.2.0
649
- # @api private
650
- def mime_type_for(format)
651
- @formats.key(format)
652
- end
653
-
654
- # @api private
655
- # @since 1.0.0
656
- attr_reader :root_directory
657
-
658
- def public_directory(value = nil)
659
- if value.nil?
660
- @public_directory
661
- else
662
- @public_directory = root_directory.join(value).to_s
663
- end
664
- end
665
-
666
- # Duplicate by copying the settings in a new instance.
667
- #
668
- # @return [Hanami::Controller::Configuration] a copy of the configuration
669
- #
670
- # @since 0.2.0
671
- # @api private
672
- def duplicate
673
- Configuration.new.tap do |c|
674
- c.handle_exceptions = handle_exceptions
675
- c.handled_exceptions = handled_exceptions.dup
676
- c.action_module = action_module
677
- c.modules = modules.dup
678
- c.formats = formats.dup
679
- c.default_request_format = default_request_format
680
- c.default_response_format = default_response_format
681
- c.default_charset = default_charset
682
- c.default_headers = default_headers.dup
683
- c.public_directory = public_directory
684
- c.cookies = cookies.dup
685
- end
686
- end
687
-
688
- # Return included modules
689
- #
690
- # @return [Array<Proc>] array of included blocks
691
- #
692
- # @since 0.2.0
693
- # @api private
694
- #
695
- # @see Hanami::Controller::Configuration#prepare
696
- attr_reader :modules
697
-
698
- # Reset all the values to the defaults
699
- #
700
- # @since 0.2.0
701
- # @api private
702
- def reset!
703
- @handle_exceptions = true
704
- @handled_exceptions = {}
705
- @modules = []
706
- @formats = DEFAULT_FORMATS.dup
707
- @mime_types = nil
708
- @default_request_format = nil
709
- @default_response_format = nil
710
- @default_charset = nil
711
- @default_headers = {}
712
- @cookies = {}
713
- @root_directory = ::Pathname.new(Dir.pwd).realpath
714
- @public_directory = root_directory.join(DEFAULT_PUBLIC_DIRECTORY).to_s
715
- @action_module = ::Hanami::Action
716
- end
717
-
718
- # Copy the configuration for the given action
719
- #
720
- # @param base [Class] the target action
721
- #
722
- # @return void
723
- #
724
- # @since 0.3.0
725
- # @api private
726
- #
727
- # @see Hanami::Controller::Configurable.included
728
- def copy!(base)
729
- modules.each do |mod|
730
- base.class_eval(&mod)
731
- end
732
- end
733
-
734
- # Load the framework
735
- #
736
- # @since 0.3.0
737
- # @api private
738
- def load!
739
- freeze
740
- end
741
-
742
- protected
743
- # @since 0.5.0
744
- # @api private
745
- def _sort_handled_exceptions!
746
- @handled_exceptions = Hash[
747
- @handled_exceptions.sort{|(ex1,_),(ex2,_)| ex1.ancestors.include?(ex2) ? -1 : 1 }
748
- ]
749
- end
750
-
751
- attr_accessor :handled_exceptions
752
- attr_accessor :formats
753
- attr_writer :action_module
754
- attr_writer :modules
755
- attr_writer :default_request_format
756
- attr_writer :default_response_format
757
- attr_writer :default_charset
758
- attr_writer :default_headers
759
- attr_writer :cookies
760
- attr_writer :public_directory
761
- end
762
- end
763
- end