pundit 2.3.2 → 2.5.0

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +26 -0
  4. data/.github/PULL_REQUEST_TEMPLATE/gem_release_template.md +4 -4
  5. data/.github/workflows/main.yml +92 -52
  6. data/.github/workflows/push_gem.yml +4 -4
  7. data/.rubocop.yml +18 -8
  8. data/.rubocop_ignore_git.yml +7 -0
  9. data/.yardopts +1 -1
  10. data/CHANGELOG.md +68 -37
  11. data/CODE_OF_CONDUCT.md +1 -1
  12. data/CONTRIBUTING.md +1 -0
  13. data/Gemfile +22 -2
  14. data/README.md +88 -15
  15. data/Rakefile +1 -0
  16. data/lib/generators/pundit/install/install_generator.rb +3 -1
  17. data/lib/generators/pundit/policy/policy_generator.rb +3 -1
  18. data/lib/generators/rspec/policy_generator.rb +4 -1
  19. data/lib/generators/test_unit/policy_generator.rb +4 -1
  20. data/lib/pundit/authorization.rb +152 -77
  21. data/lib/pundit/cache_store/legacy_store.rb +7 -0
  22. data/lib/pundit/cache_store/null_store.rb +9 -0
  23. data/lib/pundit/cache_store.rb +22 -0
  24. data/lib/pundit/context.rb +76 -26
  25. data/lib/pundit/policy_finder.rb +22 -1
  26. data/lib/pundit/railtie.rb +19 -0
  27. data/lib/pundit/rspec.rb +90 -7
  28. data/lib/pundit/version.rb +2 -1
  29. data/lib/pundit.rb +43 -15
  30. data/pundit.gemspec +8 -12
  31. data/spec/authorization_spec.rb +61 -4
  32. data/spec/policies/post_policy_spec.rb +27 -0
  33. data/spec/policy_finder_spec.rb +5 -1
  34. data/spec/pundit/helper_spec.rb +18 -0
  35. data/spec/pundit_spec.rb +58 -15
  36. data/spec/rspec_dsl_spec.rb +81 -0
  37. data/spec/simple_cov_check_action_formatter.rb +79 -0
  38. data/spec/spec_helper.rb +22 -339
  39. data/spec/support/lib/controller.rb +38 -0
  40. data/spec/support/lib/custom_cache.rb +19 -0
  41. data/spec/support/lib/instance_tracking.rb +20 -0
  42. data/spec/support/models/article.rb +4 -0
  43. data/spec/support/models/article_tag.rb +7 -0
  44. data/spec/support/models/artificial_blog.rb +7 -0
  45. data/spec/support/models/blog.rb +4 -0
  46. data/spec/support/models/comment.rb +5 -0
  47. data/spec/support/models/comment_four_five_six.rb +5 -0
  48. data/spec/support/models/comment_scope.rb +13 -0
  49. data/spec/support/models/comments_relation.rb +15 -0
  50. data/spec/support/models/customer/post.rb +11 -0
  51. data/spec/support/models/default_scope_contains_error.rb +5 -0
  52. data/spec/support/models/dummy_current_user.rb +7 -0
  53. data/spec/support/models/foo.rb +4 -0
  54. data/spec/support/models/post.rb +25 -0
  55. data/spec/support/models/post_four_five_six.rb +9 -0
  56. data/spec/support/models/project_one_two_three/avatar_four_five_six.rb +7 -0
  57. data/spec/support/models/project_one_two_three/tag_four_five_six.rb +11 -0
  58. data/spec/support/models/wiki.rb +4 -0
  59. data/spec/support/policies/article_tag_other_name_policy.rb +13 -0
  60. data/spec/support/policies/base_policy.rb +23 -0
  61. data/spec/support/policies/blog_policy.rb +5 -0
  62. data/spec/support/policies/comment_policy.rb +11 -0
  63. data/spec/support/policies/criteria_policy.rb +5 -0
  64. data/spec/support/policies/default_scope_contains_error_policy.rb +10 -0
  65. data/spec/support/policies/denier_policy.rb +7 -0
  66. data/spec/support/policies/dummy_current_user_policy.rb +9 -0
  67. data/spec/support/policies/nil_class_policy.rb +17 -0
  68. data/spec/support/policies/post_policy.rb +36 -0
  69. data/spec/support/policies/project/admin/comment_policy.rb +15 -0
  70. data/spec/support/policies/project/comment_policy.rb +17 -0
  71. data/spec/support/policies/project/criteria_policy.rb +7 -0
  72. data/spec/support/policies/project/post_policy.rb +13 -0
  73. data/spec/support/policies/project_one_two_three/avatar_four_five_six_policy.rb +6 -0
  74. data/spec/support/policies/project_one_two_three/comment_four_five_six_policy.rb +6 -0
  75. data/spec/support/policies/project_one_two_three/criteria_four_five_six_policy.rb +6 -0
  76. data/spec/support/policies/project_one_two_three/post_four_five_six_policy.rb +6 -0
  77. data/spec/support/policies/project_one_two_three/tag_four_five_six_policy.rb +6 -0
  78. data/spec/support/policies/publication_policy.rb +13 -0
  79. data/spec/support/policies/wiki_policy.rb +8 -0
  80. metadata +66 -158
  81. /data/.github/{PULL_REQUEST_TEMPLATE/pull_request_template.md → pull_request_template.md} +0 -0
  82. /data/lib/generators/pundit/install/templates/{application_policy.rb → application_policy.rb.tt} +0 -0
  83. /data/lib/generators/pundit/policy/templates/{policy.rb → policy.rb.tt} +0 -0
  84. /data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
  85. /data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
