canard 0.5.0.pre → 0.6.0.pre

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 (64) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +3 -0
  3. data/.rubocop.yml +27 -0
  4. data/.rubocop_todo.yml +37 -0
  5. data/.travis.yml +1 -1
  6. data/Gemfile +7 -6
  7. data/README.md +40 -37
  8. data/Rakefile +5 -2
  9. data/canard.gemspec +8 -7
  10. data/lib/ability.rb +14 -13
  11. data/lib/canard.rb +4 -2
  12. data/lib/canard/abilities.rb +7 -9
  13. data/lib/canard/adapters/active_record.rb +32 -29
  14. data/lib/canard/adapters/mongoid.rb +18 -11
  15. data/lib/canard/find_abilities.rb +8 -9
  16. data/lib/canard/railtie.rb +11 -16
  17. data/lib/canard/user_model.rb +66 -67
  18. data/lib/canard/version.rb +3 -1
  19. data/lib/generators/ability_definition.rb +16 -14
  20. data/lib/generators/canard/ability/ability_generator.rb +16 -12
  21. data/lib/generators/rspec/ability/ability_generator.rb +9 -9
  22. data/lib/tasks/canard.rake +6 -6
  23. data/test/abilities/administrators.rb +2 -2
  24. data/test/canard/abilities_test.rb +14 -21
  25. data/test/canard/ability_test.rb +40 -52
  26. data/test/canard/adapters/active_record_test.rb +71 -135
  27. data/test/canard/adapters/mongoid_test.rb +61 -132
  28. data/test/canard/canard_test.rb +8 -10
  29. data/test/canard/find_abilities_test.rb +9 -11
  30. data/test/canard/user_model_test.rb +22 -32
  31. data/test/dummy/Rakefile +3 -1
  32. data/test/dummy/app/abilities/admins.rb +4 -4
  33. data/test/dummy/app/abilities/authors.rb +3 -3
  34. data/test/dummy/app/abilities/editors.rb +2 -2
  35. data/test/dummy/app/abilities/guests.rb +3 -3
  36. data/test/dummy/app/abilities/users.rb +4 -4
  37. data/test/dummy/app/controllers/application_controller.rb +2 -0
  38. data/test/dummy/app/models/activity.rb +3 -1
  39. data/test/dummy/app/models/member.rb +3 -3
  40. data/test/dummy/app/models/mongoid_user.rb +5 -3
  41. data/test/dummy/app/models/plain_ruby_non_user.rb +2 -2
  42. data/test/dummy/app/models/plain_ruby_user.rb +3 -3
  43. data/test/dummy/app/models/post.rb +3 -1
  44. data/test/dummy/app/models/user.rb +3 -2
  45. data/test/dummy/app/models/user_without_role.rb +4 -4
  46. data/test/dummy/app/models/user_without_role_mask.rb +3 -3
  47. data/test/dummy/config.ru +3 -1
  48. data/test/dummy/config/application.rb +9 -8
  49. data/test/dummy/config/boot.rb +4 -2
  50. data/test/dummy/config/environment.rb +3 -1
  51. data/test/dummy/config/environments/development.rb +2 -0
  52. data/test/dummy/config/environments/test.rb +4 -2
  53. data/test/dummy/config/initializers/secret_token.rb +2 -0
  54. data/test/dummy/config/initializers/session_store.rb +3 -1
  55. data/test/dummy/config/initializers/wrap_parameters.rb +3 -1
  56. data/test/dummy/config/mongoid3.yml +5 -1
  57. data/test/dummy/config/routes.rb +2 -0
  58. data/test/dummy/db/migrate/20120430083231_initialize_db.rb +7 -7
  59. data/test/dummy/db/schema.rb +11 -11
  60. data/test/dummy/script/rails +4 -2
  61. data/test/support/reloadable.rb +14 -15
  62. data/test/test_helper.rb +7 -13
  63. metadata +18 -18
  64. data/test/dummy/config/mongoid2.yml +0 -9
@@ -1,51 +1,54 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Canard
2
4
  module Adapters
3
- module ActiveRecord
4
-
5
+ module ActiveRecord # :nodoc:
5
6
  private
6
7
 
