hanami-controller 1.3.3 → 2.0.0.alpha1

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -7
  3. data/README.md +295 -537
  4. data/hanami-controller.gemspec +3 -3
  5. data/lib/hanami/action.rb +653 -38
  6. data/lib/hanami/action/base_params.rb +2 -2
  7. data/lib/hanami/action/cache.rb +1 -139
  8. data/lib/hanami/action/cache/cache_control.rb +4 -4
  9. data/lib/hanami/action/cache/conditional_get.rb +4 -5
  10. data/lib/hanami/action/cache/directives.rb +1 -1
  11. data/lib/hanami/action/cache/expires.rb +3 -3
  12. data/lib/hanami/action/cookie_jar.rb +3 -3
  13. data/lib/hanami/action/cookies.rb +3 -62
  14. data/lib/hanami/action/flash.rb +2 -2
  15. data/lib/hanami/action/glue.rb +5 -31
  16. data/lib/hanami/action/halt.rb +12 -0
  17. data/lib/hanami/action/mime.rb +77 -491
  18. data/lib/hanami/action/params.rb +3 -3
  19. data/lib/hanami/action/rack/file.rb +1 -1
  20. data/lib/hanami/action/request.rb +30 -20
  21. data/lib/hanami/action/response.rb +174 -0
  22. data/lib/hanami/action/session.rb +8 -117
  23. data/lib/hanami/action/validatable.rb +2 -2
  24. data/lib/hanami/controller.rb +0 -210
  25. data/lib/hanami/controller/configuration.rb +51 -506
  26. data/lib/hanami/controller/version.rb +1 -1
  27. metadata +12 -21
  28. data/lib/hanami/action/callable.rb +0 -92
  29. data/lib/hanami/action/callbacks.rb +0 -214
  30. data/lib/hanami/action/configurable.rb +0 -50
  31. data/lib/hanami/action/exposable.rb +0 -126
  32. data/lib/hanami/action/exposable/guard.rb +0 -104
  33. data/lib/hanami/action/head.rb +0 -121
  34. data/lib/hanami/action/rack.rb +0 -411
  35. data/lib/hanami/action/rack/callable.rb +0 -47
  36. data/lib/hanami/action/rack/errors.rb +0 -53
  37. data/lib/hanami/action/redirect.rb +0 -59
  38. data/lib/hanami/action/throwable.rb +0 -169
@@ -2,7 +2,7 @@ require 'rack/request'
2
2
  require 'hanami/utils/hash'
3
3
 
4
4
  module Hanami
5
- module Action
5
+ class Action
6
6
  class BaseParams
7
7
  # The key that returns raw input from the Rack env
8
8
  #
@@ -173,7 +173,7 @@ module Hanami
173
173
  def _router_params(fallback = {})
174
174
  env.fetch(ROUTER_PARAMS) do
175
175
  if session = fallback.delete(RACK_SESSION) # rubocop:disable Lint/AssignmentInCondition
176
- fallback[RACK_SESSION] = Utils::Hash.new(session).symbolize!.to_hash
176
+ fallback[RACK_SESSION] = Utils::Hash.deep_symbolize(session)
177
177
  end
178
178
 
179
179
  fallback
@@ -3,7 +3,7 @@ require 'hanami/action/cache/expires'
3
3
  require 'hanami/action/cache/conditional_get'
4
4
 
5
5
  module Hanami
6
- module Action
6
+ class Action
7
7
  # Cache type API
8
8
  #
9
9
  # @since 0.3.0
@@ -26,144 +26,6 @@ module Hanami
26
26
  include CacheControl, Expires
27
27
  end
28
28
  end
