hanami-controller 2.0.0.beta4 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a363029b7df3ddc560e2975862f72548788a2a2910c2d32519f073556b4bfbb2
4
- data.tar.gz: e7d67505e3b0161a656d24e1ff634bd02c11d4fad1e217a1ee482271be6dbbd9
3
+ metadata.gz: 0a5d623c09e8ecb8c267de856196333c5da74e066b55501af2acc706349d0d73
4
+ data.tar.gz: '0786076a81b7a11ca79aedba2ff0318f207683e71ba931293dcc1f585a191e0b'
5
5
  SHA512:
6
- metadata.gz: 0a9aeb4ea44db1fe6f137dee8f3e5e05bda318a8c53f1f57c30204a0077b5dcfd82aefab569fd7169c2c728de2331fcaa52f1fcdec2e3adb6d4679c38791edf6
7
- data.tar.gz: 726de07b87cd8055da9973ea0365c00bde1f8808a1593ef3830051e196c722f001f6dc13615182f067542c605c9437259d1d36028031867edf3abd8d9612e817
6
+ metadata.gz: 81f1cddefe11892d05ccb63e8649bc9fb6e50f2258eb02503044577e9c0e445c57cbf2318046a4002e3c9b107f9df530463cbeb10460bb3339bb52b747deb0eb
7
+ data.tar.gz: eb26f557543e0d345580b9160ec4123def85b4a4ec5a1ad0a17f8a8d15d05dc34f12e13705082e21b95a5cc3095d36677b099a319a1c2472c7180e413f5c5faf
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Complete, fast and testable actions for Rack
4
4
 
5
+ ## v2.0.0.rc1 - 2022-11-08
6
+
7
+ ### Changed
8
+
9
+ - [Tim Riley] Simplify assignment of response format: `response.format = :json` (was `response.format = format(:json)`)
10
+
5
11
  ## v2.0.0.beta4 - 2022-10-24
6
12
 
7
13
  ### Added
data/README.md CHANGED
@@ -744,7 +744,7 @@ However, you can force this value:
744
744
  class Show < Hanami::Action
745
745
  def handle(*, res)
746
746
  # ...
747
- res.format = format(:json)
747
+ res.format = :json
748
748
  end
749
749
  end
750
750
 
@@ -820,7 +820,7 @@ response.format # => :custom
820
820
  class Show < Hanami::Action
821
821
  def handle(*, res)
822
822
  # ...
823
- res.format = format(:custom)
823
+ res.format = :custom
824
824
  end
825
825
  end
826
826
 
@@ -841,7 +841,7 @@ end
841
841
 
842
842
  class Csv < Hanami::Action
843
843
  def handle(*, res)
844
- res.format = format(:csv)
844
+ res.format = :csv
845
845
  res.body = Enumerator.new do |yielder|
846
846
  yielder << csv_header
847
847
 
@@ -21,8 +21,8 @@ Gem::Specification.new do |spec|
21
21
  spec.required_ruby_version = ">= 3.0"
22
22
 
23
23
  spec.add_dependency "rack", "~> 2.0"
24
- spec.add_dependency "hanami-utils", "~> 2.0.beta"
25
- spec.add_dependency "dry-configurable", "~> 0.13", ">= 0.13.0"
24
+ spec.add_dependency "hanami-utils", "~> 2.0.0.rc1"
25
+ spec.add_dependency "dry-configurable", "~> 1.0", "< 2"
26
26
 
27
27
  spec.add_development_dependency "bundler", ">= 1.6", "< 3"
28
28
  spec.add_development_dependency "rack-test", "~> 2.0"
@@ -5,6 +5,19 @@ require "hanami/utils/hash"
5
5
 
6
6
  module Hanami
7
7
  class Action
8
+ # Provides access to params included in a Rack request.
9
+ #
10
+ # Offers useful access to params via methods like {#[]}, {#get} and {#to_h}.
11
+ #
12
+ # These params are available via {Request#params}.
13
+ #
14
+ # This class is used by default when {Hanami::Action::Validatable} is not included, or when no
15
+ # {Validatable::ClassMethods#params params} validation schema is defined.
16
+ #
17
+ # @see Hanami::Action::Request#params
18
+ #
19
+ # @api private
20
+ # @since 0.7.0
8
21
  class BaseParams
9
22
  # @attr_reader env [Hash] the Rack env
10
23
  #
@@ -18,12 +31,10 @@ module Hanami
18
31
  # @api private
19
32
  attr_reader :raw
20
33
 
21
- # Initialize the params and freeze them.
34
+ # Returns a new frozen params object for the Rack env.
22
35
  #
