pundit 2.0.1 → 2.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: dffd7b483c73feb3955b9f1eb6767d9fedb72eaf
4
- data.tar.gz: 5de4a5628f75bfcd87879c52917634f1ddde7072
2
+ SHA256:
3
+ metadata.gz: def6c710d9f9d1705ca43cdad9364bb34ce5d878b8a3a9bf26d336802e40efeb
4
+ data.tar.gz: 0d6618cb61dfef8ae18f811a73b3f059d9945f8def7f9b2f794ae095b3a0f0cf
5
5
  SHA512:
6
- metadata.gz: f21abdc81639b1d05209f1dfc71579294ba5226372493936ea9e6cfc2cc356e620223042f9f58679a2bb276dabab3f81e793a22d4b6e4bb69ef7edb467d399c1
7
- data.tar.gz: fe50e431d42e21e415ad361a1a0f536373e4a90b6f0631321dce3ba1b8e804c13b3e1d44f0446b3b1e71c68dbd868b5881b7bbaf6367e69b92bf23acf34a1022
6
+ metadata.gz: 7105cd0a84469071de9211e19f7e7a31f4ea8b5283d7b1ed007b6533805de18d105c09128a9936144612f3daa8fadfdf0698f7448d8db94e47bb459efaa11c4b
7
+ data.tar.gz: 3805e2664f21f30c66e9a9a05606f0d0d18b1607137e794948c7907bd33c6d6e64a45b9abb97d2f1a21df0d46497ff708679442807e152fa167abc461c8c0abe
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .config
5
+ .coverage
5
6
  .yardoc
6
7
  Gemfile.lock
7
8
  InstalledFiles
data/.rubocop.yml CHANGED
@@ -1,10 +1,7 @@
1
1
  AllCops:
2
- DisplayCopNames: true
3
- TargetRubyVersion: 2.2
2
+ TargetRubyVersion: 2.6
4
3
  Exclude:
5
- - "gemfiles/**/*"
6
- - "vendor/**/*"
7
- - "lib/generators/**/*"
4
+ - "lib/generators/**/templates/**/*"
8
5
 
9
6
  Metrics/BlockLength:
10
7
  Exclude:
@@ -30,33 +27,9 @@ Metrics/CyclomaticComplexity:
30
27
  Metrics/PerceivedComplexity:
31
28
  Enabled: false
32
29
 
33
- Style/StructInheritance:
34
- Enabled: false
35
-
36
30
  Layout/AlignParameters:
37
31
  EnforcedStyle: with_fixed_indentation
38
32
 
39
- Style/StringLiterals:
40
- EnforcedStyle: double_quotes
41
-
42
- Style/StringLiteralsInInterpolation:
43
- EnforcedStyle: double_quotes
44
-
45
- Layout/ClosingParenthesisIndentation:
46
- Enabled: false
47
-
48
- Style/OneLineConditional:
49
- Enabled: false
50
-
51
- Style/AndOr:
52
- Enabled: false
53
-
54
- Style/Not:
55
- Enabled: false
56
-
57
- Documentation:
58
- Enabled: false # TODO: Enable again once we have more docs
59
-
60
33
  Layout/CaseIndentation:
61
34
  EnforcedStyle: case
62
35
  SupportedStyles:
@@ -64,40 +37,31 @@ Layout/CaseIndentation:
64
37
  - end
65
38
  IndentOneStep: true
66
39
 
40
+ Layout/EndAlignment:
41
+ EnforcedStyleAlignWith: variable
42
+
67
43
  Style/PercentLiteralDelimiters:
68
44
  PreferredDelimiters:
69
45
  '%w': "[]"
70
46
  '%W': "[]"
71
47
 
72
- Layout/AccessModifierIndentation:
73
- EnforcedStyle: outdent
74
-
75
- Style/SignalException:
76
- Enabled: false
77
-
78
- Layout/IndentationWidth:
79
- Enabled: false
80
-
81
- Style/TrivialAccessors:
82
- ExactNameMatch: true
83
-
84
- Layout/EndAlignment:
85
- EnforcedStyleAlignWith: variable
86
-
87
- Layout/DefEndAlignment:
88
- Enabled: false
48
+ Style/StringLiterals:
49
+ EnforcedStyle: double_quotes
89
50
 
90
- Lint/HandleExceptions:
91
- Enabled: false
51
+ Style/StringLiteralsInInterpolation:
52
+ EnforcedStyle: double_quotes
92
53
 
