rolify 4.1.1 → 6.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.
Files changed (55) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/activerecord.yml +27 -0
  3. data/.github/workflows/mongoid.yml +32 -0
  4. data/.hakiri.yml +1 -0
  5. data/Appraisals +42 -0
  6. data/CHANGELOG.rdoc +52 -8
  7. data/CONTRIBUTORS +11 -0
  8. data/Gemfile +6 -14
  9. data/LICENSE +1 -1
  10. data/README.md +72 -26
  11. data/Rakefile +6 -1
  12. data/gemfiles/activerecord_4.gemfile +20 -0
  13. data/gemfiles/activerecord_5.gemfile +22 -0
  14. data/gemfiles/activerecord_6.gemfile +22 -0
  15. data/gemfiles/mongoid_5.gemfile +20 -0
  16. data/gemfiles/mongoid_6.gemfile +19 -0
  17. data/gemfiles/mongoid_7.gemfile +20 -0
  18. data/lib/generators/active_record/rolify_generator.rb +45 -11
  19. data/lib/generators/active_record/templates/migration.rb +2 -3
  20. data/lib/generators/active_record/templates/model.rb +15 -0
  21. data/lib/generators/rolify/templates/initializer.rb +4 -1
  22. data/lib/rolify.rb +3 -4
  23. data/lib/rolify/adapters/active_record/resource_adapter.rb +14 -8
  24. data/lib/rolify/adapters/active_record/role_adapter.rb +40 -17
  25. data/lib/rolify/adapters/mongoid/role_adapter.rb +38 -8
  26. data/lib/rolify/configure.rb +4 -2
  27. data/lib/rolify/dynamic.rb +2 -16
  28. data/lib/rolify/finders.rb +6 -1
  29. data/lib/rolify/matchers.rb +2 -2
  30. data/lib/rolify/resource.rb +1 -1
  31. data/lib/rolify/role.rb +11 -2
  32. data/lib/rolify/version.rb +1 -1
  33. data/rolify.gemspec +15 -7
  34. data/spec/common_helper.rb +16 -0
  35. data/spec/generators/rolify/rolify_activerecord_generator_spec.rb +112 -6
  36. data/spec/generators_helper.rb +9 -2
  37. data/spec/rolify/config_spec.rb +2 -0
  38. data/spec/rolify/custom_spec.rb +1 -1
  39. data/spec/rolify/resource_spec.rb +6 -0
  40. data/spec/rolify/shared_examples/shared_examples_for_finders.rb +50 -32
  41. data/spec/rolify/shared_examples/shared_examples_for_has_role.rb +65 -0
  42. data/spec/rolify/utils_spec.rb +19 -0
  43. data/spec/spec_helper.rb +19 -6
  44. data/spec/support/adapters/active_record.rb +4 -3
  45. data/spec/support/adapters/mongoid.rb +19 -2
  46. data/spec/support/adapters/{mongoid.yml → mongoid_5.yml} +2 -2
  47. data/spec/support/adapters/mongoid_6.yml +6 -0
  48. data/spec/support/adapters/mongoid_7.yml +6 -0
  49. data/spec/support/adapters/utils/active_record.rb +12 -0
  50. data/spec/support/adapters/utils/mongoid.rb +13 -0
  51. metadata +60 -26
  52. data/.travis.yml +0 -25
  53. data/gemfiles/Gemfile.rails-3.2 +0 -27
  54. data/gemfiles/Gemfile.rails-4.0 +0 -33
  55. data/gemfiles/Gemfile.rails-4.1 +0 -37
@@ -52,9 +52,8 @@ module Rolify
52
52
  private
53
53
 
54
54
  def sanity_check(role_cnames)
55
- return true if (ARGV[0] =~ /assets:/) == 0
55
+ return true if ARGV.reduce(nil) { |acc,arg| arg =~ /assets:/ if acc.nil? } == 0
56
56
 
57
- role_cnames = [ "Role" ] if role_cnames.empty?
58
57
  role_cnames.each do |role_cname|
59
58
  role_class = role_cname.constantize
60
59
  if role_class.superclass.to_s == "ActiveRecord::Base" && role_table_missing?(role_class)
@@ -67,6 +66,9 @@ module Rolify
67
66
 
68
67
  def role_table_missing?(role_class)
69
68
  !role_class.table_exists?
69
+ rescue ActiveRecord::NoDatabaseError
70
+ true
70
71
  end
72
+
71
73
  end
72
74
  end
@@ -2,29 +2,15 @@ require "rolify/configure"
2
2
 
3
3
  module Rolify
