canard 0.4.2.pre → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,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