Module: Feature

Defined in:
lib/feature.rb,
lib/feature/testing.rb,
lib/feature/repository.rb,
lib/feature/repository/yaml_repository.rb,
lib/feature/repository/redis_repository.rb,
lib/feature/generators/install_generator.rb,
lib/feature/repository/simple_repository.rb,
lib/feature/repository/active_record_repository.rb

Overview

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'

Defined Under Namespace

Modules: Repository Classes: InstallGenerator

Class Method Summary collapse

Class Method Details

.active?(feature) ⇒ Boolean

Requests if feature is active

Parameters:

  • feature (Symbol)

Returns:

  • (Boolean)


67
68
69
# File 'lib/feature.rb', line 67

def self.active?(feature)
  active_features.include?(feature)
end

.active_featuresArray

Return list of active feature flags.

Returns:

  • (Array)

    list of symbols



118
119
120
121
122
123
124
# 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) ⇒ Boolean

Requests if feature is inactive (or unknown)

Parameters:

  • feature (Symbol)

Returns:

  • (Boolean)


76
77
78
# File 'lib/feature.rb', line 76

def self.inactive?(feature)
  !active?(feature)
end

.refresh!Object

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



55
56
57
58
59
# 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) ⇒ Object

Execute the code block with the given features active

Example usage:

Feature.run_with_activated(:feature, :another_feature) do
  # your test code here
end


16
17
18
19
20
21
22
23
# 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) ⇒ Object

Execute the code block with the given features deactive

Example usage:

Feature.run_with_deactivated(:feature, :another_feature) do
  # your test code here
end


31
32
33
34
35
36
37
38
# 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) ⇒ Object

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

Parameters:

  • repository (Object)

    the repository to get the features from

  • refresh (Boolean|Integer) (defaults to: false)

    optional (default: false) - auto refresh or refresh after given number of seconds



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 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) ⇒ Object

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

Parameters:

  • feature (Symbol)
  • value (Object)

    / lambda to use if feature is active

  • value (Object)

    / lambda to use if feature is inactive



106
107
108
109
110
111
112
# 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) ⇒ Object

Execute the given block if feature is active

Parameters:

  • feature (Symbol)

Raises:

  • (ArgumentError)


84
85
86
87
88
# 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_configObject

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



42
43
44
45
46
47
48
49
50
51
52
# 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) ⇒ Object

Execute the given block if feature is inactive

Parameters:

  • feature (Symbol)

Raises:

  • (ArgumentError)


94
95
96
97
98
# 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