4
4
  module Dynamic
5
- def load_dynamic_methods
6
- if ENV['ADAPTER'] == 'active_record'
7
- # supported Rails version >= 3.2 with AR should use find_each, since use of .all.each is deprecated
8
- self.role_class.includes(:resource).find_each do |r|
9
- define_dynamic_method(r.name, r.resource)
10
- end
11
- else
12
- # for compatibility with MongoidDB and older Rails AR - does not support polymorphic includes
13
- self.role_class.all.each do |r|
14
- define_dynamic_method(r.name, r.resource)
15
- end
16
- end
17
- end
18
-
19
5
  def define_dynamic_method(role_name, resource)
20
6
  class_eval do
21
7
  define_method("is_#{role_name}?".to_sym) do
22
8
  has_role?("#{role_name}")
23
- end if !method_defined?("is_#{role_name}?".to_sym)
9
+ end if !method_defined?("is_#{role_name}?".to_sym) && self.adapter.where_strict(self.role_class, name: role_name).exists?
24
10
 
25
11
  define_method("is_#{role_name}_of?".to_sym) do |arg|
26
12
  has_role?("#{role_name}", arg)
27
- end if !method_defined?("is_#{role_name}_of?".to_sym) && resource
13
+ end if !method_defined?("is_#{role_name}_of?".to_sym) && resource && self.adapter.where_strict(self.role_class, name: role_name, resource: resource).exists?
28
14
  end
29
15
  end
30
16
  end
@@ -1,7 +1,12 @@
1
1
  module Rolify
2
2
  module Finders
3
3
  def with_role(role_name, resource = nil)
4
- self.adapter.scope(self, :name => role_name, :resource => resource)
4
+ strict = self.strict_rolify and resource and resource != :any
5
+ self.adapter.scope(
6
+ self,
7
+ { :name => role_name, :resource => resource },
8
+ strict
9
+ )
5
10
  end
6
11
 
7
12
  def without_role(role_name, resource = nil)
@@ -5,11 +5,11 @@ RSpec::Matchers.define :have_role do |*args|
5
5
  resource.has_role?(*args)
6
6
  end
7
7
 
8
- failure_message_for_should do |resource|
8
+ failure_message do |resource|
9
9
  "expected to have role #{args.map(&:inspect).join(" ")}"
10
10
  end
11
11
 
12
- failure_message_for_should_not do |resource|
12
+ failure_message_when_negated do |resource|
13
13
  "expected not to have role #{args.map(&:inspect).join(" ")}"
14
14
  end
15
15
  end
@@ -11,7 +11,7 @@ module Rolify
11
11
 
12
12
  def with_role(role_name, user = nil)
13
13
  if role_name.is_a? Array
14
- role_name.map!(&:to_s)
14
+ role_name = role_name.map(&:to_s)
15
15
  else
16
16
  role_name = role_name.to_s
17
17
  end
data/lib/rolify/role.rb CHANGED
@@ -44,6 +44,15 @@ module Rolify
44
44
  self.class.adapter.where_strict(self.roles, name: role_name, resource: resource).any?
45
45
  end
46
46
 
47
+ def has_cached_role?(role_name, resource = nil)
48
+ return has_strict_cached_role?(role_name, resource) if self.class.strict_rolify and resource and resource != :any
49
+ self.class.adapter.find_cached(self.roles, name: role_name, resource: resource).any?
50
+ end
51
+
52
+ def has_strict_cached_role?(role_name, resource = nil)
53
+ self.class.adapter.find_cached_strict(self.roles, name: role_name, resource: resource).any?
54
+ end
55
+
47
56
  def has_all_roles?(*args)
48
57
  args.each do |arg|
49
58
  if arg.is_a? Hash
@@ -77,7 +86,7 @@ module Rolify
77
86
  deprecate :has_no_role, :remove_role
78
87
 
79
88
  def roles_name
80
- self.roles.select(:name).map { |r| r.name }
89
+ self.roles.pluck(:name)
81
90
  end
82
91
 
83
92
  def method_missing(method, *args, &block)
@@ -85,7 +94,7 @@ module Rolify
85
94
  resource = args.first
86
95
  self.class.define_dynamic_method $1, resource
87
96
  return has_role?("#{$1}", resource)
88
- end unless !Rolify.dynamic_shortcuts
97
+ end if Rolify.dynamic_shortcuts
89
98
  super
90
99
  end
91
100
 
@@ -1,3 +1,3 @@
1
1
  module Rolify
2
- VERSION = "4.1.1"
2
+ VERSION = "6.0.0"
3
3
  end
