pundit 2.5.0 → 2.5.1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +1 -1
  4. data/lib/pundit/authorization.rb +18 -0
  5. data/lib/pundit/cache_store/legacy_store.rb +3 -0
  6. data/lib/pundit/cache_store/null_store.rb +3 -0
  7. data/lib/pundit/cache_store.rb +2 -0
  8. data/lib/pundit/context.rb +13 -0
  9. data/lib/pundit/error.rb +71 -0
  10. data/lib/pundit/helper.rb +16 -0
  11. data/lib/pundit/policy_finder.rb +11 -0
  12. data/lib/pundit/railtie.rb +1 -0
  13. data/lib/pundit/rspec.rb +2 -0
  14. data/lib/pundit/version.rb +1 -1
  15. data/lib/pundit.rb +10 -69
  16. metadata +4 -68
  17. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
  18. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -26
  19. data/.github/PULL_REQUEST_TEMPLATE/gem_release_template.md +0 -8
  20. data/.github/pull_request_template.md +0 -9
  21. data/.github/workflows/main.yml +0 -147
  22. data/.github/workflows/push_gem.yml +0 -33
  23. data/.gitignore +0 -19
  24. data/.rubocop.yml +0 -73
  25. data/.rubocop_ignore_git.yml +0 -7
  26. data/.yardopts +0 -1
  27. data/CODE_OF_CONDUCT.md +0 -28
  28. data/CONTRIBUTING.md +0 -31
  29. data/Gemfile +0 -28
  30. data/Rakefile +0 -21
  31. data/config/rubocop-rspec.yml +0 -5
  32. data/pundit.gemspec +0 -31
  33. data/spec/authorization_spec.rb +0 -331
  34. data/spec/generators_spec.rb +0 -43
  35. data/spec/policies/post_policy_spec.rb +0 -49
  36. data/spec/policy_finder_spec.rb +0 -191
  37. data/spec/pundit/helper_spec.rb +0 -18
  38. data/spec/pundit_spec.rb +0 -474
  39. data/spec/rspec_dsl_spec.rb +0 -81
  40. data/spec/simple_cov_check_action_formatter.rb +0 -79
  41. data/spec/spec_helper.rb +0 -35
  42. data/spec/support/lib/controller.rb +0 -38
  43. data/spec/support/lib/custom_cache.rb +0 -19
  44. data/spec/support/lib/instance_tracking.rb +0 -20
  45. data/spec/support/models/article.rb +0 -4
  46. data/spec/support/models/article_tag.rb +0 -7
  47. data/spec/support/models/artificial_blog.rb +0 -7
  48. data/spec/support/models/blog.rb +0 -4
  49. data/spec/support/models/comment.rb +0 -5
  50. data/spec/support/models/comment_four_five_six.rb +0 -5
  51. data/spec/support/models/comment_scope.rb +0 -13
  52. data/spec/support/models/comments_relation.rb +0 -15
  53. data/spec/support/models/customer/post.rb +0 -11
  54. data/spec/support/models/default_scope_contains_error.rb +0 -5
  55. data/spec/support/models/dummy_current_user.rb +0 -7
  56. data/spec/support/models/foo.rb +0 -4
  57. data/spec/support/models/post.rb +0 -25
  58. data/spec/support/models/post_four_five_six.rb +0 -9
  59. data/spec/support/models/project_one_two_three/avatar_four_five_six.rb +0 -7
  60. data/spec/support/models/project_one_two_three/tag_four_five_six.rb +0 -11
  61. data/spec/support/models/wiki.rb +0 -4
  62. data/spec/support/policies/article_tag_other_name_policy.rb +0 -13
  63. data/spec/support/policies/base_policy.rb +0 -23
  64. data/spec/support/policies/blog_policy.rb +0 -5
  65. data/spec/support/policies/comment_policy.rb +0 -11
  66. data/spec/support/policies/criteria_policy.rb +0 -5
  67. data/spec/support/policies/default_scope_contains_error_policy.rb +0 -10
  68. data/spec/support/policies/denier_policy.rb +0 -7
  69. data/spec/support/policies/dummy_current_user_policy.rb +0 -9
  70. data/spec/support/policies/nil_class_policy.rb +0 -17
  71. data/spec/support/policies/post_policy.rb +0 -36
  72. data/spec/support/policies/project/admin/comment_policy.rb +0 -15
  73. data/spec/support/policies/project/comment_policy.rb +0 -17
  74. data/spec/support/policies/project/criteria_policy.rb +0 -7
  75. data/spec/support/policies/project/post_policy.rb +0 -13
  76. data/spec/support/policies/project_one_two_three/avatar_four_five_six_policy.rb +0 -6
  77. data/spec/support/policies/project_one_two_three/comment_four_five_six_policy.rb +0 -6
  78. data/spec/support/policies/project_one_two_three/criteria_four_five_six_policy.rb +0 -6
  79. data/spec/support/policies/project_one_two_three/post_four_five_six_policy.rb +0 -6
  80. data/spec/support/policies/project_one_two_three/tag_four_five_six_policy.rb +0 -6
  81. data/spec/support/policies/publication_policy.rb +0 -13
  82. data/spec/support/policies/wiki_policy.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e34d4263a4c386c0078ddfed804532e292357926fefb505b62bcea9c6e3d08d
