pundit 0.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.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ bin
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby-19mode
6
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pundit.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jonas Nicklas, Elabs AB
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,260 @@
1
+ # Pundit
2
+
3
+ Pundit provides a set of helpers which guide you in leveraging regular Ruby
4
+ classes and object oriented design patterns to build a simple, robust and
5
+ scaleable authorization system.
6
+
7
+ ## Installation
8
+
9
+ ``` ruby
10
+ gem "pundit"
11
+ ```
12
+
13
+ Include Pundit in your application controller:
14
+
15
+ ``` ruby
16
+ class ApplicationController < ActionController::Base
17
+ include Pundit
18
+ protect_from_forgery
19
+ end
20
+ ```
21
+
22
+ Optionally, you can run the generator, which will set up an application policy
23
+ with some useful defaults for you:
24
+
25
+ ``` sh
26
+ rails g pundit:install
27
+ ```
28
+
29
+ ## Policies
30
+
31
+ Pundit is focused around the notion of policy classes. We suggest that you put
32
+ these classes in `app/policies`. This is a simple example:
33
+
34
+ ``` ruby
35
+ class PostPolicy
36
+ attr_reader :user, :post
37
+
38
+ def initialize(user, post)
39
+ @user = user
40
+ @post = post
41
+ end
42
+
43
+ def create?
44
+ user.admin? or not post.published?
45
+ end
46
+ end
47
+ ```
48
+
49
+ As you can see, this is just a plain Ruby class. As a convenience, we can inherit
50
+ from Struct:
51
+
52
+ ``` ruby
53
+ class PostPolicy < Struct.new(:user, :post)
54
+ def create?
55
+ user.admin? or not post.published?
56
+ end
57
+ end
58
+ ```
59
+
60
+ Pundit makes the following assumptions about this class:
61
+
62
+ - The class has the same name as some kind of model class, only suffixed
63
+ with the word "Policy".
64
+ - The first argument is a user. In your controller, Pundit will call the
65
+ `current_user` method to retrieve what to send into this argument
66
+ - The second argument is some kind of model object, whose authorization
67
+ you want to check. This does not need to be an ActiveRecord or even
68
+ an ActiveModel object, it can be anything really.
69
+ - The class implements some kind of query method, in this case `create?`.
70
+ Usually, this will map to the name of a particular controller action.
71
+
72
+ That's it really.
73
+
74
+ Supposing that you have an instance of class `Post`, Pundit now lets you do
75
+ this in your controller:
76
+
77
+ ``` ruby
78
+ def create
79
+ @post = Post.new(params[:post])
80
+ authorize @post
81
+ if @post.save
82
+ redirect_to @post
83
+ else
84
+ render :new
85
+ end
86
+ end
87
+ ```
88
+
89
+ The authorize method automatically infers that `Post` will have a matching
90
+ `PostPolicy` class, and instantiates this class, handing in the current user
91
+ and the given record. It then infers from the action name, that it should call
92
+ `create?` on this instance of the policy. In this case, you can imagine that
93
+ `authorize` would have done something like this:
94
+
95
+ ``` ruby
96
+ raise "not authorized" unless PostPolicy.new(current_user, @post).create?
97
+ ```
98
+
99
+ You can pass a second arguent to `authorize` if the name of the permission you
100
+ want to check doesn't match the action name. For example:
101
+
102
+ ``` ruby
103
+ def publish
104
+ @post = Post.find(params[:id])
105
+ authorize @post, :update?
106
+ @post.publish!
107
+ redirect_to @post
108
+ end
109
+ ```
110
+
111
+ You can easily get a hold of an instance of the policy through the `policy`
112
+ method in both the view and controller. This is especially useful for
113
+ conditionally showing links or buttons in the view:
114
+
115
+ ``` erb
116
+ <% if policy(@post).create? %>
117
+ <%= link_to "New post", new_post_path %>
118
+ <% end %>
119
+ ```
120
+
121
+ ## Ensuring policies are used
122
+
123
+ Pundit adds a method called `verify_authorized` to your controllers. This
124
+ method will raise an exception if `authorize` has not yet been called. You
125
+ should run this method in an `after_filter` to ensure that you haven't
126
+ forgotten to authorize the action. For example:
127
+
128
+ ``` ruby
129
+ class ApplicationController < ActionController::Base
130
+ after_filter :verify_authorized, :except => :index
131
+ end
132
+ ```
133
+
134
+ ## Scopes
135
+
136
+ Often, you will want to have some kind of view listing records which a
137
+ particular user has access to. When using Pundit, you are expected to
138
+ define a class called a policy scope. It can look something like this:
139
+
140
+ ``` ruby
141
+ class PostPolicy < Struct.new(:user, :post)
142
+ class Scope < Struct.new(:user, :scope)
143
+ def resolve
144
+ if user.admin?
145
+ scope
146
+ else
147
+ scope.where(:published => true)
148
+ end
149
+ end
150
+ end
151
+
152
+ def create?
153
+ user.admin? or not post.published?
154
+ end
155
+ end
156
+ ```
157
+
158
+ Pundit makes the following assumptions about this class:
159
+
160
+ - The class has the name `Scope` and is nested under the policy class.
161
+ - The first argument is a user. In your controller, Pundit will call the
162
+ `current_user` method to retrieve what to send into this argument.
163
+ - The second argument is a scope of some kind on which to perform some kind of
164
+ query. It will usually be an ActiveRecord class or a
165
+ `ActiveRecord::Relation`, but it could be something else entirely.
166
+ - Instances of this class respond to the method `resolve`, which should return
167
+ some kind of result which can be iterated over. For ActiveRecord classes,
168
+ this would usually be an `ActiveRecord::Relation`.
169
+
170
+ You can now use this class from your controller via the `policy_scope` method:
171
+
172
+ ``` ruby
173
+ def index
174
+ @posts = policy_scope(Post)
175
+ end
176
+ ```
177
+
178
+ Just as with your policy, this will automatically infer that you want to use
179
+ the `PostPolicy::Scope` class, it will instantiate this class and call
180
+ `resolve` on the instance. In this case it is a shortcut for doing:
181
+
182
+ ``` ruby
183
+ def index
184
+ @posts = PostPolicy::Scope.new(current_user, Post).resolve
185
+ end
186
+ ```
187
+
188
+ You can, and are encouraged to, use this method in views:
189
+
190
+ ``` erb
191
+ <% policy_scope(@user.posts).each do |post| %>
192
+ <p><% link_to @post.title, post_path(post) %></p>
193
+ <% end %>
194
+ ```
195
+
196
+ ## Just plain old Ruby
197
+
198
+ As you can see, Pundit doesn't do anything you couldn't have easily done
199
+ yourself. It's a very small library, it just provides a few neat helpers.
200
+ Together these give you the power of building a well structured, fully working
201
+ authorization system without using any special DSLs or funky syntax or
202
+ anything.
203
+
204
+ Remember that all of the policy and scope classes are just plain Ruby classes,
205
+ which means you can use the same mechanisms you always use to DRY things up.
206
+ Encapsulate a set of permissions into a module and include them in multiple
207
+ policies. Use `alias_method` to make some permissions behave the same as
208
+ others. Inherit from a base set of permissions. Use metaprogramming if you
209
+ really have to.
210
+
211
+ ## Generator
212
+
213
+ Use the supplied generator to generate policies:
214
+
215
+ ``` sh
216
+ rails g pundit:policy post
217
+ ```
218
+
219
+ ## Closed systems
220
+
221
+ In many applications, only logged in users are really able to do anything. If
222
+ you're building such a system, it can be kind of cumbersome to check that the
223
+ user in a policy isn't `nil` for every single permission.
224
+
225
+ We suggest that you define a filter that redirects unauthenticated users to the
226
+ login page. As a secondary defence, if you've defined an ApplicationPolicy, it
227
+ might be a good idea to raise an exception if somehow an unauthenticated user
228
+ got through. This way you can fail more gracefully.
229
+
230
+ ``` ruby
231
+ class ApplicationPolicy
232
+ def initialize(user, record)
233
+ raise Pundit::NotAuthorized, "must be logged in" unless user
234
+ @user = user
235
+ @record = record
236
+ end
237
+ end
238
+ ```
239
+
240
+ ## Manually retrieving policies and scopes
241
+
242
+ Sometimes you want to retrieve a policy for a record outside the controller or
243
+ view. For example when you delegate permissions from one policy to another.
244
+
245
+ You can easily retrieve policies and scopes like this:
246
+
247
+ ``` ruby
248
+ Pundit.policy!(user, post)
249
+ Pundit.policy(user, post)
250
+
251
+ Pundit.policy_scope!(user, Post)
252
+ Pundit.policy_scope(user, Post)
253
+ ```
254
+
255
+ The bang methods will raise an exception if the policy does not exist, whereas
256
+ those without the bang will return nil.
257
+
258
+ # License
259
+
260
+ Licensed under the MIT license, see the separate LICENSE.txt file.
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+
5
+ desc "Run all examples"
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ #t.rspec_path = 'bin/rspec'
8
+ t.rspec_opts = %w[--color]
9
+ end
10
+
11
+ YARD::Rake::YardocTask.new do |t|
12
+ t.files = ['lib/**/*.rb']
13
+ #t.options = ['--any', '--extra', '--opts'] # optional
14
+ end
15
+
16
+ task :default => [:spec]
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Generates an application policy as a starting point for your application.
@@ -0,0 +1,11 @@
1
+ module Pundit
2
+ module Generators
3
+ class InstallGenerator < ::Rails::Generators::Base
4
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
5
+
6
+ def copy_application_policy
7
+ template 'application_policy.rb', 'app/policies/application_policy.rb'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ class ApplicationPolicy
2
+ attr_reader :user, :record
3
+
4
+ def initialize(user, record)
5
+ @user = user
6
+ @record = record
7
+ end
8
+
9
+ def index?
10
+ scope.exists?
11
+ end
12
+
13
+ def show?
14
+ scope.where(:id => record.id).exists?
15
+ end
16
+
17
+ def create?
18
+ false
19
+ end
20
+
21
+ def new?
22
+ create?
23
+ end
24
+
25
+ def update?
26
+ false
27
+ end
28
+
29
+ def edit?
30
+ update?
31
+ end
32
+
33
+ def destroy?
34
+ false
35
+ end
36
+
37
+ def scope
38
+ Pundit.policy_scope!(user, record.class)
39
+ end
40
+ end
41
+
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generates a policy for a model with the given name.
3
+
4
+ Example:
5
+ rails generate pundit:policy user
6
+
7
+ This will create:
8
+ app/policies/user_policy.rb
@@ -0,0 +1,11 @@
1
+ module Pundit
2
+ module Generators
3
+ class PolicyGenerator < ::Rails::Generators::NamedBase
4
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
5
+
6
+ def create_policy
7
+ template 'policy.rb', File.join('app/policies', class_path, "#{file_name}_policy.rb")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Policy < ApplicationPolicy
3
+ class Scope < Struct.new(:user, :scope)
4
+ def resolve
5
+ scope
6
+ end
7
+ end
8
+ end
9
+ <% end -%>
@@ -0,0 +1,60 @@
1
+ require "pundit/version"
2
+ require "pundit/policy_finder"
3
+ require "active_support/concern"
4
+ require "active_support/core_ext/string/inflections"
5
+ require "active_support/core_ext/object/blank"
6
+
7
+ module Pundit
8
+ class NotAuthorizedError < StandardError; end
9
+ class NotDefinedError < StandardError; end
10
+
11
+ extend ActiveSupport::Concern
12
+
13
+ class << self
14
+ def policy_scope(user, scope)
15
+ policy = PolicyFinder.new(scope).scope
16
+ policy.new(user, scope).resolve if policy
17
+ end
18
+
19
+ def policy_scope!(user, scope)
20
+ PolicyFinder.new(scope).scope!.new(user, scope).resolve
21
+ end
22
+
23
+ def policy(user, record)
24
+ scope = PolicyFinder.new(record).policy
25
+ scope.new(user, record) if scope
26
+ end
27
+
28
+ def policy!(user, record)
29
+ PolicyFinder.new(record).policy!.new(user, record)
30
+ end
31
+ end
32
+
33
+ included do
34
+ if respond_to?(:helper_method)
35
+ helper_method :policy_scope
36
+ helper_method :policy
37
+ end
38
+ end
39
+
40
+ def verify_authorized
41
+ raise NotAuthorizedError unless @_policy_authorized
42
+ end
43
+
44
+ def authorize(record, query=nil)
45
+ query ||= params[:action].to_s + "?"
46
+ @_policy_authorized = true
47
+ unless policy(record).public_send(query)
48
+ raise NotAuthorizedError, "not allowed to #{query} this #{record}"
49
+ end
50
+ true
51
+ end
52
+
53
+ def policy_scope(scope)
54
+ Pundit.policy_scope!(current_user, scope)
55
+ end
56
+
57
+ def policy(record)
58
+ Pundit.policy!(current_user, record)
59
+ end
60
+ end
@@ -0,0 +1,49 @@
1
+ module Pundit
2
+ class PolicyFinder
3
+ attr_reader :object
4
+
5
+ def initialize(object)
6
+ @object = object
7
+ end
8
+
9
+ def name
10
+ if object.respond_to?(:model_name)
11
+ object.model_name.to_s
12
+ elsif object.class.respond_to?(:model_name)
13
+ object.class.model_name.to_s
14
+ elsif object.is_a?(Class)
15
+ object.to_s
16
+ else
17
+ object.class.to_s
18
+ end
19
+ end
20
+
21
+ def scope
22
+ scope_name.constantize
23
+ rescue NameError
24
+ nil
25
+ end
26
+
27
+ def policy
28
+ policy_name.constantize
29
+ rescue NameError
30
+ nil
31
+ end
32
+
33
+ def scope!
34
+ scope or raise NotDefinedError, "unable to find scope #{scope_name} for #{object}"
35
+ end
36
+
37
+ def policy!
38
+ policy or raise NotDefinedError, "unable to find policy #{policy_name} for #{object}"
39
+ end
40
+
41
+ def scope_name
42
+ "#{name}Policy::Scope"
43
+ end
44
+
45
+ def policy_name
46
+ "#{name}Policy"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,47 @@
1
+ module Pundit
2
+ module RSpec
3
+ module Matchers
4
+ extend ::RSpec::Matchers::DSL
5
+
6
+ matcher :permit do |user, record|
7
+ match do |policy|
8
+ permissions.all? { |permission| policy.new(user, record).public_send(permission) }
9
+ end
10
+
11
+ failure_message_for_should do |policy|
12
+ "Expected #{policy} to grant #{permissions.to_sentence} on #{record} but it didn't"
13
+ end
14
+
15
+ failure_message_for_should_not do |policy|
16
+ "Expected #{policy} not to grant #{permissions.to_sentence} on #{record} but it did"
17
+ end
18
+
19
+ def permissions
20
+ example.metadata[:permissions]
21
+ end
22
+ end
23
+ end
24
+
25
+ module DSL
26
+ def permissions(*list, &block)
27
+ describe(list.to_sentence, :permissions => list, :caller => caller) { instance_eval(&block) }
28
+ end
29
+ end
30
+
31
+ module PolicyExampleGroup
32
+ include Pundit::RSpec::Matchers
33
+
34
+ def self.included(base)
35
+ base.metadata[:type] = :policy
36
+ base.extend Pundit::RSpec::DSL
37
+ super
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ RSpec.configure do |config|
44
+ config.include Pundit::RSpec::PolicyExampleGroup, :type => :policy, :example_group => {
45
+ :file_path => /spec\/policies/
46
+ }
47
+ end
@@ -0,0 +1,3 @@
1
+ module Pundit
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pundit/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "pundit"
8
+ gem.version = Pundit::VERSION
9
+ gem.authors = ["Jonas Nicklas", "Elabs AB"]
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}
13
+ gem.homepage = "http://github.com/elabs/pundit"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "rails", "~>3.0"
21
+ gem.add_development_dependency "rspec", "~>2.0"
22
+ gem.add_development_dependency "pry"
23
+ gem.add_development_dependency "rake"
24
+ gem.add_development_dependency "yard"
25
+ end
@@ -0,0 +1,181 @@
1
+ require "pundit"
2
+ require "pry"
3
+ require "active_model/naming"
4
+
5
+ class PostPolicy < Struct.new(:user, :post)
6
+ def update?
7
+ post.user == user
8
+ end
9
+ def destroy?
10
+ false
11
+ end
12
+ def show?
13
+ true
14
+ end
15
+ end
16
+ class PostPolicy::Scope < Struct.new(:user, :scope)
17
+ def resolve
18
+ scope.published
19
+ end
20
+ end
21
+ class Post < Struct.new(:user)
22
+ def self.published
23
+ :published
24
+ end
25
+ end
26
+
27
+ class CommentPolicy < Struct.new(:user, :comment); end
28
+ class CommentPolicy::Scope < Struct.new(:user, :scope)
29
+ def resolve
30
+ scope
31
+ end
32
+ end
33
+ class Comment; extend ActiveModel::Naming; end
34
+
35
+ class Article; end
36
+
37
+ describe Pundit do
38
+ let(:user) { stub }
39
+ let(:post) { Post.new(user) }
40
+ let(:comment) { Comment.new }
41
+ let(:article) { Article.new }
42
+ let(:controller) { stub(:current_user => user, :params => { :action => "update" }).tap { |c| c.extend(Pundit) } }
43
+
44
+ describe ".policy_scope" do
45
+ it "returns an instantiated policy scope given a plain model class" do
46
+ Pundit.policy_scope(user, Post).should == :published
47
+ end
48
+
49
+ it "returns an instantiated policy scope given an active model class" do
50
+ Pundit.policy_scope(user, Comment).should == Comment
51
+ end
52
+
53
+ it "returns nil if the given policy scope can't be found" do
54
+ Pundit.policy_scope(user, Article).should be_nil
55
+ end
56
+ end
57
+
58
+ describe ".policy_scope!" do
59
+ it "returns an instantiated policy scope given a plain model class" do
60
+ Pundit.policy_scope!(user, Post).should == :published
61
+ end
62
+
63
+ it "returns an instantiated policy scope given an active model class" do
64
+ Pundit.policy_scope!(user, Comment).should == Comment
65
+ end
66
+
67
+ it "throws an exception if the given policy scope can't be found" do
68
+ expect { Pundit.policy_scope!(user, Article) }.to raise_error(Pundit::NotDefinedError)
69
+ end
70
+ end
71
+
72
+ describe ".policy" do
73
+ it "returns an instantiated policy given a plain model instance" do
74
+ policy = Pundit.policy(user, post)
75
+ policy.user.should == user
76
+ policy.post.should == post
77
+ end
78
+
79
+ it "returns an instantiated policy given an active model instance" do
80
+ policy = Pundit.policy(user, comment)
81
+ policy.user.should == user
82
+ policy.comment.should == comment
83
+ end
84
+
85
+ it "returns an instantiated policy given a plain model class" do
86
+ policy = Pundit.policy(user, Post)
87
+ policy.user.should == user
88
+ policy.post.should == Post
89
+ end
90
+
91
+ it "returns an instantiated policy given an active model class" do
92
+ policy = Pundit.policy(user, Comment)
93
+ policy.user.should == user
94
+ policy.comment.should == Comment
95
+ end
96
+
97
+ it "returns nil if the given policy can't be found" do
98
+ Pundit.policy(user, article).should be_nil
99
+ Pundit.policy(user, Article).should be_nil
100
+ end
101
+ end
102
+
103
+ describe ".policy!" do
104
+ it "returns an instantiated policy given a plain model instance" do
105
+ policy = Pundit.policy!(user, post)
106
+ policy.user.should == user
107
+ policy.post.should == post
108
+ end
109
+
110
+ it "returns an instantiated policy given an active model instance" do
111
+ policy = Pundit.policy!(user, comment)
112
+ policy.user.should == user
113
+ policy.comment.should == comment
114
+ end
115
+
116
+ it "returns an instantiated policy given a plain model class" do
117
+ policy = Pundit.policy!(user, Post)
118
+ policy.user.should == user
119
+ policy.post.should == Post
120
+ end
121
+
122
+ it "returns an instantiated policy given an active model class" do
123
+ policy = Pundit.policy!(user, Comment)
124
+ policy.user.should == user
125
+ policy.comment.should == Comment
126
+ end
127
+
128
+ it "throws an exception if the given policy can't be found" do
129
+ expect { Pundit.policy!(user, article) }.to raise_error(Pundit::NotDefinedError)
130
+ expect { Pundit.policy!(user, Article) }.to raise_error(Pundit::NotDefinedError)
131
+ end
132
+ end
133
+
134
+ describe "#verify_authorized" do
135
+ it "does nothing when authorized" do
136
+ controller.authorize(post)
137
+ controller.verify_authorized
138
+ end
139
+
140
+ it "raises an exception when not authorized" do
141
+ expect { controller.verify_authorized }.to raise_error(Pundit::NotAuthorizedError)
142
+ end
143
+ end
144
+
145
+ describe "#authorize" do
146
+ it "infers the policy name and authorized based on it" do
147
+ controller.authorize(post).should be_true
148
+ end
149
+
150
+ it "can be given a different permission to check" do
151
+ controller.authorize(post, :show?).should be_true
152
+ expect { controller.authorize(post, :destroy?) }.to raise_error(Pundit::NotAuthorizedError)
153
+ end
154
+
155
+ it "raises an error when the permission check fails" do
156
+ expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
157
+ end
158
+ end
159
+
160
+ describe ".policy" do
161
+ it "returns an instantiated policy" do
162
+ policy = controller.policy(post)
163
+ policy.user.should == user
164
+ policy.post.should == post
165
+ end
166
+
167
+ it "throws an exception if the given policy can't be found" do
168
+ expect { controller.policy(article) }.to raise_error(Pundit::NotDefinedError)
169
+ end
170
+ end
171
+
172
+ describe ".policy_scope" do
173
+ it "returns an instantiated policy scope" do
174
+ controller.policy_scope(Post).should == :published
175
+ end
176
+
177
+ it "throws an exception if the given policy can't be found" do
178
+ expect { controller.policy_scope(Article) }.to raise_error(Pundit::NotDefinedError)
179
+ end
180
+ end
181
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pundit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jonas Nicklas
9
+ - Elabs AB
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-11-19 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '3.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '3.0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rspec
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '2.0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: rake
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: yard
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: Object oriented authorization for Rails applications
96
+ email:
97
+ - jonas.nicklas@gmail.com
98
+ - dev@elabs.se
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - .gitignore
104
+ - .travis.yml
105
+ - Gemfile
106
+ - LICENSE.txt
107
+ - README.md
108
+ - Rakefile
109
+ - lib/generators/pundit/install/USAGE
110
+ - lib/generators/pundit/install/install_generator.rb
111
+ - lib/generators/pundit/install/templates/application_policy.rb
112
+ - lib/generators/pundit/policy/USAGE
113
+ - lib/generators/pundit/policy/policy_generator.rb
114
+ - lib/generators/pundit/policy/templates/policy.rb
115
+ - lib/pundit.rb
116
+ - lib/pundit/policy_finder.rb
117
+ - lib/pundit/rspec.rb
118
+ - lib/pundit/version.rb
119
+ - pundit.gemspec
120
+ - spec/pundit_spec.rb
121
+ homepage: http://github.com/elabs/pundit
122
+ licenses: []
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 1.8.24
142
+ signing_key:
143
+ specification_version: 3
144
+ summary: OO authorization for Rails
145
+ test_files:
146
+ - spec/pundit_spec.rb
147
+ has_rdoc: