Purpose
Featury is designed to group and manage multiple features within a project. It provides the flexibility to utilize any pre-existing solution or create your own. It's easily adjustable to align with the unique needs and objectives of your project.
Quick Start
Installation
gem "featury"
Usage
Basic class for your features
For instance, assume that you are utilizing Flipper for managing features. In such scenario, the base class could potentially be structured as follows:
class ApplicationFeature < Featury::Base
action :enabled? do |features:, **options|
features.all? { |feature| Flipper.enabled?(feature, *options.values) }
end
action :disabled? do |features:, **options|
features.any? { |feature| !Flipper.enabled?(feature, *options.values) }
end
action :enable do |features:, **options|
features.all? { |feature| Flipper.enable(feature, *options.values) }
end
action :disable do |features:, **options|
features.all? { |feature| Flipper.disable(feature, *options.values) }
end
end
Features of your project
class UserFeature::Onboarding < ApplicationFeature
resource :user, type: User
condition ->(resources:) { resources.user.onboarding_awaiting? }
prefix :user_onboarding
features :passage # => :user_onboarding_passage
groups BillingFeature,
PaymentSystemFeature
end
class BillingFeature < ApplicationFeature
prefix :billing
features :api, # => :billing_api
:webhooks # => :billing_webhooks
end
class PaymentSystemFeature < ApplicationFeature
prefix :payment_system
features :api, # => :payment_system_api
:webhooks # => :payment_system_webhooks
end
The resource
method provides an indication of how the transmitted information ought to be processed.
Besides the options provided by Servactory, additional ones are available for stipulating the processing mode of the transmitted data.
If a resource needs to be conveyed as a feature flag option, utilize the option
parameter:
resource :user, type: User, option: true
To transfer a resource to a nested group, utilize the nested
option:
resource :user, type: User, nested: true
Working with the features of your project
Each of these actions will be applied to every feature flag. Subsequently, the outcome of these actions will be contingent upon the combined results of all feature flags.
UserFeature::Onboarding.enabled?(user:) # => true
UserFeature::Onboarding.disabled?(user:) # => false
UserFeature::Onboarding.enable(user:) # => true
UserFeature::Onboarding.disable(user:) # => true
You can also utilize the with
method to pass necessary arguments.
feature = UserFeature::Onboarding.with(user:)
feature.enabled? # => true
feature.disabled? # => false
feature.enable # => true
feature.disable # => true
If a feature flag is deactivated, possibly via automation processes,
the primary feature class subsequently responds with false
when
queried about its enablement status.
In the preceding example, there might be a scenario where the payment system is undergoing technical maintenance and therefore is temporarily shut down. Consequently, the onboarding process for new users will be halted until further notice.
Contributing
This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the Contributor Covenant code of conduct. We recommend reading the contributing guide as well.
License
Featury is available as open source under the terms of the MIT License.