4
- data.tar.gz: 67c3471d5354cba97b650185770f81bdcc79699f8cbc4d8e60c99b57639a6cee
3
+ metadata.gz: 5c6f7c834aabbea0d1c74b4101d67a936f0c062db2c5a67dcb45c824d0a1f80e
4
+ data.tar.gz: 651d652baa3a1f511e794b80f4e514b5e2bb74f75abeaa184dff48dae63e27bf
5
5
  SHA512:
6
- metadata.gz: e67f07116623c8fd505ed254a165136be512ea36f7635ca2e6062fd59bf73a23eb1a4bf5790a390ff6b4e014e3baf0f7f8e7b649e6e50a8985fcff2e6c27cecd
7
- data.tar.gz: 65f7d1132b00f9bdcb8b717e08c402a5f6a9a90de5fa07e017b831cbb3ac7b9c11f8869466e3112fea4acddd1699dc495fe30b3234fab06c213ea65dd459c1fd
6
+ metadata.gz: e4081cc21e4827985808334e5753a6b6f812743308cc251f8e4923b0b3a73c41b64bb6da64da57919ac62672537e3d464b187f0d28811a0aaab9c17ea9354ec5
7
+ data.tar.gz: a7868288d12d4f63cc95b5d18f54bfdafbcf586c7f415a713713f1f520140c2f7c353572cdab770baf16f5525ec4fc369679fd5e640233360b743f34d66580d9
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.5.1 (2025-09-12)
6
+
7
+ ### Fixed
8
+ - Requiring only `pundit/rspec` no longer raises an error in Active Support [#857](https://github.com/varvet/pundit/issues/857)
9
+
5
10
  ## 2.5.0 (2025-03-03)
6
11
 
7
12
  ### Added
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Pundit
2
2
 
3
3
  [![Main](https://github.com/varvet/pundit/actions/workflows/main.yml/badge.svg)](https://github.com/varvet/pundit/actions/workflows/main.yml)
4
- [![Code Climate](https://api.codeclimate.com/v1/badges/a940030f96c9fb43046a/maintainability)](https://codeclimate.com/github/varvet/pundit/maintainability)
4
+ [![Maintainability](https://qlty.sh/gh/varvet/projects/pundit/maintainability.svg)](https://qlty.sh/gh/varvet/projects/pundit)
5
5
  [![Inline docs](https://inch-ci.org/github/varvet/pundit.svg?branch=main)](https://inch-ci.org/github/varvet/pundit)
6
6
  [![Gem Version](https://badge.fury.io/rb/pundit.svg)](https://badge.fury.io/rb/pundit)
7
7
 
@@ -9,6 +9,7 @@ module Pundit
9
9
  # end
10
10
  # @see #pundit
11
11
  # @api public
12
+ # @since v2.2.0
12
13
  module Authorization
13
14
  extend ActiveSupport::Concern
14
15
 
@@ -30,6 +31,7 @@ module Pundit
30
31
  # @return [Pundit::Context]
31
32
  # @see #pundit_user
32
33
  # @see #policies
34
+ # @since v2.3.2
33
35
  def pundit
34
36
  @pundit ||= Pundit::Context.new(
35
37
  user: pundit_user,
@@ -45,6 +47,7 @@ module Pundit
45
47
  # @see #pundit
46
48
  # @see #pundit_reset!
47
49
  # @return [Object] the user object to be used with pundit
50
+ # @since v0.2.2
48
51
  def pundit_user
49
52
  current_user
50
53
  end
@@ -59,6 +62,7 @@ module Pundit
59
62
  # with the correct context for the new pundit_user.
60
63
  #
61
64
  # @return [void]
65
+ # @since v2.5.0
62
66
  def pundit_reset!
63
67
  @pundit = nil
64
68
  @_pundit_policies = nil
@@ -81,6 +85,7 @@ module Pundit
81
85
  # @return [record] Always returns the passed object record
82
86
  # @see Pundit::Context#authorize
83
87
  # @see #verify_authorized
88
+ # @since v0.1.0
84
89
  def authorize(record, query = nil, policy_class: nil)
85
90
  query ||= "#{action_name}?"
86
91
 
@@ -94,6 +99,7 @@ module Pundit
94
99
  # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
95
100
  # @return [void]
96
101
  # @see #verify_authorized
102
+ # @since v1.0.0
97
103
  def skip_authorization
98
104
  @_pundit_policy_authorized = :skipped
99
105
  end
@@ -101,6 +107,7 @@ module Pundit
101
107
  # @return [Boolean] wether or not authorization has been performed
102
108
  # @see #authorize
103
109
  # @see #skip_authorization
110
+ # @since v1.0.0
104
111
  def pundit_policy_authorized?
105
112
  !!@_pundit_policy_authorized
106
113
  end
@@ -115,6 +122,7 @@ module Pundit
115
122
  # @return [void]
116
123
  # @see #authorize
117
124
  # @see #skip_authorization
125
+ # @since v0.1.0
118
126
  def verify_authorized
119
127
  raise AuthorizationNotPerformedError, self.class unless pundit_policy_authorized?
120
128
  end
@@ -124,6 +132,7 @@ module Pundit
124
132
  # Cache of policies. You should not rely on this method.
125
133
  #
126
134
  # @api private
135
+ # @since v1.0.0
127
136
  def policies
128
137
  @_pundit_policies ||= {}
129
138
  end
@@ -137,6 +146,7 @@ module Pundit
137
146
  # @see https://github.com/varvet/pundit#policies
138
147
  # @param record [Object] the object we're retrieving the policy for
139
148
  # @return [Object] instance of policy class with query methods
149
+ # @since v0.1.0
140
150
  def policy(record)
141
151
  pundit.policy!(record)
142
152
  end
@@ -149,6 +159,7 @@ module Pundit
149
159
  # @param scope [Object] the object we're retrieving the policy scope for
150
160
  # @param policy_scope_class [#resolve] the policy scope class we want to force use of
151
161
  # @return [#resolve, nil] instance of scope class which can resolve to a scope
162
+ # @since v0.1.0
152
163
  def policy_scope(scope, policy_scope_class: nil)
153
164
  @_pundit_policy_scoped = true
154
165
  policy_scope_class ? policy_scope_class.new(pundit_user, scope).resolve : pundit_policy_scope(scope)
@@ -159,6 +170,7 @@ module Pundit
159
170
  # @see https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used
160
171
  # @return [void]
161
172
  # @see #verify_policy_scoped
173
+ # @since v1.0.0
162
174
  def skip_policy_scope
163
175
  @_pundit_policy_scoped = :skipped
164
176
  end
@@ -166,6 +178,7 @@ module Pundit
166
178
  # @return [Boolean] wether or not policy scoping has been performed
167
179
  # @see #policy_scope
168
180
  # @see #skip_policy_scope
181
+ # @since v1.0.0
169
182
  def pundit_policy_scoped?
170
183
  !!@_pundit_policy_scoped
171
184
  end
@@ -181,6 +194,7 @@ module Pundit
181
194
  # @return [void]
182
195
  # @see #policy_scope
183
196
  # @see #skip_policy_scope
197
+ # @since v0.2.1
184
198
  def verify_policy_scoped
185
199
  raise PolicyScopingNotPerformedError, self.class unless pundit_policy_scoped?
186
200
  end
@@ -190,6 +204,7 @@ module Pundit
190
204
  # Cache of policy scope. You should not rely on this method.
191
205
  #
192
206
  # @api private
207
+ # @since v1.0.0
193
208
  def policy_scopes
194
209
  @_pundit_policy_scopes ||= {}
195
210
  end
@@ -206,6 +221,7 @@ module Pundit
206
221
  # @note This also memoizes the instance with `scope` as the key.
207
222
  # @see Pundit::Helper#policy_scope
208
223
  # @api private
224
+ # @since v1.0.0
209
225
  def pundit_policy_scope(scope)
210
226
  policy_scopes[scope] ||= pundit.policy_scope!(scope)
211
227
  end
@@ -228,6 +244,7 @@ module Pundit
228
244
  # @param action [Symbol, String] the name of the action being performed on the record (e.g. `:update`).
229
245
  # If omitted then this defaults to the Rails controller action name.
230
246
  # @return [Hash{String => Object}] the permitted attributes
247
+ # @since v1.0.0
231
248
  def permitted_attributes(record, action = action_name)
232
249
  policy = policy(record)
233
250
  method_name = if policy.respond_to?("permitted_attributes_for_#{action}")
@@ -242,6 +259,7 @@ module Pundit
242
259
  #
243
260
  # @param record [Object] the object we're retrieving params for
244
261
  # @return [ActionController::Parameters] the params
262
+ # @since v2.0.0
245
263
  def pundit_params_for(record)
246
264
  params.require(PolicyFinder.new(record).param_key)
247
265
  end
@@ -7,7 +7,9 @@ module Pundit
7
7
  # The original cache mechanism used by Pundit.
8
8
  #
9
9
  # @api private
10
+ # @since v2.3.2
10
11
  class LegacyStore
12
+ # @since v2.3.2
11
13
  def initialize(hash = {})
12
14
  @store = hash
13
15
  end
@@ -15,6 +17,7 @@ module Pundit
15
17
  # A cache store that uses only the record as a cache key, and ignores the user.
16
18
  #
17
19
  # @note `nil` results are not cached.
20
+ # @since v2.3.2
18
21
  def fetch(user:, record:)
19
22
  _ = user
20
23
  @store[record] ||= yield
@@ -8,10 +8,12 @@ module Pundit
8
8
  #
9
9
  # @see Pundit::Context#initialize
10
10
  # @api private
11
+ # @since v2.3.2
11
12
  class NullStore
12
13
  @instance = new
13
14
 
14
15
  class << self
16
+ # @since v2.3.2
15
17
  # @return [NullStore] the singleton instance
16
18
  attr_reader :instance
17
19
  end
@@ -19,6 +21,7 @@ module Pundit
19
21
  # Always yields, does not cache anything.
20
22
  # @yield
21
23
  # @return [any] whatever the block returns.
24
+ # @since v2.3.2
22
25
  def fetch(*, **)
23
26
  yield
24
27
  end
@@ -5,12 +5,14 @@ module Pundit
5
5
  #
6
6
  # Cache stores are used to cache policy lookups, so you get the same policy
7
7
  # instance for the same record.
8
+ # @since v2.3.2
8
9
  module CacheStore
9
10
  # @!group Cache Store Interface
10
11
 
11
12
  # @!method fetch(user:, record:, &block)
12
13
  # Looks up a stored policy or generate a new one.
13
14
  #
15
+ # @since v2.3.2
14
16
  # @note This is a method template, but the method does not exist in this module.
15
17
  # @param user [Object] the user that initiated the action
16
18
  # @param record [Object] the object being accessed
@@ -25,10 +25,13 @@ module Pundit
25
25
  # context.authorize(Post.find(id), query: :show?)
26
26
  # end
27
27
  # end
28
+ #
29
+ # @since v2.3.2
28
30
  class Context
29
31
  # @see Pundit::Authorization#pundit
30
32
  # @param user later passed to policies and scopes
31
33
  # @param policy_cache [#fetch] cache store for policies (see e.g. {CacheStore::NullStore})
34
+ # @since v2.3.2
32
35
  def initialize(user:, policy_cache: CacheStore::NullStore.instance)
33
36
  @user = user
34
37
  @policy_cache = policy_cache
@@ -36,10 +39,12 @@ module Pundit
36
39
 
37
40
  # @api public
38
41
  # @see #initialize
42
+ # @since v2.3.2
39
43
  attr_reader :user
40
44
 
41
45
  # @api private
42
46
  # @see #initialize
47
+ # @since v2.3.2
43
48
  attr_reader :policy_cache
44
49
 
45
50
  # @!group Policies
@@ -53,6 +58,7 @@ module Pundit
53
58
  # @param policy_class [Class] the policy class we want to force use of
54
59
  # @raise [NotAuthorizedError] if the given query method returned false
55
60
  # @return [Object] Always returns the passed object record
61
+ # @since v2.3.2
56
62
  def authorize(possibly_namespaced_record, query:, policy_class:)
57
63
  record = pundit_model(possibly_namespaced_record)
58
64
  policy = if policy_class
@@ -72,6 +78,7 @@ module Pundit
72
78
  # @param record [Object] the object we're retrieving the policy for
73
79
  # @raise [InvalidConstructorError] if the policy constructor called incorrectly
74
80
  # @return [Object, nil] instance of policy class with query methods
81
+ # @since v2.3.2
75
82
  def policy(record)
76
83
  cached_find(record, &:policy)
77
84
  end
@@ -83,6 +90,7 @@ module Pundit
83
90
  # @raise [NotDefinedError] if the policy cannot be found
84
91
  # @raise [InvalidConstructorError] if the policy constructor called incorrectly
85
92
  # @return [Object] instance of policy class with query methods
93
+ # @since v2.3.2
86
94
  def policy!(record)
87
95
  cached_find(record, &:policy!)
88
96
  end
@@ -97,6 +105,7 @@ module Pundit
97
105
  # @param scope [Object] the object we're retrieving the policy scope for
98
106
  # @raise [InvalidConstructorError] if the policy constructor called incorrectly
99
107
  # @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
108
+ # @since v2.3.2
100
109
  def policy_scope(scope)
101
110
  policy_scope_class = policy_finder(scope).scope
102
111
  return unless policy_scope_class
@@ -117,6 +126,7 @@ module Pundit
117
126
  # @raise [NotDefinedError] if the policy scope cannot be found
118
127
  # @raise [InvalidConstructorError] if the policy constructor called incorrectly
119
128
  # @return [Scope{#resolve}] instance of scope class which can resolve to a scope
129
+ # @since v2.3.2
120
130
  def policy_scope!(scope)
121
131
  policy_scope_class = policy_finder(scope).scope!
122
132
 
@@ -144,6 +154,7 @@ module Pundit
144
154
  # @yieldreturn [#new(user, model)]
145
155
  # @return [Policy, nil] an instantiated policy
146
156
  # @raise [InvalidConstructorError] if policy can't be instantated
157
+ # @since v2.3.2
147
158
  def cached_find(record)
148
159
  policy_cache.fetch(user: user, record: record) do
149
160
  klass = yield policy_finder(record)
@@ -163,6 +174,7 @@ module Pundit
163
174
  #
164
175
  # @api private
165
176
  # @return [PolicyFinder]
177
+ # @since v2.3.2
166
178
  def policy_finder(record)
167
179
  PolicyFinder.new(record)
168
180
  end
@@ -170,6 +182,7 @@ module Pundit
170
182
  # Given a possibly namespaced record, return the actual record.
171
183
  #
172
184
  # @api private
185
+ # @since v2.3.2
173
186
  def pundit_model(record)
174
187
  record.is_a?(Array) ? record.last : record
175
188
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pundit
4
+ # @api private
5
+ # @since v1.0.0
6
+ # To avoid name clashes with common Error naming when mixing in Pundit,
7
+ # keep it here with compact class style definition.
8
+ class Error < StandardError; end
9
+
10
+ # Error that will be raised when authorization has failed
11
+ # @since v0.1.0
12
+ class NotAuthorizedError < Error
13
+ # @see #initialize
14
+ # @since v0.2.3
15
+ attr_reader :query
16
+ # @see #initialize
17
+ # @since v0.2.3
18
+ attr_reader :record
19
+ # @see #initialize
20
+ # @since v0.2.3
21
+ attr_reader :policy
22
+
23
+ # @since v1.0.0
24
+ #
25
+ # @overload initialize(message)
26
+ # Create an error with a simple error message.
27
+ # @param [String] message A simple error message string.
28
+ #
29
+ # @overload initialize(options)
30
+ # Create an error with the specified attributes.
31
+ # @param [Hash] options The error options.
32
+ # @option options [String] :message Optional custom error message. Will default to a generalized message.
33
+ # @option options [Symbol] :query The name of the policy method that was checked.
34
+ # @option options [Object] :record The object that was being checked with the policy.
35
+ # @option options [Class] :policy The class of policy that was used for the check.
36
+ def initialize(options = {})
37
+ if options.is_a? String
38
+ message = options
39
+ else
40
+ @query = options[:query]
41
+ @record = options[:record]
42
+ @policy = options[:policy]
43
+
44
+ message = options.fetch(:message) do
45
+ record_name = record.is_a?(Class) ? record.to_s : "this #{record.class}"
46
+ "not allowed to #{policy.class}##{query} #{record_name}"
47
+ end
48
+ end
49
+
50
+ super(message)
51
+ end
52
+ end
53
+
54
+ # Error that will be raised if a policy or policy scope constructor is not called correctly.
55
+ # @since v2.0.0
56
+ class InvalidConstructorError < Error; end
57
+
58
+ # Error that will be raised if a controller action has not called the
59
+ # `authorize` or `skip_authorization` methods.
60
+ # @since v0.2.3
61
+ class AuthorizationNotPerformedError < Error; end
62
+
63
+ # Error that will be raised if a controller action has not called the
64
+ # `policy_scope` or `skip_policy_scope` methods.
65
+ # @since v0.3.0
66
+ class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
67
+
68
+ # Error that will be raised if a policy or policy scope is not defined.
69
+ # @since v0.1.0
70
+ class NotDefinedError < Error; end
71
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pundit
4
+ # Rails view helpers, to allow a slightly different view-specific
5
+ # implementation of the methods in {Pundit::Authorization}.
6
+ #
7
+ # @api private
8
+ # @since v1.0.0
9
+ module Helper
10
+ # @see Pundit::Authorization#pundit_policy_scope
11
+ # @since v1.0.0
12
+ def policy_scope(scope)
13
+ pundit_policy_scope(scope)
14
+ end
15
+ end
16
+ end
@@ -5,6 +5,7 @@ require "active_support/core_ext/string/inflections"
5
5
 
6
6
  module Pundit
7
7
  # Finds policy and scope classes for given object.
8
+ # @since v0.1.0
8
9
  # @api public
9
10
  # @example
10
11
  # user = User.find(params[:id])
@@ -16,12 +17,15 @@ module Pundit
16
17
  # A constant applied to the end of the class name to find the policy class.
17
18
  #
18
19
  # @api private
20
+ # @since v2.5.0
19
21
  SUFFIX = "Policy"
20
22
 
21
23
  # @see #initialize
24
+ # @since v0.1.0
22
25
  attr_reader :object
23
26
 
24
27
  # @param object [any] the object to find policy and scope classes for
28
+ # @since v0.1.0
25
29
  def initialize(object)
26
30
  @object = object
27
31
  end
@@ -32,6 +36,7 @@ module Pundit
32
36
  # scope = finder.scope #=> UserPolicy::Scope
33
37
  # scope.resolve #=> <#ActiveRecord::Relation ...>
34
38
  #
39
+ # @since v0.1.0
35
40
  def scope
36
41
  "#{policy}::Scope".safe_constantize
37
42
  end
@@ -43,6 +48,7 @@ module Pundit
43
48
  # policy.show? #=> true
44
49
  # policy.update? #=> false
45
50
  #
51
+ # @since v0.1.0
46
52
  def policy
47
53
  klass = find(object)
48
54
  klass.is_a?(String) ? klass.safe_constantize : klass
@@ -51,6 +57,7 @@ module Pundit
51
57
  # @return [Scope{#resolve}] scope class which can resolve to a scope
52
58
  # @raise [NotDefinedError] if scope could not be determined
53
59
  #
60
+ # @since v0.1.0
54
61
  def scope!
55
62
  scope or raise NotDefinedError, "unable to find scope `#{find(object)}::Scope` for `#{object.inspect}`"
56
63
  end
@@ -58,12 +65,14 @@ module Pundit
58
65
  # @return [Class] policy class with query methods
59
66
  # @raise [NotDefinedError] if policy could not be determined
60
67
  #
68
+ # @since v0.1.0
61
69
  def policy!
62
70
  policy or raise NotDefinedError, "unable to find policy `#{find(object)}` for `#{object.inspect}`"
63
71
  end
64
72
 
65
73
  # @return [String] the name of the key this object would have in a params hash
66
74
  #
75
+ # @since v1.1.0
67
76
  def param_key # rubocop:disable Metrics/AbcSize
68
77
  model = object.is_a?(Array) ? object.last : object
69
78
 
@@ -83,6 +92,7 @@ module Pundit
83
92
  # Uses recursion to handle namespaces.
84
93
  #
85
94
  # @return [String, Class] the policy class, or its name.
95
+ # @since v0.2.0
86
96
  def find(subject)
87
97
  if subject.is_a?(Array)
88
98
  modules = subject.dup
@@ -107,6 +117,7 @@ module Pundit
107
117
  # - Supports object instances.
108
118
  #
109
119
  # @return [String, Class] the class, or its name.
120
+ # @since v1.1.0
110
121
  def find_class_name(subject)
111
122
  if subject.respond_to?(:model_name)
112
123
  subject.model_name
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pundit
4
+ # @since v2.5.0
4
5
  class Railtie < Rails::Railtie
5
6
  if Rails.version.to_f >= 8.0
6
7
  initializer "pundit.stats_directories" do
data/lib/pundit/rspec.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pundit"
3
4
  # Array#to_sentence
4
5
  require "active_support/core_ext/array/conversions"
5
6
 
6
7
  module Pundit
7
8
  # Namespace for Pundit's RSpec integration.
9
+ # @since v0.1.0
8
10
  module RSpec
9
11
  # Namespace for Pundit's RSpec matchers.
10
12
  module Matchers
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Pundit
4
4
  # The current version of Pundit.
5
- VERSION = "2.5.0"
5
+ VERSION = "2.5.1"
6
6
  end
data/lib/pundit.rb CHANGED
@@ -3,83 +3,30 @@
3
3
  require "active_support"
4
4
 
5
5
  require "pundit/version"
6
+ require "pundit/error"
6
7
  require "pundit/policy_finder"
7
- require "pundit/authorization"
8
8
  require "pundit/context"
9
+ require "pundit/authorization"
10
+ require "pundit/helper"
9
11
  require "pundit/cache_store"
10
12
  require "pundit/cache_store/null_store"
11
13
  require "pundit/cache_store/legacy_store"
12
14
  require "pundit/railtie" if defined?(Rails)
13
15
 
14
- # @api private
15
- # To avoid name clashes with common Error naming when mixing in Pundit,
16
- # keep it here with compact class style definition.
17
- class Pundit::Error < StandardError; end # rubocop:disable Style/ClassAndModuleChildren
18
-
19
16
  # Hello? Yes, this is Pundit.
20
17
  #
21
18
  # @api public
22
19
  module Pundit
23
20
  # @api private
21
+ # @since v1.0.0
24
22
  # @deprecated See {Pundit::PolicyFinder}
25
23
  SUFFIX = Pundit::PolicyFinder::SUFFIX
26
24
 
27
25
  # @api private
28
26
  # @private
27
+ # @since v0.1.0
29
28
  module Generators; end
30
29
 
31
- # Error that will be raised when authorization has failed
32
- class NotAuthorizedError < Error
33
- # @see #initialize
34
- attr_reader :query
35
- # @see #initialize
36
- attr_reader :record
37
- # @see #initialize
38
- attr_reader :policy
39
-
40
- # @overload initialize(message)
41
- # Create an error with a simple error message.
42
- # @param [String] message A simple error message string.
43
- #
44
- # @overload initialize(options)
45
- # Create an error with the specified attributes.
46
- # @param [Hash] options The error options.
47
- # @option options [String] :message Optional custom error message. Will default to a generalized message.
48
- # @option options [Symbol] :query The name of the policy method that was checked.
49
- # @option options [Object] :record The object that was being checked with the policy.
50
- # @option options [Class] :policy The class of policy that was used for the check.
51
- def initialize(options = {})
52
- if options.is_a? String
53
- message = options
54
- else
55
- @query = options[:query]
56
- @record = options[:record]
57
- @policy = options[:policy]
58
-
59
- message = options.fetch(:message) do
60
- record_name = record.is_a?(Class) ? record.to_s : "this #{record.class}"
61
- "not allowed to #{policy.class}##{query} #{record_name}"
62
- end
63
- end
64
-
65
- super(message)
66
- end
67
- end
68
-
69
- # Error that will be raised if a policy or policy scope constructor is not called correctly.
70
- class InvalidConstructorError < Error; end
71
-
72
- # Error that will be raised if a controller action has not called the
73
- # `authorize` or `skip_authorization` methods.
74
- class AuthorizationNotPerformedError < Error; end
75
-
76
- # Error that will be raised if a controller action has not called the
77
- # `policy_scope` or `skip_policy_scope` methods.
78
- class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
79
-
80
- # Error that will be raised if a policy or policy scope is not defined.
81
- class NotDefinedError < Error; end
82
-
83
30
  def self.included(base)
84
31
  location = caller_locations(1, 1).first
85
32
  warn <<~WARNING
@@ -91,6 +38,7 @@ module Pundit
91
38
 
92
39
  class << self
93
40
  # @see Pundit::Context#authorize
41
+ # @since v1.0.0
94
42
  def authorize(user, record, query, policy_class: nil, cache: nil)
95
43
  context = if cache
96
44
  policy_cache = CacheStore::LegacyStore.new(cache)
@@ -103,34 +51,27 @@ module Pundit
103
51
  end
104
52
 
105
53
  # @see Pundit::Context#policy_scope
54
+ # @since v0.1.0
106
55
  def policy_scope(user, *args, **kwargs, &block)
107
56
  Context.new(user: user).policy_scope(*args, **kwargs, &block)
108
57
  end
109
58
 
110
59
  # @see Pundit::Context#policy_scope!
60
+ # @since v0.1.0
111
61
  def policy_scope!(user, *args, **kwargs, &block)
112
62
  Context.new(user: user).policy_scope!(*args, **kwargs, &block)
113
63
  end
114
64
 
115
65
  # @see Pundit::Context#policy
66
+ # @since v0.1.0
116
67
  def policy(user, *args, **kwargs, &block)
117
68
  Context.new(user: user).policy(*args, **kwargs, &block)
118
69
  end
119
70
 
120
71
  # @see Pundit::Context#policy!
72
+ # @since v0.1.0
121
73
  def policy!(user, *args, **kwargs, &block)
122
74
  Context.new(user: user).policy!(*args, **kwargs, &block)
123
75
  end
124
76
  end
125
-
126
- # Rails view helpers, to allow a slightly different view-specific
127
- # implementation of the methods in {Pundit::Authorization}.
128
- #
129
- # @api private
130
- module Helper
131
- # @see Pundit::Authorization#pundit_policy_scope
132
- def policy_scope(scope)
133
- pundit_policy_scope(scope)
134
- end
135
- end
136
77
  end