data/rolify.gemspec CHANGED
@@ -9,20 +9,28 @@ Gem::Specification.new do |s|
9
9
  s.version = Rolify::VERSION
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.homepage = 'https://github.com/RolifyCommunity/rolify'
12
- s.rubyforge_project = s.name
13
12
 
14
13
  s.license = 'MIT'
15
14
 
16
- s.authors = ['Florent Monbillard']
17
- s.email = ['f.monbillard@gmail.com']
15
+ s.authors = [
16
+ 'Florent Monbillard',
17
+ 'Wellington Cordeiro'
18
+ ]
19
+ s.email = [
20
+ 'f.monbillard@gmail.com',
21
+ 'wellington@wellingtoncordeiro.com'
22
+ ]
18
23
 
19
24
  s.files = `git ls-files`.split("\n")
20
25
  s.test_files = `git ls-files -- spec/*`.split("\n")
21
26
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
27
  s.require_paths = ['lib']
23
28
 
24
- s.add_development_dependency 'ammeter', '~> 1.1.2' # Spec generator
25
- s.add_development_dependency 'bundler', '>= 1.7.12' # packaging feature
26
- s.add_development_dependency 'rake', '~> 10.4.2' # Tasks manager
27
- s.add_development_dependency 'rspec-rails', '2.99.0'
29
+ s.required_ruby_version = '>= 2.5'
30
+
31
+ s.add_development_dependency 'ammeter', '~> 1.1' # Spec generator
32
+ s.add_development_dependency 'appraisal', '~> 2.0'
33
+ s.add_development_dependency 'bundler', '~> 2.0' # packaging feature
34
+ s.add_development_dependency 'rake', '~> 12.3' # Tasks manager
35
+ s.add_development_dependency 'rspec-rails', '~> 3.8'
28
36
  end
@@ -0,0 +1,16 @@
1
+ require 'test-unit'
2
+
3
+ begin
4
+ require 'pry'
5
+ rescue LoadError
6
+ end
7
+
8
+ # `Test::Unit::AutoRunner.need_auto_run=` was introduced to the test-unit
9
+ # gem in version 2.4.9. Previous to this version `Test::Unit.run=` was
10
+ # used. The implementation of test-unit included with Ruby has neither
11
+ # method.
12
+ if defined? Test::Unit::AutoRunner
13
+ Test::Unit::AutoRunner.need_auto_run = false
14
+ elsif defined?(Test::Unit)
15
+ Test::Unit.run = false
16
+ end
@@ -8,6 +8,7 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
8
8
  destination File.expand_path("../../../../tmp", __FILE__)
9
9
  teardown :cleanup_destination_root
10
10
 
11
+ let(:adapter) { 'SQLite3Adapter' }
11
12
  before {
12
13
  prepare_destination
13
14
  }
@@ -20,6 +21,8 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
20
21
  before(:all) { arguments %w(Role) }
21
22
 