23
36
  # @param env [Hash] a Rack env or an hash of params.
24
37
  #
25
- # @return [Params]
26
- #
27
38
  # @since 0.7.0
28
39
  # @api private
29
40
  def initialize(env)
@@ -33,26 +44,27 @@ module Hanami
33
44
  freeze
34
45
  end
35
46
 
36
- # Returns the object associated with the given key
47
+ # Returns the value for the given params key.
37
48
  #
38
49
  # @param key [Symbol] the key
39
50
  #
40
- # @return [Object,nil] return the associated object, if found
51
+ # @return [Object,nil] the associated value, if found
41
52
  #
42
53
  # @since 0.7.0
54
+ # @api public
43
55
  def [](key)
44
56
  @params[key]
45
57
  end
46
58
 
47
- # Get an attribute value associated with the given key.
48
- # Nested attributes are reached by listing all the keys to get to the value.
59
+ # Returns an value associated with the given params key.
60
+ #
61
+ # You can access nested attributes by listing all the keys in the path. This uses the same key
62
+ # path semantics as `Hash#dig`.
49
63
  #
50
64
  # @param keys [Array<Symbol,Integer>] the key
51
65
  #
52
66
  # @return [Object,NilClass] return the associated value, if found
53
67
  #
54
- # @since 0.7.0
55
- #
56
68
  # @example
57
69
  # require "hanami/controller"
58
70
  #
@@ -73,6 +85,9 @@ module Hanami
73
85
  # end
74
86
  # end
75
87
  # end
88
+ #
89
+ # @since 0.7.0
90
+ # @api public
76
91
  def get(*keys)
77
92
  @params.dig(*keys)
78
93
  end
@@ -83,32 +98,40 @@ module Hanami
83
98
  # @since 0.8.0
84
99
  alias_method :dig, :get
85
100
 
86
- # Provide a common interface with Params
101
+ # Returns true at all times, providing a common interface with {Params}.
87
102
  #
88
103
  # @return [TrueClass] always returns true
89
104
  #
90
- # @since 0.7.0
91
- #
92
105
  # @see Hanami::Action::Params#valid?
106
+ #
107
+ # @api public
108
+ # @since 0.7.0
93
109
  def valid?
94
110
  true
95
111
  end
96
112
 
97
- # Serialize params to Hash
113
+ # Returns a hash of the parsed request params.
98
114
  #
99
- # @return [::Hash]
115
+ # @return [Hash]
100
116
  #
101
117
  # @since 0.7.0
118
+ # @api public
102
119
  def to_h
103
120
  @params
104
121
  end
105
122
  alias_method :to_hash, :to_h
106
123
 
107
- # Iterates through params
124
+ # Iterates over the params.
125
+ #
126
+ # Calls the given block with each param key-value pair; returns the full hash of params.
127
+ #
128
+ # @yieldparam key [Symbol]
129
+ # @yieldparam value [Object]
108
130
  #
109
- # @param blk [Proc]
131
+ # @return [to_h]
110
132
  #
111
133
  # @since 0.7.1
134
+ # @api public
112
135
  def each(&blk)
113
136
  to_h.each(&blk)
114
137
  end
@@ -5,6 +5,12 @@ require_relative "mime"
5
5
 
6
6
  module Hanami
7
7
  class Action
8
+ # Config for `Hanami::Action` classes.
9
+ #
10
+ # @see Hanami::Action.config
11
+ #
12
+ # @api public
13
+ # @since 2.0.0
8
14
  class Config < Dry::Configurable::Config
9
15
  # Default MIME type to format mapping
10
16
  #
@@ -151,7 +157,7 @@ module Hanami
151
157
  #
152
158
  # The given format must be coercible to a symbol, and be a valid MIME
153
159
  # type alias. If it isn't, at runtime the framework will raise an
154
- # `Hanami::Controller::UnknownFormatError`.
160
+ # `Hanami::Action::UnknownFormatError`.
155
161
  #
156
162
  # By default, this value is nil.
157
163
  #
@@ -168,7 +174,7 @@ module Hanami
168
174
  #
169
175
  # The given format must be coercible to a symbol, and be a valid MIME
170
176
  # type alias. If it isn't, at the runtime the framework will raise an
171
- # `Hanami::Controller::UnknownFormatError`.
177
+ # `Hanami::Action::UnknownFormatError`.
172
178
  #
173
179
  # By default, this value is nil.
174
180
  #
@@ -116,12 +116,6 @@ module Hanami
116
116
  # @api private
117
117
  HTTP_ACCEPT = "HTTP_ACCEPT"
118
118
 
