pundit 1.0.1 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e2a27c306e9cc67fc0ecabc8c910f7e4a5b0706a
4
- data.tar.gz: e94f7b364462ea0cf5b4c30d48620f523d89ff4a
3
+ metadata.gz: a2c188098c86ad5a0804044f80219014564501ef
4
+ data.tar.gz: 2ab7f79275d9ae66e5d04cf980c11e2c2983a4ef
5
5
  SHA512:
6
- metadata.gz: d754a6ba6a9b2c00eff1100c320cba4ab34dbca2877e966d477febec75aa79348b978397f53a7961f771f694ac377fb0b87a4af8e79be75e840d15ff0cf53189
7
- data.tar.gz: ce78572422e59c3cd811b9062cc033aabfe69713a7e7ee364a0fe12c505f4399ebbd645683d0935b1f045af8903835e9a97d31e47edcf2928c4fd90f89cbe87d
6
+ metadata.gz: 55fbbf71ad514c0cfe4f8933dea59915314f749efa53ab5579f2da9dfcf2b4786343cefa53d3a35e26f4a346776c1c513884595a39561d280b259e6b6fb9b31a
7
+ data.tar.gz: bbcf9417801b22deac78afe2d5ea8a268193daf0e011f861006c25b1d0124d1f462aa37d4d38e623b9d438cb29ceb52b250575118e053862b74561795bbdd7a4
@@ -0,0 +1,95 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "gemfiles/**/*"
4
+ - "vendor/**/*"
5
+ - "lib/generators/**/*"
6
+
7
+ Metrics/MethodLength:
8
+ Max: 40
9
+
10
+ Metrics/ModuleLength:
11
+ Max: 200
12
+
13
+ Metrics/LineLength:
14
+ Max: 120
15
+
16
+ Metrics/AbcSize:
17
+ Enabled: false
18
+
19
+ Metrics/CyclomaticComplexity:
20
+ Enabled: false
21
+
22
+ Metrics/PerceivedComplexity:
23
+ Enabled: false
24
+
25
+ Style/StructInheritance:
26
+ Enabled: false
27
+
28
+ Style/AlignParameters:
29
+ EnforcedStyle: with_fixed_indentation
30
+
31
+ Style/StringLiterals:
32
+ EnforcedStyle: double_quotes
33
+
34
+ Style/StringLiteralsInInterpolation:
35
+ EnforcedStyle: double_quotes
36
+
37
+ Style/ClosingParenthesisIndentation:
38
+ Enabled: false
39
+
40
+ Style/OneLineConditional:
41
+ Enabled: false
42
+
43
+ Style/AndOr:
44
+ Enabled: false
45
+
46
+ Style/Not:
47
+ Enabled: false
48
+
49
+ Documentation:
50
+ Enabled: false # TODO: Enable again once we have more docs
51
+
52
+ Style/CaseIndentation:
53
+ IndentWhenRelativeTo: case
54
+ SupportedStyles:
55
+ - case
56
+ - end
57
+ IndentOneStep: true
58
+
59
+ Style/PercentLiteralDelimiters:
60
+ PreferredDelimiters:
61
+ '%w': "[]"
62
+ '%W': "[]"
63
+
64
+ Style/AccessModifierIndentation:
65
+ EnforcedStyle: outdent
66
+
67
+ Style/SignalException:
68
+ Enabled: false
69
+
70
+ Style/IndentationWidth:
71
+ Enabled: false
72
+
73
+ Style/TrivialAccessors:
74
+ ExactNameMatch: true
75
+
76
+ Lint/EndAlignment:
77
+ AlignWith: variable
78
+
79
+ Lint/DefEndAlignment:
80
+ Enabled: false
81
+
82
+ Lint/HandleExceptions:
83
+ Enabled: false
84
+
85
+ Style/SpecialGlobalVars:
86
+ Enabled: false
87
+
88
+ Style/TrivialAccessors:
89
+ Enabled: false
90
+
91
+ Style/IndentHash:
92
+ Enabled: false
93
+
94
+ Style/DoubleNegation:
95
+ Enabled: false
@@ -2,8 +2,8 @@ language: ruby
2
2
  sudo: false
3
3
  rvm:
4
4
  - 2.0.0
5
- - 2.1.5
6
- - 2.2.0
5
+ - 2.1
6
+ - 2.2
7
7
  - jruby-19mode
8
8
  - rbx-2
9
9
  env:
@@ -0,0 +1 @@
1
+ --api public --hide-void-return --markup markdown
@@ -1,5 +1,13 @@
1
1
  # Pundit
2
2
 
3
+ ## 1.1.0 (2016-01-14)
4
+
5
+ - Can retrieve policies via an array of symbols/objects.
6
+ - Add autodetection of param key to `permitted_attributes` helper.
7
+ - Hide some methods which should not be actions.
8
+ - Permitted attributes should be expanded.
9
+ - Generator uses `RSpec.describe` according to modern best practices.
10
+
3
11
  ## 1.0.1 (2015-05-27)
4
12
 
5
13
  - Fixed a regression where NotAuthorizedError could not be ininitialized with a string.
@@ -17,7 +25,7 @@
17
25
  - Add `skip_authorization` and `skip_policy_scope` helpers.
18
26
  - Better errors when checking multiple permissions in RSpec tests.
19
27
  - Better errors in case `nil` is passed to `policy` or `policy_scope`.
20
- - Use `inpect` when printing object for better errors.
28
+ - Use `inspect` when printing object for better errors.
21
29
  - Dropped official support for Ruby 1.9.3
22
30
 
23
31
  ## 0.3.0 (2014-08-22)
data/Gemfile CHANGED
@@ -1,5 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in pundit.gemspec
4
3
  gem "rspec", ENV["RSPEC_VERSION"] unless ENV["RSPEC_VERSION"].to_s.empty?
