pundit 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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