7
- def add_role_scopes(*args)
8
- options = args.extract_options!
9
- # TODO change to check has_roles_attribute?
10
- if active_record_table?
11
- valid_roles.each do |role|
12
- define_scopes_for_role role, options[:prefix]
13
- end
14
-
15
- # TODO change hard coded :role_mask to roles_attribute_name
16
- define_singleton_method(:with_any_role) do |*roles|
17
- where("#{role_mask_column} & :role_mask > 0", { :role_mask => mask_for(*roles) })
18
- end
19
-
20
- define_singleton_method(:with_all_roles) do |*roles|
21
- where("#{role_mask_column} & :role_mask = :role_mask", { :role_mask => mask_for(*roles) })
22
- end
23
-
24
- define_singleton_method(:with_only_roles) do |*roles|
25
- where("#{role_mask_column} = :role_mask", { :role_mask => mask_for(*roles) })
26
- end
8
+ def add_role_scopes(**options)
9
+ define_scopes(options) if active_record_table_exists?
10
+ end
11
+
12
+ def define_scopes(options)
13
+ valid_roles.each do |role|
14
+ define_scopes_for_role role, options[:prefix]
15
+ end
16
+
17
+ # TODO: change hard coded :role_mask to roles_attribute_name
18
+ define_singleton_method(:with_any_role) do |*roles|
19
+ where("#{role_mask_column} & :role_mask > 0", role_mask: mask_for(*roles))
20
+ end
21
+
22
+ define_singleton_method(:with_all_roles) do |*roles|
23
+ where("#{role_mask_column} & :role_mask = :role_mask", role_mask: mask_for(*roles))
24
+ end
25
+
26
+ define_singleton_method(:with_only_roles) do |*roles|
27
+ where("#{role_mask_column} = :role_mask", role_mask: mask_for(*roles))
27
28
  end
28
29
  end
29
30
 
30
- def active_record_table?
31
+ def active_record_table_exists?
31
32
  respond_to?(:table_exists?) && table_exists?
33
+ rescue ActiveRecord::NoDatabaseError, StandardError
34
+ false
32
35
  end
33
36
 
34
- # TODO extract has_roles_attribute? and change to has_roles_attribute? || super
37
+ # TODO: extract has_roles_attribute? and change to has_roles_attribute? || super
35
38
  def has_roles_mask_accessors?
36
- active_record_table? && column_names.include?(roles_attribute_name.to_s) || super
39
+ active_record_table_exists? && column_names.include?(roles_attribute_name.to_s) || super
37
40
  end
38
41
 
39
- def define_scopes_for_role(role, prefix=nil)
42
+ def define_scopes_for_role(role, prefix = nil)
40
43
  include_scope = [prefix, String(role).pluralize].compact.join('_')
41
44
  exclude_scope = "non_#{include_scope}"
42
45
 
43
46
  define_singleton_method(include_scope) do
44
- where("#{role_mask_column} & :role_mask > 0", { :role_mask => mask_for(role) })
47
+ where("#{role_mask_column} & :role_mask > 0", role_mask: mask_for(role))
45
48
  end
46
49
 
47
50
  define_singleton_method(exclude_scope) do
48
- where("#{role_mask_column} & :role_mask = 0 or #{role_mask_column} is null", { :role_mask => mask_for(role) })
51
+ where("#{role_mask_column} & :role_mask = 0 or #{role_mask_column} is null", role_mask: mask_for(role))
49
52
  end
50
53
  end
51
54
 
@@ -54,4 +57,4 @@ module Canard
54
57
  end
55
58
  end
56
59
  end
57
- end
60
+ end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Canard
2
4
  module Adapters
3
- module Mongoid
4
-
5
+ module Mongoid # :nodoc:
5
6
  private
6
7
 
7
8
  def add_role_scopes(*args)
@@ -10,34 +11,40 @@ module Canard
10
11
  define_scopes_for_role role, options[:prefix]
11
12
  end
12
13
 
13
- def with_any_role(*roles)
14
+ define_singleton_method(:with_any_role) do |*roles|
14
15
  where("(this.#{roles_attribute_name} & #{mask_for(*roles)}) > 0")
15
16
  end
16
17
 
17
- def with_all_roles(*roles)
18
+ define_singleton_method(:with_all_roles) do |*roles|
18
19
  where("(this.#{roles_attribute_name} & #{mask_for(*roles)}) === #{mask_for(*roles)}")
19
20
  end
20
21
 
21
- def with_only_roles(*roles)
22
+ define_singleton_method(:with_only_roles) do |*roles|
22
23
  where("this.#{roles_attribute_name} === #{mask_for(*roles)}")
