role_fu 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.
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RoleFu
4
+ # Resourceable concern - provides resource management for models with roles
5
+ module Resourceable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :roles,
10
+ as: :resource,
11
+ dependent: :destroy,
12
+ class_name: RoleFu.configuration.role_class_name
13
+ end
14
+
15
+ module ClassMethods
16
+ # Find roles defined on any instance of this resource class
17
+ # @param role_name [String, Symbol, nil] Filter by role name
18
+ # @param user [User, nil] Filter by user
19
+ # @return [ActiveRecord::Relation] Roles
20
+ def find_roles(role_name = nil, user = nil)
21
+ RoleFu.role_class.table_name
22
+ query = RoleFu.role_class.where(resource_type: name)
23
+ query = query.where(name: role_name.to_s) if role_name
24
+ query = query.joins(:users).where(RoleFu.user_class.table_name => {id: user.id}) if user
25
+ query
26
+ end
27
+
28
+ # Find resources that have a specific role applied (to a user)
29
+ # @param role_name [String, Symbol] The role name
30
+ # @param user [User, nil] Filter by specific user having the role
31
+ # @return [ActiveRecord::Relation] Resources
32
+ def with_role(role_name, user = nil)
33
+ role_table = RoleFu.role_class.table_name
34
+
35
+ query = joins(:roles).where(role_table => {name: role_name.to_s})
36
+
37
+ if user
38
+ query = query.joins(roles: :users).where(RoleFu.user_class.table_name => {id: user.id})
39
+ end
40
+
41
+ query.distinct
42
+ end
43
+
44
+ # Find resources that do NOT have a specific role applied
45
+ # @param role_name [String, Symbol] The role name
46
+ # @param user [User, nil] Filter by user
47
+ # @return [ActiveRecord::Relation] Resources
48
+ def without_role(role_name, user = nil)
49
+ where.not(id: with_role(role_name, user).select(:id))
50
+ end
51
+ end
52
+
53
+ # Get roles applied to this resource instance (plus global class-level roles if any - though RoleFu focuses on instance roles)
54
+ # @return [ActiveRecord::Relation] Roles
55
+ def applied_roles
56
+ roles
57
+ end
58
+
59
+ # Get users with a specific role on this resource
60
+ # @param role_name [String, Symbol] The role name
61
+ # @return [ActiveRecord::Relation] Relation of users
62
+ def users_with_role(role_name)
63
+ role_table = RoleFu.role_class.table_name
64
+ user_class.joins(:roles)
65
+ .where(role_table => {name: role_name.to_s, resource_type: self.class.name, resource_id: id})
66
+ .distinct
67
+ end
68
+
69
+ # Get users with any role on this resource
70
+ # @param role_names [Array<String, Symbol>] Array of role names
71
+ # @return [ActiveRecord::Relation] Relation of users
72
+ def users_with_any_role(*role_names)
73
+ role_table = RoleFu.role_class.table_name
74
+ user_class.joins(:roles)
75
+ .where(role_table => {name: role_names.flatten.map(&:to_s), resource_type: self.class.name, resource_id: id})
76
+ .distinct
77
+ end
78
+
79
+ # Get users with all specified roles on this resource
80
+ # @param role_names [Array<String, Symbol>] Array of role names
81
+ # @return [Array<User>] Array of users
82
+ def users_with_all_roles(*role_names)
83
+ role_names = role_names.flatten.map(&:to_s)
84
+ role_table = RoleFu.role_class.table_name
85
+
86
+ user_class.joins(:roles)
87
+ .where(role_table => {name: role_names, resource_type: self.class.name, resource_id: id})
88
+ .group("#{user_class.table_name}.#{user_class.primary_key}")
89
+ .having("COUNT(DISTINCT #{role_table}.name) = ?", role_names.size)
90
+ .distinct
91
+ end
92
+
93
+ # Get all users with any role on this resource
94
+ # @return [ActiveRecord::Relation] Relation of users
95
+ def users_with_roles
96
+ role_table = RoleFu.role_class.table_name
97
+ user_class.joins(:roles)
98
+ .where(role_table => {resource_type: self.class.name, resource_id: id})
99
+ .distinct
100
+ end
101
+
102
+ # Get all role names defined for this resource
103
+ # @return [Array<String>] Array of role names
104
+ def available_roles
105
+ roles.pluck(:name).uniq
106
+ end
107
+
108
+ # Check if resource has any users with a specific role
109
+ # @param role_name [String, Symbol] The role name
110
+ # @return [Boolean] true if any user has this role
111
+ def has_role?(role_name)
112
+ roles.exists?(name: role_name.to_s)
113
+ end
114
+
115
+ # Count users with a specific role
116
+ # @param role_name [String, Symbol] The role name
117
+ # @return [Integer] Number of users
118
+ def count_users_with_role(role_name)
119
+ users_with_role(role_name).count
120
+ end
121
+
122
+ # Check if a specific user has a role on this resource
123
+ # @param user [User] The user
124
+ # @param role_name [String, Symbol] The role name
125
+ # @return [Boolean] true if user has the role
126
+ def user_has_role?(user, role_name)
127
+ return false if user.nil?
128
+
129
+ user.has_role?(role_name, self)
130
+ end
131
+
132
+ # Add a role to a user on this resource
133
+ # @param user [User] The user
134
+ # @param role_name [String, Symbol] The role name
135
+ # @return [Role] The role
136
+ def add_role_to_user(user, role_name)
137
+ user.add_role(role_name, self)
138
+ end
139
+
140
+ # Remove a role from a user on this resource
141
+ # @param user [User] The user
142
+ # @param role_name [String, Symbol] The role name
143
+ # @return [Array<Role>] The removed roles
144
+ def remove_role_from_user(user, role_name)
145
+ user.remove_role(role_name, self)
146
+ end
147
+
148
+ private
149
+
150
+ # Get the User class
151
+ # @return [Class] User class
152
+ def user_class
153
+ RoleFu.user_class
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RoleFu
4
+ # Module for the Role model
5
+ module Role
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :role_assignments,
10
+ class_name: RoleFu.configuration.role_assignment_class_name,
11
+ dependent: :destroy
12
+ has_many :users,
13
+ through: :role_assignments,
14
+ class_name: RoleFu.configuration.user_class_name
15
+
16
+ belongs_to :resource, polymorphic: true, optional: true
17
+
18
+ validates :name, presence: true, uniqueness: {scope: [:resource_type, :resource_id]}
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RoleFu
4
+ # Module for the RoleAssignment model
5
+ module RoleAssignment
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ belongs_to :user, class_name: RoleFu.configuration.user_class_name
10
+ belongs_to :role, class_name: RoleFu.configuration.role_class_name
11
+
12
+ scope :global_roles, -> { joins(:role).where(RoleFu.role_class.table_name => {resource_type: nil, resource_id: nil}) }
13
+ scope :resource_specific, -> { joins(:role).where.not(RoleFu.role_class.table_name => {resource_type: nil}) }
14
+
15
+ after_destroy :cleanup_orphaned_role
16
+ end
17
+
18
+ private
19
+
20
+ def cleanup_orphaned_role
21
+ # If this record is being destroyed as part of role destruction,
22
+ # do not try to destroy the same role again.
23
+ return if destroyed_by_association&.active_record == RoleFu.role_class
24
+
25
+ # Delete role if it has no more users assigned
26
+ return if role.destroyed?
27
+
28
+ role.destroy if role.role_assignments.none?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,290 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RoleFu
4
+ # Roleable concern - provides role management for User model
5
+ module Roleable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :role_assignments,
10
+ class_name: RoleFu.configuration.role_assignment_class_name,
11
+ dependent: :destroy
12
+ has_many :roles,
13
+ through: :role_assignments,
14
+ class_name: RoleFu.configuration.role_class_name
15
+
16
+ class_attribute :role_fu_callbacks, default: {}
17
+ end
18
+
19
+ module ClassMethods
20
+ def role_fu_options(options = {})
21
+ self.role_fu_callbacks = options.slice(:before_add, :after_add, :before_remove, :after_remove)
22
+ end
23
+
24
+ # Find users with a specific role
25
+ # @param role_name [String, Symbol] The name of the role
26
+ # @param resource [ActiveRecord::Base, Class, nil, :any] The resource
27
+ # @return [ActiveRecord::Relation] Users with the role
28
+ def with_role(role_name, resource = nil)
29
+ role_table = RoleFu.role_class.table_name
30
+ RoleFu.role_assignment_class.table_name
31
+
32
+ query = joins(:roles).where(role_table => {name: role_name.to_s})
33
+
34
+ if resource.nil?
35
+ query.where(role_table => {resource_type: nil, resource_id: nil})
36
+ elsif resource == :any
37
+ query
38
+ elsif resource.is_a?(Class)
39
+ query.where(role_table => {resource_type: resource.to_s, resource_id: nil})
40
+ else
41
+ query.where(role_table => {resource_type: resource.class.name, resource_id: resource.id})
42
+ end.distinct
43
+ end
44
+
45
+ # Find users without a specific role
46
+ # @param role_name [String, Symbol] The name of the role
47
+ # @param resource [ActiveRecord::Base, Class, nil, :any] The resource
48
+ # @return [ActiveRecord::Relation] Users without the role
49
+ def without_role(role_name, resource = nil)
50
+ where.not(id: with_role(role_name, resource).select(:id))
51
+ end
52
+
53
+ # Find users with any of the specified roles
54
+ # @param args [Array<String, Symbol, Hash>] Roles to check
55
+ # @return [ActiveRecord::Relation] Users with any of the roles
56
+ def with_any_role(*args)
57
+ ids = []
58
+ args.each do |arg|
59
+ ids += if arg.is_a?(Hash)
60
+ with_role(arg[:name], arg[:resource]).pluck(:id)
61
+ else
62
+ with_role(arg).pluck(:id)
63
+ end
64
+ end
65
+ where(id: ids.uniq)
66
+ end
67
+
68
+ # Find users with all of the specified roles
69
+ # @param args [Array<String, Symbol, Hash>] Roles to check
70
+ # @return [ActiveRecord::Relation] Users with all of the roles
71
+ def with_all_roles(*args)
72
+ ids = nil
73
+ args.each do |arg|
74
+ current_ids = if arg.is_a?(Hash)
75
+ with_role(arg[:name], arg[:resource]).pluck(:id)
76
+ else
77
+ with_role(arg).pluck(:id)
78
+ end
79
+ ids = ids.nil? ? current_ids : ids & current_ids
80
+ return none if ids.empty?
81
+ end
82
+ where(id: ids)
83
+ end
84
+ end
85
+
86
+ # Add a role to the user
87
+ # @param role_name [String, Symbol] The name of the role
88
+ # @param resource [ActiveRecord::Base, Class, nil] The resource (organization, etc.) or nil for global role
89
+ # @return [Role] The role that was added
90
+ def add_role(role_name, resource = nil)
91
+ role = find_or_create_role(role_name, resource)
92
+
93
+ return role if roles.include?(role)
94
+
95
+ run_role_fu_callback(:before_add, role)
96
+ roles << role
97
+ run_role_fu_callback(:after_add, role)
98
+
99
+ role
100
+ end
101
+ alias_method :grant, :add_role
102
+
103
+ # Remove a role from the user
104
+ # @param role_name [String, Symbol] The name of the role
105
+ # @param resource [ActiveRecord::Base, Class, nil] The resource or nil for global role
106
+ # @return [Array<Role>] The roles that were removed
107
+ def remove_role(role_name, resource = nil)
108
+ roles_to_remove_relation = find_roles(role_name, resource)
109
+ return [] if roles_to_remove_relation.empty?
110
+
111
+ # Materialize before removing associations, because removing may trigger cleanup that deletes the role.
112
+ removed_roles = roles_to_remove_relation.to_a
113
+
114
+ removed_roles.each do |role|
115
+ run_role_fu_callback(:before_remove, role)
116
+ role_assignments.where(role_id: role.id).destroy_all
117
+ run_role_fu_callback(:after_remove, role)
118
+ end
119
+
120
+ removed_roles
121
+ end
122
+ alias_method :revoke, :remove_role
123
+
124
+ # Check if user has a specific role
125
+ # @param role_name [String, Symbol] The name of the role
126
+ # @param resource [ActiveRecord::Base, Class, nil, :any] The resource, nil for global, or :any for any resource
127
+ # @return [Boolean] true if user has the role
128
+ def has_role?(role_name, resource = nil)
129
+ return false if role_name.nil?
130
+
131
+ if resource == :any
132
+ roles.exists?(name: role_name.to_s)
133
+ else
134
+ find_roles(role_name, resource).any?
135
+ end
136
+ end
137
+
138
+ # Check if user has a specific role strictly (resource match must be exact, no globals overriding)
139
+ # Note: In RoleFu, has_role? is already strict about resource matching unless :any is passed,
140
+ # but this method explicitly bypasses any future global-fallback logic if we were to add it.
141
+ # Included for API compatibility.
142
+ # @param role_name [String, Symbol] The name of the role
143
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
144
+ # @return [Boolean] true if user has the role strictly
145
+ def has_strict_role?(role_name, resource = nil)
146
+ has_role?(role_name, resource)
147
+ end
148
+
149
+ # Check if user only has this one role
150
+ # @param role_name [String, Symbol] The name of the role
151
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
152
+ # @return [Boolean] true if user has this role and no others
153
+ def only_has_role?(role_name, resource = nil)
154
+ has_role?(role_name, resource) && roles.count == 1
155
+ end
156
+
157
+ # Check for role using preloaded association to avoid N+1
158
+ def has_cached_role?(role_name, resource = nil)
159
+ role_name = role_name.to_s
160
+ roles.to_a.any? do |role|
161
+ next false unless role.name == role_name
162
+
163
+ if resource == :any
164
+ true
165
+ elsif resource.is_a?(Class)
166
+ role.resource_type == resource.to_s && role.resource_id.nil?
167
+ elsif resource
168
+ role.resource_type == resource.class.name && role.resource_id == resource.id
169
+ else
170
+ role.resource_type.nil? && role.resource_id.nil?
171
+ end
172
+ end
173
+ end
174
+
175
+ # Get all role names for this user
176
+ # @param resource [ActiveRecord::Base, Class, nil] Filter by resource
177
+ # @return [Array<String>] Array of role names
178
+ def roles_name(resource = nil)
179
+ if resource
180
+ roles.where(resource: resource).pluck(:name)
181
+ else
182
+ roles.pluck(:name)
183
+ end
184
+ end
185
+
186
+ # Check if user has only global roles (no resource-specific roles)
187
+ # @return [Boolean] true if user has only global roles
188
+ def has_only_global_roles?
189
+ roles.where.not(resource_type: nil).empty?
190
+ end
191
+
192
+ # Check if user has any role (global or resource-specific)
193
+ # @param resource [ActiveRecord::Base, Class, nil] Filter by resource
194
+ # @return [Boolean] true if user has any role
195
+ def has_any_role?(resource = nil)
196
+ if resource
197
+ roles.exists?(resource: resource)
198
+ else
199
+ roles.exists?
200
+ end
201
+ end
202
+
203
+ # Check if user has all specified roles
204
+ # @param role_names [Array<String, Symbol>] Array of role names
205
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
206
+ # @return [Boolean] true if user has all roles
207
+ def has_all_roles?(*role_names, resource: nil)
208
+ role_names.flatten.all? { |role_name| has_role?(role_name, resource) }
209
+ end
210
+
211
+ # Check if user has any of the specified roles
212
+ # @param role_names [Array<String, Symbol>] Array of role names
213
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
214
+ # @return [Boolean] true if user has any of the roles
215
+ def has_any_role_of?(*role_names, resource: nil)
216
+ role_names.flatten.any? { |role_name| has_role?(role_name, resource) }
217
+ end
218
+
219
+ # Get all resources of a specific type where user has a role
220
+ # @param resource_class [Class] The resource class (e.g., Organization)
221
+ # @return [ActiveRecord::Relation] Relation of resources
222
+ def resources(resource_class)
223
+ resource_class.joins(:roles)
224
+ .merge(roles.where(resource_type: resource_class.name))
225
+ .distinct
226
+ end
227
+
228
+ private
229
+
230
+ # Find or create a role
231
+ # @param role_name [String, Symbol] The role name
232
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
233
+ # @return [Role] The found or created role
234
+ def find_or_create_role(role_name, resource)
235
+ resource_type = resource_type_for(resource)
236
+ resource_id = resource_id_for(resource)
237
+
238
+ RoleFu.role_class.find_or_create_by(
239
+ name: role_name.to_s,
240
+ resource_type: resource_type,
241
+ resource_id: resource_id
242
+ )
243
+ end
244
+
245
+ # Find roles matching criteria
246
+ # @param role_name [String, Symbol] The role name
247
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
248
+ # @return [ActiveRecord::Relation] Relation of matching roles
249
+ def find_roles(role_name, resource)
250
+ query = roles.where(name: role_name.to_s)
251
+
252
+ if resource.is_a?(Class)
253
+ query.where(resource_type: resource.to_s, resource_id: nil)
254
+ elsif resource
255
+ query.where(resource_type: resource.class.name, resource_id: resource.id)
256
+ else
257
+ query.where(resource_type: nil, resource_id: nil)
258
+ end
259
+ end
260
+
261
+ # Get resource type for a resource
262
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
263
+ # @return [String, nil] The resource type
264
+ def resource_type_for(resource)
265
+ return nil if resource.nil?
266
+
267
+ resource.is_a?(Class) ? resource.to_s : resource.class.name
268
+ end
269
+
270
+ # Get resource id for a resource
271
+ # @param resource [ActiveRecord::Base, Class, nil] The resource
272
+ # @return [Integer, nil] The resource id
273
+ def resource_id_for(resource)
274
+ return nil if resource.nil? || resource.is_a?(Class)
275
+
276
+ resource.id
277
+ end
278
+
279
+ def run_role_fu_callback(callback_name, role)
280
+ method_name = role_fu_callbacks[callback_name]
281
+ return unless method_name
282
+
283
+ if method_name.is_a?(Proc)
284
+ instance_exec(role, &method_name)
285
+ elsif respond_to?(method_name, true)
286
+ send(method_name, role)
287
+ end
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RoleFu
4
+ VERSION = "0.1.0"
5
+ end
data/lib/role_fu.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/core_ext/string/inflections"
5
+
6
+ require_relative "role_fu/version"
7
+ require_relative "role_fu/configuration"
8
+ require_relative "role_fu/role"
9
+ require_relative "role_fu/role_assignment"
10
+ require_relative "role_fu/roleable"
11
+ require_relative "role_fu/resourceable"
12
+
13
+ module RoleFu
14
+ class Error < StandardError; end
15
+ # Your code goes here...
16
+ end
data/sig/role_fu.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module RoleFu
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: role_fu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexey Poimtsev
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: appraisal
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: lefthook
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rake
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '13.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '13.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rspec
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: simplecov
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.21'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.21'
96
+ - !ruby/object:Gem::Dependency
97
+ name: sqlite3
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '2.0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '2.0'
110
+ description: RoleFu provides explicit role management with Role and RoleAssignment
111
+ models, avoiding hidden HABTM tables. Supports scopes, resource-specific roles,
112
+ and cleaner architecture.
113
+ email:
114
+ - alexey.poimtsev@gmail.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - Appraisals
120
+ - CHANGELOG.md
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - gemfiles/rails_7.0.gemfile
125
+ - gemfiles/rails_7.0.gemfile.lock
126
+ - gemfiles/rails_7.1.gemfile
127
+ - gemfiles/rails_7.1.gemfile.lock
128
+ - gemfiles/rails_7.2.gemfile
129
+ - gemfiles/rails_7.2.gemfile.lock
130
+ - gemfiles/rails_8.0.gemfile
131
+ - gemfiles/rails_8.0.gemfile.lock
132
+ - gemfiles/rails_8.1.gemfile
133
+ - gemfiles/rails_8.1.gemfile.lock
134
+ - lefthook.yml
135
+ - lib/generators/role_fu/install_generator.rb
136
+ - lib/generators/role_fu/role_fu_generator.rb
137
+ - lib/generators/role_fu/templates/migration.rb.erb
138
+ - lib/generators/role_fu/templates/role.rb.erb
139
+ - lib/generators/role_fu/templates/role_assignment.rb.erb
140
+ - lib/generators/role_fu/templates/role_fu.rb
141
+ - lib/role_fu.rb
142
+ - lib/role_fu/configuration.rb
143
+ - lib/role_fu/resourceable.rb
144
+ - lib/role_fu/role.rb
145
+ - lib/role_fu/role_assignment.rb
146
+ - lib/role_fu/roleable.rb
147
+ - lib/role_fu/version.rb
148
+ - sig/role_fu.rbs
149
+ homepage: https://github.com/alec-c4/role_fu
150
+ licenses:
151
+ - MIT
152
+ metadata:
153
+ homepage_uri: https://github.com/alec-c4/role_fu
154
+ source_code_uri: https://github.com/alec-c4/role_fu
155
+ changelog_uri: https://github.com/alec-c4/role_fu/blob/main/CHANGELOG.md
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: 3.2.0
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubygems_version: 4.0.5
171
+ specification_version: 4
172
+ summary: A modern role management gem for Rails, replacing rolify.
173
+ test_files: []