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.
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/exceptions"
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
- class Error < StandardError; end
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
- # FeatureManager
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
- # FeatureAssignableManager
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
- # ScopedBulkWrapper
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
- # FeatureQuery
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
- # FeatureManager
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 = ["gazeveco@gmail.com"]
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.txt README.md Rakefile togglefy.gemspec]
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.0
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-04-29 00:00:00.000000000 Z
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
- - gazeveco@gmail.com
113
+ - gabriel@azeveco.com
86
114
  executables: []
87
115
  extensions: []
88
116
  extra_rdoc_files: []
89
117
  files:
90
- - LICENSE.txt
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
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "togglefy/errors/error"
4
-
5
- require "togglefy/errors/feature_not_found"
6
- require "togglefy/errors/assignables_not_found"
7
- require "togglefy/errors/bulk_toggle_failed"
File without changes