@@ -2,13 +2,17 @@
2
2
 
3
3
  require "spec_helper"
4
4
 
5
- class Foo; end
6
5
  RSpec.describe Pundit::PolicyFinder do
7
6
  let(:user) { double }
8
7
  let(:post) { Post.new(user) }
9
8
  let(:comment) { CommentFourFiveSix.new }
10
9
  let(:article) { Article.new }
11
10
 
11
+ describe "SUFFIX" do
12
+ specify { expect(described_class::SUFFIX).to eq "Policy" }
13
+ specify { expect(Pundit::SUFFIX).to eq(described_class::SUFFIX) }
14
+ end
15
+
12
16
  describe "#scope" do
13
17
  subject { described_class.new(post) }
14
18
 
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Pundit::Helper do
6
+ let(:user) { double }
7
+ let(:controller) { Controller.new(user, "update", double) }
8
+ let(:view) { Controller::View.new(controller) }
9
+
10
+ describe "#policy_scope" do
11
+ it "doesn't flip pundit_policy_scoped?" do
12
+ scoped = view.policy_scope(Post)
13
+
14
+ expect(scoped).to be(Post.published)
15
+ expect(controller).not_to be_pundit_policy_scoped
16
+ end
17
+ end
18
+ end
data/spec/pundit_spec.rb CHANGED
@@ -43,25 +43,16 @@ RSpec.describe Pundit do
43
43
  expect(Pundit.authorize(user, Post, :show?)).to eq(Post)
44
44
  end
45
45
 
46
- it "can be given a different policy class" do
47
- expect(Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy)).to be_truthy
48
- end
49
-
50
- it "can be given a different policy class using namespaces" do
51
- expect(PublicationPolicy).to receive(:new).with(user, comment).and_call_original
52
- expect(Pundit.authorize(user, [:project, comment], :create?, policy_class: PublicationPolicy)).to be_truthy
53
- end
54
-
55
46
  it "works with anonymous class policies" do
56
47
  expect(Pundit.authorize(user, article_tag, :show?)).to be_truthy