93
- Style/SpecialGlobalVars:
54
+ Style/StructInheritance:
94
55
  Enabled: false
95
56
 
96
- Style/TrivialAccessors:
57
+ Style/AndOr:
97
58
  Enabled: false
98
59
 
99
- Layout/IndentHash:
60
+ Style/Not:
100
61
  Enabled: false
101
62
 
102
63
  Style/DoubleNegation:
103
64
  Enabled: false
65
+
66
+ Documentation:
67
+ Enabled: false # TODO: Enable again once we have more docs
data/.travis.yml CHANGED
@@ -1,20 +1,25 @@
1
1
  language: ruby
2
- before_install:
3
- - gem install bundler -v 1.17.3
2
+ dist: focal
4
3
 
5
4
  matrix:
6
5
  include:
7
- - rvm: 2.5.1
6
+ - name: "RuboCop lint on pre-installed Ruby version"
7
+ rvm: 2.7.1 # Pre-installed Ruby version
8
+ before_install:
9
+ - gem install bundler
8
10
  script: bundle exec rake rubocop # ONLY lint once, first
9
- - rvm: 2.1
10
- - rvm: 2.2
11
- - rvm: 2.3.5
12
- - rvm: 2.4.2
13
- - rvm: 2.5.1
14
- - rvm: 2.6.0
15
- - rvm: jruby-9.1.8.0
16
- env:
17
- - JRUBY_OPTS="--debug"
18
- - rvm: jruby-9.2.5.0
11
+ - rvm: 2.6.7
12
+ before_script:
13
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
14
+ - chmod +x ./cc-test-reporter
15
+ - ./cc-test-reporter before-build
16
+ after_script:
17
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
18
+ - rvm: 2.7.3
19
+ - rvm: 3.0.1
20
+ - rvm: jruby-9.2.17.0
19
21
  env:
20
22
  - JRUBY_OPTS="--debug"