29
-
30
- protected
31
-
32
- # Specify response freshness policy for HTTP caches (Cache-Control header).
33
- # Any number of non-value directives (:public, :private, :no_cache,
34
- # :no_store, :must_revalidate, :proxy_revalidate) may be passed along with
35
- # a Hash of value directives (:max_age, :min_stale, :s_max_age).
36
- #
37
- # See RFC 2616 / 14.9 for more on standard cache control directives:
38
- # http://tools.ietf.org/html/rfc2616#section-14.9.1
39
- #
40
- # @param values [Array<Symbols, Hash>] mapped to cache_control directives
41
- # @option values [Symbol] :public
42
- # @option values [Symbol] :private
43
- # @option values [Symbol] :no_cache
44
- # @option values [Symbol] :no_store
45
- # @option values [Symbol] :must_validate
46
- # @option values [Symbol] :proxy_revalidate
47
- # @option values [Hash] :max_age
48
- # @option values [Hash] :min_stale
49
- # @option values [Hash] :s_max_age
50
- #
51
- # @return void
52
- #
53
- # @since 0.3.0
54
- #
55
- # @example
56
- # require 'hanami/controller'
57
- # require 'hanami/action/cache'
58
- #
59
- # class Show
60
- # include Hanami::Action
61
- # include Hanami::Action::Cache
62
- #
63
- # def call(params)
64
- # # ...
65
- #
66
- # # set Cache-Control directives
67
- # cache_control :public, max_age: 900, s_maxage: 86400
68
- #
69
- # # overwrite previous Cache-Control directives
70
- # cache_control :private, :no_cache, :no_store
71
- #
72
- # => Cache-Control: private, no-store, max-age=900
73
- #
74
- # end
75
- # end
76
- def cache_control(*values)
77
- cache_control = CacheControl::Directives.new(*values)
78
- headers.merge!(cache_control.headers)
79
- end
80
-
81
- # Set the Expires header and Cache-Control/max-age directive. Amount
82
- # can be an integer number of seconds in the future or a Time object
83
- # indicating when the response should be considered "stale". The remaining
84
- # "values" arguments are passed to the #cache_control helper:
85
- #
86
- # @param amount [Integer,Time] number of seconds or point in time
87
- # @param values [Array<Symbols>] mapped to cache_control directives
88
- #
89
- # @return void
90
- #
91
- # @since 0.3.0
92
- #
93
- # @example
94
- # require 'hanami/controller'
95
- # require 'hanami/action/cache'
96
- #
97
- # class Show
98
- # include Hanami::Action
99
- # include Hanami::Action::Cache
100
- #
101
- # def call(params)
102
- # # ...
103
- #
104
- # # set Cache-Control directives and Expires
105
- # expires 900, :public
106
- #
107
- # # overwrite Cache-Control directives and Expires
108
- # expires 300, :private, :no_cache, :no_store
109
- #
110
- # => Expires: Thu, 26 Jun 2014 12:00:00 GMT
111
- # => Cache-Control: private, no-cache, no-store max-age=300
112
- #
113
- # end
114
- # end
115
- def expires(amount, *values)
116
- expires = Expires::Directives.new(amount, *values)
117
- headers.merge!(expires.headers)
118
- end
119
-
120
- # Set the etag, last_modified, or both headers on the response
121
- # and halts a 304 Not Modified if the request is still fresh
122
- # respecting IfNoneMatch and IfModifiedSince request headers
123
- #
124
- # @param options [Hash]
125
- # @option options [Integer] :etag for testing IfNoneMatch conditions
126
- # @option options [Date] :last_modified for testing IfModifiedSince conditions
127
- #
128
- # @return void
129
- #
130
- # @since 0.3.0
131
- #
132
- # @example
133
- # require 'hanami/controller'
134
- # require 'hanami/action/cache'
135
- #
136
- # class Show
137
- # include Hanami::Action
138
- # include Hanami::Action::Cache
139
- #
140
- # def call(params)
141
- # # ...
142
- #
143
- # # set etag response header and halt 304
144
- # # if request matches IF_NONE_MATCH header
145
- # fresh etag: @resource.updated_at.to_i
146
- #
147
- # # set last_modified response header and halt 304
148
- # # if request matches IF_MODIFIED_SINCE
149
- # fresh last_modified: @resource.updated_at
150
- #
151
- # # set etag and last_modified response header,
152
- # # halt 304 if request matches IF_MODIFIED_SINCE
153
- # # and IF_NONE_MATCH
154
- # fresh last_modified: @resource.updated_at
155
- #
156
- # end
157
- # end
158
- def fresh(options)
159
- conditional_get = ConditionalGet.new(@_env, options)
160
-
161
- headers.merge!(conditional_get.headers)
162
-
163
- conditional_get.fresh? do
164
- halt 304
165
- end
166
- end
167
29
  end
168
30
  end
169
31
  end
@@ -1,7 +1,7 @@
1
1
  require 'hanami/action/cache/directives'
2
2
 
3
3
  module Hanami
4
- module Action
4
+ class Action
5
5
  module Cache
6
6
  # Module with Cache-Control logic
7
7
  #
@@ -37,7 +37,7 @@ module Hanami
37
37
  def cache_control_directives
38
38
  @cache_control_directives || Object.new.tap do |null_object|
39
39
  def null_object.headers
40
- Hash.new
40
+ ::Hash.new
41
41
  end
42
42
  end
