canard 0.4.2.pre → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- Y2MxZDQwMmE0ZmI0NDE0YzZjNTA0MWNiZWQ4YzRhZmRiNDc1YzMwMA==
5
- data.tar.gz: !binary |-
6
- Yzk2MTg0YzZiZWQyMTcwNmQ3OTBkN2UyZTVlMjQzMGVhY2Q2MDQwMA==
2
+ SHA1:
3
+ metadata.gz: e544f830cff6f7f931128c3dc2742b678483d291
4
+ data.tar.gz: a972213e3379020ad58efa87c8273c66c1007740
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- N2ZjYzkxZDk1NzFiNmVhN2I2Mzg5YTgwOGFkMjE1MjU1ZWFjOTUxODg0OTQx
10
- ZGNiZDcwZjBhMTQ5ZjVmNzk1NWQ0NjFjZWYyZjE4NjhhM2NkYjI4NTM1MjRl
11
- N2YwYzMzZTk3MDQ2YmZiMjFjZjg3NzlmY2ViNzBlODkyZDhhN2Y=
12
- data.tar.gz: !binary |-
13
- MzFhZjVjMGUxNjVhNTRkMjg4YjkxYTEwNzFhMjI1MDEyYTYxOWM2YzI1NWFh
14
- MTc1ZjYyMTRiY2I5ODAxMWQ4NDE3NWZiNmRkYzgwNjUwNzE2MzAwYjgyMzgy
15
- ZmQ3Yzk4OTlkMDJkOGE0ZjAyZTBkOGY1MjlkNmY5ZmI5ODgzNDE=
6
+ metadata.gz: 652b6cb549fe75a54193a0516ef20a4de1249f5ac27cbaaa9e01d1ca19f52833755618d067efc580dad42e5951bd31fb6e42f18faa6190b23b7fc226947699f1
7
+ data.tar.gz: 8e4b03814ca265992850cb2e6e4574ba492cf44b00f1adbb92570df002f5f95be02549780bc6992f4ab9cfd09b9f0e5660daaa7fb76cd75c2bb75d6969d965ab
@@ -3,6 +3,8 @@ rvm:
3
3
  - ree
4
4
  - 1.8.7
5
5
  - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
6
8
  - jruby-18mode # JRuby in 1.8 mode
7
9
  - jruby-19mode # JRuby in 1.9 mode
8
10
  - rbx-18mode
@@ -87,6 +87,31 @@ And it's associated test spec/abilities/users_spec.rb;
87
87
 
88
88
  end
89
89
 
90
+ You can also re-use abilities defined for one role in another. This allows you to 'inherit' abilities without having to assign all of the roles to the user. To do this, pass a list of role names to the includes_abilities_of method
91
+
92
+ Canard::Abilities.for(:writer) do
93
+
94
+ can [:create], Post
95
+ can [:read], Post, user_id: user.id
96
+
97
+ end
98
+
99
+ Canard::Abilities.for(:reviewer) do
100
+
101
+ can [:read, :update], Post
102
+
103
+ end
104
+
105
+ Canard::Abilities.for(:admin) do
106
+
107
+ includes_abilities_of :writer, :reviewer
108
+
109
+ can [:delete], Post
110
+
111
+ end
112
+
113
+ A user assigned the :admin role will have all of the abilities of the :writer and :reviewer, along with their own abilities without having to have those individual roles assigned to them.
114
+
90
115
  Now lets generate some abilities for the manager and admin.
91
116
 
92
117
  $ rails g canard:ability admin can:manage:[account,statement]
@@ -123,7 +148,7 @@ User.with_all_roles(roles):: return only the users with all the specified roles
123
148
 
124
149
  == Installation
125
150
 
126
- === Rails 3.x
151
+ === Rails 3.x & 4.x
127
152
 
128
153
  Add the canard gem to your Gemfile. In Gemfile:
129
154
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
3
  require "canard/version"
4
- require 'rails'
5
4
 
6
5
  Gem::Specification.new do |s|
7
6
  s.name = "canard"
@@ -30,10 +29,6 @@ Gem::Specification.new do |s|
30
29
  end
31
30
 