57
48
  expect { Pundit.authorize(user, article_tag, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
58
49
  end
59
50
 
60
- it "raises an error with a query and action" do
51
+ it "raises an error with the policy, query and record" do
61
52
  # rubocop:disable Style/MultilineBlockChain
62
53
  expect do
63
54
  Pundit.authorize(user, post, :destroy?)
64
- end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this Post") do |error|
55
+ end.to raise_error(Pundit::NotAuthorizedError, "not allowed to PostPolicy#destroy? this Post") do |error|
65
56
  expect(error.query).to eq :destroy?
66
57
  expect(error.record).to eq post
67
58
  expect(error.policy).to have_attributes(
@@ -73,11 +64,12 @@ RSpec.describe Pundit do
73
64
  # rubocop:enable Style/MultilineBlockChain
74
65
  end
75
66
 
76
- it "raises an error with a the record, query and action when the record is namespaced" do
67
+ it "raises an error with the policy, query and record when the record is namespaced" do
77
68
  # rubocop:disable Style/MultilineBlockChain
78
69
  expect do
79
70
  Pundit.authorize(user, [:project, :admin, comment], :destroy?)
80
- end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this Comment") do |error|
71
+ end.to raise_error(Pundit::NotAuthorizedError,
72
+ "not allowed to Project::Admin::CommentPolicy#destroy? this Comment") do |error|
81
73
  expect(error.query).to eq :destroy?
82
74
  expect(error.record).to eq comment
83
75
  expect(error.policy).to have_attributes(
@@ -89,11 +81,62 @@ RSpec.describe Pundit do
89
81
  # rubocop:enable Style/MultilineBlockChain
90
82
  end
91
83
 
84
+ it "raises an error with the policy, query and the class name when a Class is given" do
85
+ # rubocop:disable Style/MultilineBlockChain
86
+ expect do
87
+ Pundit.authorize(user, Post, :destroy?)
88
+ end.to raise_error(Pundit::NotAuthorizedError, "not allowed to PostPolicy#destroy? Post") do |error|
89
+ expect(error.query).to eq :destroy?
90
+ expect(error.record).to eq Post
91
+ expect(error.policy).to have_attributes(
92
+ user: user,
93
+ record: Post
94
+ )
95
+ expect(error.policy).to be_a(PostPolicy)
96
+ end
97
+ # rubocop:enable Style/MultilineBlockChain
98
+ end
99
+
92
100
  it "raises an error with a invalid policy constructor" do
93
101
  expect do
94
102
  Pundit.authorize(user, wiki, :update?)
95
103
  end.to raise_error(Pundit::InvalidConstructorError, "Invalid #<WikiPolicy> constructor is called")
96
104
  end
105
+
106
+ context "when passed a policy class" do
107
+ it "uses the passed policy class" do
108
+ expect(Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy)).to be_truthy
109
+ end
110
+
111
+ # This is documenting past behaviour.
112
+ it "doesn't cache the policy class" do
113
+ cache = {}
114
+
115
+ expect do
116
+ Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy, cache: cache)
117
+ Pundit.authorize(user, post, :create?, policy_class: PublicationPolicy, cache: cache)
118
+ end.to change { PublicationPolicy.instances }.by(2)
119
+ end
120
+ end
121
+
122
+ context "when passed a policy class while simultaenously passing a namespace" do
123
+ it "uses the passed policy class" do
124
+ expect(PublicationPolicy).to receive(:new).with(user, comment).and_call_original
125
+ expect(Pundit.authorize(user, [:project, comment], :create?, policy_class: PublicationPolicy)).to be_truthy
126
+ end
127
+ end
128
+
129
+ context "when passed an explicit cache" do
130
+ it "uses the hash assignment interface on the cache" do
131
+ custom_cache = CustomCache.new
132
+
133
+ Pundit.authorize(user, post, :update?, cache: custom_cache)
134
+
135
+ expect(custom_cache.to_h).to match({
136
+ post => kind_of(PostPolicy)
137
+ })
138
+ end
139
+ end
97
140
  end
98
141
 
99
142
  describe ".policy_scope" do
@@ -137,8 +180,8 @@ RSpec.describe Pundit do
137
180
 
138
181
  it "raises an original error with a policy scope that contains error" do
139
182
  expect do
140
- Pundit.policy_scope(user, Thread)
141
- end.to raise_error(ArgumentError)
183
+ Pundit.policy_scope(user, DefaultScopeContainsError)
184
+ end.to raise_error(RuntimeError, "This is an arbitrary error that should bubble up")
142
185
  end
143
186
  end
144
187
 
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Pundit RSpec DSL" do
6
+ include Pundit::RSpec::PolicyExampleGroup
7
+
8
+ let(:fake_rspec) do
9
+ double = class_double(RSpec::ExampleGroups)
10
+ double.extend(::Pundit::RSpec::DSL)
11
+ double
12
+ end
13
+ let(:block) { proc { "block content" } }
14
+
15
+ let(:user) { double }
16
+ let(:other_user) { double }
17
+ let(:post) { Post.new(user) }
18
+ let(:policy) { PostPolicy }
19
+
20
+ it "calls describe with the correct metadata and without :focus" do
21
+ expected_metadata = { permissions: %i[item1 item2], caller: instance_of(Array) }
22
+ expect(fake_rspec).to receive(:describe).with("item1 and item2", match(expected_metadata)) do |&block|
23
+ expect(block.call).to eq("block content")
24
+ end
25
+
26
+ fake_rspec.permissions(:item1, :item2, &block)
27
+ end
28
+
29
+ it "calls describe with the correct metadata and with :focus" do
30
+ expected_metadata = { permissions: %i[item1 item2], caller: instance_of(Array), focus: true }
31
+ expect(fake_rspec).to receive(:describe).with("item1 and item2", match(expected_metadata)) do |&block|
32
+ expect(block.call).to eq("block content")
33
+ end
34
+
35
+ fake_rspec.permissions(:item1, :item2, :focus, &block)
36
+ end
37
+
38
+ describe "#permit" do
39
+ context "when not appropriately wrapped in permissions" do
40
+ it "raises a descriptive error" do
41
+ expect do
42
+ expect(policy).to permit(user, post)
43
+ end.to raise_error(KeyError, <<~MSG.strip)
44
+ No permissions in example metadata, did you forget to wrap with `permissions :show?, ...`?
45
+ MSG
46
+ end
47
+ end
48
+
49
+ permissions :edit?, :update? do
50
+ it "succeeds when action is permitted" do
51
+ expect(policy).to permit(user, post)
52
+ end
53
+
54
+ context "when it fails" do
55
+ it "fails with a descriptive error message" do
56
+ expect do
57
+ expect(policy).to permit(other_user, post)
58
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError, <<~MSG.strip)
59
+ Expected PostPolicy to grant edit? and update? on Post but edit? and update? were not granted
60
+ MSG
61
+ end
62
+ end
63
+
64
+ context "when negated" do
65
+ it "succeeds when action is not permitted" do
66
+ expect(policy).not_to permit(other_user, post)
67
+ end
68
+
69
+ context "when it fails" do
70
+ it "fails with a descriptive error message" do
71
+ expect do
72
+ expect(policy).not_to permit(user, post)
73
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError, <<~MSG.strip)
74
+ Expected PostPolicy not to grant edit? and update? on Post but edit? and update? were granted
75
+ MSG
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "simplecov"
4
+ require "json"
5
+
6
+ class SimpleCovCheckActionFormatter
7
+ SourceFile = Data.define(:source_file) do
8
+ def covered_strength = source_file.covered_strength
9
+ def covered_percent = source_file.covered_percent
10
+
11
+ def to_json(*args)
12
+ {
13
+ filename: source_file.filename,
14
+ covered_percent: covered_percent.nan? ? 0.0 : covered_percent,
15
+ coverage: source_file.coverage_data,
16
+ covered_strength: covered_strength.nan? ? 0.0 : covered_strength,
17
+ covered_lines: source_file.covered_lines.count,
18
+ lines_of_code: source_file.lines_of_code
19
+ }.to_json(*args)
20
+ end
21
+ end
22
+
23
+ Result = Data.define(:result) do
24
+ def included?(source_file) = result.filenames.include?(source_file.filename)
25
+
26
+ def files
27
+ result.files.filter_map do |source_file|
28
+ next unless result.filenames.include? source_file.filename
29
+
30
+ SourceFile.new(source_file)
31
+ end
32
+ end
33
+
34
+ def to_json(*args) # rubocop:disable Metrics/AbcSize
35
+ {
36
+ timestamp: result.created_at.to_i,
37
+ command_name: result.command_name,
38
+ files: files,
39
+ metrics: {
40
+ covered_percent: result.covered_percent,
41
+ covered_strength: result.covered_strength.nan? ? 0.0 : result.covered_strength,
42
+ covered_lines: result.covered_lines,
43
+ total_lines: result.total_lines
44
+ }
45
+ }.to_json(*args)
46
+ end
47
+ end
48
+
49
+ FormatterWithOptions = Data.define(:formatter) do
50
+ def new = formatter
51
+ end
52
+
53
+ class << self
54
+ def with_options(...)
55
+ FormatterWithOptions.new(new(...))
56
+ end
57
+ end
58
+
59
+ def initialize(output_filename: "coverage.json", output_directory: SimpleCov.coverage_path)
60
+ @output_filename = output_filename
61
+ @output_directory = output_directory
62
+ end
63
+
64
+ attr_reader :output_filename, :output_directory
65
+
66
+ def output_filepath = File.join(output_directory, output_filename)
67
+
68
+ def format(result_data)
69
+ result = Result.new(result_data)
70
+ json = JSON.generate(result)
71
+ File.write(output_filepath, json)
72
+ puts output_message(result_data)
73
+ json
74
+ end
75
+
76
+ def output_message(result)
77
+ "Coverage report generated for #{result.command_name} to #{output_filepath}. #{result.covered_lines} / #{result.total_lines} LOC (#{result.covered_percent.round(2)}%) covered." # rubocop:disable Layout/LineLength
78
+ end
79
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,351 +2,34 @@
2
2
 