119
- # The header key to set the mime type of the response
120
- #
121
- # @since 0.1.0
122
- # @api private
123
- CONTENT_TYPE = ::Rack::CONTENT_TYPE
124
-
125
119
  # The default mime type for an incoming HTTP request
126
120
  #
127
121
  # @since 0.1.0
@@ -1,19 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "hanami/utils/blank"
4
- require "hanami/controller/error"
5
4
  require "rack/utils"
6
5
  require "securerandom"
6
+ require_relative "errors"
7
7
 
8
8
  module Hanami
9
9
  # @api private
10
10
  class Action
11
- # Invalid CSRF Token
12
- #
13
- # @since 0.4.0
14
- class InvalidCSRFTokenError < Controller::Error
15
- end
16
-
17
11
  # CSRF Protection
18
12
  #
19
13
  # This security mechanism is enabled automatically if sessions are turned on.
@@ -2,22 +2,44 @@
2
2
 
3
3
  module Hanami
4
4
  class Action
5
+ # Base class for all Action errors.
6
+ #
7
+ # @api public
5
8
  # @since 2.0.0
6
9
  class Error < ::StandardError
7
10
  end
8
11
 
9
- # Missing session error
12
+ # Unknown format error
10
13
  #
11
- # This error is raised when `session` or `flash` is accessed/set on request/response objects
12
- # in actions which do not include `Hanami::Action::Session`.
14
+ # This error is raised when a action sets a format that it isn't recognized
15
+ # both by `Hanami::Action::Configuration` and the list of Rack mime types
13
16
  #
14
17
  # @since 2.0.0
15
18
  #
19
+ # @see Hanami::Action::Mime#format=
20
+ class UnknownFormatError < Error
21
+ # @since 2.0.0
22
+ # @api private
23
+ def initialize(format)
24
+ super("Cannot find a corresponding Mime type for '#{format}'. Please configure it with Hanami::Controller::Configuration#format.") # rubocop:disable Layout/LineLength
25
+ end
26
+ end
27
+
28
+ # Error raised when session is accessed but not enabled.
29
+ #
30
+ # This error is raised when `session` or `flash` is accessed/set on request/response objects
31
+ # in actions which do not include `Hanami::Action::Session`.
32
+ #
16
33
  # @see Hanami::Action::Session
17
34
  # @see Hanami::Action::Request#session
18
35
  # @see Hanami::Action::Response#session
19
36
  # @see Hanami::Action::Response#flash
37
+ #
38
+ # @api public
39
+ # @since 2.0.0
20
40
  class MissingSessionError < Error
41
+ # @api private
42
+ # @since 2.0.0
21
43
  def initialize(session_method)
22
44
  super(<<~TEXT)
23
45
  Sessions are not enabled. To use `#{session_method}`:
@@ -37,5 +59,11 @@ module Hanami
37
59
  TEXT
38
60
  end
39
61
  end
62
+
63
+ # Invalid CSRF Token
64
+ #
65
+ # @since 0.4.0
66
+ class InvalidCSRFTokenError < Error
67
+ end
40
68
  end
41
69
  end
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # The Hanami::Action::Flash implementation is derived from Roda's FlashHash, also released under the
4
+ # MIT Licence:
5
+ #
6
+ # Copyright (c) 2014-2020 Jeremy Evans
7
+ # Copyright (c) 2010-2014 Michel Martens, Damian Janowski and Cyril David
8
+ # Copyright (c) 2008-2009 Christian Neukirchen
9
+
3
10
  module Hanami
4
11
  class Action
5
- # A container to transport data with the HTTP session, with a lifespan of
6
- # just one HTTP request or redirect.
7
- #
8
- # Behaves like a hash, returning entries for the current request, except for
9
- # {#[]=}, which updates the hash for the next request.
12
+ # A container to transport data with the HTTP session, with a lifespan of just one HTTP request
13
+ # or redirect.
10
14
  #
11
- # This implementation is derived from Roda's FlashHash, also released under
12
- # the MIT Licence:
13
- #
14
- # Copyright (c) 2014-2020 Jeremy Evans
15
- # Copyright (c) 2010-2014 Michel Martens, Damian Janowski and Cyril David
16
- # Copyright (c) 2008-2009 Christian Neukirchen
15
+ # Behaves like a hash, returning entries for the current request, except for {#[]=}, which
16
+ # updates the hash for the next request.
17
17
  #
18
18
  # @since 0.3.0
19
19
  # @api public
@@ -30,9 +30,9 @@ module Hanami
30
30
  # @api public
31
31
  attr_reader :next
32
32
 