32
31
  s.requirements << 'cancan for Rails3 and earlier or the Rails4 compatible cancancan fork.'
33
- if Rails.version > '3'
34
- s.add_runtime_dependency "cancancan"
35
- else
36
- s.add_runtime_dependency "cancan"
37
- end
32
+ s.add_runtime_dependency "cancancan"
38
33
  s.add_runtime_dependency "role_model"
39
34
  end
@@ -26,9 +26,12 @@
26
26
  class Ability
27
27
 
28
28
  include CanCan::Ability
29
+ extend Forwardable
29
30
 
30
31
  attr_reader :user
31
32
 
33
+ def_delegators :Canard, :ability_definitions, :ability_key
34
+
32
35
  def initialize(object=nil)
33
36
 
34
37
  # If object has a user attribute set the user from it otherwise assume
@@ -38,7 +41,7 @@ class Ability
38
41
  if @user
39
42
  # Add the base user abilities.
40
43
  user_class_name = String(@user.class.name)
41
- append_abilities ability_key(user_class_name) unless user_class_name.empty?
44
+ append_abilities user_class_name unless user_class_name.empty?
42
45
  else
43
46
  # If user not set then lets create a guest
44
47
  @user = Object.new
@@ -53,17 +56,15 @@ class Ability
53
56
 
54
57
  end
55
58
 
56
- private
59
+ protected
57
60
 
58
- def append_abilities(key)
59
- ability_definitions = Canard.ability_definitions
61
+ def append_abilities(dirty_key)
62
+ key = ability_key(dirty_key)
60
63
  instance_eval(&ability_definitions[key]) if ability_definitions.has_key?(key)
61
64
  end
62
65
 
63
- def ability_key(class_name)
64
- class_name.gsub!('::', '')
65
- class_name.gsub!(/(.)([A-Z])/,'\1_\2')
66
- class_name.downcase!.to_sym
66
+ def includes_abilities_of(*other_roles)
67
+ other_roles.each { |other_role| append_abilities(other_role) }
67
68
  end
68
69
 
69
70
  end
@@ -1,3 +1,4 @@
1
+ require 'forwardable'
1
2
  require 'cancan'
2
3
  require 'role_model'
3
4
  require 'canard/abilities'
@@ -1,28 +1,33 @@
1
1
  module Canard
2
2
  class Abilities
3
-
3
+
4
4
  @definitions = {}
5
5
  @default_path = 'app/abilities'
6
6
 
7
7
  class << self
8
8
 
9
+ extend Forwardable
10
+
11
+ def_delegators :Canard, :ability_key
12
+
9
13
  attr_accessor :default_path
10
-
14
+
11
15
  attr_writer :definition_paths
12
-
16
+
13
17
  attr_reader :definitions
14
-
18
+
15
19
  def definition_paths
16
20
  @definition_paths ||= [@default_path]
17
21
  end
18
-
22
+
19
23
  def for(name, &block)
20
24
  raise ArgumentError.new('No block of ability definitions given') unless block_given?
21
- @definitions[name.to_sym] = block
25
+ key = ability_key(name)
26
+ @definitions[key] = block
22
27
  end
23
-
28
+
24
29
  end
25
-
30
+
26
31
  end
27
-
32
+
28
33
  end
@@ -30,8 +30,8 @@ module Canard
30
30
  include_scope = role.to_s.pluralize
31
31
  exclude_scope = "non_#{include_scope}"
32
32
 
33
- scope include_scope, where("(this.#{roles_attribute_name} & #{mask_for(role)}) > 0")
34
- scope exclude_scope, any_of({roles_attribute_name => { "$exists" => false }}, {roles_attribute_name => nil}, {"$where" => "(this.#{roles_attribute_name} & #{mask_for(role)}) === 0"})
33
+ scope include_scope, lambda { where("(this.#{roles_attribute_name} & #{mask_for(role)}) > 0") }
34
+ scope exclude_scope, lambda { any_of({roles_attribute_name => { "$exists" => false }}, {roles_attribute_name => nil}, {"$where" => "(this.#{roles_attribute_name} & #{mask_for(role)}) === 0"}) }
35
35
  end