23
24
  end
24
25
  end
25
26
 
26
27
  def has_roles_mask_accessors?
27
- fields.include?(roles_attribute_name.to_s) || super
28
+ fields.include?(roles_attribute_name.to_s) || super
28
29
  end
29
30
 
30
- def define_scopes_for_role(role, prefix=nil)
31
+ def define_scopes_for_role(role, prefix = nil)
31
32
  include_scope = [prefix, String(role).pluralize].compact.join('_')
32
33
  exclude_scope = "non_#{include_scope}"
33
34
 
34
35
  scope include_scope, -> { where("(this.#{roles_attribute_name} & #{mask_for(role)}) > 0") }
35
- scope exclude_scope, -> { any_of({roles_attribute_name => { "$exists" => false }}, {roles_attribute_name => nil}, {"$where" => "(this.#{roles_attribute_name} & #{mask_for(role)}) === 0"}) }
36
+ scope exclude_scope, lambda {
37
+ any_of(
38
+ { roles_attribute_name => { '$exists' => false } },
39
+ { roles_attribute_name => nil },
40
+ '$where' => "(this.#{roles_attribute_name} & #{mask_for(role)}) === 0"
41
+ )
42
+ }
36
43
  end
37
44
  end
38
45
  end
39
46
  end
40
47
 
41
- Mongoid::Document::ClassMethods.send :include, Canard::Adapters::Mongoid
42
- Mongoid::Document::ClassMethods.send :include, Canard::UserModel
43
- Canard.find_abilities
48
+ Mongoid::Document::ClassMethods.send(:include, Canard::Adapters::Mongoid)
49
+ Mongoid::Document::ClassMethods.send(:include, Canard::UserModel)
50
+ Canard.find_abilities
@@ -1,15 +1,16 @@
1
- module Canard
1
+ # frozen_string_literal: true
2
2
 
3
+ module Canard # :nodoc:
3
4
  def self.ability_definitions
4
5
  Abilities.definitions
5
6
  end
6
7
 
7
8
  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
9
+ String(class_name)
10
+ .gsub('::', '')
11
+ .gsub(/(.)([A-Z])/, '\1_\2')
12
+ .downcase
13
+ .to_sym
13
14
  end
14
15
 
15
16
  def self.load_paths
@@ -22,7 +23,5 @@ module Canard
22
23
  load file
23
24
  end
24
25
  end
25
-
26
26
  end
27
-
28
- end
27
+ end
@@ -1,21 +1,18 @@
1
- require 'canard'
2
- require 'rails'
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Canard
5
- class Railtie < Rails::Railtie
6
-
7
- initializer "canard.no_eager_loading", :before => 'before_eager_loading' do |app|
8
- ActiveSupport::Dependencies.autoload_paths.reject!{ |path| Canard.load_paths.include?(path) }
4
+ class Railtie < Rails::Railtie # :nodoc:
5
+ initializer 'canard.no_eager_loading', before: 'before_eager_loading' do |app|
6
+ ActiveSupport::Dependencies.autoload_paths.reject! { |path| Canard.load_paths.include?(path) }
9
7
  # Don't eagerload our configs, we'll deal with them ourselves
10
8
  app.config.eager_load_paths = app.config.eager_load_paths.reject do |path|
11
9
  Canard.load_paths.include?(path)
12
10
  end
13
- if app.config.respond_to?(:watchable_dirs)
14
- app.config.watchable_dirs.merge! Hash[ Canard.load_paths.product([[:rb]]) ]
15
- end
11
+
12
+ app.config.watchable_dirs.merge! Hash[Canard.load_paths.product([[:rb]])] if app.config.respond_to?(:watchable_dirs)
16
13
  end
17
14
 
18
- initializer "canard.active_record" do |app|
15
+ initializer 'canard.active_record' do |_app|
19
16
  ActiveSupport.on_load :active_record do
20
17
  require 'canard/adapters/active_record'
21
18
  Canard::Abilities.default_path = File.expand_path('app/abilities', Rails.root)
@@ -24,19 +21,17 @@ module Canard
24
21
  end
25
22
  end
26
23
 
27
- initializer "canard.mongoid" do |app|
24
+ initializer 'canard.mongoid' do |_app|
28
25
  require 'canard/adapters/mongoid' if defined?(Mongoid)
