module Feature

Feature module provides all methods

@note all features not active will be handled has inactive

Example usage:

repository = SimpleRepository.new
repository.add_active_feature(:feature_name)

Feature.set_repository(repository)
Feature.active?(:feature_name)
# => true
Feature.inactive?(:inactive_feature)
# => false

Feature.with(:feature_name) do
  # code will be executed
end

This file provides functionality for testing your code with features activated or deactivated. This file should only be required in test/spec code!

To enable Feature testing capabilities do:

require 'feature/testing'

Public Class Methods

active?(feature) click to toggle source

Requests if feature is active

@param [Symbol] feature @return [Boolean]

# File lib/feature.rb, line 67
def self.active?(feature)
  active_features.include?(feature)
end
active_features() click to toggle source

Return list of active feature flags.

@return [Array] list of symbols

# File lib/feature.rb, line 118
def self.active_features
  raise 'missing Repository for obtaining feature lists' unless @repository

  refresh! if @auto_refresh || @perform_initial_refresh || (@next_refresh_after && Time.now > @next_refresh_after)

  @active_features
end
inactive?(feature) click to toggle source

Requests if feature is inactive (or unknown)

@param [Symbol] feature @return [Boolean]

# File lib/feature.rb, line 76
def self.inactive?(feature)
  !active?(feature)
end
refresh!() click to toggle source

Refreshes list of active features from repository. Useful when using an repository with external source.

# File lib/feature.rb, line 55
def self.refresh!
  @active_features = @repository.active_features
  @next_refresh_after = Time.now + @refresh_after if @refresh_after
  @perform_initial_refresh = false
end
run_with_activated(*features, &blk) click to toggle source

Execute the code block with the given features active

Example usage:

Feature.run_with_activated(:feature, :another_feature) do
  # your test code here
end
# File lib/feature/testing.rb, line 16
def self.run_with_activated(*features, &blk)
  with_stashed_config do
    @active_features.concat(features).uniq!
    @auto_refresh = false
    @perform_initial_refresh = false
    blk.call
  end
end
run_with_deactivated(*features, &blk) click to toggle source

Execute the code block with the given features deactive

Example usage:

Feature.run_with_deactivated(:feature, :another_feature) do
  # your test code here
end
# File lib/feature/testing.rb, line 31
def self.run_with_deactivated(*features, &blk)
  with_stashed_config do
    @active_features -= features
    @auto_refresh = false
    @perform_initial_refresh = false
    blk.call
  end
end
set_repository(repository, refresh = false) click to toggle source

Set the feature repository The given repository has to respond to method ‘active_features’ with an array of symbols

@param [Object] repository the repository to get the features from @param [Boolean|Integer] refresh optional (default: false) - auto refresh or refresh after given number of seconds

# File lib/feature.rb, line 36
def self.set_repository(repository, refresh = false)
  unless repository.respond_to?(:active_features)
    raise ArgumentError, 'given repository does not respond to active_features'
  end

  @perform_initial_refresh = true
  @repository = repository
  if [true, false].include?(refresh)
    @auto_refresh = refresh
  else
    @auto_refresh = false
    @refresh_after = refresh
    @next_refresh_after = Time.now + @refresh_after
  end
end
switch(feature, l1, l2) click to toggle source

Return value or execute Proc/lambda depending on Feature status.

@param [Symbol] feature @param [Object] value / lambda to use if feature is active @param [Object] value / lambda to use if feature is inactive

# File lib/feature.rb, line 106
def self.switch(feature, l1, l2)
  if active?(feature)
    l1.instance_of?(Proc) ? l1.call : l1
  else
    l2.instance_of?(Proc) ? l2.call : l2
  end
end
with(feature) { || ... } click to toggle source

Execute the given block if feature is active

@param [Symbol] feature

# File lib/feature.rb, line 84
def self.with(feature)
  raise ArgumentError, "no block given to #{__method__}" unless block_given?

  yield if active?(feature)
end
with_stashed_config() { || ... } click to toggle source

Execute the given code block and store + restore the feature configuration before/after the execution

# File lib/feature/testing.rb, line 42
def self.with_stashed_config
  @active_features = [] if @active_features.nil?
  old_features = @active_features.dup
  old_auto_refresh = @auto_refresh
  old_perform_initial_refresh = @perform_initial_refresh
  yield
ensure
  @active_features = old_features
  @auto_refresh = old_auto_refresh
  @perform_initial_refresh = old_perform_initial_refresh
end
without(feature) { || ... } click to toggle source

Execute the given block if feature is inactive

@param [Symbol] feature

# File lib/feature.rb, line 94
def self.without(feature)
  raise ArgumentError, "no block given to #{__method__}" unless block_given?

  yield if inactive?(feature)
end