36
36
 
37
37
  end
@@ -1,9 +1,15 @@
1
1
  module Canard
2
2
 
3
- class << self
4
- def ability_definitions
5
- Abilities.definitions
6
- end
3
+ def self.ability_definitions
4
+ Abilities.definitions
5
+ end
6
+
7
+ def self.ability_key(class_name)
8
+ klass_name = String(class_name)
9
+ klass_name.gsub!('::', '')
10
+ klass_name.gsub!(/(.)([A-Z])/,'\1_\2')
11
+ klass_name.downcase!
12
+ klass_name.to_sym
7
13
  end
8
14
 
9
15
  def self.load_paths
@@ -1,3 +1,3 @@
1
1
  module Canard
2
- VERSION = "0.4.2.pre"
2
+ VERSION = "0.4.3"
3
3
  end
@@ -4,13 +4,13 @@ require 'canard'
4
4
  describe 'Canard::Abilities' do
5
5
 
6
6
  subject { Canard::Abilities }
7
-
7
+
8
8
  describe "ability_paths" do
9
-
9
+
10
10
  it "defaults to app/abilities" do
11
11
  subject.definition_paths.must_include 'app/abilities'
12
12
  end
13
-
13
+
14
14
  it "appends paths" do
15
15
  subject.definition_paths << 'other_abilities'
16
16
  subject.definition_paths.must_include 'other_abilities'
@@ -18,47 +18,53 @@ describe 'Canard::Abilities' do
18
18
 
19
19
  it "can be overwritten" do
20
20
  subject.definition_paths = ['other_abilities']
21
-
21
+
22
22
  subject.definition_paths.must_equal ['other_abilities']
23
23
  end
24
24
 
25
25
  end
26
-
26
+
27
27
  describe "default_path" do
28
-
28
+
29
29
  it "defaults to app/abilities" do
30
30
  subject.default_path.must_equal 'app/abilities'
31
31
  end
32
32
 
33
33
  it "can be changhed" do
34
34
  subject.default_path = 'other_abilities'
35
-
35
+
36
36
  subject.default_path.must_equal 'other_abilities'
37
37
  end
38
38
 
39
-
39
+
40
40
  end
41
-
41
+
42
42
  describe "for" do
43
-
43
+
44
44
  it "adds the block to the definitions" do
45
45
  block = lambda { puts 'some block' }
46
-
46
+
47
47
  subject.for(:definition, &block)
48
48
 
49
49
  assert_equal block, subject.definitions[:definition]
50
50
  end
51
-
51
+
52
52
  it "normalises the key to a symbol" do
53
53
  subject.for('definition') { puts 'a block' }
54
-
54
+
55
55
  subject.definitions.keys.must_include :definition
56
56
  end
57
-
57
+
58
58
  it "rasises ArgumentError if no block is provided" do
59
59
  proc { subject.for(:definition) }.must_raise ArgumentError
60
60
  end
61
-
61
+
62
+ it 'creates a lowercaae key' do
63
+ subject.for('NotCamelCase') { puts 'a block' }
64
+
65
+ subject.definitions.keys.must_include :not_camel_case
66
+ end
67
+
62
68
  end
63
-
69
+
64
70
  end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  describe Ability do
4
4
 
5
5
  before do
6
- Canard::Abilities.default_path = File.expand_path('../../dummy/app/abilities', __FILE__)
6
+ Canard::Abilities.definition_paths = [File.expand_path('../../dummy/app/abilities', __FILE__)]
7
7
  # reload abilities because the reloader will have removed them after the railtie ran
8
8
  Canard.find_abilities
9
9
  end
@@ -93,6 +93,29 @@ describe Ability do
93
93
 
94
94
  end
95
95
 
