cancannible 0.0.2 → 2.0.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.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- YWE0OWZkMjhlMWQ3ODMzNTVmZWNiMTk2ZWM5YmU2YjMyY2I1NTAwMA==
5
- data.tar.gz: !binary |-
6
- YjQ0NDZhNzQ5MzdhMDJiMDQ4NzRjMjI1MDE5ZGY1N2ViZjU2NThlMA==
2
+ SHA256:
3
+ metadata.gz: 8ba63fd7b6b80a32a3bc93fbbe43845439c1eaffa9661e35510dbeff487af673
4
+ data.tar.gz: fdf8f225705b0e0fa9ea469674d62ce22b5340f48cb23fb94a2b8501112417cf
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- Zjc2OGYzMGI1ODA5ZmY4ZmQ3ZGRhNTU5MDM2MmRiOWJmNDNmNzI4MzZjYTY0
10
- ZDNiNDM3ODVmZTExYzM5NDQ1ZmQyNDZmZjc0NDFiYWIxZTM2YjcwMTdiMGU0
11
- YTliZGI0YjFhNDdjY2RmZWNhZjNhY2YyNDU5YTQ3MDQ3NDRhNjY=
12
- data.tar.gz: !binary |-
13
- MjFhMzBmNzQ5YTcyMzBmOTViMTYwMjEwNDI2YjllNjUxZjEzYjkxNmZjOTVi
14
- YmVkOWZjMWUyODBiMDQ3MmY4YWExMDJiNmUzZTkzZTBlY2MwZWFjMzFmOWM0
15
- MjNiMTBmMGFjNGI3OTllNTkxMjM3NTBmZDViOWYwNmVlZGMwZWE=
6
+ metadata.gz: f9068c6dce19852c747512ddafa0a29461586128d67408bc5c53f07e029e8273d0cb343acb4400dcfd180afd6596202837fac699838f62d6e252a56dd35f99df
7
+ data.tar.gz: e5ec5d5accb0e40139dbeee9b6bc211d3652688c7ffb17c1788c86cea455c626914b233d4eb52de2786993989df8018d38ddfb07bef5bedb2f04484d43f62054
@@ -0,0 +1,34 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ '*' ]
13
+ pull_request:
14
+ branches: [ main ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ ruby-version: ['2.7', '3.0']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: Install dependencies
32
+ run: bundle install
33
+ - name: Run tests
34
+ run: bundle exec rake
data/Gemfile CHANGED
@@ -1,8 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # currently testing on the 3.2 branch of rails
4
- # gem "activemodel", '~> 3.2'
5
- # gem "activerecord", '~> 3.2'
6
-
7
3
  # Specify your gem's dependencies in cancannible.gemspec
8
4
  gemspec
data/Guardfile CHANGED
@@ -1,18 +1,8 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- # Note: The cmd option is now required due to the increasing number of ways
5
- # rspec may be run, below are examples of the most common uses.
6
- # * bundler: 'bundle exec rspec'
7
- # * bundler binstubs: 'bin/rspec'
8
- # * spring: 'bin/rsspec' (This will use spring if running and you have
9
- # installed the spring binstubs per the docs)
10
- # * zeus: 'zeus rspec' (requires the server to be started separetly)
11
- # * 'just' rspec: 'rspec'
12
- guard :rspec, cmd: 'bundle exec rspec' do
4
+ guard :rspec, cmd: 'bundle exec rspec', all_on_start: false, all_after_pass: false do
13
5
  watch(%r{^spec/.+_spec\.rb$})
14
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/cancannible/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
15
7
  watch('spec/spec_helper.rb') { "spec" }
16
-
17
8
  end
18
-
data/README.md CHANGED
@@ -1,22 +1,28 @@
1
1
  # Cancannible
2
- [![Build Status](https://travis-ci.org/evendis/cancannible.svg?branch=master)](https://travis-ci.org/evendis/cancannible)
3
2
 
4
- Cancannible is a gem that extends CanCan with a range of capabilities:
3
+ Cancannible is a gem that extends [CanCanCan](https://github.com/CanCanCommunity/cancancan) with a range of capabilities:
4
+
5
5
  * database-persisted permissions
6
6
  * export CanCan methods to the model layer (so that permissions can be applied in model methods, and easily set in a test case)
7
7
  * permissions inheritance (so that, for example, a User can inherit permissions from Roles and/or Groups)
8
8
  * caching of abilities (so that they don't need to be recalculated on each web request)
9
9
  * general-purpose access refinements (so that, for example, CanCan will automatically enforce multi-tenant or other security restrictions)
10
+ * battle-tested with Rails 3.2.x and 4.2.x
11
+
12
+ Two demo applications are available (with source) that show cancannible in action:
13
+
14
+ * [cancannibledemo.evendis.com](http://cancannibledemo.evendis.com) uses Rails 3.2.x
15
+ * [cancannibledemo4.evendis.com](http://cancannibledemo4.evendis.com) uses Rails 4.2.x
10
16
 
11
17
  ## Limitations
12
- Cancannible's origin was in a web application that's been in production for over 3 years.
18
+
19
+ Cancannible's origin was in a web application that's been in production for over 4 years.
13
20
  This gem is an initial refactoring as a separate component. It continues to be used in production, but
14
21
  there are some limitations and constraints that will ideally be removed or changed over time:
15
22
 
16
23
  * It only supports ActiveRecord for permissions storage (specifically, it has been tested with PostgreSQL and SQLite)
17
24
  * It currently assumes permissions are stored in a Permission model with a specific structure
18
- * It works with the [CanCan](https://github.com/ryanb/cancan) gem. It has not yet been tested with the new [CanCanCan](https://github.com/CanCanCommunity/cancancan) gem.
19
- * It assumes and is only tested with Rails 3.2. Not yet with Rails 4.
25
+ * It works with the [CanCanCan](https://github.com/CanCanCommunity/cancancan) gem.
20
26
  * It assumes your CanCan rules are setup with the default `Ability` class
21
27
 
22
28
 
@@ -120,6 +126,23 @@ For example, this is a simple scheme using Redis:
120
126
  end
121
127
 
122
128
 
129
+ ## Testing the gem
130
+
131
+ The RSpec test suite runs as the default rake task:
132
+
133
+ rake
134
+ # same as:
135
+ rake spec
136
+
137
+ For convenience, guard is included in the development gem environment, so you can start automatic testing-on-change:
138
+
139
+ bundle exec guard
140
+
141
+ [Appraisal](https://github.com/thoughtbot/appraisal) is also included to run tests across Rails 3 and 4 environments:
142
+
143
+ appraisal rake spec
144
+
145
+
123
146
  ## Contributing
124
147
 
125
148
  1. Fork it ( https://github.com/evendis/cancannible/fork )
data/cancannible.gemspec CHANGED
@@ -18,14 +18,17 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_runtime_dependency "activesupport", "~> 3.2"
22
- spec.add_runtime_dependency "activemodel", "~> 3.2"
23
- spec.add_runtime_dependency "cancan", "~> 1.6"
21
+ spec.add_runtime_dependency "activesupport", "~> 6.1"
22
+ spec.add_runtime_dependency "activemodel", "~> 6.1"
23
+ spec.add_runtime_dependency "cancancan"
24
24
 
25
- spec.add_development_dependency "activerecord", "~> 3.2"
26
- spec.add_development_dependency "sqlite3", "~> 1.3"
27
- spec.add_development_dependency "bundler", "~> 1.6"
28
- spec.add_development_dependency "rake", "~> 10.0"
29
- spec.add_development_dependency "rspec", "~> 3.0"
30
- spec.add_development_dependency "guard-rspec", "~> 4.0"
25
+ spec.add_development_dependency "activerecord", "~> 6.1"
26
+ spec.add_development_dependency "sqlite3", ">= 1.3.2"
27
+
28
+ spec.add_development_dependency "bundler"
29
+ spec.add_development_dependency "rake"
30
+ spec.add_development_dependency "rdoc"
31
+ spec.add_development_dependency "rspec"
32
+ spec.add_development_dependency "guard-rspec"
33
+ spec.add_development_dependency "rb-fsevent"
31
34
  end
@@ -1,5 +1,4 @@
1
1
  module Cancannible
2
-
3
2
  mattr_accessor :refinements
4
3
  mattr_accessor :get_cached_abilities
5
4
  mattr_accessor :store_cached_abilities
@@ -24,5 +23,4 @@ module Cancannible
24
23
  self.refinements[stage] ||= []
25
24
  self.refinements[stage] << refinement
26
25
  end
27
-
28
- end
26
+ end
@@ -23,34 +23,25 @@ module Cancannible::Grantee
23
23
  resource_id = resource.try(:id)
24
24
  end
25
25
 
26
- permission = find_by_asserted_and_ability_and_resource_id_and_resource_type(
27
- asserted, ability, resource_id, resource_type)
28
- unless permission
29
- permission = find_or_initialize_by_asserted_and_ability_and_resource_id_and_resource_type(
30
- !asserted, ability, resource_id, resource_type)
31
- permission.asserted = asserted
32
- permission.save!
33
- end
26
+ # This looks ugly, but it avoid version-specific issues with find_by*/find_or_initialize_by* methods
27
+ permission = where(asserted: asserted, ability: ability, resource_id: resource_id, resource_type: resource_type).first
28
+ permission ||= where(asserted: !asserted, ability: ability, resource_id: resource_id, resource_type: resource_type).first
29
+ permission ||= new(asserted: asserted, ability: ability, resource_id: resource_id, resource_type: resource_type)
30
+ permission.asserted = asserted
31
+ permission.save!
32
+
33
+ proxy_association.owner.instance_variable_set :@abilities, nil # invalidate the owner's ability collection
34
34
 
35
- # if Rails.version =~ /3\.0/ # the rails 3.0 way
36
- # proxy_owner.instance_variable_set :@permissions, nil # invalidate the owner's permissions collection
37
- # proxy_owner.instance_variable_set :@abilities, nil # invalidate the owner's ability collection
38
- # else
39
- proxy_association.owner.instance_variable_set :@abilities, nil # invalidate the owner's ability collection
40
- # end
41
35
  permission
42
36
  end
43
37
  end
44
-
45
38
  end
46
39
 
47
40
  module ClassMethods
48
-
49
41
  # Command: configures the set of associations (array of symbols) from which permissions should be inherited
50
42
  def inherit_permissions_from(*relations)
51
43
  self.inheritable_permissions = relations
52
44
  end
53
-
54
45
  end
55
46
 
56
47
  # Returns the Ability set for the owner.
@@ -59,7 +50,13 @@ module Cancannible::Grantee
59
50
  @abilities = if refresh
60
51
  nil
61
52
  elsif Cancannible.get_cached_abilities.respond_to?(:call)
62
- Cancannible.get_cached_abilities.call(self)
53
+ result = Cancannible.get_cached_abilities.call(self)
54
+ if result
55
+ # performs a crude compatibility check
56
+ rules_size = result.send(:rules).size rescue nil
57
+ rules_index_size = (result.instance_variable_get(:@rules_index) || []).size
58
+ result if !rules_size.nil? && rules_index_size == rules_size
59
+ end
63
60
  end
64
61
  return @abilities if @abilities
65
62
 
@@ -70,7 +67,7 @@ module Cancannible::Grantee
70
67
  ability_class.new(self)
71
68
  end
72
69
 
73
- Cancannible.store_cached_abilities.call(self,@abilities) if Cancannible.store_cached_abilities.respond_to?(:call)
70
+ Cancannible.store_cached_abilities.call(self, @abilities) if Cancannible.store_cached_abilities.respond_to?(:call)
74
71
  @abilities
75
72
  end
76
73
 
@@ -104,16 +101,18 @@ module Cancannible::Grantee
104
101
  def cannot(ability, resource)
105
102
  permissions << [ability, resource, false]
106
103
  end
107
-
108
104
  end
109
105
 
110
-
111
106
  module Cancannible
112
107
  # This module is automatically included into all controllers.
113
108
  # It overrides some CanCan ControllerAdditions
114
109
  module ControllerAdditions
110
+ # Returns abilities cached in the current_user model.
111
+ # If that fails, returns a default Ability instance
115
112
  def current_ability
116
- current_user.try(:abilities)
113
+ current_user.try(:abilities) || if ability_class = ('::Ability'.constantize rescue nil)
114
+ ability_class.new(current_user)
115
+ end
117
116
  end
118
117
  end
119
118
  end
@@ -2,14 +2,11 @@ module Cancannible::PreloadAdapter
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
-
6
5
  # Tap Ability.new to first preload permissions via Cancannible
7
6
  alias_method :cancan_initialize, :initialize
8
7
  def initialize(user)
9
- Cancannible::Preloader.preload_abilities!(user,self)
8
+ Cancannible::Preloader.preload_abilities!(user, self)
10
9
  cancan_initialize(user)
11
10
  end
12
-
13
11
  end
14
-
15
- end
12
+ end
@@ -1,19 +1,19 @@
1
1
  class Cancannible::Preloader
2
-
3
- def self.preload_abilities!(grantee,cancan_ability_object)
4
- new(grantee,cancan_ability_object).preload!
2
+ def self.preload_abilities!(grantee, cancan_ability_object)
3
+ new(grantee, cancan_ability_object).preload!
5
4
  end
6
5
 
7
6
  attr_accessor :grantee
8
7
  attr_accessor :cancan_ability_object
9
8
 
10
- def initialize(grantee,cancan_ability_object)
9
+ def initialize(grantee, cancan_ability_object)
11
10
  self.grantee = grantee
12
11
  self.cancan_ability_object = cancan_ability_object
13
12
  end
14
13
 
15
14
  def preload!
16
15
  return unless grantee.respond_to?(:inherited_permissions)
16
+
17
17
  # load inherited permissions to CanCan Abilities
18
18
  preload_abilities_from_permissions(grantee.inherited_permissions)
19
19
  # load user-based permissions from database to CanCan Abilities
@@ -39,17 +39,15 @@ class Cancannible::Preloader
39
39
  end
40
40
 
41
41
  if permission.resource_id.nil?
42
-
43
42
  if action == :cannot
44
43
  # apply generic unrestricted permission to the class
45
- cancan_ability_object.send( action, ability, resource_type )
44
+ cancan_ability_object.send(action, ability, resource_type)
46
45
  else
47
-
48
46
  refinements = resolve_resource_refinements(ability,model_resource)
49
47
 
50
48
  if refinements.empty?
51
49
  # apply generic unrestricted permission to the class
52
- cancan_ability_object.send( action, ability, resource_type )
50
+ cancan_ability_object.send(action, ability, resource_type)
53
51
  else
54
52
  secondary_refinements = resolve_resource_refinements(ability,model_resource,2).presence || [{}]
55
53
  refinements.each do |refinement|
@@ -58,25 +56,22 @@ class Cancannible::Preloader
58
56
  end
59
57
  end
60
58
  end
61
-
62
59
  end
63
-
64
60
  elsif resource_type.find_by_id(permission.resource_id)
65
61
  cancan_ability_object.send( action, ability, resource_type, id: permission.resource_id)
66
62
  end
67
-
68
63
  end
69
64
  end
70
65
 
71
66
  def resolve_resource_type(given_resource_type)
72
67
  model_resource = nil
73
68
  resource_type = given_resource_type
74
- resource_type = resource_type==resource_type.downcase ? resource_type.to_sym : resource_type.constantize rescue nil
69
+ resource_type = resource_type == resource_type.downcase ? resource_type.to_sym : resource_type.constantize rescue nil
75
70
  model_resource = resource_type.respond_to?(:new) ? resource_type.new : resource_type rescue nil
76
71
  [resource_type,model_resource]
77
72
  end
78
73
 
79
- def resolve_resource_refinements(ability,model_resource,stage=1)
74
+ def resolve_resource_refinements(ability, model_resource, stage=1)
80
75
  Array(Cancannible.refinements[stage-1]).each_with_object([]) do |refinement,memo|
81
76
  refinement_attributes = refinement.dup
82
77
 
@@ -111,5 +106,4 @@ class Cancannible::Preloader
111
106
  memo.push(restriction) if restriction.present?
112
107
  end
113
108
  end
114
-
115
- end
109
+ end
@@ -1,3 +1,3 @@
1
1
  module Cancannible
2
- VERSION = "0.0.2"
2
+ VERSION = '2.0.0'
3
3
  end
data/lib/cancannible.rb CHANGED
@@ -2,8 +2,8 @@ require 'active_support'
2
2
  require 'active_support/core_ext'
3
3
  require 'cancan'
4
4
 
5
- require "cancannible/version"
6
- require "cancannible/config"
7
- require "cancannible/preload_adapter"
8
- require "cancannible/preloader"
9
- require "cancannible/grantee"
5
+ require 'cancannible/version'
6
+ require 'cancannible/config'
7
+ require 'cancannible/preload_adapter'
8
+ require 'cancannible/preloader'
9
+ require 'cancannible/grantee'
@@ -34,6 +34,5 @@ module Cancannible
34
34
  end
35
35
  end
36
36
  end
37
-
38
37
  end
39
38
  end
@@ -1,5 +1,4 @@
1
1
  Cancannible.setup do |config|
2
-
3
2
  # ABILITY CACHING
4
3
  # ===============
5
4
  # Cancannible supports optional ability caching. This can provide a significant performance
@@ -24,6 +23,7 @@ Cancannible.setup do |config|
24
23
 
25
24
 
26
25
  # ACCESS REFINMENTS
26
+ # =================
27
27
  # Cancannible allows general-purpose access refinements to be declared here. This will be enforced
28
28
  # in addition to any rules defined in you Ability.rb file.
29
29
 
@@ -99,5 +99,4 @@ Cancannible.setup do |config|
99
99
  #
100
100
  # By default, access refinements are "stage 1" i.e. applied directly to the permissions being loaded.
101
101
  # By specifying stage 2, this refinement is applied on top of all stage 1 refinements (if possible / applicable)
102
-
103
102
  end
@@ -1,4 +1,4 @@
1
- class CreateCancanniblePermissions < ActiveRecord::Migration
1
+ class CreateCancanniblePermissions < ActiveRecord::Migration[6.1]
2
2
  def change
3
3
  create_table :permissions, force: true do |table|
4
4
  table.integer :permissible_id
@@ -1,8 +1,12 @@
1
1
  # The Permission class stores permissions managed by CanCan and Cancannible
2
2
  class Permission < ActiveRecord::Base
3
3
  belongs_to :permissible, polymorphic: true
4
- belongs_to :resource, polymorphic: true
4
+ belongs_to :resource, polymorphic: true, optional: true
5
5
 
6
- validates_uniqueness_of :ability, scope: [:resource_id, :resource_type, :permissible_id, :permissible_type]
6
+ validates :ability, uniqueness: { scope: [:resource_id, :resource_type, :permissible_id, :permissible_type] }
7
7
 
8
- end
8
+ # Note: for Rails 3 you may need to declare attr_accessible as follows, depending on your whitelist_attributes setting.
9
+ # A future version of cancannible should make this unnecessary.
10
+ #
11
+ # attr_accessible :asserted, :ability, :resource_id, :resource_type
12
+ end
data/spec/spec_helper.rb CHANGED
@@ -6,11 +6,11 @@ require 'sqlite3'
6
6
 
7
7
  # Requires supporting files with custom matchers and macros, etc,
8
8
  # in ./support/ and its subdirectories.
9
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each {|f| require f}
10
10
 
11
11
  RSpec.configure do |config|
12
12
  config.before do
13
13
  Cancannible.reset!
14
14
  run_migrations
15
15
  end
16
- end
16
+ end
@@ -1,5 +1,4 @@
1
1
  module MigrationsHelper
2
-
3
2
  def run_migrations
4
3
  ActiveRecord::Base.establish_connection({
5
4
  adapter: 'sqlite3',
@@ -8,7 +7,6 @@ module MigrationsHelper
8
7
 
9
8
  ActiveRecord::Migration.suppress_messages do
10
9
  ActiveRecord::Schema.define(:version => 0) do
11
-
12
10
  create_table "members", :force => true do |t|
13
11
  t.string "name"
14
12
  t.string "email"
@@ -49,13 +47,11 @@ module MigrationsHelper
49
47
  t.string "name"
50
48
  t.integer "category_id"
51
49
  end
52
-
53
50
  end
54
51
  end
55
52
  end
56
-
57
53
  end
58
54
 
59
55
  RSpec.configure do |conf|
60
56
  conf.include MigrationsHelper
61
- end
57
+ end
@@ -1,13 +1,10 @@
1
1
  # These model definitions are just used for the test scenarios
2
2
 
3
- # The Permission class stores permissions maanged by CanCan and Cancannible
4
3
  class Permission < ActiveRecord::Base
5
4
  belongs_to :permissible, polymorphic: true
6
- belongs_to :resource, polymorphic: true
5
+ belongs_to :resource, polymorphic: true, optional: true
7
6
 
8
- validates_uniqueness_of :ability,
9
- :scope => [:resource_id, :resource_type,
10
- :permissible_id, :permissible_type]
7
+ validates :ability, uniqueness: { scope: [:resource_id, :resource_type, :permissible_id, :permissible_type] }
11
8
  end
12
9
 
13
10
  class Member < ActiveRecord::Base
@@ -29,7 +26,7 @@ class RolesUsers < ActiveRecord::Base
29
26
  end
30
27
 
31
28
  class Role < ActiveRecord::Base
32
- has_many :roles_users, :class_name => 'RolesUsers'
29
+ has_many :roles_users, class_name: 'RolesUsers'
33
30
  has_many :users, through: :roles_users
34
31
 
35
32
  include Cancannible::Grantee
@@ -3,29 +3,46 @@ require 'spec_helper'
3
3
  describe Cancannible do
4
4
  let(:grantee_class) { Member }
5
5
  let(:grantee) { grantee_class.create! }
6
+ let(:cached_object) do
7
+ abilities = Ability.new(grantee)
8
+ abilities.can :read, :all
9
+ abilities
10
+ end
6
11
 
7
12
  describe "#abilities" do
8
13
  subject { grantee.abilities }
9
14
 
10
15
  context "when get_cached_abilities provided" do
11
16
  before do
12
- Cancannible.get_cached_abilities = proc{|grantee| "get_cached_abilities for #{grantee.id}" }
17
+ Cancannible.get_cached_abilities = proc { |grantee| cached_object }
18
+ end
19
+
20
+ it "returns the cached object" do
21
+ expect(cached_object.instance_variable_defined?(:@rules_index)).to eql(true)
22
+ expect(subject).to eql(cached_object)
13
23
  end
14
- it "should returned the cached object" do
15
- should eql("get_cached_abilities for #{grantee.id}")
24
+ context 'when incompatible cached_object' do
25
+ let(:cached_object) { 'bogative' }
26
+ it 'returns a new object' do
27
+ expect(subject).to be_an(Ability)
28
+ expect(subject).to_not eql(cached_object)
29
+ end
16
30
  end
17
31
  context "unless reload requested" do
18
32
  subject { grantee.abilities(true) }
19
- it { should be_an(Ability) }
33
+ it 'returns a new object' do
34
+ expect(subject).to be_an(Ability)
35
+ expect(subject).to_not eql(cached_object)
36
+ end
20
37
  end
21
38
  end
22
39
 
23
40
  context "when store_cached_abilities provided" do
24
41
  before do
25
42
  @stored = nil
26
- Cancannible.store_cached_abilities = proc{ |grantee,ability| @stored = { grantee_id: grantee.id, ability: ability } }
43
+ Cancannible.store_cached_abilities = proc { |grantee, ability| @stored = { grantee_id: grantee.id, ability: ability } }
27
44
  end
28
- it "should store the cached object" do
45
+ it "stores the cached object" do
29
46
  expect { subject }.to change { @stored }.from(nil)
30
47
  expect(@stored[:grantee_id]).to eql(grantee.id)
31
48
  expect(@stored[:ability]).to be_an(Ability)
@@ -36,32 +53,29 @@ describe Cancannible do
36
53
  before do
37
54
  @stored = nil
38
55
  @store = 0
39
- Cancannible.get_cached_abilities = proc{|grantee| @stored }
40
- Cancannible.store_cached_abilities = proc{ |grantee,ability| @store += 1 ; @stored = { grantee_id: grantee.id, ability: ability } }
56
+ Cancannible.get_cached_abilities = proc { |grantee| @stored[:ability] if @stored }
57
+ Cancannible.store_cached_abilities = proc { |grantee, ability| @store += 1 ; @stored = { grantee_id: grantee.id, ability: ability } }
41
58
  end
42
- it "should store the cached object on the first call" do
59
+ it "stores the cached object on the first call" do
43
60
  expect { subject }.to change { @stored }.from(nil)
44
61
  expect(@store).to eql(1)
45
62
  expect(@stored[:grantee_id]).to eql(grantee.id)
46
63
  expect(@stored[:ability]).to be_an(Ability)
47
64
  end
48
- it "should return the cached object on the second call" do
65
+ it "returns the cached object on the second call" do
49
66
  expect { subject }.to change { @stored }.from(nil)
50
67
  expect(@store).to eql(1)
51
68
  expect { grantee.abilities }.to_not change { @store }
52
- expect(grantee.abilities[:grantee_id]).to eql(grantee.id)
53
- expect(grantee.abilities[:ability]).to be_an(Ability)
69
+ expect(grantee.abilities).to be_an(Ability)
70
+ expect(@stored[:grantee_id]).to eql(grantee.id)
54
71
  end
55
72
  it "should re-cache object on the second call if refresh requested" do
56
73
  expect { subject }.to change { @stored }.from(nil)
57
74
  expect(@store).to eql(1)
58
75
  expect { grantee.abilities(true) }.to change { @store }.from(1).to(2)
59
- expect(grantee.abilities[:grantee_id]).to eql(grantee.id)
60
- expect(grantee.abilities[:ability]).to be_an(Ability)
76
+ expect(grantee.abilities).to be_an(Ability)
77
+ expect(@stored[:grantee_id]).to eql(grantee.id)
61
78
  end
62
79
  end
63
-
64
-
65
80
  end
66
-
67
- end
81
+ end
@@ -14,4 +14,4 @@ describe Cancannible do
14
14
  subject
15
15
  end
16
16
  end
17
- end
17
+ end
@@ -1,6 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
-
4
3
  describe Cancannible do
5
4
  let(:grantee_class) { User }
6
5
  let(:ability) { :blow }
@@ -9,7 +8,6 @@ describe Cancannible do
9
8
  subject(:grantee) { grantee_class.create!(username: username) }
10
9
 
11
10
  describe "#can?" do
12
-
13
11
  context "with custom attribute association restriction" do
14
12
  let(:resource_class) { Widget }
15
13
  before do
@@ -245,7 +243,5 @@ describe Cancannible do
245
243
  it { should be_falsey }
246
244
  end
247
245
  end
248
-
249
246
  end
250
-
251
247
  end
@@ -4,7 +4,6 @@ describe Cancannible::Grantee do
4
4
  let(:grantee_class) { Member }
5
5
 
6
6
  context "without permissions inheritance" do
7
-
8
7
  describe "##inheritable_permissions" do
9
8
  subject { grantee_class.inheritable_permissions }
10
9
  it { should be_empty }
@@ -43,9 +42,13 @@ describe Cancannible::Grantee do
43
42
  context "when permission is not asserted" do
44
43
  it { should be_truthy }
45
44
  end
46
- context "when permission is not asserted but can is" do
45
+ context "when :can already asserted" do
47
46
  before { grantee.can(:read, resource) }
48
47
  it { should be_falsey }
48
+ context "and then reset as :cannot" do
49
+ before { grantee.cannot(:read, resource) }
50
+ it { should be_truthy }
51
+ end
49
52
  end
50
53
  context "when permission is asserted" do
51
54
  before { grantee.cannot(:read, resource) }
@@ -54,31 +57,6 @@ describe Cancannible::Grantee do
54
57
  end
55
58
  end
56
59
 
57
- context "with a nil resource" do
58
- let!(:resource) { nil }
59
- describe "#can? -> nil" do
60
- subject { grantee.can?(:read, nil) }
61
- context "when permission is not set" do
62
- it { should be_falsey }
63
- end
64
- context "when permission is set" do
65
- before { grantee.can(:read, resource) }
66
- it { should be_truthy }
67
- end
68
- end
69
- describe "#can? -> ''" do
70
- subject { grantee.can?(:read, '') }
71
- context "when permission is not set" do
72
- it { should be_falsey }
73
- end
74
- context "when permission is set" do
75
- before { grantee.can(:read, resource) }
76
- it { should be_falsey }
77
- end
78
- end
79
- end
80
-
81
-
82
60
  context "with a resource class" do
83
61
  let!(:resource) { Widget }
84
62
 
@@ -117,15 +95,14 @@ describe Cancannible::Grantee do
117
95
  context "with a non-existent model" do
118
96
  describe "instance" do
119
97
  let!(:obsolete_permission) {grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'Bogative', resource_id: 33) }
120
- it "should not error on load" do
121
- expect { grantee.abilities }.to_not raise_error
98
+ it "raises CanCan::Error" do
99
+ expect { grantee.abilities }.to raise_error(CanCan::Error)
122
100
  end
123
101
  end
124
102
  describe "class" do
125
103
  let!(:obsolete_permission) {grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'Bogative') }
126
- it "should not error on load" do
127
- grantee.abilities
128
- expect { grantee.abilities }.to_not raise_error
104
+ it "raises CanCan::Error" do
105
+ expect { grantee.abilities }.to raise_error(CanCan::Error)
129
106
  end
130
107
  end
131
108
  end
@@ -134,19 +111,17 @@ describe Cancannible::Grantee do
134
111
  class SuperBogative < ActiveRecord::Base
135
112
  end
136
113
  context "instance" do
137
- let!(:obsolete_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative', resource_id: 33) }
138
- it "should not error on load" do
114
+ let!(:invalid_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative', resource_id: 33) }
115
+ it "does not error on load" do
139
116
  expect { grantee.abilities }.to_not raise_error
140
117
  end
141
118
  end
142
119
  context "class" do
143
- let!(:obsolete_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative') }
144
- it "should not error on load" do
120
+ let!(:invalid_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative') }
121
+ it "does not error on load" do
145
122
  expect { grantee.abilities }.to_not raise_error
146
123
  end
147
124
  end
148
125
  end
149
-
150
126
  end
151
-
152
127
  end
@@ -1,11 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
-
4
3
  describe Cancannible do
5
4
  let(:grantee_class) { User }
6
5
 
7
6
  context "with mulitple sources of permissions inheritance" do
8
-
9
7
  describe "##inheritable_permissions" do
10
8
  subject { grantee_class.inheritable_permissions }
11
9
  it { should eql([:roles, :group]) }
@@ -15,12 +13,12 @@ describe Cancannible do
15
13
  let!(:role_b) { Role.create! }
16
14
  let!(:group_a) { Group.create! }
17
15
  let!(:group_b) { Group.create! }
18
- subject(:grantee) {
16
+ subject(:grantee) do
19
17
  u = grantee_class.new(group: group_a)
20
18
  u.roles << role_a
21
19
  u.save!
22
20
  u
23
- }
21
+ end
24
22
 
25
23
  context "with a symbolic resource" do
26
24
  let!(:resource) { :something }
@@ -43,10 +41,8 @@ describe Cancannible do
43
41
  it { should be_truthy }
44
42
  end
45
43
  end
46
-
47
44
  end
48
45
 
49
-
50
46
  context "with a resource class" do
51
47
  let!(:resource) { Widget }
52
48
 
@@ -68,7 +64,6 @@ describe Cancannible do
68
64
  it { should be_truthy }
69
65
  end
70
66
  end
71
-
72
67
  end
73
68
 
74
69
  context "with a resource instance" do
@@ -136,10 +131,6 @@ describe Cancannible do
136
131
  it { should be_truthy }
137
132
  end
138
133
  end
139
-
140
-
141
134
  end
142
-
143
135
  end
144
-
145
136
  end
metadata CHANGED
@@ -1,141 +1,169 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cancannible
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Gallagher
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-31 00:00:00.000000000 Z
11
+ date: 2022-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '3.2'
26
+ version: '6.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activemodel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.2'
33
+ version: '6.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.2'
40
+ version: '6.1'
41
41
  - !ruby/object:Gem::Dependency
42
- name: cancan
42
+ name: cancancan
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1.6'
47
+ version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1.6'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.2'
61
+ version: '6.1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.2'
68
+ version: '6.1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '1.3'
75
+ version: 1.3.2
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '1.3'
82
+ version: 1.3.2
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: bundler
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '1.6'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '1.6'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '10.0'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '10.0'
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rdoc
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rspec
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - ~>
129
+ - - ">="
116
130
  - !ruby/object:Gem::Version
117
- version: '3.0'
131
+ version: '0'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - ~>
136
+ - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: '3.0'
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: guard-rspec
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
- - - ~>
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rb-fsevent
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
130
158
  - !ruby/object:Gem::Version
131
- version: '4.0'
159
+ version: '0'
132
160
  type: :development
133
161
  prerelease: false
134
162
  version_requirements: !ruby/object:Gem::Requirement
135
163
  requirements:
136
- - - ~>
164
+ - - ">="
137
165
  - !ruby/object:Gem::Version
138
- version: '4.0'
166
+ version: '0'
139
167
  description: Extends CanCan with dynamic, inheritable permissions stored in a database,
140
168
  with caching and multi-tenant refinements
141
169
  email:
@@ -144,9 +172,8 @@ executables: []
144
172
  extensions: []
145
173
  extra_rdoc_files: []
146
174
  files:
147
- - .gitignore
148
- - .rspec
149
- - .travis.yml
175
+ - ".github/workflows/ruby.yml"
176
+ - ".gitignore"
150
177
  - Gemfile
151
178
  - Guardfile
152
179
  - LICENSE.txt
@@ -176,24 +203,23 @@ homepage: https://github.com/evendis/cancannible
176
203
  licenses:
177
204
  - MIT
178
205
  metadata: {}
179
- post_install_message:
206
+ post_install_message:
180
207
  rdoc_options: []
181
208
  require_paths:
182
209
  - lib
183
210
  required_ruby_version: !ruby/object:Gem::Requirement
184
211
  requirements:
185
- - - ! '>='
212
+ - - ">="
186
213
  - !ruby/object:Gem::Version
187
214
  version: '0'
188
215
  required_rubygems_version: !ruby/object:Gem::Requirement
189
216
  requirements:
190
- - - ! '>='
217
+ - - ">="
191
218
  - !ruby/object:Gem::Version
192
219
  version: '0'
193
220
  requirements: []
194
- rubyforge_project:
195
- rubygems_version: 2.2.2
196
- signing_key:
221
+ rubygems_version: 3.2.20
222
+ signing_key:
197
223
  specification_version: 4
198
224
  summary: Dynamic, configurable permissions for CanCan
199
225
  test_files:
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
data/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- # These are specific configuration settings required for travis-ci
2
- language: ruby
3
- rvm:
4
- - 1.9.3