canard 0.2.7 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  *.gem
2
3
  .bundle
3
4
  pkg/*
data/TODO CHANGED
@@ -1,7 +1,6 @@
1
- * Test the ability class.
2
1
  * Test the generators.
3
2
  * Test the railtie
4
3
  * Expand the tests to produce all the standard abilities: index,show,read,new,create,edit,update,destroy.
5
4
  * Add test unit generator.
6
5
  * Add install generator to allow overriding of the default tests.
7
- * Add some rdocs.
6
+ * Make the Ability user referece configureable.
data/lib/ability.rb CHANGED
@@ -1,11 +1,39 @@
1
+ # Canard provides a CanCan Ability class for you. The Canard Ability class
2
+ # looks for and applies abilities for the object passed when a new Ability
3
+ # instance is initialized.
4
+ #
5
+ # If the passed object has a reference to user the user is set to that.
6
+ # Otherwise the passed object is assumed to be the user. This gives the
7
+ # flexibility to have a seperate model for authorization from the model used
8
+ # to authenticate the user.
9
+ #
10
+ # Abilities are applied in the order they are set with the acts_as_user method
11
+ # for example for the User model
12
+ #
13
+ # class User < ActiveRecord::Base
14
+ #
15
+ # acts_as_user :roles => :manager, :admin
16
+ #
17
+ # end
18
+ #
19
+ # the abilities would be applied in the order: users, managers, admins
20
+ # with each subsequent set of abilities building on or overriding the existing
21
+ # abilities.
22
+ #
23
+ # If there is no object passed to the Ability.new method a guest ability is
24
+ # created and Canard will look for a guests.rb amongst the ability definitions
25
+ # and give the guest those abilities.
1
26
  class Ability
2
27
 
3
28
  include CanCan::Ability
4
29
 
30
+ attr_reader :user
31
+
5
32
  def initialize(object=nil)
6
33
 
7
- # If a user was passed set the user from it.
8
- @user = object.is_a?(Account) ? object.user : object
34
+ # If object has a user attribute set the user from it otherwise assume
35
+ # this is the user.
36
+ @user = object.respond_to?(:user) ? object.user : object
9
37
 
10
38
  if @user
11
39
  # Add the base user abilities.
@@ -26,12 +54,8 @@ class Ability
26
54
 
27
55
  private
28
56
 
29
- def user
30
- @user
31
- end
32
-
33
57
  def ability_definitions
34
- Canard::Abilities.definitions
58
+ Canard.ability_definitions
35
59
  end
36
60
 
37
61
  def append_abilities(role)
@@ -4,7 +4,11 @@ module Canard
4
4
  # A string specifying the location that should be searched for ability
5
5
  # definitions. By default, Canard will attempt to load abilities from
6
6
  # Rails.root + /abilities/.
7
- attr_accessor :abilities_path
7
+ attr_writer :abilities_path
8
+
9
+ def abilities_path
10
+ @abilities_path ||= File.expand_path('abilities', Rails.root)
11
+ end
8
12
 
9
13
  def ability_definitions
10
14
  Abilities.definitions
@@ -18,7 +22,6 @@ module Canard
18
22
  end
19
23
 
20
24
  def self.find_abilities #:nodoc:
21
-
22
25
  absolute_abilities_path = File.expand_path(abilities_path)
23
26
 
24
27
  if File.directory? absolute_abilities_path
@@ -7,7 +7,6 @@ module Canard
7
7
  initializer "canard.active_record" do |app|
8
8
  ActiveSupport.on_load :active_record do
9
9
  extend Canard::UserModel
10
- Canard.abilities_path ||= File.expand_path('abilities', Rails.root)
11
10
  Canard.find_abilities
12
11
  end
13
12
  end
@@ -2,6 +2,43 @@ module Canard
2
2
 
3
3
  module UserModel
4
4
 
5
+ # Canard applies roles to a model using the acts_as_user class method. The following User model
6
+ # will be given the :manager and :admin roles
7
+ #
8
+ # class User < ActiveRecord::Base
9
+ #
10
+ # acts_as_user :roles => :manager, :admin
11
+ #
12
+ # end
13
+ #
14
+ # == Scopes
15
+ #
16
+ # Beyond applying the roles to model acts_as_user also creates some useful scopes on the User
17
+ # model;
18
+ #
19
+ # User.with_any_role(:manager, :admin)
20
+ #
21
+ # returns all the managers and admins
22
+ #
23
+ # User.with_all_roles(:manager, :admin)
24
+ #
25
+ # returns only the users with both the manager and admin roles
26
+ #
27
+ # User.admins
28
+ #
29
+ # returns all the admins as
30
+ #
31
+ # User.managers
32
+ #
33
+ # returns all the users with the maager role likewise
34
+ #
35
+ # User.non_admins
36
+ #
37
+ # returns all the users who don't have the admin role and
38
+ #
39
+ # User.non_managers
40
+ #
41
+ # returns all the users who don't have the manager role.
5
42
  def acts_as_user(*args)
6
43
  include RoleModel
7
44
 
@@ -1,3 +1,3 @@
1
1
  module Canard
2
- VERSION = "0.2.7"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -1,9 +1,5 @@
1
1
  abilities_for(:admin) do
2
-
3
- can :manage, [Activity, User, Variation, Year]
4
-
5
- cannot :destroy, User do |u|
6
- (user == u)
7
- end
8
-
2
+
3
+ can :manage, [Activity, User]
4
+
9
5
  end
@@ -39,7 +39,7 @@ describe 'Canard::Abilities' do
39
39
 
40
40
  end
41
41
 
42
- describe "define" do
42
+ describe "for" do
43
43
 
44
44
  it "adds the block to the definitions" do
45
45
  block = lambda { puts 'some block' }
@@ -0,0 +1,113 @@
1
+ require 'test_helper'
2
+
3
+ describe Ability do
4
+
5
+ before do
6
+ # reload abilities because the reloader will have removed them after the railtie ran
7
+ Canard.find_abilities
8
+ end
9
+
10
+ describe "new" do
11
+
12
+ describe "with a user" do
13
+
14
+ let(:user) { User.new }
15
+ subject { Ability.new(user) }
16
+
17
+ it "assign the user to Ability#user" do
18
+ subject.user.must_equal user
19
+ end
20
+
21
+ end
22
+
23
+ describe "with a model that references a user" do
24
+
25
+ let(:user) { User.create }
26
+ let(:member) { Member.new(:user => user) }
27
+
28
+ subject { Ability.new(member) }
29
+
30
+ it "assign the user to Ability#user" do
31
+ subject.user.must_equal user
32
+ end
33
+
34
+ end
35
+
36
+ describe "for a user with author role" do
37
+
38
+ let(:user) { User.create(:roles => [:author]) }
39
+ let(:member) { Member.create(:user => user) }
40
+ let(:other_member) { Member.new(:user => User.create) }
41
+ subject { Ability.new(user) }
42
+
43
+ it "has all the abilities of the base class" do
44
+ subject.can?(:edit, member).must_equal true
45
+ subject.can?(:update, member).must_equal true
46
+
47
+ subject.can?(:edit, other_member).wont_equal true
48
+ subject.can?(:update, other_member).wont_equal true
49
+ end
50
+
51
+ it "has all the abilities of an author" do
52
+ subject.can?(:new, Post).must_equal true
53
+ subject.can?(:create, Post).must_equal true
54
+ subject.can?(:edit, Post).must_equal true
55
+ subject.can?(:update, Post).must_equal true
56
+ subject.can?(:show, Post).must_equal true
57
+ subject.can?(:index, Post).must_equal true
58
+ end
59
+
60
+ it "has no admin abilities" do
61
+ subject.cannot?(:destroy, Post).must_equal true
62
+ end
63
+
64
+ end
65
+
66
+ describe "for a user with admin and author role" do
67
+
68
+ let(:user) { User.create(:roles => [:author, :admin]) }
69
+ let(:member) { Member.create(:user => user) }
70
+ let(:other_user) { User.create }
71
+ let(:other_member) { Member.new(:user => other_user) }
72
+ subject { Ability.new(user) }
73
+
74
+ it "has all the abilities of the base class" do
75
+ subject.can?(:edit, member).must_equal true
76
+ subject.can?(:update, member).must_equal true
77
+
78
+ subject.cannot?(:edit, other_member).must_equal true
79
+ subject.cannot?(:update, other_member).must_equal true
80
+ end
81
+
82
+ it "has all the abilities of an author" do
83
+ subject.can?(:new, Post).must_equal true
84
+ end
85
+
86
+ it "has the abilities of an admin" do
87
+ subject.can?(:manage, Post).must_equal true
88
+ subject.can?(:manage, other_user).must_equal true
89
+ subject.can?(:destroy, other_user).must_equal true
90
+ subject.cannot?(:destroy, user).must_equal true
91
+ end
92
+
93
+ end
94
+
95
+ describe "for a guest" do
96
+
97
+ subject { Ability.new }
98
+
99
+ it "applies the guest abilities" do
100
+ subject.can?(:index, Post)
101
+ subject.can?(:show, Post)
102
+
103
+ subject.cannot?(:create, Post)
104
+ subject.cannot?(:update, Post)
105
+ subject.cannot?(:destroy, Post)
106
+
107
+ subject.cannot?(:show, User)
108
+ subject.cannot?(:show, Member)
109
+ end
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,9 @@
1
+ Canard::Abilities.for(:admin) do
2
+
3
+ can :manage, [Post, User]
4
+
5
+ cannot :destroy, User do |u|
6
+ (user == u)
7
+ end
8
+
9
+ end
@@ -0,0 +1,5 @@
1
+ Canard::Abilities.for(:author) do
2
+
3
+ can [:create, :update, :read], Post
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ Canard::Abilities.for(:guest) do
2
+
3
+ can :read, Post
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ Canard::Abilities.for(:user) do
2
+
3
+ can [:edit, :update], Member, :user_id => user.id
4
+
5
+ end
@@ -0,0 +1,2 @@
1
+ class Activity
2
+ end
@@ -0,0 +1,7 @@
1
+ class Member < ActiveRecord::Base
2
+
3
+ belongs_to :user
4
+
5
+ attr_accessible :user, :user_id
6
+
7
+ end
@@ -0,0 +1,2 @@
1
+ class Post < ActiveRecord::Base
2
+ end
@@ -1,7 +1,8 @@
1
1
  class User < ActiveRecord::Base
2
2
 
3
3
  extend Canard::UserModel
4
- acts_as_user :roles => [:admin, :author, :viewer]
4
+
5
+ acts_as_user :roles => [:viewer, :author, :admin]
5
6
 
6
7
  attr_accessible :roles
7
8
  end
@@ -0,0 +1,18 @@
1
+ class InitializeDb < ActiveRecord::Migration
2
+
3
+ def change
4
+ create_table :users, :force => true do |t|
5
+ t.string :roles_mask
6
+ end
7
+ create_table :user_without_roles, :force => true do |t|
8
+ t.string :roles_mask
9
+ end
10
+ create_table :user_without_role_masks, :force => true do |t|
11
+ end
12
+
13
+ create_table :members, :force => true do |t|
14
+ t.references :user
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended to check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(:version => 20120430083231) do
15
+
16
+ create_table "members", :force => true do |t|
17
+ t.integer "user_id"
18
+ end
19
+
20
+ create_table "user_without_role_masks", :force => true do |t|
21
+ end
22
+
23
+ create_table "user_without_roles", :force => true do |t|
24
+ t.string "roles_mask"
25
+ end
26
+
27
+ create_table "users", :force => true do |t|
28
+ t.string "roles_mask"
29
+ end
30
+
31
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -23,7 +23,7 @@ describe Canard do
23
23
  it "finds the abilities with the new syntax" do
24
24
  Canard.find_abilities
25
25
 
26
- Canard.ability_definitions.keys.must_include :moderator
26
+ Canard.ability_definitions.keys.must_include :author
27
27
  end
28
28
 
29
29
  it "reloads existing abilities" do
@@ -31,7 +31,7 @@ describe Canard do
31
31
  Canard::Abilities.send(:instance_variable_set, '@definitions', {})
32
32
  Canard.find_abilities
33
33
 
34
- Canard.ability_definitions.keys.must_include :moderator
34
+ Canard.ability_definitions.keys.must_include :author
35
35
  Canard.ability_definitions.keys.must_include :admin
36
36
  end
37
37
 
@@ -41,7 +41,7 @@ describe Canard do
41
41
 
42
42
  it "raises a deprecation warning" do
43
43
  assert_deprecated do
44
- Canard.abilities_for(:this) { puts 'that' }
44
+ Canard.abilities_for(:this) { return 'that' }
45
45
  end
46
46
  end
47
47
 
data/test/test_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ gem 'minitest'
1
2
  require 'minitest/autorun'
2
3
 
3
4
  # Configure Rails Environment
@@ -11,5 +12,6 @@ Rails.backtrace_cleaner.remove_silencers!
11
12
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
12
13
 
13
14
  ActiveRecord::Migration.verbose = false
14
- load(File.dirname(__FILE__) + '/schema.rb')
15
+ load(File.expand_path('../dummy/db/schema.rb', __FILE__))
16
+
15
17
 
@@ -29,7 +29,7 @@ describe Canard::UserModel do
29
29
  describe 'and :roles => [] specified' do
30
30
 
31
31
  it 'should set the valid_roles for the class' do
32
- User.valid_roles.must_equal [:admin, :author, :viewer]
32
+ User.valid_roles.must_equal [:viewer, :author, :admin]
33
33
  end
34
34
 
35
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-10 00:00:00.000000000Z
12
+ date: 2012-05-02 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
16
- requirement: &2152271020 !ruby/object:Gem::Requirement
16
+ requirement: &2152517180 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '2'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2152271020
24
+ version_requirements: *2152517180
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sqlite3
27
- requirement: &2152263860 !ruby/object:Gem::Requirement
27
+ requirement: &2152516180 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2152263860
35
+ version_requirements: *2152516180
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rails
38
- requirement: &2152261660 !ruby/object:Gem::Requirement
38
+ requirement: &2152514320 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 3.2.3
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2152261660
46
+ version_requirements: *2152514320
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: activesupport
49
- requirement: &2152259720 !ruby/object:Gem::Requirement
49
+ requirement: &2152512180 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *2152259720
57
+ version_requirements: *2152512180
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: cancan
60
- requirement: &2152258740 !ruby/object:Gem::Requirement
60
+ requirement: &2152511480 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *2152258740
68
+ version_requirements: *2152511480
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: role_model
71
- requirement: &2152256860 !ruby/object:Gem::Requirement
71
+ requirement: &2152510060 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *2152256860
79
+ version_requirements: *2152510060
80
80
  description: Wraps CanCan and RoleModel up to make role based authorisation really
81
81
  easy in Rails 3.x.
82
82
  email:
@@ -107,10 +107,17 @@ files:
107
107
  - lib/generators/rspec/ability/templates/abilities_spec.rb.erb
108
108
  - test/abilities/admins.rb
109
109
  - test/abilities_test.rb
110
+ - test/ability_test.rb
110
111
  - test/canard_test.rb
111
112
  - test/dummy/Rakefile
112
- - test/dummy/app/abilities/moderators.rb
113
+ - test/dummy/app/abilities/admins.rb
114
+ - test/dummy/app/abilities/authors.rb
115
+ - test/dummy/app/abilities/guests.rb
116
+ - test/dummy/app/abilities/users.rb
113
117
  - test/dummy/app/controllers/application_controller.rb
118
+ - test/dummy/app/models/activity.rb
119
+ - test/dummy/app/models/member.rb
120
+ - test/dummy/app/models/post.rb
114
121
  - test/dummy/app/models/user.rb
115
122
  - test/dummy/app/models/user_without_role.rb
116
123
  - test/dummy/app/models/user_without_role_mask.rb
@@ -126,10 +133,12 @@ files:
126
133
  - test/dummy/config/initializers/wrap_parameters.rb
127
134
  - test/dummy/config/locales/en.yml
128
135
  - test/dummy/config/routes.rb
136
+ - test/dummy/db/migrate/20120430083231_initialize_db.rb
137
+ - test/dummy/db/schema.rb
129
138
  - test/dummy/db/test.sqlite3
130
139
  - test/dummy/log/.gitkeep
140
+ - test/dummy/script/rails
131
141
  - test/find_abilities_test.rb
132
- - test/schema.rb
133
142
  - test/support/reloadable.rb
134
143
  - test/test_helper.rb
135
144
  - test/user_model_test.rb
@@ -160,10 +169,17 @@ summary: Adds role based authorisation to Rails by combining RoleModel and CanCa
160
169
  test_files:
161
170
  - test/abilities/admins.rb
162
171
  - test/abilities_test.rb
172
+ - test/ability_test.rb
163
173
  - test/canard_test.rb
164
174
  - test/dummy/Rakefile
165
- - test/dummy/app/abilities/moderators.rb
175
+ - test/dummy/app/abilities/admins.rb
176
+ - test/dummy/app/abilities/authors.rb
177
+ - test/dummy/app/abilities/guests.rb
178
+ - test/dummy/app/abilities/users.rb
166
179
  - test/dummy/app/controllers/application_controller.rb
180
+ - test/dummy/app/models/activity.rb
181
+ - test/dummy/app/models/member.rb
182
+ - test/dummy/app/models/post.rb
167
183
  - test/dummy/app/models/user.rb
168
184
  - test/dummy/app/models/user_without_role.rb
169
185
  - test/dummy/app/models/user_without_role_mask.rb
@@ -179,10 +195,12 @@ test_files:
179
195
  - test/dummy/config/initializers/wrap_parameters.rb
180
196
  - test/dummy/config/locales/en.yml
181
197
  - test/dummy/config/routes.rb
198
+ - test/dummy/db/migrate/20120430083231_initialize_db.rb
199
+ - test/dummy/db/schema.rb
182
200
  - test/dummy/db/test.sqlite3
183
201
  - test/dummy/log/.gitkeep
202
+ - test/dummy/script/rails
184
203
  - test/find_abilities_test.rb
185
- - test/schema.rb
186
204
  - test/support/reloadable.rb
187
205
  - test/test_helper.rb
188
206
  - test/user_model_test.rb
@@ -1,9 +0,0 @@
1
- Canard::Abilities.for(:moderator) do
2
-
3
- can :manage, [Post]
4
-
5
- cannot :destroy, User do |u|
6
- (user == u)
7
- end
8
-
9
- end
data/test/schema.rb DELETED
@@ -1,12 +0,0 @@
1
- ActiveRecord::Schema.define :version => 0 do
2
-
3
- create_table :users, :force => true do |t|
4
- t.string :roles_mask
5
- end
6
- create_table :user_without_roles, :force => true do |t|
7
- t.string :roles_mask
8
- end
9
- create_table :user_without_role_masks, :force => true do |t|
10
- end
11
-
12
- end