5
4
  gemspec
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Pundit
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/elabs/pundit.png?branch=master)](https://travis-ci.org/elabs/pundit)
4
- [![Code Climate](https://codeclimate.com/github/elabs/pundit.png)](https://codeclimate.com/github/elabs/pundit)
5
- [![Inline docs](http://inch-ci.org/github/elabs/pundit.png)](http://inch-ci.org/github/elabs/pundit)
3
+ [![Build Status](https://secure.travis-ci.org/elabs/pundit.svg?branch=master)](https://travis-ci.org/elabs/pundit)
4
+ [![Code Climate](https://codeclimate.com/github/elabs/pundit.svg)](https://codeclimate.com/github/elabs/pundit)
5
+ [![Inline docs](http://inch-ci.org/github/elabs/pundit.svg?branch=master)](http://inch-ci.org/github/elabs/pundit)
6
+ [![Gem Version](https://badge.fury.io/rb/pundit.svg)](http://badge.fury.io/rb/pundit)
6
7
 
7
8
  Pundit provides a set of helpers which guide you in leveraging regular Ruby
8
9
  classes and object oriented design patterns to build a simple, robust and
@@ -130,6 +131,26 @@ def publish
130
131
  end
131
132
  ```
132
133
 
134
+ If you don't have an instance for the first argument to `authorize`, then you can pass
135
+ the class. For example:
136
+
137
+ Policy:
138
+ ```ruby
139
+ class PostPolicy < ApplicationPolicy
140
+ def admin_list?
141
+ user.admin?
142
+ end
143
+ end
144
+ ```
145
+
146
+ Controller:
147
+ ```ruby
148
+ def admin_list
149
+ authorize Post # we don't have a particular post to authorize
150
+ # Rest of controller action
151
+ end
152
+ ```
153
+
133
154
  You can easily get a hold of an instance of the policy through the `policy`
134
155
  method in both the view and controller. This is especially useful for
135
156
  conditionally showing links or buttons in the view:
@@ -172,7 +193,7 @@ forgotten to authorize the action. For example:
172
193
 
173
194
  ``` ruby
174
195
  class ApplicationController < ActionController::Base
175
- after_action :verify_authorized, :except => :index
196
+ after_action :verify_authorized
176
197
  end
177
198
  ```
178
199
 
@@ -184,7 +205,8 @@ authorize individual instances.
184
205
 
185
206
  ``` ruby
186
207
  class ApplicationController < ActionController::Base
187
- after_action :verify_policy_scoped, :only => :index
208
+ after_action :verify_authorized, except: :index
209
+ after_action :verify_policy_scoped, only: :index
188
210
  end
189
211
  ```
190
212
 
@@ -222,7 +244,7 @@ class PostPolicy < ApplicationPolicy
222
244
  attr_reader :user, :scope
223
245
 
224
246
  def initialize(user, scope)
225
- @user = user
247
+ @user = user
226
248
  @scope = scope
227
249
  end
228
250
 
@@ -230,7 +252,7 @@ class PostPolicy < ApplicationPolicy
230
252
  if user.admin?
231
253
  scope.all
232
254
  else
233
- scope.where(:published => true)
255
+ scope.where(published: true)
234
256
  end
235
257
  end
236
258
  end
@@ -263,7 +285,7 @@ class PostPolicy < ApplicationPolicy
263
285
  if user.admin?
264
286
  scope.all
265
287
  else
266
- scope.where(:published => true)
288
+ scope.where(published: true)
267
289
  end
268
290
  end
269
291
  end
@@ -351,7 +373,7 @@ got through. This way you can fail more gracefully.
351
373
  class ApplicationPolicy
352
374
  def initialize(user, record)
353
375
  raise Pundit::NotAuthorizedError, "must be logged in" unless user
354
- @user = user
376
+ @user = user
355
377
  @record = record
356
378
  end
357
379
  end
@@ -470,7 +492,7 @@ class UserContext
470
492
 
471
493
  def initialize(user, ip)
472
494
  @user = user
473
- @ip = ip
495
+ @ip = ip
474
496
  end
475
497
  end
476
498
 
@@ -559,24 +581,24 @@ Then put your policy specs in `spec/policies`, and make them look somewhat like
559
581
  describe PostPolicy do
560
582
  subject { described_class }
561
583
 
562
- permissions :update? do
584
+ permissions :update?, :edit? do
563
585
  it "denies access if post is published" do
564
- expect(subject).not_to permit(User.new(:admin => false), Post.new(:published => true))
586
+ expect(subject).not_to permit(User.new(admin: false), Post.new(published: true))
565
587
  end
566
588
 
567
589
  it "grants access if post is published and user is an admin" do
568
- expect(subject).to permit(User.new(:admin => true), Post.new(:published => true))
590
+ expect(subject).to permit(User.new(admin: true), Post.new(published: true))
569
591
  end
570
592
 
571
593
  it "grants access if post is unpublished" do
572
- expect(subject).to permit(User.new(:admin => false), Post.new(:published => false))
594
+ expect(subject).to permit(User.new(admin: false), Post.new(published: false))
573
595
  end
574
596
  end
575
597
  end
576
598
  ```
577
599
 
578
600
  An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
579
- [excellent post](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/).
601
+ [excellent post](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/) and implemented in the third party [pundit-matchers](https://github.com/chrisalley/pundit-matchers) gem.
580
602
 
581
603
  # External Resources
582
604
 
@@ -584,6 +606,7 @@ An alternative approach to Pundit policy specs is scoping them to a user context
584
606
  - [Migrating to Pundit from CanCan](http://blog.carbonfive.com/2013/10/21/migrating-to-pundit-from-cancan/)
585
607
  - [Testing Pundit Policies with RSpec](http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/)
586
608
  - [Using Pundit outside of a Rails controller](https://github.com/elabs/pundit/pull/136)
609
+ - [Straightforward Rails Authorization with Pundit](http://www.sitepoint.com/straightforward-rails-authorization-with-pundit/)
587
610
 
588
611
  # License
589
612
 
data/Rakefile CHANGED
@@ -1,17 +1,19 @@
1
- require 'rubygems'
2
- require 'bundler/gem_tasks'
3
- require 'rspec/core/rake_task'
4
- require 'yard'
1
+ require "rubygems"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+ require "yard"
5
+ require "rubocop/rake_task"
6
+
7
+ RuboCop::RakeTask.new
5
8
 
6
9
  desc "Run all examples"
7
10
  RSpec::Core::RakeTask.new(:spec) do |t|
8
- #t.rspec_path = 'bin/rspec'
9
11
  t.rspec_opts = %w[--color]
10
12
  end
11
13
 
12
14
  YARD::Rake::YardocTask.new do |t|
13
- t.files = ['lib/**/*.rb']
14
- #t.options = ['--any', '--extra', '--opts'] # optional
15
+ t.files = ["lib/**/*.rb"]
15
16
  end
16
17
 
17
- task :default => [:spec]
18
+ task default: :spec
19
+ task default: :rubocop unless RUBY_ENGINE == "rbx"
@@ -1,6 +1,6 @@
1
1
  require '<%= File.exists?('spec/rails_helper.rb') ? 'rails_helper' : 'spec_helper' %>'
2
2
 
3
- describe <%= class_name %>Policy do
3
+ RSpec.describe <%= class_name %>Policy do
4
4
 
5
5
  let(:user) { User.new }
6
6
 
@@ -6,10 +6,17 @@ require "active_support/core_ext/object/blank"
6
6
  require "active_support/core_ext/module/introspection"
7
7
  require "active_support/dependencies/autoload"
8
8
 
9
+ # @api public
9
10
  module Pundit
10
11
  SUFFIX = "Policy"
11
12
 
13
+ # @api private
14
+ module Generators; end
15
+
16
+ # @api private
12
17
  class Error < StandardError; end
18
+
19
+ # Error that will be raiser when authorization has failed
13
20
  class NotAuthorizedError < Error
14
21
  attr_reader :query, :record, :policy
15
22
 
@@ -27,42 +34,86 @@ module Pundit
27
34
  super(message)
28
35
  end
29
36
  end
37
+
38
+ # Error that will be raised if a controller action has not called the
39
+ # `authorize` or `skip_authorization` methods.
30
40
  class AuthorizationNotPerformedError < Error; end
41
+
42
+ # Error that will be raised if a controller action has not called the
43
+ # `policy_scope` or `skip_policy_scope` methods.
31
44
  class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
45
+
46
+ # Error that will be raised if a policy or policy scope is not defined.
32
47
  class NotDefinedError < Error; end
33
48
 
34
49
  extend ActiveSupport::Concern
35
50
 
36
51
  class << self
52
+ # Retrieves the policy for the given record, initializing it with the
53
+ # record and user and finally throwing an error if the user is not
54
+ # authorized to perform the given action.
55
+ #
56
+ # @param user [Object] the user that initiated the action
57
+ # @param record [Object] the object we're checking permissions of
58
+ # @param record [Symbol] the query method to check on the policy (e.g. `:show?`)
59
+ # @raise [NotAuthorizedError] if the given query method returned false
60
+ # @return [true] Always returns true
37
61
  def authorize(user, record, query)
38
62
  policy = policy!(user, record)
39
63
 
40
64
  unless policy.public_send(query)
41
- raise NotAuthorizedError.new(query: query, record: record, policy: policy)
65
+ raise NotAuthorizedError, query: query, record: record, policy: policy
42
66
  end
43
67
 
44
68
  true
45
69
  end
46
70
 
71
+ # Retrieves the policy scope for the given record.
72
+ #
73
+ # @see https://github.com/elabs/pundit#scopes
74
+ # @param user [Object] the user that initiated the action
75
+ # @param record [Object] the object we're retrieving the policy scope for
76
+ # @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
47
77
  def policy_scope(user, scope)
48
78
  policy_scope = PolicyFinder.new(scope).scope
49
79
  policy_scope.new(user, scope).resolve if policy_scope
50
80
  end
51
81
 
82
+ # Retrieves the policy scope for the given record.
83
+ #
84
+ # @see https://github.com/elabs/pundit#scopes
85
+ # @param user [Object] the user that initiated the action
86
+ # @param record [Object] the object we're retrieving the policy scope for
87
+ # @raise [NotDefinedError] if the policy scope cannot be found
88
+ # @return [Scope{#resolve}] instance of scope class which can resolve to a scope
52
89
  def policy_scope!(user, scope)
53
90
  PolicyFinder.new(scope).scope!.new(user, scope).resolve
54
91
  end
55
92
 
93
+ # Retrieves the policy for the given record.
94
+ #
95
+ # @see https://github.com/elabs/pundit#policies
96
+ # @param user [Object] the user that initiated the action
97
+ # @param record [Object] the object we're retrieving the policy for
98
+ # @return [Object, nil] instance of policy class with query methods
56
99
  def policy(user, record)
57
100
  policy = PolicyFinder.new(record).policy
58
101
  policy.new(user, record) if policy
59
102
  end
60
103
 
104
+ # Retrieves the policy for the given record.
105
+ #
106
+ # @see https://github.com/elabs/pundit#policies
107
+ # @param user [Object] the user that initiated the action
108
+ # @param record [Object] the object we're retrieving the policy for
109
+ # @raise [NotDefinedError] if the policy cannot be found
110
+ # @return [Object] instance of policy class with query methods
61
111
  def policy!(user, record)
62
112
  PolicyFinder.new(record).policy!.new(user, record)
63
113
  end
64
114
  end
65
115
 
116
+ # @api private
66
117
  module Helper
67
118
  def policy_scope(scope)
68
119
  pundit_policy_scope(scope)
@@ -88,68 +139,141 @@ module Pundit
88
139
  hide_action :pundit_user
89
140
  hide_action :skip_authorization
90
141
  hide_action :skip_policy_scope
142
+ hide_action :pundit_policy_authorized?
143
+ hide_action :pundit_policy_scoped?
91
144
  end
92
145
  end
93
146
 
147
+ # @return [Boolean] whether authorization has been performed, i.e. whether
148
+ # one {#authorize} or {#skip_authorization} has been called
94
149
  def pundit_policy_authorized?
95
150
  !!@_pundit_policy_authorized
96
151
  end
97
152
 
153
+ # @return [Boolean] whether policy scoping has been performed, i.e. whether
154
+ # one {#policy_scope} or {#skip_policy_scope} has been called
98
155
  def pundit_policy_scoped?
99
156
  !!@_pundit_policy_scoped
100
157
  end
101
158
 
159
+ # Raises an error if authorization has not been performed, usually used as an
160
+ # `after_action` filter to prevent programmer error in forgetting to call
161
+ # {#authorize} or {#skip_authorization}.
162
+ #
163
+ # @see https://github.com/elabs/pundit#ensuring-policies-are-used
164
+ # @raise [AuthorizationNotPerformedError] if authorization has not been performed
165
+ # @return [void]
102
166
  def verify_authorized
103
- raise AuthorizationNotPerformedError unless pundit_policy_authorized?
167
+ raise AuthorizationNotPerformedError, self.class unless pundit_policy_authorized?
104
168
  end
105
169
 
170
+ # Raises an error if policy scoping has not been performed, usually used as an
171
+ # `after_action` filter to prevent programmer error in forgetting to call
172
+ # {#policy_scope} or {#skip_policy_scope} in index actions.
173
+ #
174
+ # @see https://github.com/elabs/pundit#ensuring-policies-are-used
175
+ # @raise [AuthorizationNotPerformedError] if policy scoping has not been performed
176
+ # @return [void]
106
177
  def verify_policy_scoped
107
- raise PolicyScopingNotPerformedError unless pundit_policy_scoped?
178
+ raise PolicyScopingNotPerformedError, self.class unless pundit_policy_scoped?
108
179
  end
109
180
 
110
- def authorize(record, query=nil)
181
+ # Retrieves the policy for the given record, initializing it with the record
182
+ # and current user and finally throwing an error if the user is not
183
+ # authorized to perform the given action.
184
+ #
185
+ # @param record [Object] the object we're checking permissions of
186
+ # @param record [Symbol, nil] the query method to check on the policy (e.g. `:show?`)
187
+ # @raise [NotAuthorizedError] if the given query method returned false
188
+ # @return [true] Always returns true
189
+ def authorize(record, query = nil)
111
190
  query ||= params[:action].to_s + "?"
112
191
 
113
192
  @_pundit_policy_authorized = true
114
193
 
115
194
  policy = policy(record)
195
+
116
196
  unless policy.public_send(query)
117
- raise NotAuthorizedError.new(query: query, record: record, policy: policy)
197
+ raise NotAuthorizedError, query: query, record: record, policy: policy
118
198
  end
119
199
 
120
200
  true
121
201
  end
122
202
 
203
+ # Allow this action not to perform authorization.
204
+ #
205
+ # @see https://github.com/elabs/pundit#ensuring-policies-are-used
206
+ # @return [void]
123
207
  def skip_authorization
124
208
  @_pundit_policy_authorized = true
125
209
  end
126
210
 
211
+ # Allow this action not to perform policy scoping.
212
+ #
213
+ # @see https://github.com/elabs/pundit#ensuring-policies-are-used
214
+ # @return [void]
127
215
  def skip_policy_scope
128
216
  @_pundit_policy_scoped = true
129
217
  end
130
218
 
219
+ # Retrieves the policy scope for the given record.
220
+ #
221
+ # @see https://github.com/elabs/pundit#scopes
222
+ # @param record [Object] the object we're retrieving the policy scope for
223
+ # @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
131
224
  def policy_scope(scope)
132
225
  @_pundit_policy_scoped = true
133
226
  pundit_policy_scope(scope)
134
227
  end
135
228
 
229
+ # Retrieves the policy for the given record.
230
+ #
231
+ # @see https://github.com/elabs/pundit#policies
232
+ # @param record [Object] the object we're retrieving the policy for
233
+ # @return [Object, nil] instance of policy class with query methods
136
234
  def policy(record)
137
235
  policies[record] ||= Pundit.policy!(pundit_user, record)
138
236
  end
139
237
 
140
- def permitted_attributes(record)
141
- name = record.class.to_s.demodulize.underscore
142
- params.require(name).permit(policy(record).permitted_attributes)
238
+ # Retrieves a set of permitted attributes from the policy by instantiating
239
+ # the policy class for the given record and calling `permitted_attributes` on
240
+ # it, or `permitted_attributes_for_{action}` if it is defined. It then infers
241
+ # what key the record should have in the params hash and retrieves the
242
+ # permitted attributes from the params hash under that key.
243
+ #
244
+ # @see https://github.com/elabs/pundit#strong-parameters
245
+ # @param record [Object] the object we're retrieving permitted attributes for
246
+ # @return [Hash{String => Object}] the permitted attributes
247
+ def permitted_attributes(record, action = params[:action])
248
+ param_key = PolicyFinder.new(record).param_key
249
+ policy = policy(record)
250
+ method_name = if policy.respond_to?("permitted_attributes_for_#{action}")
251
+ "permitted_attributes_for_#{action}"
252
+ else
253
+ "permitted_attributes"
254
+ end
255
+ params.require(param_key).permit(policy.public_send(method_name))
143
256
  end
144
257
 
258
+ # Cache of policies. You should not rely on this method.
259
+ #
260
+ # @api private
145
261
  def policies
146
262
  @_pundit_policies ||= {}
147
263
  end
148
264
 
265
+ # Cache of policy scope. You should not rely on this method.
266
+ #
267
+ # @api private
149
268
  def policy_scopes
150
269
  @_pundit_policy_scopes ||= {}
151
270
  end
152
271
 
272
+ # Hook method which allows customizing which user is passed to policies and
273
+ # scopes initialized by {#authorize}, {#policy} and {#policy_scope}.
274
+ #
275
+ # @see https://github.com/elabs/pundit#customize-pundit-user
276
+ # @return [Object] the user object to be used with pundit
153
277
  def pundit_user
154
278
  current_user
155
279
  end
@@ -1,17 +1,40 @@
1
1
  module Pundit
2
+ # Finds policy and scope classes for given object.
3
+ # @api public
4
+ # @example
5
+ # user = User.find(params[:id])
6
+ # finder = PolicyFinder.new(user)
7
+ # finder.policy #=> UserPolicy
8
+ # finder.scope #=> UserPolicy::Scope
9
+ #
2
10
  class PolicyFinder
3
11
  attr_reader :object
4
12
 
13
+ # @param object [any] the object to find policy and scope classes for
14
+ #
5
15
  def initialize(object)
6
16
  @object = object
7
17
  end
8
18
 
19
+ # @return [nil, Scope{#resolve}] scope class which can resolve to a scope
20
+ # @see https://github.com/elabs/pundit#scopes
21
+ # @example
22
+ # scope = finder.scope #=> UserPolicy::Scope
23
+ # scope.resolve #=> <#ActiveRecord::Relation ...>
24
+ #
9
25
  def scope
10
26
  policy::Scope if policy
11
27
  rescue NameError
12
28
  nil
13
29
  end
14
30
 
31
+ # @return [nil, Class] policy class with query methods
32
+ # @see https://github.com/elabs/pundit#policies
33
+ # @example
34
+ # policy = finder.policy #=> UserPolicy
35
+ # policy.show? #=> true
36
+ # policy.update? #=> false
37
+ #
15
38
  def policy
16
39
  klass = find
17
40
  klass = klass.constantize if klass.is_a?(String)
@@ -20,16 +43,34 @@ module Pundit
20
43
  nil
21
44
  end
22
45
 
46
+ # @return [Scope{#resolve}] scope class which can resolve to a scope
47
+ # @raise [NotDefinedError] if scope could not be determined
48
+ #
23
49
  def scope!
24
50
  raise NotDefinedError, "unable to find policy scope of nil" if object.nil?
25
51
  scope or raise NotDefinedError, "unable to find scope `#{find}::Scope` for `#{object.inspect}`"
26
52
  end
27
53
 
54
+ # @return [Class] policy class with query methods
55
+ # @raise [NotDefinedError] if policy could not be determined
56
+ #
28
57
  def policy!
29
58
  raise NotDefinedError, "unable to find policy of nil" if object.nil?
30
59
  policy or raise NotDefinedError, "unable to find policy `#{find}` for `#{object.inspect}`"
31
60
  end
32
61
 
62
+ # @return [String] the name of the key this object would have in a params hash
63
+ #
64
+ def param_key
65
+ if object.respond_to?(:model_name)
66
+ object.model_name.param_key.to_s
67
+ elsif object.is_a?(Class)
68
+ object.to_s.demodulize.underscore
69
+ else
70
+ object.class.to_s.demodulize.underscore
71
+ end
72
+ end
73
+
33
74
  private
34
75
 
35
76
  def find
@@ -40,21 +81,27 @@ module Pundit
40
81
  elsif object.class.respond_to?(:policy_class)
41
82
  object.class.policy_class
42
83
  else
43
- klass = if object.respond_to?(:model_name)
44
- object.model_name
45
- elsif object.class.respond_to?(:model_name)
46
- object.class.model_name
47
- elsif object.is_a?(Class)
48
- object
49
- elsif object.is_a?(Symbol)
50
- object.to_s.camelize
51
- elsif object.is_a?(Array)
52
- object.join('/').camelize
84
+ klass = if object.is_a?(Array)
85
+ object.map { |x| find_class_name(x) }.join("::")
53
86
  else
54
- object.class
87
+ find_class_name(object)
55
88
  end
56
89
  "#{klass}#{SUFFIX}"
57
90
  end
58
91
  end
92
+
93
+ def find_class_name(subject)
94
+ if subject.respond_to?(:model_name)
95
+ subject.model_name
96
+ elsif subject.class.respond_to?(:model_name)
97
+ subject.class.model_name
98
+ elsif subject.is_a?(Class)
99
+ subject
100
+ elsif subject.is_a?(Symbol)
101
+ subject.to_s.camelize
102
+ else
103
+ subject.class
104
+ end
105
+ end
59
106
  end
60
107
  end
@@ -7,23 +7,29 @@ module Pundit
7
7
 
8
8
  matcher :permit do |user, record|
9
9
  match_proc = lambda do |policy|
10
- @violating_permissions = permissions.find_all { |permission| not policy.new(user, record).public_send(permission) }
10
+ @violating_permissions = permissions.find_all do |permission|
11
+ not policy.new(user, record).public_send(permission)
12
+ end
11
13
  @violating_permissions.empty?
12
14
  end
13
15
 
14
16
  match_when_negated_proc = lambda do |policy|
15
- @violating_permissions = permissions.find_all { |permission| policy.new(user, record).public_send(permission) }
17
+ @violating_permissions = permissions.find_all do |permission|
18
+ policy.new(user, record).public_send(permission)
19
+ end
16
20
  @violating_permissions.empty?
17
21
  end
18
22
 
19
23
  failure_message_proc = lambda do |policy|
20
24
  was_were = @violating_permissions.count > 1 ? "were" : "was"
21
- "Expected #{policy} to grant #{permissions.to_sentence} on #{record} but #{@violating_permissions.to_sentence} #{was_were} not granted"
25
+ "Expected #{policy} to grant #{permissions.to_sentence} on \
26
+ #{record} but #{@violating_permissions.to_sentence} #{was_were} not granted"
22
27
  end
23
28
 
24
29
  failure_message_when_negated_proc = lambda do |policy|
25
30
  was_were = @violating_permissions.count > 1 ? "were" : "was"
26
- "Expected #{policy} not to grant #{permissions.to_sentence} on #{record} but #{@violating_permissions.to_sentence} #{was_were} granted"
31
+ "Expected #{policy} not to grant #{permissions.to_sentence} on \
32
+ #{record} but #{@violating_permissions.to_sentence} #{was_were} granted"
27
33
  end
28
34
 
29
35
  if respond_to?(:match_when_negated)
@@ -47,7 +53,7 @@ module Pundit
47
53
 
48
54
  module DSL
49
55
  def permissions(*list, &block)
50
- describe(list.to_sentence, :permissions => list, :caller => caller) { instance_eval(&block) }
56
+ describe(list.to_sentence, permissions: list, caller: caller) { instance_eval(&block) }
51
57
  end
52
58
  end
53
59
 
@@ -65,14 +71,14 @@ end
65
71
 
66
72
  RSpec.configure do |config|
67
73
  if RSpec::Core::Version::STRING.split(".").first.to_i >= 3
68
- config.include(Pundit::RSpec::PolicyExampleGroup, {
69
- :type => :policy,
70
- :file_path => /spec\/policies/,
71
- })
74
+ config.include(Pundit::RSpec::PolicyExampleGroup,
75
+ type: :policy,
76
+ file_path: %r{spec/policies}
77
+ )
72
78
  else
73
- config.include(Pundit::RSpec::PolicyExampleGroup, {
74
- :type => :policy,
75
- :example_group => { :file_path => /spec\/policies/ }
76
- })
79
+ config.include(Pundit::RSpec::PolicyExampleGroup,
80
+ type: :policy,
81
+ example_group: { file_path: %r{spec/policies} }
82
+ )
77
83
  end
78
84
  end
@@ -1,3 +1,3 @@
1
1
  module Pundit
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -1,20 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
2
+ lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'pundit/version'
4
+ require "pundit/version"
5
5
 
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "pundit"
8
8
  gem.version = Pundit::VERSION
9
9
  gem.authors = ["Jonas Nicklas", "Elabs AB"]
10
10
  gem.email = ["jonas.nicklas@gmail.com", "dev@elabs.se"]
11
- gem.description = %q{Object oriented authorization for Rails applications}
12
- gem.summary = %q{OO authorization for Rails}
11
+ gem.description = "Object oriented authorization for Rails applications"
12
+ gem.summary = "OO authorization for Rails"
13
13
  gem.homepage = "https://github.com/elabs/pundit"
14
14
  gem.license = "MIT"
15
15
 
16
16
  gem.files = `git ls-files`.split($/)
17
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
20
 
@@ -26,4 +26,5 @@ Gem::Specification.new do |gem|
26
26
  gem.add_development_dependency "pry"
27
27
  gem.add_development_dependency "rake"
28
28
  gem.add_development_dependency "yard"
29
+ gem.add_development_dependency "rubocop"
29
30
  end
@@ -3,13 +3,18 @@ require "spec_helper"
3
3
  describe Pundit do
4
4
  let(:user) { double }
5
5
  let(:post) { Post.new(user) }
6
+ let(:customer_post) { Customer::Post.new(user) }
7
+ let(:post_four_five_six) { PostFourFiveSix.new(user) }
6
8
  let(:comment) { Comment.new }
9
+ let(:comment_four_five_six) { CommentFourFiveSix.new }
7
10
  let(:article) { Article.new }
8
- let(:controller) { Controller.new(user, { :action => 'update' }) }
11
+ let(:controller) { Controller.new(user, action: "update") }
9
12
  let(:artificial_blog) { ArtificialBlog.new }
10
13
  let(:article_tag) { ArticleTag.new }
11
14
  let(:comments_relation) { CommentsRelation.new }
12
15
  let(:empty_comments_relation) { CommentsRelation.new(true) }
16
+ let(:tag_four_five_six) { ProjectOneTwoThree::TagFourFiveSix.new(user) }
17
+ let(:avatar_four_five_six) { ProjectOneTwoThree::AvatarFourFiveSix.new }
13
18
 
14
19
  describe ".authorize" do
15
20
  it "infers the policy and authorizes based on it" do
@@ -22,7 +27,10 @@ describe Pundit do
22
27
  end
23
28
 
24
29
  it "raises an error with a query and action" do
25
- expect { Pundit.authorize(user, post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this #<Post>") do |error|
30
+ # rubocop:disable Style/MultilineBlockChain
31
+ expect do
32
+ Pundit.authorize(user, post, :destroy?)
33
+ end.to raise_error(Pundit::NotAuthorizedError, "not allowed to destroy? this #<Post>") do |error|
26
34
  expect(error.query).to eq :destroy?
27
35
  expect(error.record).to eq post
28
36
  expect(error.policy).to eq Pundit.policy(user, post)
@@ -74,7 +82,9 @@ describe Pundit do
74
82
  end
75
83
 
76
84
  it "throws an exception if the given policy scope is nil" do
77
- expect { Pundit.policy_scope!(user, nil) }.to raise_error(Pundit::NotDefinedError, "unable to find policy scope of nil")
85
+ expect do
86
+ Pundit.policy_scope!(user, nil)
87
+ end.to raise_error(Pundit::NotDefinedError, "unable to find policy scope of nil")
78
88
  end
79
89
  end
80
90
 
@@ -103,6 +113,93 @@ describe Pundit do
103
113
  expect(policy.comment).to eq Comment
104
114
  end
105
115
 
116
+ it "returns an instantiated policy given a symbol" do
117
+ policy = Pundit.policy(user, :criteria)
118
+ expect(policy.class).to eq CriteriaPolicy
119
+ expect(policy.user).to eq user
120
+ expect(policy.criteria).to eq :criteria
121
+ end
122
+
123
+ it "returns an instantiated policy given an array of symbols" do
124
+ policy = Pundit.policy(user, [:project, :criteria])
125
+ expect(policy.class).to eq Project::CriteriaPolicy
126
+ expect(policy.user).to eq user
127
+ expect(policy.criteria).to eq [:project, :criteria]
128
+ end
129
+
130
+ it "returns an instantiated policy given an array of a symbol and plain model instance" do
131
+ policy = Pundit.policy(user, [:project, post])
132
+ expect(policy.class).to eq Project::PostPolicy
133
+ expect(policy.user).to eq user
134
+ expect(policy.post).to eq [:project, post]
135
+ end
136
+
137
+ it "returns an instantiated policy given an array of a symbol and an active model instance" do
138
+ policy = Pundit.policy(user, [:project, comment])
139
+ expect(policy.class).to eq Project::CommentPolicy
140
+ expect(policy.user).to eq user
141
+ expect(policy.post).to eq [:project, comment]
142
+ end
143
+
144
+ it "returns an instantiated policy given an array of a symbol and a plain model class" do
145
+ policy = Pundit.policy(user, [:project, Post])
146
+ expect(policy.class).to eq Project::PostPolicy
147
+ expect(policy.user).to eq user
148
+ expect(policy.post).to eq [:project, Post]
149
+ end
150
+
151
+ it "returns an instantiated policy given an array of a symbol and an active model class" do
152
+ policy = Pundit.policy(user, [:project, Comment])
153
+ expect(policy.class).to eq Project::CommentPolicy
154
+ expect(policy.user).to eq user
155
+ expect(policy.post).to eq [:project, Comment]
156
+ end
157
+
158
+ it "returns correct policy class for an array of a multi-word symbols" do
159
+ policy = Pundit.policy(user, [:project_one_two_three, :criteria_four_five_six])
160
+ expect(policy.class).to eq ProjectOneTwoThree::CriteriaFourFiveSixPolicy
161
+ end
162
+
163
+ it "returns correct policy class for an array of a multi-word symbol and a multi-word plain model instance" do
164
+ policy = Pundit.policy(user, [:project_one_two_three, post_four_five_six])
165
+ expect(policy.class).to eq ProjectOneTwoThree::PostFourFiveSixPolicy
166
+ end
167
+
168
+ it "returns correct policy class for an array of a multi-word symbol and a multi-word active model instance" do
169
+ policy = Pundit.policy(user, [:project_one_two_three, comment_four_five_six])
170
+ expect(policy.class).to eq ProjectOneTwoThree::CommentFourFiveSixPolicy
171
+ end
172
+
173
+ it "returns correct policy class for an array of a multi-word symbol and a multi-word plain model class" do
174
+ policy = Pundit.policy(user, [:project_one_two_three, PostFourFiveSix])
175
+ expect(policy.class).to eq ProjectOneTwoThree::PostFourFiveSixPolicy
176
+ end
177
+
178
+ it "returns correct policy class for an array of a multi-word symbol and a multi-word active model class" do
179
+ policy = Pundit.policy(user, [:project_one_two_three, CommentFourFiveSix])
180
+ expect(policy.class).to eq ProjectOneTwoThree::CommentFourFiveSixPolicy
181
+ end
182
+
183
+ it "returns correct policy class for a multi-word scoped plain model class" do
184
+ policy = Pundit.policy(user, ProjectOneTwoThree::TagFourFiveSix)
185
+ expect(policy.class).to eq ProjectOneTwoThree::TagFourFiveSixPolicy
186
+ end
187
+
188
+ it "returns correct policy class for a multi-word scoped plain model instance" do
189
+ policy = Pundit.policy(user, tag_four_five_six)
190
+ expect(policy.class).to eq ProjectOneTwoThree::TagFourFiveSixPolicy
191
+ end
192
+
193
+ it "returns correct policy class for a multi-word scoped active model class" do
194
+ policy = Pundit.policy(user, ProjectOneTwoThree::AvatarFourFiveSix)
195
+ expect(policy.class).to eq ProjectOneTwoThree::AvatarFourFiveSixPolicy
196
+ end
197
+
198
+ it "returns correct policy class for a multi-word scoped active model instance" do
199
+ policy = Pundit.policy(user, avatar_four_five_six)
200
+ expect(policy.class).to eq ProjectOneTwoThree::AvatarFourFiveSixPolicy
201
+ end
202
+
106
203
  it "returns nil if the given policy can't be found" do
107
204
  expect(Pundit.policy(user, article)).to be_nil
108
205
  expect(Pundit.policy(user, Article)).to be_nil
@@ -136,20 +233,6 @@ describe Pundit do
136
233
  expect(policy.user).to eq user
137
234
  expect(policy.tag).to eq ArticleTag
138
235
  end
139
-
140
- it "returns an instantiated policy given a symbol" do
141
- policy = Pundit.policy(user, :criteria)
142
- expect(policy.class).to eq CriteriaPolicy
143
- expect(policy.user).to eq user
144
- expect(policy.criteria).to eq :criteria
145
- end
146
-
147
- it "returns an instantiated policy given an array" do
148
- policy = Pundit.policy(user, [:project, :criteria])
149
- expect(policy.class).to eq Project::CriteriaPolicy
150
- expect(policy.user).to eq user
151
- expect(policy.criteria).to eq [:project, :criteria]
152
- end
153
236
  end
154
237
  end
155
238
 
@@ -185,7 +268,7 @@ describe Pundit do
185
268
  expect(policy.criteria).to eq :criteria
186
269
  end
187
270
 
188
- it "returns an instantiated policy given an array" do
271
+ it "returns an instantiated policy given an array of symbols" do
189
272
  policy = Pundit.policy!(user, [:project, :criteria])
190
273
  expect(policy.class).to eq Project::CriteriaPolicy
191
274
  expect(policy.user).to eq user
@@ -295,7 +378,7 @@ describe Pundit do
295
378
  end
296
379
 
297
380
  describe "#pundit_user" do
298
- it 'returns the same thing as current_user' do
381
+ it "returns the same thing as current_user" do
299
382
  expect(controller.pundit_user).to eq controller.current_user
300
383
  end
301
384
  end
@@ -338,10 +421,49 @@ describe Pundit do
338
421
 
339
422
  describe "#permitted_attributes" do
340
423
  it "checks policy for permitted attributes" do
341
- params = ActionController::Parameters.new({ action: 'update', post: { title: 'Hello', votes: 5, admin: true } })
424
+ params = ActionController::Parameters.new(action: "update", post: {
425
+ title: "Hello",
426
+ votes: 5,
427
+ admin: true
428
+ })
429
+
430
+ expect(Controller.new(user, params).permitted_attributes(post)).to eq("title" => "Hello", "votes" => 5)
431
+ expect(Controller.new(double, params).permitted_attributes(post)).to eq("votes" => 5)
432
+ end
433
+
434
+ it "checks policy for permitted attributes for record of a ActiveModel type" do
435
+ params = ActionController::Parameters.new(action: "update", customer_post: {
436
+ title: "Hello",
437
+ votes: 5,
438
+ admin: true
439
+ })
440
+
441
+ expect(Controller.new(user, params).permitted_attributes(customer_post)).to eq("title" => "Hello", "votes" => 5)
442
+ expect(Controller.new(double, params).permitted_attributes(customer_post)).to eq("votes" => 5)
443
+ end
444
+ end
445
+
446
+ describe "#permitted_attributes_for_action" do
447
+ it "is checked if it is defined in the policy" do
448
+ params = ActionController::Parameters.new(action: "revise", post: {
449
+ title: "Hello",
450
+ body: "blah",
451
+ votes: 5,
452
+ admin: true
453
+ })
454
+
455
+ expect(Controller.new(user, params).permitted_attributes(post)).to eq("body" => "blah")
456
+ end
457
+
458
+ it "can be explicitly set" do
459
+ params = ActionController::Parameters.new(action: "update", post: {
460
+ title: "Hello",
461
+ body: "blah",
462
+ votes: 5,
463
+ admin: true
464
+ })
342
465
 
343
- expect(Controller.new(user, params).permitted_attributes(post)).to eq({ 'title' => 'Hello', 'votes' => 5 })
344
- expect(Controller.new(double, params).permitted_attributes(post)).to eq({ 'votes' => 5 })
466
+ expect(Controller.new(user, params).permitted_attributes(post, :revise)).to eq("body" => "blah")
345
467
  end
346
468
  end
347
469
 
@@ -26,15 +26,24 @@ RSpec.configure do |config|
26
26
  end
27
27
 
28
28
  class PostPolicy < Struct.new(:user, :post)
29
+ class Scope < Struct.new(:user, :scope)
30
+ def resolve
31
+ scope.published
32
+ end
33
+ end
34
+
29
35
  def update?
30
36
  post.user == user
31
37
  end
38
+
32
39
  def destroy?
33
40
  false
34
41
  end
42
+
35
43
  def show?
36
44
  true
37
45
  end
46
+
38
47
  def permitted_attributes
39
48
  if post.user == user
40
49
  [:title, :votes]
@@ -42,61 +51,98 @@ class PostPolicy < Struct.new(:user, :post)
42
51
  [:votes]
43
52
  end
44
53
  end
45
- end
46
- class PostPolicy::Scope < Struct.new(:user, :scope)
47
- def resolve
48
- scope.published
54
+
55
+ def permitted_attributes_for_revise
56
+ [:body]
49
57
  end
50
58
  end
59
+
51
60
  class Post < Struct.new(:user)
52
61
  def self.published
53
62
  :published
54
63
  end
55
- def to_s; "Post"; end
56
- def inspect; "#<Post>"; end
64
+
65
+ def to_s
66
+ "Post"
67
+ end
68
+
69
+ def inspect
70
+ "#<Post>"
71
+ end
57
72
  end
58
73
 
59
- class CommentPolicy < Struct.new(:user, :comment); end
60
- class CommentPolicy::Scope < Struct.new(:user, :scope)
61
- def resolve
62
- scope
74
+ module Customer
75
+ class Post < Post
76
+ def model_name
77
+ OpenStruct.new(param_key: "customer_post")
78
+ end
79
+
80
+ def policy_class
81
+ PostPolicy
82
+ end
83
+ end
84
+ end
85
+
86
+ class CommentPolicy < Struct.new(:user, :comment)
87
+ class Scope < Struct.new(:user, :scope)
88
+ def resolve
89
+ scope
90
+ end
63
91
  end
64
92
  end
65
- class Comment; extend ActiveModel::Naming; end
66
93
 
67
- # minimum mock for an ActiveRecord Relation returning comments
94
+ class Comment
95
+ extend ActiveModel::Naming
96
+ end
97
+
68
98
  class CommentsRelation
69
- def initialize(empty=false); @empty=empty; end
70
- def blank?; @empty; end
71
- def model_name; Comment.model_name; end
99
+ def initialize(empty = false)
100
+ @empty = empty
101
+ end
102
+
103
+ def blank?
104
+ @empty
105
+ end
106
+
107
+ def model_name
108
+ Comment.model_name
109
+ end
72
110
  end
73
111
 
74
112
  class Article; end
75
113
 
76
114
  class BlogPolicy < Struct.new(:user, :blog); end
115
+
77
116
  class Blog; end
117
+
78
118
  class ArtificialBlog < Blog
79
119
  def self.policy_class
80
120
  BlogPolicy
81
121
  end
82
122
  end
123
+
124
+ class ArticleTagOtherNamePolicy < Struct.new(:user, :tag)
125
+ def show?
126
+ true
127
+ end
128
+
129
+ def destroy?
130
+ false
131
+ end
132
+ end
133
+
83
134
  class ArticleTag
84
135
  def self.policy_class
85
- Struct.new(:user, :tag) do
86
- def show?
87
- true
88
- end
89
- def destroy?
90
- false
91
- end
92
- end
136
+ ArticleTagOtherNamePolicy
93
137
  end
94
138
  end
95
139
 
96
140
  class CriteriaPolicy < Struct.new(:user, :criteria); end
97
141
 
98
142
  module Project
143
+ class CommentPolicy < Struct.new(:user, :post); end
99
144
  class CriteriaPolicy < Struct.new(:user, :criteria); end
145
+ class PostPolicy < Struct.new(:user, :post); end
100
146
  end
101
147
 
102
148
  class DenierPolicy < Struct.new(:user, :record)
@@ -127,3 +173,23 @@ class NilClassPolicy
127
173
  raise "I'm only here to be annoying!"
128
174
  end
129
175
  end
176
+
177
+ class PostFourFiveSix < Struct.new(:user); end
178
+
179
+ class CommentFourFiveSix; extend ActiveModel::Naming; end
180
+
181
+ module ProjectOneTwoThree
182
+ class CommentFourFiveSixPolicy < Struct.new(:user, :post); end
183
+
184
+ class CriteriaFourFiveSixPolicy < Struct.new(:user, :criteria); end
185
+
186
+ class PostFourFiveSixPolicy < Struct.new(:user, :post); end
187
+
188
+ class TagFourFiveSix < Struct.new(:user); end
189
+
190
+ class TagFourFiveSixPolicy < Struct.new(:user, :tag); end
191
+
192
+ class AvatarFourFiveSix; extend ActiveModel::Naming; end
193
+
194
+ class AvatarFourFiveSixPolicy < Struct.new(:user, :avatar); end
195
+ end
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: 1.0.1
4
+ version: 1.1.0
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: 2015-05-27 00:00:00.000000000 Z
12
+ date: 2016-01-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -123,6 +123,20 @@ dependencies:
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rubocop
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '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'
126
140
  description: Object oriented authorization for Rails applications
127
141
  email:
128
142
  - jonas.nicklas@gmail.com
@@ -132,7 +146,9 @@ extensions: []
132
146
  extra_rdoc_files: []
133
147
  files:
134
148
  - ".gitignore"
149
+ - ".rubocop.yml"
135
150
  - ".travis.yml"
151
+ - ".yardopts"
136
152
  - CHANGELOG.md
137
153
  - CODE_OF_CONDUCT.md
138
154
  - CONTRIBUTING.md
@@ -178,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
194
  version: '0'
179
195
  requirements: []
180
196
  rubyforge_project:
181
- rubygems_version: 2.4.6
197
+ rubygems_version: 2.4.8
182
198
  signing_key:
183
199
  specification_version: 4
184
200
  summary: OO authorization for Rails