class Rollout

Constants

RAND_BASE
VERSION

Attributes

options[R]
storage[R]

Public Class Methods

new(storage, opts = {}) click to toggle source
# File lib/rollout.rb, line 18
def initialize(storage, opts = {})
  @storage = storage
  @options = opts
  @groups  = { all: ->(_user) { true } }

  extend(Logging) if opts[:logging]
end

Public Instance Methods

activate(feature) click to toggle source
# File lib/rollout.rb, line 30
def activate(feature)
  with_feature(feature) do |f|
    f.percentage = 100
  end
end
activate_group(feature, group) click to toggle source
# File lib/rollout.rb, line 61
def activate_group(feature, group)
  with_feature(feature) do |f|
    f.add_group(group)
  end
end
activate_percentage(feature, percentage) click to toggle source
# File lib/rollout.rb, line 122
def activate_percentage(feature, percentage)
  with_feature(feature) do |f|
    f.percentage = percentage
  end
end
activate_user(feature, user) click to toggle source
# File lib/rollout.rb, line 73
def activate_user(feature, user)
  with_feature(feature) do |f|
    f.add_user(user)
  end
end
activate_users(feature, users) click to toggle source
# File lib/rollout.rb, line 85
def activate_users(feature, users)
  with_feature(feature) do |f|
    users.each { |user| f.add_user(user) }
  end
end
active?(feature, user = nil) click to toggle source
# File lib/rollout.rb, line 108
def active?(feature, user = nil)
  feature = get(feature)
  feature.active?(self, user)
end
active_features(user = nil) click to toggle source
# File lib/rollout.rb, line 173
def active_features(user = nil)
  multi_get(*features).select do |f|
    f.active?(self, user)
  end.map(&:name)
end
active_in_group?(group, user) click to toggle source
# File lib/rollout.rb, line 134
def active_in_group?(group, user)
  f = @groups[group.to_sym]
  f&.call(user)
end
clear!() click to toggle source
# File lib/rollout.rb, line 179
def clear!
  features.each do |feature|
    with_feature(feature, &:clear)
    @storage.del(key(feature))
  end

  @storage.del(features_key)
end
clear_feature_data(feature) click to toggle source
# File lib/rollout.rb, line 150
def clear_feature_data(feature)
  with_feature(feature) do |f|
    f.data = {}
  end
end
deactivate(feature) click to toggle source
# File lib/rollout.rb, line 36
def deactivate(feature)
  with_feature(feature, &:clear)
end
deactivate_group(feature, group) click to toggle source
# File lib/rollout.rb, line 67
def deactivate_group(feature, group)
  with_feature(feature) do |f|
    f.remove_group(group)
  end
end
deactivate_percentage(feature) click to toggle source
# File lib/rollout.rb, line 128
def deactivate_percentage(feature)
  with_feature(feature) do |f|
    f.percentage = 0
  end
end
deactivate_user(feature, user) click to toggle source
# File lib/rollout.rb, line 79
def deactivate_user(feature, user)
  with_feature(feature) do |f|
    f.remove_user(user)
  end
end
deactivate_users(feature, users) click to toggle source
# File lib/rollout.rb, line 91
def deactivate_users(feature, users)
  with_feature(feature) do |f|
    users.each { |user| f.remove_user(user) }
  end
end
define_group(group, &block) click to toggle source
# File lib/rollout.rb, line 104
def define_group(group, &block)
  @groups[group.to_sym] = block
end
delete(feature) click to toggle source
# File lib/rollout.rb, line 40
def delete(feature)
  features = (@storage.get(features_key) || '').split(',')
  features.delete(feature.to_s)
  @storage.set(features_key, features.join(','))
  @storage.del(key(feature))

  if respond_to?(:logging)
    logging.delete(feature)
  end
end
exists?(feature) click to toggle source
# File lib/rollout.rb, line 188
def exists?(feature)
  # since redis-rb v4.2, `#exists?` replaces `#exists` which now returns integer value instead of boolean
  # https://github.com/redis/redis-rb/pull/918
  if @storage.respond_to?(:exists?)
    @storage.exists?(key(feature))
  else
    @storage.exists(key(feature))
  end
end
feature_states(user = nil) click to toggle source
# File lib/rollout.rb, line 167
def feature_states(user = nil)
  multi_get(*features).each_with_object({}) do |f, hash|
    hash[f.name] = f.active?(self, user)
  end
end
features() click to toggle source
# File lib/rollout.rb, line 163
def features
  (@storage.get(features_key) || '').split(',').map(&:to_sym)
end
get(feature) click to toggle source
# File lib/rollout.rb, line 139
def get(feature)
  string = @storage.get(key(feature))
  Feature.new(feature, string, @options)
end
groups() click to toggle source
# File lib/rollout.rb, line 26
def groups
  @groups.keys
end
inactive?(feature, user = nil) click to toggle source
# File lib/rollout.rb, line 118
def inactive?(feature, user = nil)
  !active?(feature, user)
end
multi_get(*features) click to toggle source
# File lib/rollout.rb, line 156
def multi_get(*features)
  return [] if features.empty?

  feature_keys = features.map { |feature| key(feature) }
  @storage.mget(*feature_keys).map.with_index { |string, index| Feature.new(features[index], string, @options) }
end
set(feature, desired_state) click to toggle source
# File lib/rollout.rb, line 51
def set(feature, desired_state)
  with_feature(feature) do |f|
    if desired_state
      f.percentage = 100
    else
      f.clear
    end
  end
end
set_feature_data(feature, data) click to toggle source
# File lib/rollout.rb, line 144
def set_feature_data(feature, data)
  with_feature(feature) do |f|
    f.data.merge!(data) if data.is_a? Hash
  end
end
set_users(feature, users) click to toggle source
# File lib/rollout.rb, line 97
def set_users(feature, users)
  with_feature(feature) do |f|
    f.users = []
    users.each { |user| f.add_user(user) }
  end
end
user_in_active_users?(feature, user = nil) click to toggle source
# File lib/rollout.rb, line 113
def user_in_active_users?(feature, user = nil)
  feature = get(feature)
  feature.user_in_active_users?(user)
end
with_feature(feature) { |f| ... } click to toggle source
# File lib/rollout.rb, line 198
def with_feature(feature)
  f = get(feature)

  if count_observers > 0
    before = Marshal.load(Marshal.dump(f))
    yield(f)
    save(f)
    changed
    notify_observers(:update, before, f)
  else
    yield(f)
    save(f)
  end
end

Private Instance Methods

features_key() click to toggle source
# File lib/rollout.rb, line 219
def features_key
  'feature:__features__'
end
key(name) click to toggle source
# File lib/rollout.rb, line 215
def key(name)
  "feature:#{name}"
end
save(feature) click to toggle source
# File lib/rollout.rb, line 223
def save(feature)
  @storage.set(key(feature.name), feature.serialize)
  @storage.set(features_key, (features | [feature.name.to_sym]).join(','))
end