96
+ describe "a user with editor role" do
97
+ let(:user) { User.create(:roles => [:editor]) }
98
+ let(:member) { Member.create(:user => user) }
99
+ let(:other_user) { User.create }
100
+ let(:other_member) { Member.new(:user => other_user) }
101
+ subject { Ability.new(user) }
102
+
103
+ it "has all the abilities of the base class" do
104
+ subject.can?(:edit, member).must_equal true
105
+ subject.can?(:update, member).must_equal true
106
+
107
+ subject.cannot?(:edit, other_member).must_equal true
108
+ subject.cannot?(:update, other_member).must_equal true
109
+ end
110
+
111
+ it "has most of the abilities of authors, except it can't create Posts" do
112
+ subject.can?(:update, Post).must_equal true
113
+ subject.can?(:read, Post).must_equal true
114
+ subject.cannot?(:create, Post).must_equal true
115
+ end
116
+
117
+ end
118
+
96
119
  describe "with no user" do
97
120
 
98
121
  subject { Ability.new }
@@ -149,21 +172,4 @@ describe Ability do
149
172
 
150
173
  end
151
174
  end
152
-
153
- describe "ability_key" do
154
-
155
- it "returns a snake case version of the string" do
156
- class_name = 'CamelCaseString'
157
- key = :camel_case_string
158
-
159
- Ability.new.send(:ability_key, class_name).must_equal key
160
- end
161
-
162
- it "prepends namespaces to the class name" do
163
- class_name = 'Namespace::CamelCaseString'
164
- key = :namespace_camel_case_string
165
-
166
- Ability.new.send(:ability_key, class_name).must_equal key
167
- end
168
- end
169
175
  end
@@ -7,9 +7,9 @@ describe Canard::Adapters::ActiveRecord do
7
7
  describe 'with a role_mask' do
8
8
 
9
9
  describe 'and :roles => [] specified' do
10
-
10
+
11
11
  it 'sets the valid_roles for the class' do
12
- User.valid_roles.must_equal [:viewer, :author, :admin]
12
+ User.valid_roles.must_equal [:viewer, :author, :admin, :editor]
13
13
  end
14
14
 
15
15
  end
@@ -35,23 +35,23 @@ describe Canard::Adapters::ActiveRecord do
35
35
  end
36
36
 
37
37
  describe "with no table" do
38
-
38
+
39
39
  subject { Class.new(ActiveRecord::Base) }
40
40
 
41
41
  it "sets no roles" do
42
42
  subject.class_eval { acts_as_user :roles => [:admin] }
43
43
  subject.valid_roles.must_equal []
44
44
  end
45
-
45
+
46
46
  it "does not raise any errors" do
47
47
  proc { subject.class_eval { acts_as_user :roles => [:admin] } }.must_be_silent
48
48
  end
49
-
49
+
50
50
  it "returns nil" do
51
51
  subject.class_eval { acts_as_user :roles => [:admin] }.must_be_nil
52
52
  end
53
53
  end
54
-
54
+
55
55
  describe 'with an alternative roles_mask specified' do
56
56
 
57
57
  before do
@@ -15,4 +15,20 @@ describe Canard do
15
15
 
16
16
  end
17
17
 
18
+ describe "ability_key" do
19
+
20
+ it "returns a snake case version of the string" do
21
+ class_name = 'CamelCaseString'
22
+ key = :camel_case_string
23
+
24
+ Canard.ability_key(class_name).must_equal key
25
+ end
26
+
27
+ it "prepends namespaces to the class name" do
28
+ class_name = 'Namespace::CamelCaseString'
29
+ key = :namespace_camel_case_string
30
+
31
+ Canard.ability_key(class_name).must_equal key
32
+ end
33
+ end
18
34
  end
@@ -5,7 +5,7 @@ describe Canard do
5
5
  describe "find_abilities" do
6
6
 
7
7
  before do
8
- Canard::Abilities.default_path = File.expand_path('../../dummy/app/abilities', __FILE__)
8
+ Canard::Abilities.definition_paths = [File.expand_path('../../dummy/app/abilities', __FILE__)]
9
9
  end
10
10
 
11
11
  it "loads the abilities into ability_definitions" do
@@ -12,7 +12,7 @@ describe Canard::UserModel do
12
12
 
13
13
  it 'adds role_model to the class' do
14
14
  PlainRubyUser.included_modules.must_include RoleModel
15
- PlainRubyUser.must_respond_to :roles
15
+ PlainRubyUser.new.must_respond_to :roles
16
16
  end