23
+ - rvm: truffleruby-head
24
+ allow_failures:
25
+ - rvm: truffleruby-head
data/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Pundit
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 2.1.1 (2021-08-13)
6
+
7
+ Friday 13th-release!
8
+
9
+ Careful! The bugfix below (#626) could break existing code. If you rely on the
10
+ return value for `authorize` and namespaced policies you might need to do some
11
+ changes.
12
+
13
+ ### Fixed
14
+
15
+ - `.authorize` and `#authorize` return the instance, even for namespaced
16
+ policies (#626)
17
+
18
+ ### Changed
19
+
20
+ - Generate application scope with `protected` attr_readers. (#616)
21
+
22
+ ### Removed
23
+
24
+ - Dropped support for Ruby end-of-life versions: 2.1 and 2.2. (#604)
25
+ - Dropped support for Ruby end-of-life versions: 2.3 (#633)
26
+ - Dropped support for Ruby end-of-life versions: 2.4, 2.5 and JRuby 9.1 (#676)
27
+ - Dropped support for RSpec 2 (#615)
28
+
29
+ ## 2.1.0 (2019-08-14)
30
+
31
+ ### Fixed
32
+
33
+ - Avoid name clashes with the Error class. (#590)
34
+
35
+ ### Changed
36
+
37
+ - Return a safer default NotAuthorizedError message. (#583)
38
+
3
39
  ## 2.0.1 (2019-01-18)
4
40
 
5
41
  ### Breaking changes
data/Gemfile CHANGED
@@ -1,16 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  ruby RUBY_VERSION
4
6
 
5
7
  gemspec
6
-
7
- group :development, :test do
8
- gem "actionpack"
9
- gem "activemodel"
10
- gem "bundler"
11
- gem "pry"
12
- gem "rake"
13
- gem "rspec"
14
- gem "rubocop"
15
- gem "yard"
16
- end
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2018 Jonas Nicklas, Varvet AB
1
+ Copyright (c) 2019 Jonas Nicklas, Varvet AB
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  Pundit provides a set of helpers which guide you in leveraging regular Ruby
9
9
  classes and object oriented design patterns to build a simple, robust and
10
- scaleable authorization system.
10
+ scalable authorization system.
11
11
 
12
12
  Links:
13
13
 
@@ -31,7 +31,6 @@ Include Pundit in your application controller:
31
31
  ``` ruby
32
32
  class ApplicationController < ActionController::Base
33
33
  include Pundit
34
- protect_from_forgery
35
34
  end
36
35
  ```
37
36
 
@@ -61,7 +60,7 @@ class PostPolicy
61
60
  end
62
61
 
63
62
  def update?
64
- user.admin? or not post.published?
63
+ user.admin? || !post.published?
65
64
  end
66
65
  end
67
66
  ```
@@ -165,13 +164,18 @@ def admin_list
165
164
  end
166
165
  ```
167
166
 
168
- `authorize` returns the object passed to it, so you can chain it like this:
167
+ `authorize` returns the instance passed to it, so you can chain it like this:
169
168
 
170
169
  Controller:
171
170
  ```ruby
172
171
  def show
173
172
  @user = authorize User.find(params[:id])
174
173
  end
174
+
175
+ # return the record even for namespaced policies
176
+ def show
177
+ @user = authorize [:admin, User.find(params[:id])]
178
+ end
175
179
  ```
176
180
 
177
181
  You can easily get a hold of an instance of the policy through the `policy`
@@ -220,8 +224,6 @@ define a class called a policy scope. It can look something like this:
220
224
  ``` ruby
221
225
  class PostPolicy < ApplicationPolicy
222
226
  class Scope
223
- attr_reader :user, :scope
224
-
225
227
  def initialize(user, scope)
226
228
  @user = user
227
229
  @scope = scope
@@ -234,6 +236,10 @@ class PostPolicy < ApplicationPolicy
234
236
  scope.where(published: true)
235
237
  end
236
238
  end
239
+
240
+ private
241
+
242
+ attr_reader :user, :scope
237
243
  end
238
244
 
239
245
  def update?
@@ -296,13 +302,11 @@ def index
296
302
  end
297
303
  ```
298
304
 
299
- Just as with your policy, this will automatically infer that you want to use
300
- the `PostPolicy::Scope` class, it will instantiate this class and call
301
- `resolve` on the instance. In this case it is a shortcut for doing:
305
+ In this case it is a shortcut for doing:
302
306
 
303
307
  ``` ruby
304
308
  def index
305
- @posts = PostPolicy::Scope.new(current_user, Post).resolve
309
+ @publications = PublicationPolicy::Scope.new(current_user, Post).resolve
306
310
  end
307
311
  ```
308
312
 
@@ -391,6 +395,16 @@ class Post
391
395
  end
392
396
  ```
393
397
 
398
+ Alternatively, you can declare an instance method:
399
+
400
+ ``` ruby
401
+ class Post
402
+ def policy_class
403
+ PostablePolicy
404
+ end
405
+ end
406
+ ```
407
+
394
408
  ## Just plain old Ruby
395
409
 
396
410
  As you can see, Pundit doesn't do anything you couldn't have easily done
@@ -476,7 +490,6 @@ method in every controller.
476
490
 
477
491
  ```ruby
478
492
  class ApplicationController < ActionController::Base
479
- protect_from_forgery
480
493
  include Pundit
481
494
 
482
495
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
@@ -597,8 +610,7 @@ class Admin::PostController < AdminController
597
610
  end
598
611
 
599
612
  def show
600
- post = Post.find(params[:id])
601
- authorize(post)
613
+ post = authorize Post.find(params[:id])
602
614
  end
603
615
  end
604
616
  ```
@@ -641,9 +653,8 @@ end
641
653
 
642
654
  ## Strong parameters
643
655
 
644
- In Rails 4 (or Rails 3.2 with the
645
- [strong_parameters](https://github.com/rails/strong_parameters) gem),
646
- mass-assignment protection is handled in the controller. With Pundit you can
656
+ In Rails,
657
+ mass-assignment protection is handled in the controller. With Pundit you can
647
658
  control which attributes a user has access to update via your policies. You can
648
659
  set up a `permitted_attributes` method in your policy like this:
649
660
 
@@ -782,9 +793,14 @@ Pundit does not provide a DSL for testing scopes. Just test it like a regular Ru
782
793
  - [RailsApps Example Application: Pundit and Devise](https://github.com/RailsApps/rails-devise-pundit)
783
794
  - [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
784
795
  - [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
796
+ - [Testing Pundit with Minitest](https://github.com/varvet/pundit/issues/204#issuecomment-60166450)
785
797
  - [Using Pundit outside of a Rails controller](https://github.com/varvet/pundit/pull/136)
786
798
  - [Straightforward Rails Authorization with Pundit](http://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
787
799
 
800
+ ## Other implementations
801
+
802
+ - [Flask-Pundit](https://github.com/anurag90x/flask-pundit) (Python) is a [Flask](http://flask.pocoo.org/) extension "heavily inspired by" Pundit
803
+
788
804
  # License
789
805
 
790
806
  Licensed under the MIT license, see the separate LICENSE.txt file.
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rubygems"
2
4
  require "bundler/gem_tasks"
3
5
  require "rspec/core/rake_task"
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pundit
2
4
  module Generators
3
5
  class InstallGenerator < ::Rails::Generators::Base
4
- source_root File.expand_path('templates', __dir__)
6
+ source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  def copy_application_policy
7
- template 'application_policy.rb', 'app/policies/application_policy.rb'
9
+ template "application_policy.rb", "app/policies/application_policy.rb"
8
10
  end
9
11
  end
10
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ApplicationPolicy
2
4
  attr_reader :user, :record
3
5
 
@@ -35,8 +37,6 @@ class ApplicationPolicy
35
37
  end
36
38
 
37
39
  class Scope
38
- attr_reader :user, :scope
39
-
40
40
  def initialize(user, scope)
41
41
  @user = user
42
42
  @scope = scope
@@ -45,5 +45,9 @@ class ApplicationPolicy
45
45
  def resolve
46
46
  scope.all
47
47
  end
48
+
49
+ private
50
+
51
+ attr_reader :user, :scope
48
52
  end
49
53
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pundit
2
4
  module Generators
3
5
  class PolicyGenerator < ::Rails::Generators::NamedBase
4
- source_root File.expand_path('templates', __dir__)
6
+ source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  def create_policy
7
- template 'policy.rb', File.join('app/policies', class_path, "#{file_name}_policy.rb")
9
+ template "policy.rb", File.join("app/policies", class_path, "#{file_name}_policy.rb")
8
10
  end
9
11
 
10
12
  hook_for :test_framework
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rspec
2
4
  module Generators
3
5
  class PolicyGenerator < ::Rails::Generators::NamedBase
4
- source_root File.expand_path('templates', __dir__)
6
+ source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  def create_policy_spec
7
- template 'policy_spec.rb', File.join('spec/policies', class_path, "#{file_name}_policy_spec.rb")
9
+ template "policy_spec.rb", File.join("spec/policies", class_path, "#{file_name}_policy_spec.rb")
8
10
  end
9
11
  end
10
12
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TestUnit
2
4
  module Generators
3
5
  class PolicyGenerator < ::Rails::Generators::NamedBase
4
- source_root File.expand_path('templates', __dir__)
6
+ source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  def create_policy_test
7
- template 'policy_test.rb', File.join('test/policies', class_path, "#{file_name}_policy_test.rb")
9
+ template "policy_test.rb", File.join("test/policies", class_path, "#{file_name}_policy_test.rb")
8
10
  end
9
11
  end
10
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pundit
2
4
  # Finds policy and scope classes for given object.
3
5
  # @api public
@@ -66,7 +68,7 @@ module Pundit
66
68
  end
67
69
  end
68
70
 
69
- private
71
+ private
70
72
 
71
73
  def find(subject)
72
74
  if subject.is_a?(Array)
data/lib/pundit/rspec.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "active_support/core_ext/array/conversions"
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Pundit
4
4
  module RSpec
@@ -72,17 +72,9 @@ module Pundit
72
72
  end
73
73
 
74
74
  RSpec.configure do |config|
75
- if RSpec::Core::Version::STRING.split(".").first.to_i >= 3
76
- config.include(
77
- Pundit::RSpec::PolicyExampleGroup,
78
- type: :policy,
79
- file_path: %r{spec/policies}
80
- )
81
- else
82
- config.include(
83
- Pundit::RSpec::PolicyExampleGroup,
84
- type: :policy,
85
- example_group: { file_path: %r{spec/policies} }
86
- )
87
- end
75
+ config.include(
76
+ Pundit::RSpec::PolicyExampleGroup,
77
+ type: :policy,
78
+ file_path: %r{spec/policies}
79
+ )
88
80
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pundit
4
- VERSION = "2.0.1".freeze
4
+ VERSION = "2.1.1"
5
5
  end
data/lib/pundit.rb CHANGED
@@ -8,16 +8,18 @@ require "active_support/core_ext/object/blank"
8
8
  require "active_support/core_ext/module/introspection"
9
9
  require "active_support/dependencies/autoload"
10
10
 
11
+ # @api private
12
+ # To avoid name clashes with common Error naming when mixing in Pundit,
13
+ # keep it here with compact class style definition.
14
+ class Pundit::Error < StandardError; end # rubocop:disable Style/ClassAndModuleChildren
15
+
11
16
  # @api public
12
17
  module Pundit
13
- SUFFIX = "Policy".freeze
18
+ SUFFIX = "Policy"
14
19
 
15
20
  # @api private
16
21
  module Generators; end
17
22
 
18
- # @api private
19
- class Error < StandardError; end
20
-
21
23
  # Error that will be raised when authorization has failed
22
24
  class NotAuthorizedError < Error
23
25
  attr_reader :query, :record, :policy
@@ -30,7 +32,7 @@ module Pundit
30
32
  @record = options[:record]
31
33
  @policy = options[:policy]
32
34
 
33
- message = options.fetch(:message) { "not allowed to #{query} this #{record.inspect}" }
35
+ message = options.fetch(:message) { "not allowed to #{query} this #{record.class}" }
34
36
  end
35
37
 
36
38
  super(message)
@@ -69,7 +71,7 @@ module Pundit
69
71
 
70
72
  raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
71
73
 
72
- record
74
+ record.is_a?(Array) ? record.last : record
73
75
  end
74
76
 
75
77
  # Retrieves the policy scope for the given record.
@@ -122,7 +124,7 @@ module Pundit
122
124
  # @return [Object, nil] instance of policy class with query methods
123
125
  def policy(user, record)
124
126
  policy = PolicyFinder.new(record).policy
125
- policy.new(user, pundit_model(record)) if policy
127
+ policy&.new(user, pundit_model(record))
126
128
  rescue ArgumentError
127
129
  raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
128
130
  end
@@ -142,7 +144,7 @@ module Pundit
142
144
  raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
143
145
  end
144
146
 
145
- private
147
+ private
146
148
 
147
149
  def pundit_model(record)
148
150
  record.is_a?(Array) ? record.last : record
@@ -165,7 +167,7 @@ module Pundit
165
167
  end
166
168
  end
167
169
 
168
- protected
170
+ protected
169
171
 
170
172
  # @return [Boolean] whether authorization has been performed, i.e. whether
171
173
  # one {#authorize} or {#skip_authorization} has been called
@@ -220,7 +222,7 @@ protected
220
222
 
221
223
  raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
222
224
 
223
- record
225
+ record.is_a?(Array) ? record.last : record
224
226
  end
225
227
 
226
228
  # Allow this action not to perform authorization.
@@ -315,7 +317,7 @@ protected
315
317
  current_user
316
318
  end
317
319
 
318
- private
320
+ private
319
321
 
320
322
  def pundit_policy_scope(scope)
321
323
  policy_scopes[scope] ||= Pundit.policy_scope!(pundit_user, scope)
data/pundit.gemspec CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path("lib", __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require "pundit/version"
@@ -12,10 +14,19 @@ Gem::Specification.new do |gem|
12
14
  gem.homepage = "https://github.com/varvet/pundit"
13
15
  gem.license = "MIT"
14
16
 
15
- gem.files = `git ls-files`.split($/)
17
+ gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
16
18
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
17
19
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
20
  gem.require_paths = ["lib"]
19
21
 
20
22
  gem.add_dependency "activesupport", ">= 3.0.0"
23
+ gem.add_development_dependency "actionpack", ">= 3.0.0"
24
+ gem.add_development_dependency "activemodel", ">= 3.0.0"
25
+ gem.add_development_dependency "bundler"
26
+ gem.add_development_dependency "pry"
27
+ gem.add_development_dependency "rake"
28
+ gem.add_development_dependency "rspec", ">= 3.0.0"
29
+ gem.add_development_dependency "rubocop", "0.74.0"
30
+ gem.add_development_dependency "simplecov", ">= 0.17.0"
31
+ gem.add_development_dependency "yard"
21
32
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
- describe PostPolicy do
5
+ RSpec.describe PostPolicy do
4
6
  let(:user) { double }
5
7
  let(:own_post) { double(user: user) }
6
8
  let(:other_post) { double(user: double) }
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
- describe Pundit::PolicyFinder do
5
+ RSpec.describe Pundit::PolicyFinder do
4
6
  let(:user) { double }
5
7
  let(:post) { Post.new(user) }
6
8
  let(:comment) { CommentFourFiveSix.new }
@@ -22,37 +24,100 @@ describe Pundit::PolicyFinder do
22
24
  end
23
25
 
24
26
  describe "#policy" do
25
- subject { described_class.new(post) }
27
+ context "with an instance" do
28
+ it "returns the associated policy" do
29
+ object = described_class.new(post)
30
+
31
+ expect(object.policy).to eq PostPolicy
32
+ end
33
+ end
34
+
35
+ context "with an array of symbols" do
36
+ it "returns the associated namespaced policy" do
37
+ object = described_class.new(%i[project post])
38
+
39
+ expect(object.policy).to eq Project::PostPolicy
40
+ end
41
+ end
26
42
 
27
- it "returns a policy" do
28
- expect(subject.policy).to eq PostPolicy
43
+ context "with an array of a symbol and an instance" do
44
+ it "returns the associated namespaced policy" do
45
+ object = described_class.new([:project, post])
46
+
47
+ expect(object.policy).to eq Project::PostPolicy
48
+ end
29
49
  end
30
50
 
31
- context "with a string" do
32
- it "returns a policy" do
33
- allow(subject).to receive(:find).and_return "PostPolicy"
34
- expect(subject.policy).to eq PostPolicy
51
+ context "with an array of a symbol and a class with a specified policy class" do
52
+ it "returns the associated namespaced policy" do
53
+ object = described_class.new([:project, Customer::Post])
54
+
55
+ expect(object.policy).to eq Project::PostPolicy
56
+ end
57
+ end
58
+
59
+ context "with an array of a symbol and a class with a specified model name" do
60
+ it "returns the associated namespaced policy" do
61
+ object = described_class.new([:project, CommentsRelation])
62
+
63
+ expect(object.policy).to eq Project::CommentPolicy
35
64
  end
36
65
  end
37
66
 
38
67
  context "with a class" do
39
- it "returns a policy" do
40
- allow(subject).to receive(:find).and_return PostPolicy
41
- expect(subject.policy).to eq PostPolicy
68
+ it "returns the associated policy" do
69
+ object = described_class.new(Post)
70
+
71
+ expect(object.policy).to eq PostPolicy
72
+ end
73
+ end
74
+
75
+ context "with a class which has a specified policy class" do
76
+ it "returns the associated policy" do
77
+ object = described_class.new(Customer::Post)
78
+
79
+ expect(object.policy).to eq PostPolicy
80
+ end
81
+ end
82
+
83
+ context "with an instance which has a specified policy class" do
84
+ it "returns the associated policy" do
85
+ object = described_class.new(Customer::Post.new(user))
86
+
87
+ expect(object.policy).to eq PostPolicy
88
+ end
89
+ end
90
+
91
+ context "with a class which has a specified model name" do
92
+ it "returns the associated policy" do
93
+ object = described_class.new(CommentsRelation)
94
+
95
+ expect(object.policy).to eq CommentPolicy
96
+ end
97
+ end
98
+
99
+ context "with an instance which has a specified policy class" do
100
+ it "returns the associated policy" do
101
+ object = described_class.new(CommentsRelation.new)
102
+
103
+ expect(object.policy).to eq CommentPolicy
42
104
  end
43
105
  end
44
106
 
45
107
  context "with nil" do
46
- it "returns nil" do
47
- allow(subject).to receive(:find).and_return nil
48
- expect(subject.policy).to eq nil
108
+ it "returns a NilClassPolicy" do
109
+ object = described_class.new(nil)
110
+
111
+ expect(object.policy).to eq NilClassPolicy
49
112
  end
50
113
  end
51
114
 
52
- context "with a string that can't be constantized" do
115
+ context "with a class that doesn't have an associated policy" do
53
116
  it "returns nil" do
54
- allow(subject).to receive(:find).and_return "FooPolicy"
55
- expect(subject.policy).to eq nil
117
+ class Foo; end
118
+ object = described_class.new(Foo)
119
+
120
+ expect(object.policy).to eq nil
56
121
  end
57
122
  end
58
123
  end
data/spec/pundit_spec.rb CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
- describe Pundit do
5
+ RSpec.describe Pundit do
4
6
  let(:user) { double }
5
7
  let(:post) { Post.new(user) }
6
8
  let(:customer_post) { Customer::Post.new(user) }
@@ -23,6 +25,26 @@ describe Pundit do
23
25
  expect(Pundit.authorize(user, post, :update?)).to be_truthy
24
26
  end
25
27
 
28
+ it "returns the record on successful authorization" do
29
+ expect(Pundit.authorize(user, post, :update?)).to eq(post)
30
+ end
31
+
32
+ it "returns the record when passed record with namespace " do
33
+ expect(Pundit.authorize(user, [:project, comment], :update?)).to eq(comment)
34
+ end
35
+
36
+ it "returns the record when passed record with nested namespace " do
37
+ expect(Pundit.authorize(user, [:project, :admin, comment], :update?)).to eq(comment)
38
+ end
39
+
40
+ it "returns the policy name symbol when passed record with headless policy" do
41
+ expect(Pundit.authorize(user, :publication, :create?)).to eq(:publication)
42
+ end
43
+
44
+ it "returns the class when passed record not a particular instance" do
45
+ expect(Pundit.authorize(user, Post, :show?)).to eq(Post)
46
+ end
47
+
26
48
  it "can be given a different policy class" do
27
49
  expect(Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy)).to be_truthy
28
50
  end
@@ -36,7 +58,7 @@ describe Pundit do
36
58
  # rubocop:disable Style/MultilineBlockChain
37
59
  expect do
38
60
  Pundit.authorize(user, post, :destroy?)
39
- end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this #<Post>") do |error|
61
+ end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this Post") do |error|
40
62
  expect(error.query).to eq :destroy?
41
63
  expect(error.record).to eq post
42
64
  expect(error.policy).to eq Pundit.policy(user, post)
@@ -408,7 +430,23 @@ describe Pundit do
408
430
  end
409
431
 
410
432
  it "returns the record on successful authorization" do
411
- expect(controller.authorize(post)).to be(post)
433
+ expect(controller.authorize(post)).to eq(post)
434
+ end
435
+
436
+ it "returns the record when passed record with namespace " do
437
+ expect(controller.authorize([:project, comment], :update?)).to eq(comment)
438
+ end
439
+
440
+ it "returns the record when passed record with nested namespace " do
441
+ expect(controller.authorize([:project, :admin, comment], :update?)).to eq(comment)
442
+ end
443
+
444
+ it "returns the policy name symbol when passed record with headless policy" do
445
+ expect(controller.authorize(:publication, :create?)).to eq(:publication)
446
+ end
447
+
448
+ it "returns the class when passed record not a particular instance" do
449
+ expect(controller.authorize(Post, :show?)).to eq(Post)
412
450
  end
413
451
 
414
452
  it "can be given a different permission to check" do
@@ -518,11 +556,13 @@ describe Pundit do
518
556
 
519
557
  describe "#permitted_attributes" do
520
558
  it "checks policy for permitted attributes" do
521
- params = ActionController::Parameters.new(post: {
522
- title: "Hello",
523
- votes: 5,
524
- admin: true
525
- })
559
+ params = ActionController::Parameters.new(
560
+ post: {
561
+ title: "Hello",
562
+ votes: 5,
563
+ admin: true
564
+ }
565
+ )
526
566
 
527
567
  action = "update"
528
568
 
@@ -534,11 +574,13 @@ describe Pundit do
534
574
  end
535
575
 
536
576
  it "checks policy for permitted attributes for record of a ActiveModel type" do
537
- params = ActionController::Parameters.new(customer_post: {
538
- title: "Hello",
539
- votes: 5,
540
- admin: true
541
- })
577
+ params = ActionController::Parameters.new(
578
+ customer_post: {
579
+ title: "Hello",
580
+ votes: 5,
581
+ admin: true
582
+ }
583
+ )
542
584
 
543
585
  action = "update"
544
586
 
@@ -554,24 +596,28 @@ describe Pundit do
554
596
 
555
597
  describe "#permitted_attributes_for_action" do
556
598
  it "is checked if it is defined in the policy" do
557
- params = ActionController::Parameters.new(post: {
558
- title: "Hello",
559
- body: "blah",
560
- votes: 5,
561
- admin: true
562
- })
599
+ params = ActionController::Parameters.new(
600
+ post: {
601
+ title: "Hello",
602
+ body: "blah",
603
+ votes: 5,
604
+ admin: true
605
+ }
606
+ )
563
607
 
564
608
  action = "revise"
565
609
  expect(Controller.new(user, action, params).permitted_attributes(post).to_h).to eq("body" => "blah")
566
610
  end
567
611
 
568
612
  it "can be explicitly set" do
569
- params = ActionController::Parameters.new(post: {
570
- title: "Hello",
571
- body: "blah",
572
- votes: 5,
573
- admin: true
574
- })
613
+ params = ActionController::Parameters.new(
614
+ post: {
615
+ title: "Hello",
616
+ body: "blah",
617
+ votes: 5,
618
+ admin: true
619
+ }
620
+ )
575
621
 
576
622
  action = "update"
577
623
  expect(Controller.new(user, action, params).permitted_attributes(post, :revise).to_h).to eq("body" => "blah")
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "simplecov"
4
+ SimpleCov.start do
5
+ add_filter "/spec/"
6
+ end
7
+
1
8
  require "pundit"
2
9
  require "pundit/rspec"
3
10
 
@@ -9,22 +16,6 @@ require "active_support/core_ext"
9
16
  require "active_model/naming"
10
17
  require "action_controller/metal/strong_parameters"
11
18
 
12
- I18n.enforce_available_locales = false
13
-
14
- module PunditSpecHelper
15
- extend RSpec::Matchers::DSL
16
-
17
- matcher :be_truthy do
18
- match do |actual|
19
- actual
20
- end
21
- end
22
- end
23
-
24
- RSpec.configure do |config|
25
- config.include PunditSpecHelper
26
- end
27
-
28
19
  class PostPolicy < Struct.new(:user, :post)
29
20
  class Scope < Struct.new(:user, :scope)
30
21
  def resolve
@@ -84,10 +75,6 @@ module Customer
84
75
  def self.policy_class
85
76
  PostPolicy
86
77
  end
87
-
88
- def policy_class
89
- self.class.policy_class
90
- end
91
78
  end
92
79
  end
93
80
 
@@ -135,7 +122,7 @@ class CommentsRelation
135
122
  @empty
136
123
  end
137
124
 
138
- def model_name
125
+ def self.model_name
139
126
  Comment.model_name
140
127
  end
141
128
  end
@@ -172,6 +159,10 @@ class CriteriaPolicy < Struct.new(:user, :criteria); end
172
159
 
173
160
  module Project
174
161
  class CommentPolicy < Struct.new(:user, :comment)
162
+ def update?
163
+ true
164
+ end
165
+
175
166
  class Scope < Struct.new(:user, :scope)
176
167
  def resolve
177
168
  scope
@@ -188,6 +179,14 @@ module Project
188
179
  end
189
180
  end
190
181
  end
182
+
183
+ module Admin
184
+ class CommentPolicy < Struct.new(:user, :comment)
185
+ def update?
186
+ true
187
+ end
188
+ end
189
+ end
191
190
  end
192
191
 
193
192
  class DenierPolicy < Struct.new(:user, :record)
@@ -199,9 +198,9 @@ end
199
198
  class Controller
200
199
  include Pundit
201
200
  # Mark protected methods public so they may be called in test
202
- # rubocop:disable Layout/AccessModifierIndentation, Style/AccessModifierDeclarations
201
+ # rubocop:disable Style/AccessModifierDeclarations
203
202
  public(*Pundit.protected_instance_methods)
204
- # rubocop:enable Layout/AccessModifierIndentation, Style/AccessModifierDeclarations
203
+ # rubocop:enable Style/AccessModifierDeclarations
205
204
 
206
205
  attr_reader :current_user, :action_name, :params
207
206
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pundit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-18 00:00:00.000000000 Z
12
+ date: 2021-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -25,6 +25,132 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 3.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: actionpack
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 3.0.0
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 3.0.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: activemodel
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 3.0.0
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 3.0.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: bundler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 3.0.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 3.0.0
112
+ - !ruby/object:Gem::Dependency
113
+ name: rubocop
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '='
117
+ - !ruby/object:Gem::Version
118
+ version: 0.74.0
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '='
124
+ - !ruby/object:Gem::Version
125
+ version: 0.74.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: simplecov
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 0.17.0
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: 0.17.0
140
+ - !ruby/object:Gem::Dependency
141
+ name: yard
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
28
154
  description: Object oriented authorization for Rails applications
29
155
  email:
30
156
  - jonas.nicklas@gmail.com
@@ -82,8 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
208
  - !ruby/object:Gem::Version
83
209
  version: '0'
84
210
  requirements: []
85
- rubyforge_project:
86
- rubygems_version: 2.5.2
211
+ rubygems_version: 3.2.25
87
212
  signing_key:
88
213
  specification_version: 4
89
214
  summary: OO authorization for Rails