33
- # Initializes a new flash instance
33
+ # Returns a new flash object.
34
34
  #
35
- # @param hash [Hash, nil] the flash hash for the current request. nil will become an empty hash.
35
+ # @param hash [Hash, nil] the flash hash for the current request; `nil` will become an empty hash.
36
36
  #
37
37
  # @since 0.3.0
38
38
  # @api public
@@ -41,7 +41,9 @@ module Hanami
41
41
  @next = {}
42
42
  end
43
43
 
44
- # @return [Hash] The flash hash for the current request
44
+ # Returns the flash hash for the current request.
45
+ #
46
+ # @return [Hash] the flash hash for the current request
45
47
  #
46
48
  # @since 2.0.0
47
49
  # @api public
@@ -49,7 +51,7 @@ module Hanami
49
51
  @flash
50
52
  end
51
53
 
52
- # Returns the value for the given key in the current hash
54
+ # Returns the value for the given key in the current hash.
53
55
  #
54
56
  # @param key [Object] the key
55
57
  #
@@ -61,7 +63,7 @@ module Hanami
61
63
  @flash[key]
62
64
  end
63
65
 
64
- # Updates the next hash with the given key and value
66
+ # Updates the next hash with the given key and value.
65
67
  #
66
68
  # @param key [Object] the key
67
69
  # @param value [Object] the value
@@ -72,9 +74,12 @@ module Hanami
72
74
  @next[key] = value
73
75
  end
74
76
 
75
- # Calls the given block once for each element in the current hash
77
+ # Calls the given block once for each element in the current hash.
76
78
  #
77
- # @param block [Proc]
79
+ # @yieldparam element [Array<(Object, Object)>] array containing the key and value from the
80
+ # hash
81
+ #
82
+ # @return [now]
78
83
  #
79
84
  # @since 1.2.0
80
85
  # @api public
@@ -82,10 +87,12 @@ module Hanami
82
87
  @flash.each(&block)
83
88
  end
84
89
 
85
- # Returns a new array with the results of running block once for every
86
- # element in the current hash
90
+ # Returns an array of objects returned by the block, called once for each element in the
91
+ # current hash.
92
+ #
93
+ # @yieldparam element [Array<(Object, Object)>] array containing the key and value from the
94
+ # hash
87
95
  #
88
- # @param block [Proc]
89
96
  # @return [Array]
90
97
  #
91
98
  # @since 1.2.0
@@ -114,7 +121,7 @@ module Hanami
114
121
  @flash.key?(key)
115
122
  end
116
123
 
117
- # Removes entries from the next hash
124
+ # Removes entries from the next hash.
118
125
  #
119
126
  # @overload discard(key)
120
127
  # Removes the given key from the next hash
@@ -4,9 +4,11 @@ require "hanami/http/status"
4
4
 
5
5
  module Hanami
6
6
  class Action
7
+ # @api private
8
+ # @since 2.0.0
7
9
  module Halt
8
- # @since 2.0.0
9
10
  # @api private
11
+ # @since 2.0.0
10
12
  def self.call(status, body = nil)
11
13
  body ||= Http::Status.message_for(status)
12
14
  throw :halt, [status, body]
@@ -3,6 +3,7 @@
3
3
  require "hanami/utils"
4
4
  require "rack/utils"
5
5
  require "rack/mime"
6
+ require_relative "errors"
6
7
 
7
8
  module Hanami
8
9
  class Action
@@ -117,7 +118,7 @@ module Hanami
117
118
  return if format.nil?
118
119
 
119
120
  config.mime_type_for(format) ||
120
- TYPES.fetch(format) { raise Hanami::Controller::UnknownFormatError.new(format) }
121
+ TYPES.fetch(format) { raise Hanami::Action::UnknownFormatError.new(format) }
121
122
  end
122
123
 
123
124
  # Transforms MIME Types to symbol
@@ -144,13 +145,26 @@ module Hanami
144
145
  TYPES.key(content_type)
145
146
  end
146
147
 
148
+ # @since 2.0.0
149
+ # @api private
150
+ def self.detect_format_and_content_type(value, config)
151
+ case value
152
+ when Symbol
153
+ [value, format_to_mime_type(value, config)]
154
+ when String
155
+ [detect_format(value, config), value]
156
+ else
157
+ raise UnknownFormatError.new(value)
158
+ end
159
+ end
160
+
147
161
  # Transforms symbols to MIME Types
148
162
  # @example
149
163
  # restrict_mime_types(config, [:json]) #=> ["application/json"]
150
164
  #
151
165
  # @return [Array<String>, nil]
152
166
  #