3
3
  if ENV["COVERAGE"]
4
4
  require "simplecov"
5
+ require "simplecov_json_formatter"
6
+ require_relative "simple_cov_check_action_formatter"
7
+ SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ SimpleCov::Formatter::JSONFormatter,
10
+ SimpleCovCheckActionFormatter.with_options(
11
+ output_filename: "simplecov-check-action.json"
12
+ )
13
+ ])
5
14
  SimpleCov.start do
6
15
  add_filter "/spec/"
16
+ enable_coverage :branch
17
+ primary_coverage :branch
7
18
  end
8
19
  end
9
20
 
21
+ # @see https://github.com/rails/rails/issues/54260
22
+ require "logger" if RUBY_ENGINE == "jruby" && RUBY_ENGINE_VERSION.start_with?("9.3")
23
+
10
24
  require "pundit"
11
25
  require "pundit/rspec"
12
-
13
- require "rack"
14
- require "rack/test"
15
- require "pry"
16
- require "active_support"
17
- require "active_support/core_ext"
18
26
  require "active_model/naming"
19
- require "action_controller/metal/strong_parameters"
20
-
21
- module InstanceTracking
22
- module ClassMethods
23
- def instances
24
- @instances || 0
25
- end
26
-
27
- attr_writer :instances
28
- end
29
-
30
- def self.prepended(other)
31
- other.extend(ClassMethods)
32
- end
33
-
34
- def initialize(*args, **kwargs, &block)
35
- self.class.instances += 1
36
- super(*args, **kwargs, &block)
37
- end
38
- end
39
-
40
- class BasePolicy
41
- prepend InstanceTracking
42
-
43
- class BaseScope
44
- prepend InstanceTracking
45
-
46
- def initialize(user, scope)
47
- @user = user
48
- @scope = scope
49
- end
50
-
51
- attr_reader :user, :scope
52
- end
53
-
54
- def initialize(user, record)
55
- @user = user
56
- @record = record
57
- end
58
-
59
- attr_reader :user, :record
60
- end
61
-
62
- class PostPolicy < BasePolicy
63
- class Scope < BaseScope
64
- def resolve
65
- scope.published
66
- end
67
- end
68
-
69
- alias post record
70
-
71
- def update?
72
- post.user == user
73
- end
74
-
75
- def destroy?
76
- false
77
- end
78
-
79
- def show?
80
- true
81
- end
82
-
83
- def permitted_attributes
84
- if post.user == user
85
- %i[title votes]
86
- else
87
- [:votes]
88
- end
89
- end
90
-
91
- def permitted_attributes_for_revise
92
- [:body]
93
- end
94
- end
95
-
96
- class Post
97
- def initialize(user = nil)
98
- @user = user
99
- end
100
-
101
- attr_reader :user
102
-
103
- def self.published
104
- :published
105
- end
106
-
107
- def self.read
108
- :read
109
- end
110
-
111
- def to_s
112
- "Post"
113
- end
114
-
115
- def inspect
116
- "#<Post>"
117
- end
118
- end
119
-
120
- module Customer
121
- class Post < ::Post
122
- def model_name
123
- OpenStruct.new(param_key: "customer_post")
124
- end
125
-
126
- def self.policy_class
127
- PostPolicy
128
- end
129
- end
130
- end
131
-
132
- class CommentScope
133
- attr_reader :original_object
134
-
135
- def initialize(original_object)
136
- @original_object = original_object
137
- end
138
-
139
- def ==(other)
140
- original_object == other.original_object
141
- end
142
- end
143
-
144
- class CommentPolicy < BasePolicy
145
- class Scope < BaseScope
146
- def resolve
147
- CommentScope.new(scope)
148
- end
149
- end
150
-
151
- alias comment record
152
- end
153
-
154
- class PublicationPolicy < BasePolicy
155
- class Scope < BaseScope
156
- def resolve
157
- scope.published
158
- end
159
- end
160
-
161
- def create?
162
- true
163
- end
164
- end
165
-
166
- class Comment
167
- extend ActiveModel::Naming
168
- end
169
-
170
- class CommentsRelation
171
- def initialize(empty: false)
172
- @empty = empty
173
- end
174
-
175
- def blank?
176
- @empty
177
- end
178
-
179
- def self.model_name
180
- Comment.model_name
181
- end
182
- end
183
-
184
- class Article; end
185
-
186
- class BlogPolicy < BasePolicy
187
- alias blog record
188
- end
189
-
190
- class Blog; end
191
-
192
- class ArtificialBlog < Blog
193
- def self.policy_class
194
- BlogPolicy
195
- end
196
- end
197
-
198
- class ArticleTagOtherNamePolicy < BasePolicy
199
- def show?
200
- true
201
- end
202
-
203
- def destroy?
204
- false
205
- end
206
-
207
- alias tag record
208
- end
209
-
210
- class ArticleTag
211
- def self.policy_class
212
- ArticleTagOtherNamePolicy
213
- end
214
- end
215
-
216
- class CriteriaPolicy < BasePolicy
217
- alias criteria record
218
- end
219
-
220
- module Project
221
- class CommentPolicy < BasePolicy
222
- class Scope < BaseScope
223
- def resolve
224
- scope
225
- end
226
- end
227
-
228
- def update?
229
- true
230
- end
231
-
232
- alias comment record
233
- end
234
-
235
- class CriteriaPolicy < BasePolicy
236
- alias criteria record
237
- end
238
-
239
- class PostPolicy < BasePolicy
240
- class Scope < BaseScope
241
- def resolve
242
- scope.read
243
- end
244
- end
245
-
246
- alias post record
247
- end
248
-
249
- module Admin
250
- class CommentPolicy < BasePolicy
251
- def update?
252
- true
253
- end
254
-
255
- def destroy?
256
- false
257
- end
258
- end
259
- end
260
- end
261
-
262
- class DenierPolicy < BasePolicy
263
- def update?
264
- false
265
- end
266
- end
267
27
 
