hanami-controller 1.3.3 → 2.0.0.alpha4
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 +82 -0
- data/LICENSE.md +1 -1
- data/README.md +299 -537
- data/hanami-controller.gemspec +4 -3
- data/lib/hanami/action/application_action.rb +131 -0
- data/lib/hanami/action/application_configuration/content_security_policy.rb +118 -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/application_configuration.rb +90 -0
- data/lib/hanami/action/base_params.rb +2 -2
- data/lib/hanami/action/cache/cache_control.rb +4 -4
- data/lib/hanami/action/cache/conditional_get.rb +3 -1
- data/lib/hanami/action/cache/directives.rb +1 -1
- data/lib/hanami/action/cache/expires.rb +3 -3
- data/lib/hanami/action/cache.rb +1 -139
- data/lib/hanami/action/configuration.rb +428 -0
- data/lib/hanami/action/cookie_jar.rb +3 -3
- data/lib/hanami/action/cookies.rb +3 -62
- data/lib/hanami/action/csrf_protection.rb +214 -0
- data/lib/hanami/action/flash.rb +102 -207
- data/lib/hanami/action/glue.rb +5 -31
- data/lib/hanami/action/halt.rb +12 -0
- data/lib/hanami/action/mime.rb +78 -485
- data/lib/hanami/action/params.rb +2 -2
- data/lib/hanami/action/rack/file.rb +1 -1
- data/lib/hanami/action/request.rb +30 -20
- data/lib/hanami/action/response.rb +193 -0
- data/lib/hanami/action/session.rb +11 -128
- data/lib/hanami/action/standalone_action.rb +578 -0
- data/lib/hanami/action/validatable.rb +1 -1
- data/lib/hanami/action/view_name_inferrer.rb +46 -0
- data/lib/hanami/action.rb +129 -73
- data/lib/hanami/controller/version.rb +1 -1
- data/lib/hanami/controller.rb +0 -227
- data/lib/hanami/http/status.rb +2 -2
- metadata +44 -26
- data/lib/hanami/action/callable.rb +0 -92
- data/lib/hanami/action/callbacks.rb +0 -214
- data/lib/hanami/action/configurable.rb +0 -50
- data/lib/hanami/action/exposable/guard.rb +0 -104
- data/lib/hanami/action/exposable.rb +0 -126
- data/lib/hanami/action/head.rb +0 -121
- data/lib/hanami/action/rack/callable.rb +0 -47
- data/lib/hanami/action/rack/errors.rb +0 -53
- data/lib/hanami/action/rack.rb +0 -411
- data/lib/hanami/action/redirect.rb +0 -59
- data/lib/hanami/action/throwable.rb +0 -169
- data/lib/hanami/controller/configuration.rb +0 -763
- data/lib/hanami-controller.rb +0 -1
@@ -1,92 +0,0 @@
|
|
1
|
-
module Hanami
|
2
|
-
module Action
|
3
|
-
module Callable
|
4
|
-
# Execute application logic.
|
5
|
-
# It implements the Rack protocol.
|
6
|
-
#
|
7
|
-
# The request params are passed as an argument to the `#call` method.
|
8
|
-
#
|
9
|
-
# If routed with Hanami::Router, it extracts the relevant bits from the
|
10
|
-
# Rack `env` (eg the requested `:id`).
|
11
|
-
#
|
12
|
-
# Otherwise everything it's passed as it is: the full Rack `env`
|
13
|
-
# in production, and the given `Hash` for unit tests. See the examples
|
14
|
-
# below.
|
15
|
-
#
|
16
|
-
# Application developers are forced to implement this method in their
|
17
|
-
# actions.
|
18
|
-
#
|
19
|
-
# @param env [Hash] the full Rack env or the params. This value may vary,
|
20
|
-
# see the examples below.
|
21
|
-
#
|
22
|
-
# @return [Array] a serialized Rack response (eg. `[200, {}, ["Hi!"]]`)
|
23
|
-
#
|
24
|
-
# @since 0.1.0
|
25
|
-
#
|
26
|
-
# @example with Hanami::Router
|
27
|
-
# require 'hanami/controller'
|
28
|
-
#
|
29
|
-
# class Show
|
30
|
-
# include Hanami::Action
|
31
|
-
#
|
32
|
-
# def call(params)
|
33
|
-
# # ...
|
34
|
-
# puts params # => { id: 23 } extracted from Rack env
|
35
|
-
# end
|
36
|
-
# end
|
37
|
-
#
|
38
|
-
# @example Standalone
|
39
|
-
# require 'hanami/controller'
|
40
|
-
#
|
41
|
-
# class Show
|
42
|
-
# include Hanami::Action
|
43
|
-
#
|
44
|
-
# def call(params)
|
45
|
-
# # ...
|
46
|
-
# puts params
|
47
|
-
# # => { :"rack.version"=>[1, 2],
|
48
|
-
# # :"rack.input"=>#<StringIO:0x007fa563463948>, ... }
|
49
|
-
# end
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# @example Unit Testing
|
53
|
-
# require 'hanami/controller'
|
54
|
-
#
|
55
|
-
# class Show
|
56
|
-
# include Hanami::Action
|
57
|
-
#
|
58
|
-
# def call(params)
|
59
|
-
# # ...
|
60
|
-
# puts params # => { id: 23, key: 'value' } passed as it is from testing
|
61
|
-
# end
|
62
|
-
# end
|
63
|
-
#
|
64
|
-
# action = Show.new
|
65
|
-
# response = action.call({ id: 23, key: 'value' })
|
66
|
-
def call(env)
|
67
|
-
_rescue do
|
68
|
-
@_env = env
|
69
|
-
@headers = ::Rack::Utils::HeaderHash.new(configuration.default_headers)
|
70
|
-
@params = self.class.params_class.new(@_env)
|
71
|
-
super @params
|
72
|
-
end
|
73
|
-
|
74
|
-
finish
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
# Prepare the Rack response before the control is returned to the
|
80
|
-
# webserver.
|
81
|
-
#
|
82
|
-
# @since 0.1.0
|
83
|
-
# @api private
|
84
|
-
#
|
85
|
-
# @see Hanami::Action#finish
|
86
|
-
def finish
|
87
|
-
super
|
88
|
-
response
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,214 +0,0 @@
|
|
1
|
-
require 'hanami/utils/class_attribute'
|
2
|
-
require 'hanami/utils/callbacks'
|
3
|
-
|
4
|
-
module Hanami
|
5
|
-
module Action
|
6
|
-
# Before and after callbacks
|
7
|
-
#
|
8
|
-
# @since 0.1.0
|
9
|
-
# @see Hanami::Action::ClassMethods#before
|
10
|
-
# @see Hanami::Action::ClassMethods#after
|
11
|
-
module Callbacks
|
12
|
-
# Override Ruby's hook for modules.
|
13
|
-
# It includes callbacks logic
|
14
|
-
#
|
15
|
-
# @param base [Class] the target action
|
16
|
-
#
|
17
|
-
# @since 0.1.0
|
18
|
-
# @api private
|
19
|
-
#
|
20
|
-
# @see http://www.ruby-doc.org/core/Module.html#method-i-included
|
21
|
-
def self.included(base)
|
22
|
-
base.class_eval do
|
23
|
-
extend ClassMethods
|
24
|
-
prepend InstanceMethods
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Callbacks API class methods
|
29
|
-
#
|
30
|
-
# @since 0.1.0
|
31
|
-
# @api private
|
32
|
-
module ClassMethods
|
33
|
-
# Override Ruby's hook for modules.
|
34
|
-
# It includes callbacks logic
|
35
|
-
#
|
36
|
-
# @param base [Class] the target action
|
37
|
-
#
|
38
|
-
# @since 0.1.0
|
39
|
-
# @api private
|
40
|
-
#
|
41
|
-
# @see http://www.ruby-doc.org/core/Module.html#method-i-extended
|
42
|
-
def self.extended(base)
|
43
|
-
base.class_eval do
|
44
|
-
include Utils::ClassAttribute
|
45
|
-
|
46
|
-
class_attribute :before_callbacks
|
47
|
-
self.before_callbacks = Utils::Callbacks::Chain.new
|
48
|
-
|
49
|
-
class_attribute :after_callbacks
|
50
|
-
self.after_callbacks = Utils::Callbacks::Chain.new
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Define a callback for an Action.
|
55
|
-
# The callback will be executed **before** the action is called, in the
|
56
|
-
# order they are added.
|
57
|
-
#
|
58
|
-
# @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
|
59
|
-
# each of them is representing a name of a method available in the
|
60
|
-
# context of the Action.
|
61
|
-
#
|
62
|
-
# @param blk [Proc] an anonymous function to be executed
|
63
|
-
#
|
64
|
-
# @return [void]
|
65
|
-
#
|
66
|
-
# @since 0.3.2
|
67
|
-
#
|
68
|
-
# @see Hanami::Action::Callbacks::ClassMethods#append_after
|
69
|
-
#
|
70
|
-
# @example Method names (symbols)
|
71
|
-
# require 'hanami/controller'
|
72
|
-
#
|
73
|
-
# class Show
|
74
|
-
# include Hanami::Action
|
75
|
-
#
|
76
|
-
# before :authenticate, :set_article
|
77
|
-
#
|
78
|
-
# def call(params)
|
79
|
-
# end
|
80
|
-
#
|
81
|
-
# private
|
82
|
-
# def authenticate
|
83
|
-
# # ...
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# # `params` in the method signature is optional
|
87
|
-
# def set_article(params)
|
88
|
-
# @article = Article.find params[:id]
|
89
|
-
# end
|
90
|
-
# end
|
91
|
-
#
|
92
|
-
# # The order of execution will be:
|
93
|
-
# #
|
94
|
-
# # 1. #authenticate
|
95
|
-
# # 2. #set_article
|
96
|
-
# # 3. #call
|
97
|
-
#
|
98
|
-
# @example Anonymous functions (Procs)
|
99
|
-
# require 'hanami/controller'
|
100
|
-
#
|
101
|
-
# class Show
|
102
|
-
# include Hanami::Action
|
103
|
-
#
|
104
|
-
# before { ... } # 1 do some authentication stuff
|
105
|
-
# before {|params| @article = Article.find params[:id] } # 2
|
106
|
-
#
|
107
|
-
# def call(params)
|
108
|
-
# end
|
109
|
-
# end
|
110
|
-
#
|
111
|
-
# # The order of execution will be:
|
112
|
-
# #
|
113
|
-
# # 1. authentication
|
114
|
-
# # 2. set the article
|
115
|
-
# # 3. #call
|
116
|
-
def append_before(*callbacks, &blk)
|
117
|
-
before_callbacks.append(*callbacks, &blk)
|
118
|
-
end
|
119
|
-
|
120
|
-
# @since 0.1.0
|
121
|
-
alias_method :before, :append_before
|
122
|
-
|
123
|
-
# Define a callback for an Action.
|
124
|
-
# The callback will be executed **after** the action is called, in the
|
125
|
-
# order they are added.
|
126
|
-
#
|
127
|
-
# @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
|
128
|
-
# each of them is representing a name of a method available in the
|
129
|
-
# context of the Action.
|
130
|
-
#
|
131
|
-
# @param blk [Proc] an anonymous function to be executed
|
132
|
-
#
|
133
|
-
# @return [void]
|
134
|
-
#
|
135
|
-
# @since 0.3.2
|
136
|
-
#
|
137
|
-
# @see Hanami::Action::Callbacks::ClassMethods#append_before
|
138
|
-
def append_after(*callbacks, &blk)
|
139
|
-
after_callbacks.append(*callbacks, &blk)
|
140
|
-
end
|
141
|
-
|
142
|
-
# @since 0.1.0
|
143
|
-
alias_method :after, :append_after
|
144
|
-
|
145
|
-
# Define a callback for an Action.
|
146
|
-
# The callback will be executed **before** the action is called.
|
147
|
-
# It will add the callback at the beginning of the callbacks' chain.
|
148
|
-
#
|
149
|
-
# @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
|
150
|
-
# each of them is representing a name of a method available in the
|
151
|
-
# context of the Action.
|
152
|
-
#
|
153
|
-
# @param blk [Proc] an anonymous function to be executed
|
154
|
-
#
|
155
|
-
# @return [void]
|
156
|
-
#
|
157
|
-
# @since 0.3.2
|
158
|
-
#
|
159
|
-
# @see Hanami::Action::Callbacks::ClassMethods#prepend_after
|
160
|
-
def prepend_before(*callbacks, &blk)
|
161
|
-
before_callbacks.prepend(*callbacks, &blk)
|
162
|
-
end
|
163
|
-
|
164
|
-
# Define a callback for an Action.
|
165
|
-
# The callback will be executed **after** the action is called.
|
166
|
-
# It will add the callback at the beginning of the callbacks' chain.
|
167
|
-
#
|
168
|
-
# @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
|
169
|
-
# each of them is representing a name of a method available in the
|
170
|
-
# context of the Action.
|
171
|
-
#
|
172
|
-
# @param blk [Proc] an anonymous function to be executed
|
173
|
-
#
|
174
|
-
# @return [void]
|
175
|
-
#
|
176
|
-
# @since 0.3.2
|
177
|
-
#
|
178
|
-
# @see Hanami::Action::Callbacks::ClassMethods#prepend_before
|
179
|
-
def prepend_after(*callbacks, &blk)
|
180
|
-
after_callbacks.prepend(*callbacks, &blk)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
# Callbacks API instance methods
|
185
|
-
#
|
186
|
-
# @since 0.1.0
|
187
|
-
# @api private
|
188
|
-
module InstanceMethods
|
189
|
-
# Implements the Rack/Hanami::Action protocol
|
190
|
-
#
|
191
|
-
# @since 0.1.0
|
192
|
-
# @api private
|
193
|
-
def call(params)
|
194
|
-
_run_before_callbacks(params)
|
195
|
-
super
|
196
|
-
_run_after_callbacks(params)
|
197
|
-
end
|
198
|
-
|
199
|
-
private
|
200
|
-
# @since 0.1.0
|
201
|
-
# @api private
|
202
|
-
def _run_before_callbacks(params)
|
203
|
-
self.class.before_callbacks.run(self, params)
|
204
|
-
end
|
205
|
-
|
206
|
-
# @since 0.1.0
|
207
|
-
# @api private
|
208
|
-
def _run_after_callbacks(params)
|
209
|
-
self.class.after_callbacks.run(self, params)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'hanami/utils/class_attribute'
|
2
|
-
|
3
|
-
module Hanami
|
4
|
-
module Action
|
5
|
-
# Configuration API
|
6
|
-
#
|
7
|
-
# @since 0.2.0
|
8
|
-
#
|
9
|
-
# @see Hanami::Controller::Configuration
|
10
|
-
module Configurable
|
11
|
-
# Override Ruby's hook for modules.
|
12
|
-
# It includes configuration logic
|
13
|
-
#
|
14
|
-
# @param base [Class] the target action
|
15
|
-
#
|
16
|
-
# @since 0.2.0
|
17
|
-
# @api private
|
18
|
-
#
|
19
|
-
# @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
|
20
|
-
#
|
21
|
-
# @example
|
22
|
-
# require 'hanami/controller'
|
23
|
-
#
|
24
|
-
# class Show
|
25
|
-
# include Hanami::Action
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
# Show.configuration
|
29
|
-
def self.included(base)
|
30
|
-
config = Hanami::Controller::Configuration.for(base)
|
31
|
-
|
32
|
-
base.class_eval do
|
33
|
-
include Utils::ClassAttribute
|
34
|
-
|
35
|
-
class_attribute :configuration
|
36
|
-
self.configuration = config
|
37
|
-
end
|
38
|
-
|
39
|
-
config.copy!(base)
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
# @since 0.2.0
|
45
|
-
def configuration
|
46
|
-
self.class.configuration
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'hanami/controller/error'
|
2
|
-
|
3
|
-
module Hanami
|
4
|
-
module Controller
|
5
|
-
# Exposure of reserved words
|
6
|
-
#
|
7
|
-
# @since 0.7.1
|
8
|
-
class IllegalExposureError < Error
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
module Action
|
13
|
-
module Exposable
|
14
|
-
# Guard for Exposures API.
|
15
|
-
# Prevents exposure of reserved words
|
16
|
-
#
|
17
|
-
# @since 0.7.1
|
18
|
-
# @api private
|
19
|
-
#
|
20
|
-
# @see Hanami::Action::Exposable::Guard::ClassMethods#expose
|
21
|
-
# @see Hanami::Action::Exposable::Guard::ClassMethods#reserved_word?
|
22
|
-
module Guard
|
23
|
-
# Override Ruby's hook for modules.
|
24
|
-
# It prepends a guard for the exposures logic
|
25
|
-
#
|
26
|
-
# @param base [Class] the target action
|
27
|
-
#
|
28
|
-
# @since 0.7.1
|
29
|
-
# @api private
|
30
|
-
#
|
31
|
-
# @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
|
32
|
-
def self.included(base)
|
33
|
-
class << base
|
34
|
-
prepend ClassMethods
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Exposures API Guard class methods
|
39
|
-
#
|
40
|
-
# @since 0.7.1
|
41
|
-
# @api private
|
42
|
-
module ClassMethods
|
43
|
-
# Prevents exposure if names contain a reserved word.
|
44
|
-
#
|
45
|
-
# @param names [Array<Symbol>] the name(s) of the attribute(s) to be
|
46
|
-
# exposed
|
47
|
-
#
|
48
|
-
# @return [void]
|
49
|
-
#
|
50
|
-
# @since 0.7.1
|
51
|
-
# @api private
|
52
|
-
def expose(*names)
|
53
|
-
detect_reserved_words!(names)
|
54
|
-
|
55
|
-
super
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
# Raises error if given names contain a reserved word.
|
61
|
-
#
|
62
|
-
# @param names [Array<Symbol>] a list of names to be checked.
|
63
|
-
#
|
64
|
-
# @return [void]
|
65
|
-
#
|
66
|
-
# @raise [IllegalExposeError] if names contain one or more of reserved
|
67
|
-
# words
|
68
|
-
#
|
69
|
-
# @since 0.7.1
|
70
|
-
# @api private
|
71
|
-
def detect_reserved_words!(names)
|
72
|
-
names.each do |name|
|
73
|
-
if reserved_word?(name)
|
74
|
-
raise Hanami::Controller::IllegalExposureError.new("#{name} is a reserved word. It cannot be exposed")
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Checks if a string is a reserved word
|
80
|
-
#
|
81
|
-
# Reserved word is a name of the method defined in one of the modules
|
82
|
-
# of a given namespace.
|
83
|
-
#
|
84
|
-
# @param name [Symbol] the word to be checked
|
85
|
-
# @param namespace [String] the namespace containing internal modules
|
86
|
-
#
|
87
|
-
# @return [true, false]
|
88
|
-
#
|
89
|
-
# @since 0.7.1
|
90
|
-
# @api private
|
91
|
-
def reserved_word?(name, namespace = 'Hanami')
|
92
|
-
if method_defined?(name) || private_method_defined?(name)
|
93
|
-
method_owner = instance_method(name).owner
|
94
|
-
|
95
|
-
Utils::String.namespace(method_owner) == namespace
|
96
|
-
else
|
97
|
-
false
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
require 'hanami/action/exposable/guard'
|
2
|
-
|
3
|
-
module Hanami
|
4
|
-
module Action
|
5
|
-
# Exposures API
|
6
|
-
#
|
7
|
-
# @since 0.1.0
|
8
|
-
#
|
9
|
-
# @see Hanami::Action::Exposable::ClassMethods#expose
|
10
|
-
module Exposable
|
11
|
-
# Override Ruby's hook for modules.
|
12
|
-
# It includes exposures logic
|
13
|
-
#
|
14
|
-
# @param base [Class] the target action
|
15
|
-
#
|
16
|
-
# @since 0.1.0
|
17
|
-
# @api private
|
18
|
-
#
|
19
|
-
# @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
|
20
|
-
def self.included(base)
|
21
|
-
base.class_eval do
|
22
|
-
extend ClassMethods
|
23
|
-
include Guard
|
24
|
-
|
25
|
-
_expose :params
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Exposures API class methods
|
30
|
-
#
|
31
|
-
# @since 0.1.0
|
32
|
-
# @api private
|
33
|
-
module ClassMethods
|
34
|
-
# Expose the given attributes on the outside of the object with
|
35
|
-
# a getter and a special method called #exposures.
|
36
|
-
#
|
37
|
-
# @param names [Array<Symbol>] the name(s) of the attribute(s) to be
|
38
|
-
# exposed
|
39
|
-
#
|
40
|
-
# @return [void]
|
41
|
-
#
|
42
|
-
# @since 0.1.0
|
43
|
-
#
|
44
|
-
# @example
|
45
|
-
# require 'hanami/controller'
|
46
|
-
#
|
47
|
-
# class Show
|
48
|
-
# include Hanami::Action
|
49
|
-
#
|
50
|
-
# expose :article, :tags
|
51
|
-
#
|
52
|
-
# def call(params)
|
53
|
-
# @article = Article.find params[:id]
|
54
|
-
# @tags = Tag.for(article)
|
55
|
-
# end
|
56
|
-
# end
|
57
|
-
#
|
58
|
-
# action = Show.new
|
59
|
-
# action.call({id: 23})
|
60
|
-
#
|
61
|
-
# action.article # => #<Article ...>
|
62
|
-
# action.tags # => [#<Tag ...>, #<Tag ...>]
|
63
|
-
#
|
64
|
-
# action.exposures # => { :article => #<Article ...>, :tags => [ ... ] }
|
65
|
-
def expose(*names)
|
66
|
-
class_eval do
|
67
|
-
names.each do |name|
|
68
|
-
attr_reader(name) unless attr_reader?(name)
|
69
|
-
end
|
70
|
-
|
71
|
-
exposures.push(*names)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Alias of #expose to be used in internal modules.
|
76
|
-
# #_expose is not watched by the Guard
|
77
|
-
alias _expose expose
|
78
|
-
|
79
|
-
# Set of exposures attribute names
|
80
|
-
#
|
81
|
-
# @return [Array] the exposures attribute names
|
82
|
-
#
|
83
|
-
# @since 0.1.0
|
84
|
-
# @api private
|
85
|
-
def exposures
|
86
|
-
@exposures ||= []
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
# Check if the attr_reader is already defined
|
91
|
-
#
|
92
|
-
# @since 0.3.0
|
93
|
-
# @api private
|
94
|
-
def attr_reader?(name)
|
95
|
-
(instance_methods | private_instance_methods).include?(name)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# Set of exposures
|
100
|
-
#
|
101
|
-
# @return [Hash] the exposures
|
102
|
-
#
|
103
|
-
# @since 0.1.0
|
104
|
-
#
|
105
|
-
# @see Hanami::Action::Exposable::ClassMethods.expose
|
106
|
-
def exposures
|
107
|
-
@exposures ||= {}.tap do |result|
|
108
|
-
self.class.exposures.each do |name|
|
109
|
-
result[name] = send(name)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Finalize the response
|
115
|
-
#
|
116
|
-
# @since 0.3.0
|
117
|
-
# @api private
|
118
|
-
#
|
119
|
-
# @see Hanami::Action#finish
|
120
|
-
def finish
|
121
|
-
super
|
122
|
-
exposures
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
data/lib/hanami/action/head.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
module Hanami
|
2
|
-
module Action
|
3
|
-
# Ensures to not send body or headers for HEAD requests and/or for status
|
4
|
-
# codes that doesn't allow them.
|
5
|
-
#
|
6
|
-
# @since 0.3.2
|
7
|
-
#
|
8
|
-
# @see http://www.ietf.org/rfc/rfc2616.txt
|
9
|
-
module Head
|
10
|
-
|
11
|
-
# Status codes that by RFC must not include a message body
|
12
|
-
#
|
13
|
-
# @since 0.3.2
|
14
|
-
# @api private
|
15
|
-
HTTP_STATUSES_WITHOUT_BODY = Set.new((100..199).to_a << 204 << 205 << 304).freeze
|
16
|
-
|
17
|
-
|
18
|
-
# Entity headers allowed in blank body responses, according to
|
19
|
-
# RFC 2616 - Section 10 (HTTP 1.1).
|
20
|
-
#
|
21
|
-
# "The response MAY include new or updated metainformation in the form
|
22
|
-
# of entity-headers".
|
23
|
-
#
|
24
|
-
# @since 0.4.0
|
25
|
-
# @api private
|
26
|
-
#
|
27
|
-
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5
|
28
|
-
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html
|
29
|
-
ENTITY_HEADERS = {
|
30
|
-
'Allow' => true,
|
31
|
-
'Content-Encoding' => true,
|
32
|
-
'Content-Language' => true,
|
33
|
-
'Content-Location' => true,
|
34
|
-
'Content-MD5' => true,
|
35
|
-
'Content-Range' => true,
|
36
|
-
'Expires' => true,
|
37
|
-
'Last-Modified' => true,
|
38
|
-
'extension-header' => true
|
39
|
-
}.freeze
|
40
|
-
|
41
|
-
# Ensures to not send body or headers for HEAD requests and/or for status
|
42
|
-
# codes that doesn't allow them.
|
43
|
-
#
|
44
|
-
# @since 0.3.2
|
45
|
-
# @api private
|
46
|
-
#
|
47
|
-
# @see Hanami::Action#finish
|
48
|
-
def finish
|
49
|
-
super
|
50
|
-
|
51
|
-
if _requires_no_body?
|
52
|
-
@_body = nil
|
53
|
-
@headers.reject! {|header,_| !keep_response_header?(header) }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
protected
|
58
|
-
# @since 0.3.2
|
59
|
-
# @api private
|
60
|
-
def _requires_no_body?
|
61
|
-
HTTP_STATUSES_WITHOUT_BODY.include?(@_status) || head?
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
# According to RFC 2616, when a response MUST have an empty body, it only
|
66
|
-
# allows Entity Headers.
|
67
|
-
#
|
68
|
-
# For instance, a <tt>204</tt> doesn't allow <tt>Content-Type</tt> or any
|
69
|
-
# other custom header.
|
70
|
-
#
|
71
|
-
# This restriction is enforced by <tt>Hanami::Action::Head#finish</tt>.
|
72
|
-
#
|
73
|
-
# However, there are cases that demand to bypass this rule to set meta
|
74
|
-
# informations via headers.
|
75
|
-
#
|
76
|
-
# An example is a <tt>DELETE</tt> request for a JSON API application.
|
77
|
-
# It returns a <tt>204</tt> but still wants to specify the rate limit
|
78
|
-
# quota via <tt>X-Rate-Limit</tt>.
|
79
|
-
#
|
80
|
-
# @since 0.5.0
|
81
|
-
#
|
82
|
-
# @see Hanami::Action::HEAD#finish
|
83
|
-
#
|
84
|
-
# @example
|
85
|
-
# require 'hanami/controller'
|
86
|
-
#
|
87
|
-
# module Books
|
88
|
-
# class Destroy
|
89
|
-
# include Hanami::Action
|
90
|
-
#
|
91
|
-
# def call(params)
|
92
|
-
# # ...
|
93
|
-
# self.headers.merge!(
|
94
|
-
# 'Last-Modified' => 'Fri, 27 Nov 2015 13:32:36 GMT',
|
95
|
-
# 'X-Rate-Limit' => '4000',
|
96
|
-
# 'Content-Type' => 'application/json',
|
97
|
-
# 'X-No-Pass' => 'true'
|
98
|
-
# )
|
99
|
-
#
|
100
|
-
# self.status = 204
|
101
|
-
# end
|
102
|
-
#
|
103
|
-
# private
|
104
|
-
#
|
105
|
-
# def keep_response_header?(header)
|
106
|
-
# super || header == 'X-Rate-Limit'
|
107
|
-
# end
|
108
|
-
# end
|
109
|
-
# end
|
110
|
-
#
|
111
|
-
# # Only the following headers will be sent:
|
112
|
-
# # * Last-Modified - because we used `super' in the method that respects the HTTP RFC
|
113
|
-
# # * X-Rate-Limit - because we explicitely allow it
|
114
|
-
#
|
115
|
-
# # Both Content-Type and X-No-Pass are removed because they're not allowed
|
116
|
-
def keep_response_header?(header)
|
117
|
-
ENTITY_HEADERS.include?(header)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|