153
- # @raise [Hanami::Controller::UnknownFormatError] if the format is invalid
167
+ # @raise [Hanami::Action::UnknownFormatError] if the format is invalid
154
168
  #
155
169
  # @since 2.0.0
156
170
  # @api private
@@ -223,8 +237,6 @@ module Hanami
223
237
 
224
238
  # Use for setting the content_type and charset if the response
225
239
  #
226
- # @see Hanami::Action::Mime#call
227
- #
228
240
  # @return [String]
229
241
  #
230
242
  # @since 2.0.0
@@ -4,13 +4,17 @@ require "rack/file"
4
4
 
5
5
  module Hanami
6
6
  class Action
7
+ # Rack extensions for actions.
8
+ #
9
+ # @api private
10
+ # @since 0.4.3
7
11
  module Rack
8
12
  # File to be sent
9
13
  #
14
+ # @see Hanami::Action::Response#send_file
15
+ #
10
16
  # @since 0.4.3
11
17
  # @api private
12
- #
13
- # @see Hanami::Action::Rack#send_file
14
18
  class File
15
19
  # @param path [String,Pathname] file path
16
20
  #
@@ -5,18 +5,31 @@ require "rack/mime"
5
5
  require "rack/request"
6
6
  require "rack/utils"
7
7
  require "securerandom"
8
+ require_relative "errors"
8
9
 
9
10
  module Hanami
10
11
  class Action
11
- # An HTTP request based on top of Rack::Request.
12
- # This guarantees backwards compatibility with with Rack.
12
+ # The HTTP request for an action, given to {Action#handle}.
13
13
  #
14
- # @since 0.3.1
14
+ # Inherits from `Rack::Request`, providing compatibility with Rack functionality.
15
15
  #
16
16
  # @see http://www.rubydoc.info/gems/rack/Rack/Request
17
+ #
18
+ # @since 0.3.1
17
19
  class Request < ::Rack::Request
20
+ # Returns the request's params.
21
+ #
22
+ # For an action with {Validatable} included, this will be a {Params} instance, otherwise a
23
+ # {BaseParams}.
24
+ #
25
+ # @return [BaseParams,Params]
26
+ #
27
+ # @since 2.0.0
28
+ # @api public
18
29
  attr_reader :params
19
30
 
31
+ # @since 2.0.0
32
+ # @api private
20
33
  def initialize(env:, params:, sessions_enabled: false)
21
34
  super(env)
22
35
 
@@ -24,11 +37,27 @@ module Hanami
24
37
  @sessions_enabled = sessions_enabled
25
38
  end
26
39
 
40
+ # Returns the request's ID
41
+ #
42
+ # @return [String]
43
+ #
44
+ # @since 2.0.0
45
+ # @api public
27
46
  def id
28
47
  # FIXME: make this number configurable and document the probabilities of clashes
29
48
  @id ||= @env[Action::REQUEST_ID] = SecureRandom.hex(Action::DEFAULT_ID_LENGTH)
30
49
  end
31
50
 
51
+ # Returns the session for the request.
52
+ #
53
+ # @return [Hash] the session object
54
+ #
55
+ # @raise [MissingSessionError] if sessions are not enabled
56
+ #
57
+ # @see Response#session
58
+ #
59
+ # @since 2.0.0
60
+ # @api public
32
61
  def session
33
62
  unless @sessions_enabled
34
63
  raise Hanami::Action::MissingSessionError.new("Hanami::Action::Request#session")
@@ -37,6 +66,16 @@ module Hanami
37
66
  super
38
67
  end
39
68
 
69
+ # Returns the flash for the request.
70
+ #
71
+ # @return [Flash]
72
+ #
73
+ # @raise [MissingSessionError] if sessions are not enabled
74
+ #
75
+ # @see Response#flash
76
+ #
77
+ # @since 2.0.0
78
+ # @api public
40
79
  def flash
41
80
  unless @sessions_enabled
42
81
  raise Hanami::Action::MissingSessionError.new("Hanami::Action::Request#flash")
@@ -45,12 +84,16 @@ module Hanami
45
84
  @flash ||= Flash.new(session[Flash::KEY])
46
85
  end
47
86
 
87
+ # @since 2.0.0
88
+ # @api private
48
89
  def accept?(mime_type)
49
90
  !!::Rack::Utils.q_values(accept).find do |mime, _|
50
91
  ::Rack::Mime.match?(mime_type, mime)
51
92
  end
52
93
  end
53
94
 
95
+ # @since 2.0.0
96
+ # @api private
54
97
  def accept_header?
55
98
  accept != Action::DEFAULT_ACCEPT
56
99
  end