hanami-controller 1.3.0 → 2.0.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
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