togglefy 1.2.0 → 1.2.1
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 +4 -4
- data/README.md +79 -54
- data/app/models/togglefy/feature.rb +87 -8
- data/app/models/togglefy/feature_assignment.rb +12 -0
- data/lib/generators/togglefy/install_generator.rb +32 -3
- data/lib/generators/togglefy/templates/older_rails_create_feature_assignments.rb +14 -0
- data/lib/generators/togglefy/templates/older_rails_create_features.rb +18 -0
- data/lib/togglefy/assignable.rb +29 -1
- data/lib/togglefy/engine.rb +2 -0
- data/lib/togglefy/errors/assignables_not_found.rb +5 -0
- data/lib/togglefy/errors/bulk_toggle_failed.rb +9 -0
- data/lib/togglefy/errors/dependency_missing.rb +6 -0
- data/lib/togglefy/errors/error.rb +2 -0
- data/lib/togglefy/errors/feature_not_found.rb +11 -2
- data/lib/togglefy/errors/invalid_feature_attribute.rb +5 -0
- data/lib/togglefy/errors.rb +16 -0
- data/lib/togglefy/feature_assignable_manager.rb +21 -0
- data/lib/togglefy/feature_manager.rb +32 -1
- data/lib/togglefy/feature_query.rb +47 -5
- data/lib/togglefy/featureable.rb +3 -0
- data/lib/togglefy/scoped_bulk_wrapper.rb +8 -0
- data/lib/togglefy/services/bulk_toggler.rb +96 -5
- data/lib/togglefy/version.rb +2 -1
- data/lib/togglefy.rb +154 -9
- data/togglefy.gemspec +6 -2
- metadata +37 -5
- data/lib/togglefy/exceptions.rb +0 -7
- /data/{LICENSE.txt → LICENSE} +0 -0
data/lib/togglefy.rb
CHANGED
@@ -8,100 +8,245 @@ require "togglefy/feature_assignable_manager"
|
|
8
8
|
require "togglefy/feature_manager"
|
9
9
|
require "togglefy/feature_query"
|
10
10
|
require "togglefy/scoped_bulk_wrapper"
|
11
|
-
require "togglefy/
|
11
|
+
require "togglefy/errors"
|
12
12
|
|
13
|
+
# The Togglefy module provides a feature management system.
|
14
|
+
# It includes methods for querying, creating, updating, toggling, and managing features.
|
15
|
+
# It also provides a way to manage features for assignable objects.
|
16
|
+
#
|
17
|
+
# == Features
|
18
|
+
#
|
19
|
+
# The Togglefy module provides a variety of features, including:
|
20
|
+
#
|
21
|
+
# - Querying features by type, group, environment, tenant, and custom filters
|
22
|
+
# - Creating, updating, and deleting features
|
23
|
+
# - Managing features for Assignables
|
24
|
+
#
|
25
|
+
# For more detailed information on each method,
|
26
|
+
# please refer to the {file:README.md README}, individual method documentation in this file or the usage documentation.
|
27
|
+
#
|
28
|
+
# == Usage
|
29
|
+
#
|
30
|
+
# Main usage for this always starts with the {Togglefy} module.
|
31
|
+
#
|
32
|
+
# Below are a few examples on how to use Togglefy:
|
33
|
+
#
|
34
|
+
# === Examples
|
35
|
+
#
|
36
|
+
# - +Togglefy.feature(:super_powers)+
|
37
|
+
# - +Togglefy.for_type(User)+
|
38
|
+
# - +Togglefy.for_group(group)+
|
39
|
+
# - +Togglefy.for_filters(filters: {group: :admin})+
|
40
|
+
# - +Togglefy.with_status(:active)+
|
41
|
+
# - +Togglefy.create(name: "Feature Name", identifier: :feature_name, description: "Feature description")+
|
42
|
+
# - +Togglefy.update(:feature_name, name: "Updated Feature Name")+
|
43
|
+
# - +Togglefy.destroy(:feature_name)+
|
44
|
+
# - +Togglefy.toggle(:feature_name)+
|
45
|
+
# - +Togglefy.inactive!(:feature_name)+
|
46
|
+
# - +Togglefy.for(assignable).enable(:feature_name)+
|
47
|
+
# - +Togglefy.for(assignable).has?(:feature_name)+
|
48
|
+
# - +Togglefy.mass_for(Assignable).bulk.enable(:feature_name)+
|
49
|
+
# - +Togglefy.mass_for(Assignable).bulk.enable(:feature_name, percentage: 35)+
|
50
|
+
# - +Togglefy.mass_for(Assignable).bulk.disable([:feature_name, :another_feature])+
|
51
|
+
#
|
52
|
+
# == Aliases
|
53
|
+
#
|
54
|
+
# The following aliases are available for convenience:
|
55
|
+
#
|
56
|
+
# - +for_role+ is an alias for +for_group+
|
57
|
+
# - +without_role+ is an alias for +without_group+
|
58
|
+
# - +for_env+ is an alias for +for_environment+
|
59
|
+
# - +without_env+ is an alias for +without_environment+
|
60
|
+
# - +create_feature+ is an alias for +create+
|
61
|
+
# - +update_feature+ is an alias for +update+
|
62
|
+
# - +toggle_feature+ is an alias for +toggle+
|
63
|
+
# - +activate_feature+ is an alias for +active!+
|
64
|
+
# - +inactivate_feature+ is an alias for +inactive!+
|
65
|
+
# - +destroy_feature+ is an alias for +destroy+
|
66
|
+
#
|
13
67
|
module Togglefy
|
14
|
-
|
15
|
-
|
16
|
-
# FeatureQuery
|
68
|
+
# Returns all features.
|
69
|
+
# @return [Array] List of all features.
|
17
70
|
def self.features
|
18
71
|
FeatureQuery.new.features
|
19
72
|
end
|
20
73
|
|
74
|
+
# Finds a feature by its identifier.
|
75
|
+
# @param identifier [String, Symbol] The unique identifier of the feature.
|
76
|
+
# @return [Feature] The feature object.
|
77
|
+
# @raise [Togglefy::FeatureNotFound] If the feature is not found by the identifier.
|
21
78
|
def self.feature(identifier)
|
22
79
|
FeatureQuery.new.feature(identifier)
|
80
|
+
rescue ActiveRecord::RecordNotFound
|
81
|
+
raise Togglefy::FeatureNotFound, "Couldn't find Togglefy::Feature with identifier '#{identifier}'"
|
23
82
|
end
|
24
83
|
|
84
|
+
# Queries features for a specific type.
|
85
|
+
# @param klass [Class] The class type to filter features by.
|
86
|
+
# @return [Array] List of features for the given type.
|
25
87
|
def self.for_type(klass)
|
26
88
|
FeatureQuery.new.for_type(klass)
|
27
89
|
end
|
28
90
|
|
91
|
+
# Queries features for a specific group.
|
92
|
+
# @param group [String, Symbol] The group name to filter features by.
|
93
|
+
# @return [Array] List of features for the given group.
|
29
94
|
def self.for_group(group)
|
30
95
|
FeatureQuery.new.for_group(group)
|
31
96
|
end
|
32
97
|
|
98
|
+
# Queries features without a group.
|
99
|
+
# @return [Array] List of features without a group.
|
33
100
|
def self.without_group
|
34
101
|
FeatureQuery.new.without_group
|
35
102
|
end
|
36
103
|
|
104
|
+
# Queries features for a specific environment.
|
105
|
+
# @param environment [String, Symbol] The environment name to filter features by.
|
106
|
+
# @return [Array] List of features for the given environment.
|
37
107
|
def self.for_environment(environment)
|
38
108
|
FeatureQuery.new.for_environment(environment)
|
39
109
|
end
|
40
110
|
|
111
|
+
# Queries features without an environment.
|
112
|
+
# @return [Array] List of features without an environment.
|
41
113
|
def self.without_environment
|
42
114
|
FeatureQuery.new.without_environment
|
43
115
|
end
|
44
116
|
|
117
|
+
# Queries features for a specific tenant.
|
118
|
+
# @param tenant_id [String] The tenant ID to filter features by.
|
119
|
+
# @return [Array] List of features for the given tenant.
|
45
120
|
def self.for_tenant(tenant_id)
|
46
121
|
FeatureQuery.new.for_tenant(tenant_id)
|
47
122
|
end
|
48
123
|
|
124
|
+
# Queries features without a tenant.
|
125
|
+
# @return [Array] List of features without a tenant.
|
49
126
|
def self.without_tenant
|
50
127
|
FeatureQuery.new.without_tenant
|
51
128
|
end
|
52
129
|
|
130
|
+
# Queries features based on custom filters.
|
131
|
+
# @param filters [Hash] A hash of filters to apply.
|
132
|
+
# @return [Array] List of features matching the filters.
|
53
133
|
def self.for_filters(filters: {})
|
54
134
|
FeatureQuery.new.for_filters(filters)
|
55
135
|
end
|
56
136
|
|
137
|
+
# Queries features by their status.
|
138
|
+
# @param status [String, Symbol, Integer] The status to filter features by.
|
139
|
+
# @return [Array] List of features with the given status.
|
57
140
|
def self.with_status(status)
|
58
141
|
FeatureQuery.new.with_status(status)
|
59
142
|
end
|
60
143
|
|
61
|
-
#
|
144
|
+
# Creates a new feature.
|
145
|
+
# @note All parameters are optional, except for the name. If sent, it should be a keyword argument.
|
146
|
+
#
|
147
|
+
# @param name [String] The name of the feature.
|
148
|
+
# @param identifier [Symbol, String, nil] The unique identifier for the feature. Optional, it can also be nil or blank
|
149
|
+
# @param description [String] A description of the feature.
|
150
|
+
# @param group [String, Symbol, nil] The group the feature belongs to.
|
151
|
+
# @param environment [String, Symbol, nil] The environment the feature is for.
|
152
|
+
# @param tenant_id [String] The tenant ID the feature is for.
|
153
|
+
# @param status [String, Symbol, Integer] The status of the feature.
|
154
|
+
# @return [Feature] The created feature.
|
155
|
+
# @example
|
156
|
+
# Togglefy.create(name: "New Feature", identifier: :new_feature, description: "A new feature")
|
157
|
+
# Togglefy.create(name: "New Feature", identifier: nil, description: "A new feature", group: :admin)
|
158
|
+
# Togglefy.create(name: "New Feature", description: "A new feature", environment: :production, tenant_id: "123abc")
|
62
159
|
def self.create(**params)
|
63
160
|
FeatureManager.new.create(**params)
|
64
161
|
end
|
65
162
|
|
163
|
+
# Updates an existing feature.
|
164
|
+
# @note All parameters but the first (identifier) should be keyword arguments.
|
165
|
+
#
|
166
|
+
# @param identifier [Symbol, String] The unique identifier of the feature.
|
167
|
+
# @param name [String] The name of the feature.
|
168
|
+
# @param identifier [Symbol, String, nil] The unique identifier for the feature. Optional, it can also be nil or blank
|
169
|
+
# @param description [String] A description of the feature.
|
170
|
+
# @param group [String, Symbol, nil] The group the feature belongs to.
|
171
|
+
# @param environment [String, Symbol, nil] The environment the feature is for.
|
172
|
+
# @param tenant_id [String] The tenant ID the feature is for.
|
173
|
+
# @param status [String, Symbol, Integer] The status of the feature.
|
174
|
+
# @return [Feature] The updated feature.
|
175
|
+
# @raise [Togglefy::FeatureNotFound] If the feature is not found by the identifier.
|
176
|
+
# @example
|
177
|
+
# Togglefy.update(:new_feature, name: "Updated Feature", description: "Updated feature description")
|
178
|
+
# Togglefy.update(:new_feature, identifier: :updated_feature, group: :support)
|
179
|
+
# Togglefy.update(:new_feature, environment: :staging, tenant_id: "abc123")
|
66
180
|
def self.update(identifier, **params)
|
67
181
|
FeatureManager.new(identifier).update(**params)
|
182
|
+
rescue ActiveRecord::RecordNotFound
|
183
|
+
raise Togglefy::FeatureNotFound, "Couldn't find Togglefy::Feature with identifier '#{identifier}'"
|
68
184
|
end
|
69
185
|
|
186
|
+
# Deletes a feature.
|
187
|
+
# @param identifier [Symbol, String] The unique identifier of the feature.
|
188
|
+
# @return [boolean] True if the feature was deleted, false otherwise.
|
189
|
+
# @raise [Togglefy::FeatureNotFound] If the feature is not found by the identifier.
|
70
190
|
def self.destroy(identifier)
|
71
191
|
FeatureManager.new(identifier).destroy
|
192
|
+
rescue ActiveRecord::RecordNotFound
|
193
|
+
raise Togglefy::FeatureNotFound, "Couldn't find Togglefy::Feature with identifier '#{identifier}'"
|
72
194
|
end
|
73
195
|
|
196
|
+
# Toggles the status of a feature.
|
197
|
+
# @param identifier [Symbol, String] The unique identifier of the feature.
|
198
|
+
# @return [boolean] True if the feature was toggled, false otherwise.
|
199
|
+
# @raise [Togglefy::FeatureNotFound] If the feature is not found by the identifier.
|
74
200
|
def self.toggle(identifier)
|
75
201
|
FeatureManager.new(identifier).toggle
|
202
|
+
rescue ActiveRecord::RecordNotFound
|
203
|
+
raise Togglefy::FeatureNotFound, "Couldn't find Togglefy::Feature with identifier '#{identifier}'"
|
76
204
|
end
|
77
205
|
|
206
|
+
# Activates a feature.
|
207
|
+
# @param identifier [Symbol, String] The unique identifier of the feature.
|
208
|
+
# @return [boolean] True if the feature was activated, false otherwise.
|
209
|
+
# @raise [Togglefy::FeatureNotFound] If the feature is not found by the identifier.
|
78
210
|
def self.active!(identifier)
|
79
211
|
FeatureManager.new(identifier).active!
|
212
|
+
rescue ActiveRecord::RecordNotFound
|
213
|
+
raise Togglefy::FeatureNotFound, "Couldn't find Togglefy::Feature with identifier '#{identifier}'"
|
80
214
|
end
|
81
215
|
|
216
|
+
# Deactivates a feature.
|
217
|
+
# @param identifier [Symbol, String] The unique identifier of the feature.
|
218
|
+
# @return [boolean] True if the feature was inactivated, false otherwise.
|
219
|
+
# @raise [Togglefy::FeatureNotFound] If the feature is not found by the identifier.
|
82
220
|
def self.inactive!(identifier)
|
83
221
|
FeatureManager.new(identifier).inactive!
|
222
|
+
rescue ActiveRecord::RecordNotFound
|
223
|
+
raise Togglefy::FeatureNotFound, "Couldn't find Togglefy::Feature with identifier '#{identifier}'"
|
84
224
|
end
|
85
225
|
|
86
|
-
#
|
226
|
+
# Manages features for a specific assignable object.
|
227
|
+
# @param assignable [Object] The assignable object.
|
228
|
+
# @return [FeatureAssignableManager] The manager for the assignable object.
|
87
229
|
def self.for(assignable)
|
88
230
|
FeatureAssignableManager.new(assignable)
|
89
231
|
end
|
90
232
|
|
91
|
-
#
|
233
|
+
# Provides bulk management for a specific class.
|
234
|
+
# @param klass [Class] The class to manage features for.
|
235
|
+
# @return [ScopedBulkWrapper] The bulk wrapper for the class.
|
92
236
|
def self.mass_for(klass)
|
93
237
|
Togglefy::ScopedBulkWrapper.new(klass)
|
94
238
|
end
|
95
239
|
|
96
240
|
class << self
|
97
|
-
#
|
241
|
+
# Aliases for group-related Features.
|
98
242
|
alias for_role for_group
|
99
243
|
alias without_role without_group
|
100
244
|
|
245
|
+
# Aliases for environment-related Features.
|
101
246
|
alias for_env for_environment
|
102
247
|
alias without_env without_environment
|
103
248
|
|
104
|
-
#
|
249
|
+
# Aliases for feature management Features.
|
105
250
|
alias create_feature create
|
106
251
|
alias update_feature update
|
107
252
|
alias toggle_feature toggle
|
data/togglefy.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "togglefy"
|
7
7
|
spec.version = Togglefy::VERSION
|
8
8
|
spec.authors = ["Gabriel Azevedo"]
|
9
|
-
spec.email = ["
|
9
|
+
spec.email = ["gabriel@azeveco.com"]
|
10
10
|
|
11
11
|
spec.summary = "Simple and open source Feature Management."
|
12
12
|
spec.description = "Togglefy is a feature management Rails gem to help you control which features an user or a group has access to."
|
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.metadata["homepage_uri"] = spec.homepage
|
20
20
|
spec.metadata["source_code_uri"] = "https://github.com/azeveco/Togglefy"
|
21
21
|
spec.metadata["changelog_uri"] = "https://github.com/azeveco/Togglefy/releases"
|
22
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/azeveco/Togglefy/issues'
|
23
|
+
spec.metadata['documentation_uri'] = 'https://rubydoc.info/github/azeveco/Togglefy'
|
22
24
|
|
23
25
|
# Specify which files should be added to the gem when it is released.
|
24
26
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -26,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
26
28
|
spec.files = Dir.glob("lib/**/*") +
|
27
29
|
Dir.glob("app/**/*") +
|
28
30
|
Dir.glob("config/**/*") +
|
29
|
-
%w[LICENSE
|
31
|
+
%w[LICENSE README.md Rakefile togglefy.gemspec]
|
30
32
|
|
31
33
|
spec.bindir = "exe"
|
32
34
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
@@ -37,4 +39,6 @@ Gem::Specification.new do |spec|
|
|
37
39
|
spec.add_development_dependency "rails", "~> 8.0.2"
|
38
40
|
spec.add_development_dependency "rspec-rails", "~> 7.1.1"
|
39
41
|
spec.add_development_dependency "sqlite3", "~> 2.1"
|
42
|
+
spec.add_development_dependency "yard", "~> 0.9.37"
|
43
|
+
spec.add_development_dependency "redcarpet", "~> 3.6"
|
40
44
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: togglefy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gabriel Azevedo
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-05-18 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bootsnap
|
@@ -79,15 +79,43 @@ dependencies:
|
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '2.1'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: yard
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 0.9.37
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 0.9.37
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: redcarpet
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '3.6'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '3.6'
|
82
110
|
description: Togglefy is a feature management Rails gem to help you control which
|
83
111
|
features an user or a group has access to.
|
84
112
|
email:
|
85
|
-
-
|
113
|
+
- gabriel@azeveco.com
|
86
114
|
executables: []
|
87
115
|
extensions: []
|
88
116
|
extra_rdoc_files: []
|
89
117
|
files:
|
90
|
-
- LICENSE
|
118
|
+
- LICENSE
|
91
119
|
- README.md
|
92
120
|
- Rakefile
|
93
121
|
- app/models/togglefy/feature.rb
|
@@ -95,16 +123,18 @@ files:
|
|
95
123
|
- lib/generators/togglefy/install_generator.rb
|
96
124
|
- lib/generators/togglefy/templates/create_feature_assignments.rb
|
97
125
|
- lib/generators/togglefy/templates/create_features.rb
|
126
|
+
- lib/generators/togglefy/templates/older_rails_create_feature_assignments.rb
|
127
|
+
- lib/generators/togglefy/templates/older_rails_create_features.rb
|
98
128
|
- lib/togglefy.rb
|
99
129
|
- lib/togglefy/assignable.rb
|
100
130
|
- lib/togglefy/engine.rb
|
131
|
+
- lib/togglefy/errors.rb
|
101
132
|
- lib/togglefy/errors/assignables_not_found.rb
|
102
133
|
- lib/togglefy/errors/bulk_toggle_failed.rb
|
103
134
|
- lib/togglefy/errors/dependency_missing.rb
|
104
135
|
- lib/togglefy/errors/error.rb
|
105
136
|
- lib/togglefy/errors/feature_not_found.rb
|
106
137
|
- lib/togglefy/errors/invalid_feature_attribute.rb
|
107
|
-
- lib/togglefy/exceptions.rb
|
108
138
|
- lib/togglefy/feature_assignable_manager.rb
|
109
139
|
- lib/togglefy/feature_manager.rb
|
110
140
|
- lib/togglefy/feature_query.rb
|
@@ -120,6 +150,8 @@ metadata:
|
|
120
150
|
homepage_uri: https://github.com/azeveco/Togglefy
|
121
151
|
source_code_uri: https://github.com/azeveco/Togglefy
|
122
152
|
changelog_uri: https://github.com/azeveco/Togglefy/releases
|
153
|
+
bug_tracker_uri: https://github.com/azeveco/Togglefy/issues
|
154
|
+
documentation_uri: https://rubydoc.info/github/azeveco/Togglefy
|
123
155
|
rdoc_options: []
|
124
156
|
require_paths:
|
125
157
|
- lib
|
data/lib/togglefy/exceptions.rb
DELETED
/data/{LICENSE.txt → LICENSE}
RENAMED
File without changes
|