43
43
  end
@@ -49,9 +49,9 @@ module Hanami
49
49
  # @api private
50
50
  #
51
51
  # @see Hanami::Action#finish
52
- def finish
52
+ def finish(_, res, _)
53
+ res.headers.merge!(self.class.cache_control_directives.headers) unless res.headers.include? HEADER
53
54
  super
54
- headers.merge!(self.class.cache_control_directives.headers) unless headers.include? HEADER
55
55
  end
56
56
 
57
57
  # Class which stores CacheControl values
@@ -1,5 +1,7 @@
1
+ require "hanami/utils/blank"
2
+
1
3
  module Hanami
2
- module Action
4
+ class Action
3
5
  module Cache
4
6
  # @since 0.3.0
5
7
  # @api private
@@ -67,10 +69,7 @@ module Hanami
67
69
  # @since 0.3.0
68
70
  # @api private
69
71
  def fresh?
70
- return false if Hanami::Utils::Blank.blank?(modified_since)
71
- return false if Hanami::Utils::Blank.blank?(@value)
72
-
73
- Time.httpdate(modified_since).to_i >= @value.to_time.to_i
72
+ !Hanami::Utils::Blank.blank?(modified_since) && Time.httpdate(modified_since).to_i >= @value.to_time.to_i
74
73
  end
75
74
 
76
75
  # @since 0.3.0
@@ -1,5 +1,5 @@
1
1
  module Hanami
2
- module Action
2
+ class Action
3
3
  module Cache
4
4
  # Cache-Control directives which have values
5
5
  #
@@ -1,7 +1,7 @@
1
1
  require 'hanami/action/cache/cache_control'
2
2
 
3
3
  module Hanami
4
- module Action
4
+ class Action
5
5
  module Cache
6
6
  # Module with Expires logic
7
7
  #
@@ -49,9 +49,9 @@ module Hanami
49
49
  # @api private
50
50
  #
51
51
  # @see Hanami::Action#finish
52
- def finish
52
+ def finish(_, res, _)
53
+ res.headers.merge!(self.class.expires_directives.headers) unless res.headers.include? HEADER
53
54
  super
54
- headers.merge!(self.class.expires_directives.headers) unless headers.include? HEADER
55
55
  end
56
56
 
57
57
  # Class which stores Expires directives
@@ -1,7 +1,7 @@
1
1
  require 'hanami/utils/hash'
2
2
 
3
3
  module Hanami
4
- module Action
4
+ class Action
5
5
  # A set of HTTP Cookies
6
6
  #
7
7
  # It acts as an Hash
@@ -55,7 +55,7 @@ module Hanami
55
55
  # @since 0.1.0
56
56
  def initialize(env, headers, default_options)
57
57
  @_headers = headers
58
- @cookies = Utils::Hash.new(extract(env)).deep_symbolize!
58
+ @cookies = Utils::Hash.deep_symbolize(extract(env))
59
59
  @default_options = default_options
60
60
  end
61
61
 
@@ -166,7 +166,7 @@ module Hanami
166
166
  # @since 0.4.0
167
167
  # @api private
168
168
  def _merge_default_values(value)
169
- cookies_options = if value.is_a? Hash
169
+ cookies_options = if value.is_a?(::Hash)
170
170
  value.merge! _add_expires_option(value)
171
171
  else
172
172
  { value: value }
@@ -1,7 +1,5 @@
1
- require 'hanami/action/cookie_jar'
2
-
3
1
  module Hanami
4
- module Action
2
+ class Action
5
3
  # Cookies API
6
4
  #
7
5
  # This module isn't included by default.
@@ -10,63 +8,6 @@ module Hanami
10
8
  #
11
9
  # @see Hanami::Action::Cookies#cookies
12
10
  module Cookies
