cantango-core 0.1.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 (100) hide show
  1. data/.document +5 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +54 -0
  4. data/Gemfile.lock +231 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.mdown +90 -0
  7. data/Rakefile +48 -0
  8. data/VERSION +1 -0
  9. data/cantango-core.gemspec +177 -0
  10. data/lib/cantango/ability.rb +5 -0
  11. data/lib/cantango/ability/base.rb +61 -0
  12. data/lib/cantango/ability/cache.rb +7 -0
  13. data/lib/cantango/ability/cache/key.rb +38 -0
  14. data/lib/cantango/ability/cached.rb +28 -0
  15. data/lib/cantango/ability/executor.rb +7 -0
  16. data/lib/cantango/ability/executor/base.rb +53 -0
  17. data/lib/cantango/ability/executor/cache_mode.rb +33 -0
  18. data/lib/cantango/ability/executor/modes.rb +52 -0
  19. data/lib/cantango/ability/executor/no_cache_mode.rb +17 -0
  20. data/lib/cantango/ability/helper.rb +11 -0
  21. data/lib/cantango/ability/helper/account.rb +13 -0
  22. data/lib/cantango/ability/helper/engine.rb +32 -0
  23. data/lib/cantango/ability/helper/role.rb +21 -0
  24. data/lib/cantango/ability/helper/role_group.rb +21 -0
  25. data/lib/cantango/ability/helper/user.rb +18 -0
  26. data/lib/cantango/cancan/rule.rb +6 -0
  27. data/lib/cantango/core.rb +84 -0
  28. data/lib/cantango/engine.rb +39 -0
  29. data/lib/cantango/filter.rb +5 -0
  30. data/lib/cantango/filter/base.rb +31 -0
  31. data/lib/cantango/helpers.rb +5 -0
  32. data/lib/cantango/helpers/debug.rb +10 -0
  33. data/lib/cantango/loader.rb +5 -0
  34. data/lib/cantango/loader/yaml.rb +33 -0
  35. data/lib/cantango/macros.rb +11 -0
  36. data/lib/cantango/macros/account.rb +14 -0
  37. data/lib/cantango/macros/user.rb +16 -0
  38. data/lib/cantango/model.rb +5 -0
  39. data/lib/cantango/model/guest.rb +25 -0
  40. data/lib/cantango/rails.rb +7 -0
  41. data/lib/cantango/rails/engine.rb +63 -0
  42. data/lib/cantango/rails/helpers/base_helper.rb +29 -0
  43. data/lib/cantango/rails/helpers/controller_helper.rb +17 -0
  44. data/lib/cantango/rails/helpers/rest_helper.rb +76 -0
  45. data/lib/cantango/rails/helpers/view_helper.rb +17 -0
  46. data/lib/cantango/rails/railtie.rb +7 -0
  47. data/lib/cantango/rspec.rb +1 -0
  48. data/lib/cantango/rspec/config.rb +3 -0
  49. data/lib/cantango/rspec/matchers.rb +1 -0
  50. data/lib/cantango/rspec/matchers/be_allowed_to.rb +28 -0
  51. data/lib/cantango/rules.rb +8 -0
  52. data/lib/cantango/rules/adaptor.rb +37 -0
  53. data/lib/cantango/rules/adaptor/active_record.rb +10 -0
  54. data/lib/cantango/rules/adaptor/data_mapper.rb +11 -0
  55. data/lib/cantango/rules/adaptor/generic.rb +16 -0
  56. data/lib/cantango/rules/adaptor/mongo.rb +19 -0
  57. data/lib/cantango/rules/adaptor/mongo_mapper.rb +10 -0
  58. data/lib/cantango/rules/adaptor/mongoid.rb +9 -0
  59. data/lib/cantango/rules/adaptor/relational.rb +13 -0
  60. data/lib/cantango/rules/dsl.rb +24 -0
  61. data/lib/cantango/rules/relation.rb +67 -0
  62. data/lib/cantango/rules/rule_class.rb +11 -0
  63. data/lib/cantango/rules/scope.rb +24 -0
  64. data/lib/cantango/scope.rb +5 -0
  65. data/lib/cantango/scope/ability.rb +20 -0
  66. data/lib/generators/cantango/install/install_generator.rb +37 -0
  67. data/lib/generators/cantango/install/templates/cantango.rb +4 -0
  68. data/lib/generators/cantango/install/templates/categories.yml +0 -0
  69. data/lib/generators/cantango/install/templates/permissions.yml +6 -0
  70. data/spec/cantango/ability/base_spec.rb +73 -0
  71. data/spec/cantango/ability/cached_spec.rb +0 -0
  72. data/spec/cantango/ability/executor/base2.rb +75 -0
  73. data/spec/cantango/ability/executor/base_spec.rb +67 -0
  74. data/spec/cantango/ability/executor/cache_mode_spec.rb +77 -0
  75. data/spec/cantango/ability/executor/modes_spec.rb +68 -0
  76. data/spec/cantango/ability/executor/no_cache_mode_spec.rb +0 -0
  77. data/spec/cantango/cancan/rule_spec.rb +0 -0
  78. data/spec/cantango/core_spec.rb +9 -0
  79. data/spec/cantango/engine_spec.rb +0 -0
  80. data/spec/cantango/filter/base_spec.rb +0 -0
  81. data/spec/cantango/helpers/debug_spec.rb +0 -0
  82. data/spec/cantango/loader/yaml_spec.rb +0 -0
  83. data/spec/cantango/macros/account_spec.rb +0 -0
  84. data/spec/cantango/macros/user_spec.rb +0 -0
  85. data/spec/cantango/rspec/be_allowed_to_spec.rb +0 -0
  86. data/spec/cantango/rules/adaptor/active_record_spec.rb +0 -0
  87. data/spec/cantango/rules/adaptor/data_mapper_spec.rb +0 -0
  88. data/spec/cantango/rules/adaptor/mongo_mapper_spec.rb +0 -0
  89. data/spec/cantango/rules/adaptor/mongoid_spec.rb +0 -0
  90. data/spec/cantango/rules/adaptor_spec.rb +0 -0
  91. data/spec/cantango/rules/dsl_spec.rb +0 -0
  92. data/spec/cantango/rules/relation_spec.rb +0 -0
  93. data/spec/cantango/rules/rule_class_spec.rb +0 -0
  94. data/spec/cantango/rules/scope_spec.rb +0 -0
  95. data/spec/cantango/rules_spec.rb +55 -0
  96. data/spec/cantango/scope/ability_spec.rb +0 -0
  97. data/spec/cantango_spec.rb +0 -0
  98. data/spec/generators/cantango/install_generator_spec.rb +42 -0
  99. data/spec/spec_helper.rb +9 -0
  100. metadata +310 -0
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,177 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "cantango-core"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kristian Mandrup", "Stanislaw Pankevich"]
12
+ s.date = "2011-11-25"
13
+ s.description = "Define your permission rules as role- or role group specific permits.\nIntegrates well with multiple Devise user acounts.\nIncludes rules caching.\nStore permissions in yaml file or key-value store"
14
+ s.email = "kmandrup@gmail.com, s.pankevich@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.mdown"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.mdown",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "cantango-core.gemspec",
29
+ "lib/cantango/ability.rb",
30
+ "lib/cantango/ability/base.rb",
31
+ "lib/cantango/ability/cache.rb",
32
+ "lib/cantango/ability/cache/key.rb",
33
+ "lib/cantango/ability/cached.rb",
34
+ "lib/cantango/ability/executor.rb",
35
+ "lib/cantango/ability/executor/base.rb",
36
+ "lib/cantango/ability/executor/cache_mode.rb",
37
+ "lib/cantango/ability/executor/modes.rb",
38
+ "lib/cantango/ability/executor/no_cache_mode.rb",
39
+ "lib/cantango/ability/helper.rb",
40
+ "lib/cantango/ability/helper/account.rb",
41
+ "lib/cantango/ability/helper/engine.rb",
42
+ "lib/cantango/ability/helper/role.rb",
43
+ "lib/cantango/ability/helper/role_group.rb",
44
+ "lib/cantango/ability/helper/user.rb",
45
+ "lib/cantango/cancan/rule.rb",
46
+ "lib/cantango/core.rb",
47
+ "lib/cantango/engine.rb",
48
+ "lib/cantango/filter.rb",
49
+ "lib/cantango/filter/base.rb",
50
+ "lib/cantango/helpers.rb",
51
+ "lib/cantango/helpers/debug.rb",
52
+ "lib/cantango/loader.rb",
53
+ "lib/cantango/loader/yaml.rb",
54
+ "lib/cantango/macros.rb",
55
+ "lib/cantango/macros/account.rb",
56
+ "lib/cantango/macros/user.rb",
57
+ "lib/cantango/model.rb",
58
+ "lib/cantango/model/guest.rb",
59
+ "lib/cantango/rails.rb",
60
+ "lib/cantango/rails/engine.rb",
61
+ "lib/cantango/rails/helpers/base_helper.rb",
62
+ "lib/cantango/rails/helpers/controller_helper.rb",
63
+ "lib/cantango/rails/helpers/rest_helper.rb",
64
+ "lib/cantango/rails/helpers/view_helper.rb",
65
+ "lib/cantango/rails/railtie.rb",
66
+ "lib/cantango/rspec.rb",
67
+ "lib/cantango/rspec/config.rb",
68
+ "lib/cantango/rspec/matchers.rb",
69
+ "lib/cantango/rspec/matchers/be_allowed_to.rb",
70
+ "lib/cantango/rules.rb",
71
+ "lib/cantango/rules/adaptor.rb",
72
+ "lib/cantango/rules/adaptor/active_record.rb",
73
+ "lib/cantango/rules/adaptor/data_mapper.rb",
74
+ "lib/cantango/rules/adaptor/generic.rb",
75
+ "lib/cantango/rules/adaptor/mongo.rb",
76
+ "lib/cantango/rules/adaptor/mongo_mapper.rb",
77
+ "lib/cantango/rules/adaptor/mongoid.rb",
78
+ "lib/cantango/rules/adaptor/relational.rb",
79
+ "lib/cantango/rules/dsl.rb",
80
+ "lib/cantango/rules/relation.rb",
81
+ "lib/cantango/rules/rule_class.rb",
82
+ "lib/cantango/rules/scope.rb",
83
+ "lib/cantango/scope.rb",
84
+ "lib/cantango/scope/ability.rb",
85
+ "lib/generators/cantango/install/install_generator.rb",
86
+ "lib/generators/cantango/install/templates/cantango.rb",
87
+ "lib/generators/cantango/install/templates/categories.yml",
88
+ "lib/generators/cantango/install/templates/permissions.yml",
89
+ "spec/cantango/ability/base_spec.rb",
90
+ "spec/cantango/ability/cached_spec.rb",
91
+ "spec/cantango/ability/executor/base2.rb",
92
+ "spec/cantango/ability/executor/base_spec.rb",
93
+ "spec/cantango/ability/executor/cache_mode_spec.rb",
94
+ "spec/cantango/ability/executor/modes_spec.rb",
95
+ "spec/cantango/ability/executor/no_cache_mode_spec.rb",
96
+ "spec/cantango/cancan/rule_spec.rb",
97
+ "spec/cantango/core_spec.rb",
98
+ "spec/cantango/engine_spec.rb",
99
+ "spec/cantango/filter/base_spec.rb",
100
+ "spec/cantango/helpers/debug_spec.rb",
101
+ "spec/cantango/loader/yaml_spec.rb",
102
+ "spec/cantango/macros/account_spec.rb",
103
+ "spec/cantango/macros/user_spec.rb",
104
+ "spec/cantango/rspec/be_allowed_to_spec.rb",
105
+ "spec/cantango/rules/adaptor/active_record_spec.rb",
106
+ "spec/cantango/rules/adaptor/data_mapper_spec.rb",
107
+ "spec/cantango/rules/adaptor/mongo_mapper_spec.rb",
108
+ "spec/cantango/rules/adaptor/mongoid_spec.rb",
109
+ "spec/cantango/rules/adaptor_spec.rb",
110
+ "spec/cantango/rules/dsl_spec.rb",
111
+ "spec/cantango/rules/relation_spec.rb",
112
+ "spec/cantango/rules/rule_class_spec.rb",
113
+ "spec/cantango/rules/scope_spec.rb",
114
+ "spec/cantango/rules_spec.rb",
115
+ "spec/cantango/scope/ability_spec.rb",
116
+ "spec/cantango_spec.rb",
117
+ "spec/generators/cantango/install_generator_spec.rb",
118
+ "spec/spec_helper.rb"
119
+ ]
120
+ s.homepage = "http://github.com/kristianmandrup/cantango"
121
+ s.licenses = ["MIT"]
122
+ s.require_paths = ["lib"]
123
+ s.rubygems_version = "1.8.10"
124
+ s.summary = "CanCan extension with role oriented permission management and more"
125
+
126
+ if s.respond_to? :specification_version then
127
+ s.specification_version = 3
128
+
129
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
130
+ s.add_runtime_dependency(%q<rails>, [">= 3.0.1"])
131
+ s.add_runtime_dependency(%q<cancan>, [">= 1.4"])
132
+ s.add_runtime_dependency(%q<sugar-high>, [">= 0.6.0"])
133
+ s.add_runtime_dependency(%q<sweetloader>, ["~> 0.1.0"])
134
+ s.add_runtime_dependency(%q<hashie>, [">= 0"])
135
+ s.add_development_dependency(%q<rspec-rails>, [">= 2.6.1"])
136
+ s.add_development_dependency(%q<forgery>, [">= 0.3"])
137
+ s.add_development_dependency(%q<factory_girl>, [">= 0"])
138
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
139
+ s.add_development_dependency(%q<rspec>, [">= 2.6.0"])
140
+ s.add_development_dependency(%q<jeweler>, [">= 1.6.4"])
141
+ s.add_development_dependency(%q<bundler>, [">= 1.1.rc"])
142
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
143
+ s.add_development_dependency(%q<rake>, [">= 0.9.2.2"])
144
+ else
145
+ s.add_dependency(%q<rails>, [">= 3.0.1"])
146
+ s.add_dependency(%q<cancan>, [">= 1.4"])
147
+ s.add_dependency(%q<sugar-high>, [">= 0.6.0"])
148
+ s.add_dependency(%q<sweetloader>, ["~> 0.1.0"])
149
+ s.add_dependency(%q<hashie>, [">= 0"])
150
+ s.add_dependency(%q<rspec-rails>, [">= 2.6.1"])
151
+ s.add_dependency(%q<forgery>, [">= 0.3"])
152
+ s.add_dependency(%q<factory_girl>, [">= 0"])
153
+ s.add_dependency(%q<sqlite3>, [">= 0"])
154
+ s.add_dependency(%q<rspec>, [">= 2.6.0"])
155
+ s.add_dependency(%q<jeweler>, [">= 1.6.4"])
156
+ s.add_dependency(%q<bundler>, [">= 1.1.rc"])
157
+ s.add_dependency(%q<rdoc>, [">= 0"])
158
+ s.add_dependency(%q<rake>, [">= 0.9.2.2"])
159
+ end
160
+ else
161
+ s.add_dependency(%q<rails>, [">= 3.0.1"])
162
+ s.add_dependency(%q<cancan>, [">= 1.4"])
163
+ s.add_dependency(%q<sugar-high>, [">= 0.6.0"])
164
+ s.add_dependency(%q<sweetloader>, ["~> 0.1.0"])
165
+ s.add_dependency(%q<hashie>, [">= 0"])
166
+ s.add_dependency(%q<rspec-rails>, [">= 2.6.1"])
167
+ s.add_dependency(%q<forgery>, [">= 0.3"])
168
+ s.add_dependency(%q<factory_girl>, [">= 0"])
169
+ s.add_dependency(%q<sqlite3>, [">= 0"])
170
+ s.add_dependency(%q<rspec>, [">= 2.6.0"])
171
+ s.add_dependency(%q<jeweler>, [">= 1.6.4"])
172
+ s.add_dependency(%q<bundler>, [">= 1.1.rc"])
173
+ s.add_dependency(%q<rdoc>, [">= 0"])
174
+ s.add_dependency(%q<rake>, [">= 0.9.2.2"])
175
+ end
176
+ end
177
+
@@ -0,0 +1,5 @@
1
+ module CanTango
2
+ module Ability
3
+ autoload_modules :Base, :Cache, :Cached, :Executor, :Helper
4
+ end
5
+ end
@@ -0,0 +1,61 @@
1
+ module CanTango
2
+ module Ability
3
+ class Base
4
+ include CanCan::Ability
5
+
6
+ attr_reader :options, :candidate
7
+
8
+ # Equivalent to a CanCan Ability#initialize call
9
+ # which executes all the permission logic
10
+ def initialize candidate, options = {}
11
+ raise "Candidate must be something!" if !candidate
12
+ @candidate, @options = candidate, options
13
+
14
+ clear_rules!
15
+ permit_rules
16
+
17
+ execute_engines! if engines_on?
18
+ end
19
+
20
+ def cached?
21
+ false
22
+ end
23
+
24
+ def rules
25
+ @rules
26
+ end
27
+
28
+ # developer can add rules here to be included in all subclasses!
29
+ def permit_rules
30
+ end
31
+
32
+ def clear_rules!
33
+ @rules ||= default_rules
34
+ end
35
+
36
+ def session
37
+ @session = options[:session] || {} # seperate session cache for each type of user?
38
+ end
39
+
40
+ def subject
41
+ return candidate.active_user if masquerade_user?
42
+ return candidate.active_account if masquerade_account?
43
+ candidate
44
+ end
45
+
46
+ def config
47
+ CanTango.config
48
+ end
49
+
50
+ Helper.modules.each do |name|
51
+ include "CanTango::Ability::Helper::#{name.to_s.camelize}".constantize
52
+ end
53
+
54
+ protected
55
+
56
+ def default_rules
57
+ []
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,7 @@
1
+ module CanTango
2
+ module Ability
3
+ module Cache
4
+ autoload_modules :Key
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ module CanTango
2
+ module Ability
3
+ module Cache
4
+ class Key
5
+ attr_reader :user, :subject
6
+
7
+ def initialize user, subject = nil
8
+ @user = user
9
+ @subject = subject || user
10
+ end
11
+
12
+ def self.create_for ability
13
+ self.new ability.user, ability.subject
14
+ end
15
+
16
+ def value
17
+ raise "No key could be generated for User:#{user.inspect} and Subject:#{subject} - key field: #{user_key_field}" if !user_key
18
+ @value ||= user_key.hash
19
+ end
20
+
21
+ def to_s
22
+ "key hash: #{value}"
23
+ end
24
+
25
+ protected
26
+
27
+ def user_key
28
+ # raise "#{user.class} must have a method ##{user_key_field}. You can configure this with CanTango.config#user.unique_key_field" if !user.respond_to?(user_key_field)
29
+ user.send(user_key_field) if user.respond_to? user_key_field
30
+ end
31
+
32
+ def user_key_field
33
+ CanTango.config.user.unique_key_field || :email
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ module CanTango
2
+ module Ability
3
+ class Cached < Base
4
+ # Equivalent to a CanCan Ability#initialize call
5
+ # which executes all the permission logic
6
+ def initialize candidate, options = {}
7
+ raise "Candidate must be something!" if !candidate
8
+ @candidate, @options = candidate, options
9
+
10
+ # return if cached_rules?
11
+
12
+ clear_rules!
13
+ permit_rules
14
+
15
+ execute_engines! if engines_on?
16
+
17
+ # cache_rules!
18
+ end
19
+
20
+ def cached?
21
+ true
22
+ end
23
+
24
+ def permit_rules
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ module CanTango
2
+ module Ability
3
+ module Executor
4
+ autoload_modules :Base, :CacheMode, :NoCacheMode, :Modes
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ module CanTango
2
+ module Ability
3
+ module Executor
4
+ class Base
5
+ include CanTango::Helpers::Debug
6
+
7
+ delegate :session, :user, :subject, :candidate, :cached?, :to => :ability
8
+
9
+ def execute!
10
+ return if !valid?
11
+ start_execute
12
+ return if cached? # rule set already loaded
13
+
14
+ clear_rules!
15
+ permit_rules
16
+
17
+ end_execute
18
+ rules # return rule set
19
+ end
20
+
21
+ def rules
22
+ @rules ||= []
23
+ end
24
+
25
+ def clear_rules!
26
+ @rules ||= []
27
+ end
28
+
29
+ def permit_rules
30
+ raise NotImplementedError
31
+ end
32
+
33
+ def cached?
34
+ false
35
+ end
36
+
37
+ protected
38
+
39
+ def start_execute
40
+ debug "Executing base Ability"
41
+ end
42
+
43
+ def end_execute
44
+ debug "DONE"
45
+ end
46
+
47
+ def key_method_names
48
+ []
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ module CanTango
2
+ class Ability
3
+ module Executor
4
+ class CachedMode < Base
5
+ include CanTango::Ability::CacheHelpers
6
+
7
+ # FIX! no reason for double cache check!
8
+ def cached?
9
+ @rules = cached_rules if cached_rules? && caching_on?
10
+ end
11
+
12
+ def cache
13
+ @cache ||= cache_class.new self, :cache_key => cache_key, :key_method_names => key_method_names
14
+ end
15
+
16
+ protected
17
+
18
+ def cache_class
19
+ CanTango::Ability::Cache
20
+ end
21
+
22
+ def start_execute
23
+ debug "Executing cached ability"
24
+ end
25
+
26
+ def end_execute
27
+ cache_rules! if caching_on?
28
+ debug "DONE"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,52 @@
1
+ module CanTango
2
+ module Ability
3
+ module Executor
4
+ class Modes < Base
5
+ def initialize candidate, options = {}
6
+ raise "Candidate must be something!" if !candidate
7
+ @candidate, @options = [candidate, options]
8
+ calculate_modal_rules.normalize!
9
+ end
10
+
11
+ def rules
12
+ @rules ||= []
13
+ end
14
+
15
+ def modal_rules mode
16
+ mode?(mode) ? get_ability(mode).rules : []
17
+ end
18
+
19
+ protected
20
+
21
+ def calculate_modal_rules
22
+ @rules = modes.inject([]) do |result, mode|
23
+ result = result + modal_rules(mode)
24
+ result
25
+ end
26
+ self
27
+ end
28
+
29
+ def normalize!
30
+ rules.flatten!
31
+ rules.compact!
32
+ end
33
+
34
+ def get_ability mode
35
+ ability_class_for(mode).new candidate, options
36
+ end
37
+
38
+ def ability_class_for mode
39
+ mode == :cache ? CanTango::Ability::Cached : CanTango::Ability::NonCached
40
+ end
41
+
42
+ def mode? mode
43
+ modes.include?(mode)
44
+ end
45
+
46
+ def modes
47
+ CanTango.config.ability.modes
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end