268
- class Controller
269
- include Pundit::Authorization
270
- # Mark protected methods public so they may be called in test
271
- # rubocop:disable Style/AccessModifierDeclarations
272
- public(*Pundit::Authorization.protected_instance_methods)
273
- # rubocop:enable Style/AccessModifierDeclarations
274
-
275
- attr_reader :current_user, :action_name, :params
276
-
277
- def initialize(current_user, action_name, params)
278
- @current_user = current_user
279
- @action_name = action_name
280
- @params = params
281
- end
282
- end
283
-
284
- class NilClassPolicy < BasePolicy
285
- class Scope
286
- def initialize(*)
287
- raise Pundit::NotDefinedError, "Cannot scope NilClass"
288
- end
289
- end
290
-
291
- def show?
292
- false
293
- end
294
-
295
- def destroy?
296
- false
297
- end
298
- end
299
-
300
- class Wiki; end
301
-
302
- class WikiPolicy
303
- class Scope
304
- # deliberate typo method
305
- def initalize; end
306
- end
307
- end
308
-
309
- class Thread
310
- def self.all; end
311
- end
312
-
313
- class ThreadPolicy < BasePolicy
314
- class Scope < BaseScope
315
- def resolve
316
- # deliberate wrong useage of the method
317
- scope.all(:unvalid, :parameters)
318
- end
319
- end
320
- end
321
-
322
- class PostFourFiveSix
323
- def initialize(user)
324
- @user = user
325
- end
326
-
327
- attr_reader(:user)
328
- end
329
-
330
- class CommentFourFiveSix; extend ActiveModel::Naming; end
331
-
332
- module ProjectOneTwoThree
333
- class CommentFourFiveSixPolicy < BasePolicy; end
334
-
335
- class CriteriaFourFiveSixPolicy < BasePolicy; end
336
-
337
- class PostFourFiveSixPolicy < BasePolicy; end
338
-
339
- class TagFourFiveSix
340
- def initialize(user)
341
- @user = user
342
- end
343
-
344
- attr_reader(:user)
345
- end
346
-
347
- class TagFourFiveSixPolicy < BasePolicy; end
348
-
349
- class AvatarFourFiveSix; extend ActiveModel::Naming; end
350
-
351
- class AvatarFourFiveSixPolicy < BasePolicy; end
352
- end
28
+ # Load all supporting files: models, policies, etc.
29
+ require "zeitwerk"
30
+ loader = Zeitwerk::Loader.new
31
+ loader.push_dir(File.expand_path("support/models", __dir__))
32
+ loader.push_dir(File.expand_path("support/policies", __dir__))
33
+ loader.push_dir(File.expand_path("support/lib", __dir__))
34
+ loader.setup
35
+ loader.eager_load