13
- protected
14
-
15
- # Gets the cookies from the request and expose them as an Hash
16
- #
17
- # It automatically sets options from global configuration, but it allows to
18
- # override values case by case.
19
- #
20
- # For a list of options please have a look at <tt>Hanami::Controller::Configuration</tt>,
21
- # and <tt>Hanami::Action::CookieJar</tt>.
22
- #
23
- # @return [Hanami::Action::CookieJar] cookies
24
- #
25
- # @since 0.1.0
26
- #
27
- # @see Hanami::Controller::Configuration#cookies
28
- # @see Hanami::Action::CookieJar#[]=
29
- #
30
- # @example Basic Usage
31
- # require 'hanami/controller'
32
- # require 'hanami/action/cookies'
33
- #
34
- # class Show
35
- # include Hanami::Action
36
- # include Hanami::Action::Cookies
37
- #
38
- # def call(params)
39
- # # ...
40
- #
41
- # # get a value
42
- # cookies[:user_id] # => '23'
43
- #
44
- # # set a value
45
- # cookies[:foo] = 'bar'
46
- #
47
- # # remove a value
48
- # cookies[:bax] = nil
49
- # end
50
- # end
51
- #
52
- # @example Cookies Options
53
- # require 'hanami/controller'
54
- # require 'hanami/action/cookies'
55
- #
56
- # class Show
57
- # include Hanami::Action
58
- # include Hanami::Action::Cookies
59
- #
60
- # def call(params)
61
- # # ...
62
- # # set a value
63
- # cookies[:foo] = { value: 'bar', max_age: 300, path: '/dashboard' }
64
- # end
65
- # end
66
- def cookies
67
- @cookies ||= CookieJar.new(@_env.dup, headers, configuration.cookies)
68
- end
69
-
70
11
  private
71
12
 
72
13
  # Finalize the response by flushing cookies into the response
@@ -75,9 +16,9 @@ module Hanami
75
16
  # @api private
76
17
  #
77
18
  # @see Hanami::Action#finish
78
- def finish
19
+ def finish(req, res, *)
20
+ res.cookies.finish
79
21
  super
80
- cookies.finish
81
22
  end
82
23
  end
83
24
  end
@@ -1,7 +1,7 @@
1
1
  require 'hanami/utils/json'
2
2
 
3
3
  module Hanami
4
- module Action
4
+ class Action
5
5
  # Container useful to transport data with the HTTP session
6
6
  # It has a life span of one HTTP request or redirect.
7
7
  #
@@ -263,7 +263,7 @@ module Hanami
263
263
  # @since 1.3.0
264
264
  # @api private
265
265
  def is_hash?(data)
266
- data && data.is_a?(Hash)
266
+ data && data.is_a?(::Hash)
267
267
  end
268
268
  end
269
269
  end
@@ -1,5 +1,5 @@
1
1
  module Hanami
2
- module Action
2
+ class Action
3
3
  # Glue code for full stack Hanami applications
4
4
  #
5
5
  # This includes missing rendering logic that it makes sense to include
@@ -14,43 +14,17 @@ module Hanami
14
14
  # @since 0.3.0
15
15
  ENV_KEY = 'hanami.action'.freeze
16
16
 
17
- # @api private
18
- # @since 0.3.2
19
- ADDITIONAL_HTTP_STATUSES_WITHOUT_BODY = Set.new([301, 302]).freeze
20
-
21
- # Override Ruby's Module#included
22
- #
23
- # @api private
24
- # @since 0.3.0
25
- def self.included(base)
26
- base.class_eval { _expose(:format) if respond_to?(:_expose) }
27
- end
28
-
29
- # Check if the current HTTP request is renderable.
30
- #
31
- # It verifies if the verb isn't HEAD, if the status demands to omit
32
- # the body and if it isn't sending a file.
33
- #
34
- # @return [TrueClass,FalseClass] the result of the check
35
- #
36
- # @api private
37
- # @since 0.3.2
38
- def renderable?
39
- !_requires_no_body? &&
40
- !sending_file? &&
41
- !ADDITIONAL_HTTP_STATUSES_WITHOUT_BODY.include?(@_status)
42
- end
43
-
44
17
  protected
18
+
45
19
  # Put the current instance into the Rack environment
46
20
  #
47
21
  # @api private
48
22
  # @since 0.3.0
49
23
  #
50
24
  # @see Hanami::Action#finish
51
- def finish
25
+ def finish(req, *)
26
+ req.env[ENV_KEY] = self
52
27
  super
53
- @_env[ENV_KEY] = self
54
28
  end
55
29
 
56
30
  # Check if the request's body is a file
@@ -59,7 +33,7 @@ module Hanami
59
33
  #
60
34
  # @since 0.4.3
61
35
  def sending_file?
62
- @_body.is_a?(::Rack::File::Iterator)
36
+ response.body.is_a?(::Rack::File::Iterator)
63
37
  end
64
38
  end
65
39
  end
@@ -0,0 +1,12 @@
1
+ require "hanami/http/status"
2
+
3
+ module Hanami
4
+ class Action
5
+ module Halt
6
+ def self.call(status, body = nil)
7
+ body ||= Http::Status.message_for(status)
8
+ throw :halt, [status, body]
9
+ end
10
+ end
11
+ end
12
+ end