29
26
  end
30
27
 
31
- initializer "canard.abilities_reloading", :after => "action_dispatch.configure" do |app|
28
+ initializer 'canard.abilities_reloading', after: 'action_dispatch.configure' do |_app|
32
29
  reloader = rails5? ? ActiveSupport::Reloader : ActionDispatch::Reloader
33
- if reloader.respond_to?(:to_prepare)
34
- reloader.to_prepare { Canard.find_abilities }
35
- end
30
+ reloader.to_prepare { Canard.find_abilities } if reloader.respond_to?(:to_prepare)
36
31
  end
37
32
 
38
33
  rake_tasks do
39
- load File.expand_path('../../tasks/canard.rake', __FILE__)
34
+ load File.expand_path('../tasks/canard.rake', __dir__)
40
35
  end
41
36
 
42
37
  private
@@ -1,77 +1,78 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Canard
4
+ # Canard applies roles to a model using the acts_as_user class method. The following User model
5
+ # will be given the :manager and :admin roles
6
+ #
7
+ # class User < ActiveRecord::Base
8
+ #
9
+ # acts_as_user :roles => [:manager, :admin]
10
+ #
11
+ # end
12
+ #
13
+ # If using Canard with a non ActiveRecord class you can still assign roles but you will need to
14
+ # extend the class with Canard::UserModel and add a roles_mask attribute.
15
+ #
16
+ # class User
17
+ #
18
+ # extend Canard::UserModel
19
+ #
20
+ # attr_accessor :roles_mask
21
+ #
22
+ # acts_as_user :roles => [:manager, :admin]
23
+ #
24
+ # end
25
+ #
26
+ # You can choose the attribute used for the roles_mask by specifying :roles_mask. If no
27
+ # roles_mask is specified it uses RoleModel's default of 'roles_mask'
28
+ #
29
+ # acts_as_user :roles_mask => :my_roles_mask, :roles => [:manager, :admin]
30
+ #
31
+ # == Scopes
32
+ #
33
+ # Beyond applying the roles to the model, acts_as_user also creates some useful scopes for
34
+ # ActiveRecord models;
35
+ #
36
+ # User.with_any_role(:manager, :admin)
37
+ #
38
+ # returns all the managers and admins
39
+ #
40
+ # User.with_all_roles(:manager, :admin)
41
+ #
42
+ # returns only the users with both the manager and admin roles
43
+ #
44
+ # User.admins
45
+ #
46
+ # returns all the admins as
47
+ #
48
+ # User.managers
49
+ #
50
+ # returns all the users with the maager role likewise
51
+ #
52
+ # User.non_admins
53
+ #
54
+ # returns all the users who don't have the admin role and
55
+ #
56
+ # User.non_managers
57
+ #
58
+ # returns all the users who don't have the manager role.
2
59
  module UserModel
3
-
4
- # Canard applies roles to a model using the acts_as_user class method. The following User model
5
- # will be given the :manager and :admin roles
6
- #
7
- # class User < ActiveRecord::Base
8
- #
9
- # acts_as_user :roles => [:manager, :admin]
10
- #
11
- # end
12
- #
13
- # If using Canard with a non ActiveRecord class you can still assign roles but you will need to
14
- # extend the class with Canard::UserModel and add a roles_mask attribute.
15
- #
16
- # class User
17
- #
18
- # extend Canard::UserModel
19
- #
20
- # attr_accessor :roles_mask
21
- #
22
- # acts_as_user :roles => [:manager, :admin]
23
- #
24
- # end
25
- #
26
- # You can choose the attribute used for the roles_mask by specifying :roles_mask. If no
27
- # roles_mask is specified it uses RoleModel's default of 'roles_mask'
28
- #
29
- # acts_as_user :roles_mask => :my_roles_mask, :roles => [:manager, :admin]
30
- #
31
- # == Scopes
32
- #
33
- # Beyond applying the roles to the model, acts_as_user also creates some useful scopes for
34
- # ActiveRecord models;
35
- #
36
- # User.with_any_role(:manager, :admin)
37
- #
38
- # returns all the managers and admins
39
- #
40
- # User.with_all_roles(:manager, :admin)
41
- #
42
- # returns only the users with both the manager and admin roles
43
- #
44
- # User.admins
45
- #
46
- # returns all the admins as
47
- #
48
- # User.managers
49
- #
50
- # returns all the users with the maager role likewise
51
- #
52
- # User.non_admins
53
- #
54
- # returns all the users who don't have the admin role and
55
- #
56
- # User.non_managers
57
- #
58
- # returns all the users who don't have the manager role.
59
60
  def acts_as_user(*args)