22
23
  before {
24
+ allow(ActiveRecord::Base).to receive_message_chain(
25
+ 'connection.class.to_s.demodulize') { adapter }
23
26
  capture(:stdout) {
24
27
  generator.create_file "app/models/user.rb" do
25
28
  <<-RUBY
@@ -43,12 +46,32 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
43
46
  describe 'app/models/role.rb' do
44
47
  subject { file('app/models/role.rb') }
45
48
  it { should exist }
46
- it { should contain "class Role < ActiveRecord::Base" }
49
+ it do
50
+ if Rails::VERSION::MAJOR < 5
51
+ should contain "class Role < ActiveRecord::Base"
52
+ else
53
+ should contain "class Role < ApplicationRecord"
54
+ end
55
+ end
47
56
  it { should contain "has_and_belongs_to_many :users, :join_table => :users_roles" }
48
- it { should contain "belongs_to :resource, :polymorphic => true" }
57
+ it do
58
+ if Rails::VERSION::MAJOR < 5
59
+ should contain "belongs_to :resource,\n"
60
+ " :polymorphic => true"
61
+ else
62
+ should contain "belongs_to :resource,\n"
63
+ " :polymorphic => true,\n"
64
+ " :optional => true"
65
+ end
66
+ end
67
+ it { should contain "belongs_to :resource,\n"
68
+ " :polymorphic => true,\n"
69
+ " :optional => true"
70
+ }
49
71
  it { should contain "validates :resource_type,\n"
50
72
  " :inclusion => { :in => Rolify.resource_types },\n"
51
73
  " :allow_nil => true" }
74
+ it { should contain "scopify" }
52
75
  end
53
76
 
54
77
  describe 'app/models/user.rb' do
@@ -62,6 +85,24 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
62
85
  it { should be_a_migration }
63
86
  it { should contain "create_table(:roles) do" }
64
87
  it { should contain "create_table(:users_roles, :id => false) do" }
88
+
89
+ context 'mysql2' do
90
+ let(:adapter) { 'Mysql2Adapter' }
91
+
92
+ it { expect(subject).to contain('add_index(:roles, :name)') }
93
+ end
94
+
95
+ context 'sqlite3' do
96
+ let(:adapter) { 'SQLite3Adapter' }
97
+
98
+ it { expect(subject).to contain('add_index(:roles, :name)') }
99
+ end
100
+
101
+ context 'pg' do
102
+ let(:adapter) { 'PostgreSQLAdapter' }
103
+
104
+ it { expect(subject).not_to contain('add_index(:roles, :name)') }
105
+ end
65
106
  end
66
107
  end
67
108
 
@@ -69,6 +110,8 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
69
110
  before(:all) { arguments %w(AdminRole AdminUser) }
70
111
 
71
112
  before {
113
+ allow(ActiveRecord::Base).to receive_message_chain(
114
+ 'connection.class.to_s.demodulize') { adapter }
72
115
  capture(:stdout) {
73
116
  generator.create_file "app/models/admin_user.rb" do
74
117
  "class AdminUser < ActiveRecord::Base\nend"
@@ -91,9 +134,18 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
91
134
  subject { file('app/models/admin_role.rb') }
92
135
 
93
136
  it { should exist }
94
- it { should contain "class AdminRole < ActiveRecord::Base" }
137
+ it do
138
+ if Rails::VERSION::MAJOR < 5
139
+ should contain "class AdminRole < ActiveRecord::Base"
140
+ else
141
+ should contain "class AdminRole < ApplicationRecord"
142
+ end
143
+ end
95
144
  it { should contain "has_and_belongs_to_many :admin_users, :join_table => :admin_users_admin_roles" }
96
- it { should contain "belongs_to :resource, :polymorphic => true" }
145
+ it { should contain "belongs_to :resource,\n"
146
+ " :polymorphic => true,\n"
147
+ " :optional => true"
148
+ }
97
149
  end
98
150
 
99
151
  describe 'app/models/admin_user.rb' do
@@ -108,6 +160,24 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
108
160
  it { should be_a_migration }
109
161
  it { should contain "create_table(:admin_roles)" }
110
162
  it { should contain "create_table(:admin_users_admin_roles, :id => false) do" }
163
+
164
+ context 'mysql2' do
165
+ let(:adapter) { 'Mysql2Adapter' }
166
+
167
+ it { expect(subject).to contain('add_index(:admin_roles, :name)') }
168
+ end
169
+
170
+ context 'sqlite3' do
171
+ let(:adapter) { 'SQLite3Adapter' }
172
+
173
+ it { expect(subject).to contain('add_index(:admin_roles, :name)') }
174
+ end
175
+
176
+ context 'pg' do
177
+ let(:adapter) { 'PostgreSQLAdapter' }
178
+
179
+ it { expect(subject).not_to contain('add_index(:admin_roles, :name)') }
180
+ end
111
181
  end
112
182
  end
113
183
 
@@ -115,6 +185,8 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
115
185
  before(:all) { arguments %w(Admin::Role Admin::User) }
116
186
 
117
187
  before {
188
+ allow(ActiveRecord::Base).to receive_message_chain(
189
+ 'connection.class.to_s.demodulize') { adapter }
118
190
  capture(:stdout) {
119
191
  generator.create_file "app/models/admin/user.rb" do
120
192
  <<-RUBY
@@ -143,9 +215,18 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
143
215
  subject { file('app/models/admin/role.rb') }
144
216
 
145
217
  it { should exist }
146
- it { should contain "class Admin::Role < ActiveRecord::Base" }
218
+ it do
219
+ if Rails::VERSION::MAJOR < 5
220
+ should contain "class Admin::Role < ActiveRecord::Base"
221
+ else
222
+ should contain "class Admin::Role < ApplicationRecord"
223
+ end
224
+ end
147
225
  it { should contain "has_and_belongs_to_many :admin_users, :join_table => :admin_users_admin_roles" }
148
- it { should contain "belongs_to :resource, :polymorphic => true" }
226
+ it { should contain "belongs_to :resource,\n"
227
+ " :polymorphic => true,\n"
228
+ " :optional => true"
229
+ }
149
230
  end
150
231
 
151
232
  describe 'app/models/admin/user.rb' do
@@ -160,6 +241,31 @@ describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_r
160
241
  it { should be_a_migration }
161
242
  it { should contain "create_table(:admin_roles)" }
162
243
  it { should contain "create_table(:admin_users_admin_roles, :id => false) do" }
244
+ it do
245
+ if Rails::VERSION::MAJOR < 5
246
+ should contain "< ActiveRecord::Migration"
247
+ else
248
+ should contain "< ActiveRecord::Migration[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
249
+ end
250
+ end
251
+
252
+ context 'mysql2' do
253
+ let(:adapter) { 'Mysql2Adapter' }
254
+
255
+ it { expect(subject).to contain('add_index(:admin_roles, :name)') }
256
+ end
257
+
258
+ context 'sqlite3' do
259
+ let(:adapter) { 'SQLite3Adapter' }
260
+
261
+ it { expect(subject).to contain('add_index(:admin_roles, :name)') }
262
+ end
263
+
264
+ context 'pg' do
265
+ let(:adapter) { 'PostgreSQLAdapter' }
266
+
267
+ it { expect(subject).not_to contain('add_index(:admin_roles, :name)') }
268
+ end
163
269
  end
164
270
  end
165
271
  end
@@ -1,21 +1,28 @@
1
1
  require 'rubygems'
2
2
  require "bundler/setup"
3
3
 
4
+ require 'pry'
5
+
4
6
  require 'rolify'
5
7
  require 'rolify/matchers'
6
- require 'rails'
8
+ require 'rails/all'
7
9
  require_relative 'support/stream_helpers'
8
10
  include StreamHelpers
9
11
 
10
12
  require 'coveralls'
11
13
  Coveralls.wear_merged!
12
14
 
15
+ require 'common_helper'
16
+
13
17
  ENV['ADAPTER'] ||= 'active_record'
14
18
 
15
19
  if ENV['ADAPTER'] == 'active_record'
20
+ load File.dirname(__FILE__) + '/support/adapters/utils/active_record.rb'
16
21
  require 'active_record/railtie'
22
+ establish_connection
17
23
  else
18
- require 'mongoid'
24
+ load File.dirname(__FILE__) + '/support/adapters/utils/mongoid.rb'
25
+ load_mongoid_config
19
26
  end
20
27
 
21
28
  module TestApp
@@ -161,6 +161,8 @@ describe Rolify do
161
161
  config.orm = "mongoid"
162
162
  end
163
163
  end
164
+
165
+ subject { Rolify }
164
166
 
165
167
  its(:dynamic_shortcuts) { should be_truthy }
166
168
  its(:orm) { should eq("mongoid") }
@@ -17,4 +17,4 @@ describe "Using Rolify with custom User and Role class names" do
17
17
  it_behaves_like "Role.scopes"
18
18
  it_behaves_like Rolify::Dynamic
19
19
  it_behaves_like "Rolify.callbacks"
20
- end
20
+ end
@@ -542,29 +542,35 @@ describe Rolify::Resource do
542
542
  context "strict user" do
543
543
  before(:all) do
544
544
  @strict_user = StrictUser.first
545
+ @strict_user.role_ids
545
546
  @strict_user.add_role(:forum, Forum.first)
546
547
  @strict_user.add_role(:forum, Forum)
547
548
  end
548
549
 
549
550
  it "should return only strict forum" do
550
551
  @strict_user.has_role?(:forum, Forum.first).should be true
552
+ @strict_user.has_cached_role?(:forum, Forum.first).should be true
551
553
  end
552
554
 
553
555
  it "should return false on strict another forum" do
554
556
  @strict_user.has_role?(:forum, Forum.last).should be false
557
+ @strict_user.has_cached_role?(:forum, Forum.last).should be false
555
558
  end
556
559
 
557
560
  it "should return true if user has role on Forum model" do
558
561
  @strict_user.has_role?(:forum, Forum).should be true
562
+ @strict_user.has_cached_role?(:forum, Forum).should be true
559
563
  end
560
564
 
561
565
  it "should return true if user has role any forum name" do
562
566
  @strict_user.has_role?(:forum, :any).should be true
567
+ @strict_user.has_cached_role?(:forum, :any).should be true
563
568
  end
564
569
 
565
570
  it "should return false when deleted role on Forum model" do
566
571
  @strict_user.remove_role(:forum, Forum)
567
572
  @strict_user.has_role?(:forum, Forum).should be false
573
+ @strict_user.has_cached_role?(:forum, Forum).should be false
568
574
  end
569
575
  end
570
576
  end