17
17
  end
18
18
 
@@ -42,7 +42,7 @@ describe Canard::UserModel do
42
42
  end
43
43
 
44
44
  describe "with no roles_mask" do
45
-
45
+
46
46
  before do
47
47
  PlainRubyNonUser.acts_as_user :roles => [:viewer, :author, :admin]
48
48
  end
@@ -51,9 +51,9 @@ describe Canard::UserModel do
51
51
  PlainRubyNonUser.valid_roles.must_equal []
52
52
  end
53
53
  end
54
-
54
+
55
55
  describe "setting the role_mask" do
56
-
56
+
57
57
  before do
58
58
  PlainRubyNonUser.send :attr_accessor, :my_roles
59
59
  PlainRubyNonUser.acts_as_user :roles => [:viewer, :author], :roles_mask => :my_roles
@@ -117,7 +117,7 @@ describe Canard::UserModel::InstanceMethods do
117
117
  subject.can?(:show, Post).must_equal true
118
118
  subject.can?(:index, Post).must_equal true
119
119
  end
120
-
120
+
121
121
  it "has no other abilities" do
122
122
  subject.cannot?(:destroy, Post).must_equal true
123
123
  end
@@ -0,0 +1,7 @@
1
+ Canard::Abilities.for(:editor) do
2
+
3
+ includes_abilities_of :author
4
+
5
+ cannot :create, Post
6
+
7
+ end
@@ -1,6 +1,6 @@
1
1
  class User < ActiveRecord::Base
2
-
3
- acts_as_user :roles => [:viewer, :author, :admin]
4
-
2
+
3
+ acts_as_user :roles => [:viewer, :author, :admin, :editor]
4
+
5
5
  attr_accessible :roles
6
6
  end
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2.pre
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - James McCarthy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-23 00:00:00.000000000 Z
11
+ date: 2015-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 3.2.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 3.2.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mongoid
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: cancancan
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ! '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: role_model
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ! '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ! '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  description: Wraps CanCan and RoleModel up to make role based authorisation really
@@ -88,8 +88,8 @@ executables: []
88
88
  extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
- - .gitignore
92
- - .travis.yml
91
+ - ".gitignore"
92
+ - ".travis.yml"
93
93
  - Gemfile
94
94
  - MIT-LICENSE
95
95
  - README.rdoc
@@ -123,6 +123,7 @@ files:
123
123
  - test/dummy/Rakefile
124
124
  - test/dummy/app/abilities/admins.rb
125
125
  - test/dummy/app/abilities/authors.rb
126
+ - test/dummy/app/abilities/editors.rb
126
127
  - test/dummy/app/abilities/guests.rb
127
128
  - test/dummy/app/abilities/users.rb
128
129
  - test/dummy/app/controllers/application_controller.rb
@@ -164,18 +165,18 @@ require_paths:
164
165
  - lib
165
166
  required_ruby_version: !ruby/object:Gem::Requirement
166
167
  requirements:
167
- - - ! '>='
168
+ - - ">="
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  required_rubygems_version: !ruby/object:Gem::Requirement
171
172
  requirements:
172
- - - ! '>'
173
+ - - ">="
173
174
  - !ruby/object:Gem::Version
174
- version: 1.3.1
175
+ version: '0'
175
176
  requirements:
176
177
  - cancan for Rails3 and earlier or the Rails4 compatible cancancan fork.
177
178
  rubyforge_project: canard
178
- rubygems_version: 2.1.11
179
+ rubygems_version: 2.4.3
179
180
  signing_key:
180
181
  specification_version: 4
181
182
  summary: Adds role based authorisation to Rails by combining RoleModel and CanCan.
@@ -191,6 +192,7 @@ test_files:
191
192
  - test/dummy/Rakefile
192
193
  - test/dummy/app/abilities/admins.rb
193
194
  - test/dummy/app/abilities/authors.rb
195
+ - test/dummy/app/abilities/editors.rb
194
196
  - test/dummy/app/abilities/guests.rb
195
197
  - test/dummy/app/abilities/users.rb
196
198
  - test/dummy/app/controllers/application_controller.rb