60
61
  include RoleModel
61
62
  include InstanceMethods
62
-
63
+
63
64
  options = args.last.is_a?(Hash) ? args.pop : {}
64
-
65
+
65
66
  if defined?(ActiveRecord) && self < ActiveRecord::Base
66
67
  extend Adapters::ActiveRecord
67
- elsif defined?(Mongoid) && self.included_modules.include?(Mongoid::Document)
68
+ elsif defined?(Mongoid) && included_modules.include?(Mongoid::Document)
68
69
  extend Adapters::Mongoid
69
- field (options[:roles_mask] || :roles_mask), :type => Integer
70
+ field (options[:roles_mask] || :roles_mask), type: Integer
70
71
  end
71
72
 
72
- roles_attribute options[:roles_mask] if options.has_key?(:roles_mask)
73
+ roles_attribute options[:roles_mask] if options.key?(:roles_mask)
73
74
 
74
- roles options[:roles] if options.has_key?(:roles) && has_roles_mask_accessors?
75
+ roles options[:roles] if options.key?(:roles) && has_roles_mask_accessors?
75
76
 
76
77
  add_role_scopes(prefix: options[:prefix]) if respond_to?(:add_role_scopes, true)
77
78
  end
@@ -81,18 +82,16 @@ module Canard
81
82
  # This is overridden by the ActiveRecord adapter as the attribute accessors
82
83
  # don't show up in instance_methods.
83
84
  def has_roles_mask_accessors?
84
- instance_method_names = instance_methods.map { |method_name| method_name.to_s }
85
- [roles_attribute_name.to_s, "#{roles_attribute_name}="].all? do |accessor|
85
+ instance_method_names = instance_methods.map(&:to_s)
86
+ [roles_attribute_name.to_s, "#{roles_attribute_name}="].all? do |accessor|
86
87
  instance_method_names.include?(accessor)
87
88
  end
88
89
  end
89
90
 
90
- module InstanceMethods
91
-
91
+ module InstanceMethods # :nodoc:
92
92
  def ability
93
93
  @ability ||= Ability.new(self)
94
94
  end
95
-
96
95
  end
97
96
  end
98
97
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Canard
2
- VERSION = "0.5.0.pre"
4
+ VERSION = '0.6.0.pre'
3
5
  end
@@ -1,43 +1,45 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/inflector'
2
4
 
3
- class AbilityDefinition
4
-
5
+ class AbilityDefinition # :nodoc:
5
6
  attr_accessor :cans, :cannots
6
-
7
+
7
8
  def self.parse(definitions)
8
9
  @@ability_definitions ||= {}
9
- limitation, ability_list, model_list = *definitions.split(':')
10
- ability_names, model_names = extract(ability_list), extract(model_list)
10
+ limitation, ability_list, model_list = definitions.split(':')
11
+ ability_names = extract(ability_list)
12
+ model_names = extract(model_list)
11
13
  model_names.each do |model_name|
12
14
  definition = @@ability_definitions[model_name] || AbilityDefinition.new
13
15
  definition.merge(limitation.pluralize, ability_names)
14
16
  @@ability_definitions[model_name] = definition
15
17
  end
16
18
  end
17
-
19
+
18
20
  def self.extract(string)
19
- return *string.gsub(/[\[\]\s]/, '').split(',')
21
+ string.gsub(/[\[\]\s]/, '').split(',')
20
22
  end
21
-
23
+
22
24
  def self.models
23
25
  @@ability_definitions
24
26
  end
25
-
27
+
26
28
  def initialize
27
- @cans, @cannots = [], []
29
+ @cans = []
30
+ @cannots = []
28
31
  end
29
-
32
+
30
33
  def merge(limitation, ability_names)
31
34
  combined_ability_names = instance_variable_get("@#{limitation}") | ability_names
32
35
  instance_variable_set("@#{limitation}", combined_ability_names)
33
36
  end
34
-
37
+
35
38
  def can
36
39
  @cans
37
40
  end
38
-
41
+
39
42
  def cannot
40
43
  @cannots
41
44
  end
42
-
43
45
  end