togls 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e26c25d5e392fcf0784759ef62cafe4716cdc85
4
- data.tar.gz: 057ac20f307b93518808f3ecef8426fb33bbd428
3
+ metadata.gz: 9abbf07a34b200f7000e94608724c8499cd0277a
4
+ data.tar.gz: 5724c3c1c652bf825a1de22b539b1f848f1d1a11
5
5
  SHA512:
6
- metadata.gz: f9a733735c31d42f0dfd3e5c2f14fea0832b814111ba3d020678d6a6eace4c82128e720601dfc9da897ed9265ad7a22ee3817252154e1a6090db30522590b506
7
- data.tar.gz: 554a8fc657ef91253afedec1793725c0c6a2b9f64388ae8686d8a54750d63f4987fa7f4448cf1b81f76dfb4ab1000feef0ae94f428a08c56841da092e13bbf4d
6
+ metadata.gz: a74f6677b8c623e757a32c3bddcc026571485263bbf75ad6ac4c5ab53c22856e26299835d1bf83e7ac6b62bfddea4698754a04ab2738249e477ab7719b16aeab
7
+ data.tar.gz: c3cd113e76fc0035bd3994684cc84208a69fb9e496a4402dfa23c9c0dc47e510277fa8cb73344c541fd8465c75ac3db03b844ecece48d1f23e40a83d88c72691
data/.codeclimate.yml CHANGED
@@ -1,2 +1,18 @@
1
- languages:
2
- Ruby: true
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ rubocop:
9
+ enabled: true
10
+ fixme:
11
+ enabled: true
12
+ ratings:
13
+ paths:
14
+ - lib/**
15
+ - exe/**
16
+ exclude_paths:
17
+ - spec/**/*
18
+ - docs/**/*
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.3.0
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.3.0
3
4
  - 2.2.3
4
5
  - 2.2.2
@@ -6,6 +6,12 @@ versions, as well as provide a rough history.
6
6
 
7
7
  #### Next Release
8
8
 
9
+ ### v2.2.0
10
+
11
+ * Changed Togls to be thread-safe
12
+ * Added Togls::TestToggleRegistry class for initializing test state
13
+ * Added ability to create additional toggle registries
14
+
9
15
  ### v2.1.1
10
16
 
11
17
  * Fixed issue #21, env variable override wasn't falling through to in
data/DEVELOPMENT.md ADDED
@@ -0,0 +1,53 @@
1
+ Welcome to the development guide for
2
+ [Togls](https://github.com/codebreakdown/togls). The hope is that the
3
+ following will aid in your development contributions to
4
+ [Togls](https://github.com/codebreakdown/togls).
5
+
6
+ # Where should I start?
7
+
8
+ We recommend generally that you start with first understanding the
9
+ existing features and documentation. These can be obtained by
10
+ referencing the [README](https://github.com/codebreakdown/togls) and the
11
+ [Wiki](https://github.com/codebreakdown/togls/wiki).
12
+
13
+ Once you are well versed in concepts, features, and documentation from
14
+ an end user standpoint. The next thing we feel is worth exploring is the
15
+ architecture. We recommend doing this after understanding it from the
16
+ end user standpoint as it should give you context when learning about
17
+ the internal concepts.
18
+
19
+ ## The Architecture
20
+
21
+ ### Models
22
+
23
+ At the core exists three main concepts, the Feature, the Rule, and the
24
+ Toggle.
25
+
26
+ #### Feature
27
+
28
+ A Feature is the code that provides some functionality coupled with a
29
+ unique identifier.
30
+
31
+ #### Rule
32
+
33
+ A Rule is conceptually the logic used to determine whether or not to
34
+ toggle a feature on or off. This is generally a Rule class provided by
35
+ [Togls](https://github.com/codebreakdown/togls/wiki) or a custom Rule
36
+ class provided by the end user conforming to the Rule interface.
37
+
38
+ #### Toggle
39
+
40
+ Conceptually, a Toggle is a switch that is used to turn something on or
41
+ off. In our case it is used to turn a Feature on or off. It does so by
42
+ consulting an associated Rule to determine if the Toggle should be on or
43
+ off.
44
+
45
+ The Toggle is really the linch pin of these three concepts as it ties
46
+ all three of them together. Forming, a functional feature toggle.
47
+
48
+ ### Repositories
49
+
50
+ In addition to the three model concepts from above. We also have
51
+ Repositories for each of the concepts respectively. They are responsible
52
+ for managing and separating the business representations from the
53
+ persistance layers.
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in togl.gemspec
4
4
  gemspec
5
5
 
6
- gem "codeclimate-test-reporter", "~> 0.4.8", group: :test, require: nil
6
+ gem 'codeclimate-test-reporter', '~> 0.4.8', group: :test, require: nil
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Brian Miller, Andrew De Ponte, Ryan Hedges
3
+ Copyright (c) 2015-2016 Brian Miller, Andrew De Ponte, Ryan Hedges
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "togls"
3
+ require 'bundler/setup'
4
+ require 'togls'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "togls"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start
data/lib/tasks/togls.rake CHANGED
@@ -1,5 +1,6 @@
1
1
  namespace :togls do
2
- desc "Output all features including status (on, off, ? - unknown due to complex rule), key, description"
2
+ desc 'Output all features including status (on, off, ? - unknown due to' \
3
+ ' complex rule), key, description'
3
4
  task :features do
4
5
  Togls.features.all.each do |toggle|
5
6
  puts toggle.to_s
data/lib/togls/feature.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  module Togls
2
+ # Feature
3
+ #
4
+ # The Feature model is the business representation of a feature. It is how
5
+ # Togls primarily interfaces with the concept of a feature.
2
6
  class Feature
3
7
  attr_reader :key, :description
4
8
 
@@ -1,11 +1,15 @@
1
1
  module Togls
2
+ # Feature Repository
3
+ #
4
+ # The Feature Repository is the primary interface for storing and retrieving
5
+ # feature entities using the initialized prioritized drivers Array.
2
6
  class FeatureRepository
3
7
  def initialize(drivers)
4
- if !drivers.is_a?(Array)
5
- raise Togls::InvalidDriver.new("FeatureRepository requires a valid driver")
8
+ unless drivers.is_a?(Array)
9
+ raise Togls::InvalidDriver, 'FeatureRepository requires a valid driver'
6
10
  end
7
11
  if drivers.empty?
8
- raise Togls::MissingDriver.new("FeatureRepository requires a driver")
12
+ raise Togls::MissingDriver, 'FeatureRepository requires a driver'
9
13
  end
10
14
  @drivers = drivers
11
15
  end
@@ -18,7 +22,7 @@ module Togls
18
22
  end
19
23
 
20
24
  def extract_feature_data(feature)
21
- { "key" => feature.key, "description" => feature.description }
25
+ { 'key' => feature.key, 'description' => feature.description }
22
26
  end
23
27
 
24
28
  def fetch_feature_data(id)
@@ -36,8 +40,8 @@ module Togls
36
40
  end
37
41
 
38
42
  def reconstitute_feature(feature_data)
39
- Togls::Feature.new(feature_data["key"],
40
- feature_data["description"])
43
+ Togls::Feature.new(feature_data['key'],
44
+ feature_data['description'])
41
45
  end
42
46
  end
43
47
  end
@@ -1,16 +1,27 @@
1
+ require 'thread'
2
+
1
3
  module Togls
2
4
  module FeatureRepositoryDrivers
5
+ # Feature Repository In-Memory Driver
6
+ #
7
+ # The Feature Repository In-Memory Driver provides the facility to store and
8
+ # retrieve features to and from the in-memory store.
3
9
  class InMemoryDriver
4
10
  def initialize
5
11
  @features = {}
12
+ @features_lock = Mutex.new
6
13
  end
7
14
 
8
15
  def store(feature_id, feature_data)
9
- @features[feature_id] = feature_data
16
+ @features_lock.synchronize do
17
+ @features[feature_id] = feature_data
18
+ end
10
19
  end
11
20
 
12
21
  def get(feature_id)
13
- @features[feature_id]
22
+ @features_lock.synchronize do
23
+ @features[feature_id]
24
+ end
14
25
  end
15
26
  end
16
27
  end
@@ -1,4 +1,8 @@
1
1
  module Togls
2
+ # Feature Repository Drivers
3
+ #
4
+ # The Feature Repository Drivers module is simply an organization bucket used
5
+ # to house the Feature Repository drivers provided by Togls.
2
6
  module FeatureRepositoryDrivers
3
7
  end
4
8
  end
@@ -1,4 +1,11 @@
1
1
  module Togls
2
+ # Feature Toggle Registry
3
+ #
4
+ # The Feature Toggle Registry conceptually houses a registry of toggles. It
5
+ # accomplishes this by technically housing a toggle repository, rule
6
+ # repository, and feature repository which is uses to store and retrieve the
7
+ # respective entities. This plays a significant portion in the primary DSL as
8
+ # well.
2
9
  class FeatureToggleRegistry
3
10
  def initialize
4
11
  @toggle_repository_drivers = [
@@ -8,25 +15,24 @@ module Togls
8
15
  [Togls::FeatureRepositoryDrivers::InMemoryDriver.new]
9
16
  @rule_repository_drivers =
10
17
  [Togls::RuleRepositoryDrivers::InMemoryDriver.new]
11
- @feature_repository = Togls::FeatureRepository.new(@feature_repository_drivers)
18
+ @feature_repository = Togls::FeatureRepository.new(
19
+ @feature_repository_drivers)
12
20
  @rule_repository = Togls::RuleRepository.new(@rule_repository_drivers)
13
- @toggle_repository = Togls::ToggleRepository.new(@toggle_repository_drivers,
14
- @feature_repository, @rule_repository)
15
- @boolean_true_rule = Togls::Rules::Boolean.new(true)
16
- @boolean_false_rule = Togls::Rules::Boolean.new(false)
17
- @rule_repository.store(@boolean_false_rule)
18
- @rule_repository.store(@boolean_true_rule)
21
+ @toggle_repository = Togls::ToggleRepository.new(
22
+ @toggle_repository_drivers, @feature_repository, @rule_repository)
23
+ @rule_repository.store(Togls::Rules::Boolean.new(true))
24
+ @rule_repository.store(Togls::Rules::Boolean.new(false))
19
25
  end
20
26
 
21
27
  def self.create(&block)
22
- feature_toggle_registry = self.new
28
+ feature_toggle_registry = new
23
29
  feature_toggle_registry.instance_eval(&block)
24
- return feature_toggle_registry
30
+ feature_toggle_registry
25
31
  end
26
32
 
27
33
  def expand(&block)
28
- self.instance_eval(&block)
29
- return self
34
+ instance_eval(&block)
35
+ self
30
36
  end
31
37
 
32
38
  def feature(key, desc)
@@ -41,7 +47,7 @@ module Togls
41
47
  if toggle.is_a?(Togls::NullToggle)
42
48
  Togls.logger.warn("Feature identified by '#{key}' has not been defined")
43
49
  end
44
- return toggle
50
+ toggle
45
51
  end
46
52
 
47
53
  def all
data/lib/togls/helpers.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  module Togls
2
+ # Helpers
3
+ #
4
+ # Collection of helper methods used through the Togls library.
2
5
  module Helpers
3
6
  def self.sha1(klass, data)
4
- Digest::SHA1.hexdigest("#{klass}:#{data.to_s}")
7
+ Digest::SHA1.hexdigest("#{klass}:#{data}")
5
8
  end
6
9
  end
7
10
  end
@@ -1,7 +1,11 @@
1
1
  module Togls
2
+ # Null Toggle
3
+ #
4
+ # The Null Toggle model is designed to be used as a response when there is no
5
+ # toggle found when requested to be retreived through a Toggle Repository.
2
6
  class NullToggle < Togls::Toggle
3
7
  def initialize
4
- feature = Togls::Feature.new("null", "the official null feature")
8
+ feature = Togls::Feature.new('null', 'the official null feature')
5
9
  super(feature)
6
10
  end
7
11
 
@@ -0,0 +1,43 @@
1
+ module Togls
2
+ # Release Toggle Registry Manager
3
+ #
4
+ # This is the primary DSL interface. It provides a DSL to facilitate housing
5
+ # and managing a toggle registry.
6
+ module ReleaseToggleRegistryManager
7
+ def self.included(mod)
8
+ mod.extend(ClassMethods)
9
+ end
10
+
11
+ # Release Toggle Registry Manager Class Methods
12
+ #
13
+ # The class methods that should be extended onto the module/class when
14
+ # ReleaseToggleRegistryManager is included.
15
+ module ClassMethods
16
+ def features(&block)
17
+ if @feature_toggle_registry.nil?
18
+ @feature_toggle_registry = FeatureToggleRegistry.new
19
+ end
20
+
21
+ @feature_toggle_registry.expand(&block) if block
22
+
23
+ @feature_toggle_registry
24
+ end
25
+
26
+ def features=(feature_toggle_registry)
27
+ @feature_toggle_registry = feature_toggle_registry
28
+ end
29
+
30
+ def feature(key)
31
+ if @feature_toggle_registry.nil?
32
+ @feature_toggle_registry = FeatureToggleRegistry.new
33
+ end
34
+
35
+ @feature_toggle_registry.get(key)
36
+ end
37
+
38
+ def logger
39
+ @logger ||= Logger.new(STDOUT)
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/togls/rule.rb CHANGED
@@ -1,15 +1,17 @@
1
1
  module Togls
2
+ # Rule
3
+ #
4
+ # The Rule is an abstract base class that is intended to act as an interface
5
+ # for other rules to be implemented against.
2
6
  class Rule
3
7
  attr_reader :data
4
8
 
5
- def initialize(data=nil)
6
- @data = data
9
+ def initialize(data = nil)
10
+ @data = data
7
11
  end
8
12
 
9
13
  def run(key, target = nil)
10
- raise Togls::NotImplemented.new(
11
- "Rule's #run method must be implemented"
12
- )
14
+ raise Togls::NotImplemented, "Rule's #run method must be implemented"
13
15
  end
14
16
 
15
17
  def id
@@ -1,11 +1,16 @@
1
1
  module Togls
2
+ # Rule Repository
3
+ #
4
+ # The Rule Repository is the intended interface to store and retrieve rules.
5
+ # It does these by interfacing with Rule Repository Drivers which are passed
6
+ # in during construction as an Array.
2
7
  class RuleRepository
3
8
  def initialize(drivers)
4
- if !drivers.is_a?(Array)
5
- raise Togls::InvalidDriver.new("RuleRepository requires a valid driver")
9
+ unless drivers.is_a?(Array)
10
+ raise Togls::InvalidDriver, 'RuleRepository requires a valid driver'
6
11
  end
7
12
  if drivers.empty?
8
- raise Togls::MissingDriver.new("RuleRepository requires a driver")
13
+ raise Togls::MissingDriver, 'RuleRepository requires a driver'
9
14
  end
10
15
  @drivers = drivers
11
16
  end
@@ -16,9 +21,9 @@ module Togls
16
21
  driver.store(rule.id, rule_data)
17
22
  end
18
23
  end
19
-
24
+
20
25
  def extract_storage_payload(rule)
21
- return { "klass" => rule.class, "data" => rule.data }
26
+ { 'klass' => rule.class, 'data' => rule.data }
22
27
  end
23
28
 
24
29
  def fetch_rule_data(id)
@@ -36,7 +41,7 @@ module Togls
36
41
  end
37
42
 
38
43
  def reconstitute_rule(rule_data)
39
- rule_data["klass"].new(rule_data["data"])
44
+ rule_data['klass'].new(rule_data['data'])
40
45
  end
41
46
  end
42
47
  end
@@ -1,16 +1,27 @@
1
+ require 'thread'
2
+
1
3
  module Togls
2
4
  module RuleRepositoryDrivers
5
+ # Rule Repository In-Memory Driver
6
+ #
7
+ # The Rule Repository In-Memory Driver provides the interface to store and
8
+ # retrieve rules. This is intended to be used by a Rule Repository instance.
3
9
  class InMemoryDriver
4
10
  def initialize
5
11
  @rules = {}
12
+ @rules_lock = Mutex.new
6
13
  end
7
14
 
8
15
  def store(rule_id, rule_data)
9
- @rules[rule_id] = rule_data
16
+ @rules_lock.synchronize do
17
+ @rules[rule_id] = rule_data
18
+ end
10
19
  end
11
-
20
+
12
21
  def get(rule_id)
13
- @rules[rule_id]
22
+ @rules_lock.synchronize do
23
+ @rules[rule_id]
24
+ end
14
25
  end
15
26
  end
16
27
  end
@@ -1,5 +1,8 @@
1
1
  module Togls
2
+ # Rule Repository Drivers
3
+ #
4
+ # The Rule Repository Drivers module is simply an organizational bucket to
5
+ # house the rule repository drivers provided by Togls.
2
6
  module RuleRepositoryDrivers
3
-
4
7
  end
5
8
  end
@@ -1,8 +1,22 @@
1
1
  module Togls
2
2
  module Rules
3
+ # Boolean Rule
4
+ #
5
+ # The Boolean Rule is a provided Rule that expects to be given a boolean as
6
+ # it's initialization data and when evaluated determines the toggle state
7
+ # based on the initialization value. Example:
8
+ #
9
+ # always_on = Togls::Rules::Boolean.new(true)
10
+ # Togls.features do
11
+ # feature(:foo).on(always_on)
12
+ # end
13
+ #
14
+ # if Togls.feature(:foo).on?
15
+ # ...
16
+ # end
3
17
  class Boolean < Rule
4
- def run(key, target = nil)
5
- return @data
18
+ def run(_key, _target = nil)
19
+ @data
6
20
  end
7
21
  end
8
22
  end
@@ -1,7 +1,23 @@
1
1
  module Togls
2
2
  module Rules
3
+ # Group Rule
4
+ #
5
+ # The Group Rule is a provided Rule that expects to be given an Array as
6
+ # it's initialization data and when evaluated determines the toggle state
7
+ # based on the given target being included in the Array that was passed in
8
+ # during initialization. This allows you to define various groups. For
9
+ # example:
10
+ #
11
+ # alpha_testers = Togls::Rules::Group.new(['bob@ex.com', 'cindy@ex.com'])
12
+ # Togls.features do
13
+ # feature(:foo).on(alpha_testers)
14
+ # end
15
+ #
16
+ # if Togls.feature(:foo).on?(current_user.email)
17
+ # ...
18
+ # end
3
19
  class Group < Rule
4
- def run(key, target)
20
+ def run(_key, target)
5
21
  @data.include?(target)
6
22
  end
7
23
  end
data/lib/togls/rules.rb CHANGED
@@ -2,6 +2,10 @@ require 'togls/rules/boolean'
2
2
  require 'togls/rules/group'
3
3
 
4
4
  module Togls
5
+ # Rules
6
+ #
7
+ # The Rules module is simply an organizational bucket to house all the rules
8
+ # that Togls provides.
5
9
  module Rules
6
10
  end
7
11
  end
@@ -0,0 +1,26 @@
1
+ module Togls
2
+ # Test Toggle Registry
3
+ #
4
+ # The Test Toggle Registry is a toggle feature toggle registry specifically
5
+ # intended to be used in the use case of automated test suites. The difference
6
+ # between this toggle registry and the normal FeatureToggleRegistry is that
7
+ # this registry only uses in-memory drivers and the FeatureToggleRegistry uses
8
+ # in-memory drivers as well as the environment override drivers.
9
+ class TestToggleRegistry < FeatureToggleRegistry
10
+ def initialize
11
+ @toggle_repository_drivers = [
12
+ Togls::ToggleRepositoryDrivers::InMemoryDriver.new]
13
+ @feature_repository_drivers =
14
+ [Togls::FeatureRepositoryDrivers::InMemoryDriver.new]
15
+ @rule_repository_drivers =
16
+ [Togls::RuleRepositoryDrivers::InMemoryDriver.new]
17
+ @feature_repository = Togls::FeatureRepository.new(
18
+ @feature_repository_drivers)
19
+ @rule_repository = Togls::RuleRepository.new(@rule_repository_drivers)
20
+ @toggle_repository = Togls::ToggleRepository.new(
21
+ @toggle_repository_drivers, @feature_repository, @rule_repository)
22
+ @rule_repository.store(Togls::Rules::Boolean.new(true))
23
+ @rule_repository.store(Togls::Rules::Boolean.new(false))
24
+ end
25
+ end
26
+ end
data/lib/togls/toggle.rb CHANGED
@@ -1,4 +1,9 @@
1
1
  module Togls
2
+ # Toggle
3
+ #
4
+ # The model representing a Toggle within the world of Togls. A Toggle's
5
+ # responsibility is binding a specific rule to a specific feature. Toggle's by
6
+ # default are associated with a boolean rule initialized to false.
2
7
  class Toggle
3
8
  attr_reader :feature
4
9
  attr_accessor :rule
@@ -17,15 +22,15 @@ module Togls
17
22
  end
18
23
 
19
24
  def off?(target = nil)
20
- return !@rule.run(@feature.key, target)
25
+ !@rule.run(@feature.key, target)
21
26
  end
22
27
 
23
28
  def to_s
24
- if @rule.is_a?(Togls::Rules::Boolean)
25
- display_value = @rule.run(@feature.key) ? ' on' : 'off'
26
- else
27
- display_value = ' ?'
28
- end
29
+ display_value = if @rule.is_a?(Togls::Rules::Boolean)
30
+ @rule.run(@feature.key) ? ' on' : 'off'
31
+ else
32
+ ' ?'
33
+ end
29
34
 
30
35
  "#{display_value} - #{@feature.key} - #{@feature.description}"
31
36
  end
@@ -1,11 +1,14 @@
1
1
  module Togls
2
+ # Toggle Repository
3
+ #
4
+ # Repository interface for storing and retrieving toggles.
2
5
  class ToggleRepository
3
6
  def initialize(drivers, feature_repository, rule_repository)
4
- if !drivers.is_a?(Array)
5
- raise Togls::InvalidDriver.new("ToggleRepository requires a valid driver")
7
+ unless drivers.is_a?(Array)
8
+ raise Togls::InvalidDriver, 'ToggleRepository requires a valid driver'
6
9
  end
7
10
  if drivers.empty?
8
- raise Togls::MissingDriver.new("ToggleRepository requires a driver")
11
+ raise Togls::MissingDriver, 'ToggleRepository requires a driver'
9
12
  end
10
13
  @drivers = drivers
11
14
  @feature_repository = feature_repository
@@ -23,24 +26,21 @@ module Togls
23
26
  end
24
27
 
25
28
  def extract_storage_payload(toggle)
26
- { "feature_id" => toggle.feature.id, "rule_id" => toggle.rule.id }
29
+ { 'feature_id' => toggle.feature.id, 'rule_id' => toggle.rule.id }
27
30
  end
28
31
 
29
32
  def get(id)
30
33
  toggle_data = fetch_toggle_data(id)
31
- if toggle_data
32
- return reconstitute_toggle(toggle_data)
33
- else
34
- return Togls::NullToggle.new
35
- end
34
+ return reconstitute_toggle(toggle_data) if toggle_data
35
+ Togls::NullToggle.new
36
36
  end
37
37
 
38
38
  def reconstitute_toggle(toggle_data)
39
- feature = @feature_repository.get(toggle_data["feature_id"])
40
- rule = @rule_repository.get(toggle_data["rule_id"])
39
+ feature = @feature_repository.get(toggle_data['feature_id'])
40
+ rule = @rule_repository.get(toggle_data['rule_id'])
41
41
  toggle = Togls::Toggle.new(feature)
42
42
  toggle.rule = rule
43
- return toggle
43
+ toggle
44
44
  end
45
45
 
46
46
  def fetch_toggle_data(id)
@@ -1,33 +1,45 @@
1
1
  module Togls
2
2
  module ToggleRepositoryDrivers
3
+ # Toggle Repository Environment Override Driver
4
+ #
5
+ # The Toggle Repository Environment Override Driver provides a Toggle
6
+ # Repository driver that passively ignores requests to store toggles but
7
+ # still responds to retrieval requests. This conceptually makes it what I am
8
+ # referring to as an "Override Driver" because it only allows retrieving
9
+ # overrides from the store.
10
+ #
11
+ # In this particular case it is an Environment Override Driver. Therefore,
12
+ # the store that backs this driver is environment variables. Specifically,
13
+ # this driver would retrieve a boolean rule initialized true if the
14
+ # associated environment variable was equal to the string, 'true'. If the
15
+ # associated environment variable was equal to the string, 'false', it would
16
+ # return a boolean rule initialized to false. Any other value and the driver
17
+ # returns nil indicating that it couldn't find the toggle in the store.
3
18
  class EnvOverrideDriver
4
19
  def store(toggle_id, toggle_data)
5
20
  end
6
21
 
7
22
  def get(toggle_id)
8
- if ENV[toggle_env_key(toggle_id)]
9
- if ENV[toggle_env_key(toggle_id)] == "true"
10
- return { "feature_id" => toggle_id,
11
- "rule_id" => Togls::Helpers.sha1(Togls::Rules::Boolean, true) }
12
- elsif ENV[toggle_env_key(toggle_id)] == "false"
13
- return { "feature_id" => toggle_id,
14
- "rule_id" => Togls::Helpers.sha1(Togls::Rules::Boolean, false) }
15
- else
16
- return nil
17
- end
23
+ return nil if ENV[toggle_env_key(toggle_id)].nil?
24
+ if ENV[toggle_env_key(toggle_id)] == 'true'
25
+ return { 'feature_id' => toggle_id, 'rule_id' => Togls::Helpers.sha1(
26
+ Togls::Rules::Boolean, true) }
27
+ elsif ENV[toggle_env_key(toggle_id)] == 'false'
28
+ return { 'feature_id' => toggle_id, 'rule_id' => Togls::Helpers.sha1(
29
+ Togls::Rules::Boolean, false) }
18
30
  else
19
31
  return nil
20
32
  end
21
33
  end
22
34
 
23
35
  def all
24
- return {}
36
+ {}
25
37
  end
26
38
 
27
39
  private
28
40
 
29
41
  def toggle_env_key(toggle_id)
30
- return "TOGLS_#{toggle_id.to_s.upcase}"
42
+ "TOGLS_#{toggle_id.to_s.upcase}"
31
43
  end
32
44
  end
33
45
  end
@@ -1,20 +1,33 @@
1
+ require 'thread'
2
+
1
3
  module Togls
2
4
  module ToggleRepositoryDrivers
5
+ # Toggle Repositoy In-Memory Driver
6
+ #
7
+ # The Toggle Repository In-Memory Driver provides the interface to store and
8
+ # retrieve toggles from the in-memory store.
3
9
  class InMemoryDriver
4
10
  def initialize
5
11
  @toggles = {}
12
+ @toggles_lock = Mutex.new
6
13
  end
7
14
 
8
15
  def store(toggle_id, toggle_data)
9
- @toggles[toggle_id] = toggle_data
16
+ @toggles_lock.synchronize do
17
+ @toggles[toggle_id] = toggle_data
18
+ end
10
19
  end
11
20
 
12
21
  def get(toggle_id)
13
- @toggles[toggle_id]
22
+ @toggles_lock.synchronize do
23
+ @toggles[toggle_id]
24
+ end
14
25
  end
15
26
 
16
27
  def all
17
- @toggles
28
+ @toggles_lock.synchronize do
29
+ @toggles
30
+ end
18
31
  end
19
32
  end
20
33
  end
@@ -1,5 +1,8 @@
1
1
  module Togls
2
+ # Toggle Repository Drivers
3
+ #
4
+ # Simply an organizational container for the Toggle Repository drivers
5
+ # provided by Togls.
2
6
  module ToggleRepositoryDrivers
3
-
4
7
  end
5
8
  end
data/lib/togls/toggler.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  module Togls
2
+ # Toggle Toggler
3
+ #
4
+ # The Toggle Toggler provides the convenience interface of being able to
5
+ # toggle a feature on/off via the `on` or `off` methods respectively.
2
6
  class Toggler
3
7
  def initialize(toggle_repository, toggle)
4
8
  @toggle_repository = toggle_repository
@@ -6,9 +10,7 @@ module Togls
6
10
  end
7
11
 
8
12
  def on(rule = nil)
9
- if rule.nil?
10
- rule = Togls::Rules::Boolean.new(true)
11
- end
13
+ rule = Togls::Rules::Boolean.new(true) if rule.nil?
12
14
  @toggle.rule = rule
13
15
  @toggle_repository.store(@toggle)
14
16
  @toggle
data/lib/togls/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Togls
2
- VERSION = "2.1.1"
2
+ VERSION = '2.2.0'.freeze
3
3
  end
data/lib/togls.rb CHANGED
@@ -1,51 +1,31 @@
1
- require "togls/version"
2
- require "togls/errors"
3
- require "togls/helpers"
4
- require "togls/toggle_repository_drivers"
5
- require "togls/toggle_repository_drivers/in_memory_driver"
6
- require "togls/toggle_repository_drivers/env_override_driver"
7
- require "togls/feature_repository_drivers"
8
- require "togls/feature_repository_drivers/in_memory_driver"
9
- require "togls/rule_repository_drivers"
10
- require "togls/rule_repository_drivers/in_memory_driver"
11
- require "togls/toggler"
12
- require "togls/feature_toggle_registry"
13
- require "togls/feature_repository"
14
- require "togls/rule_repository"
15
- require "togls/toggle_repository"
16
- require "togls/feature"
17
- require "togls/toggle"
18
- require "togls/null_toggle"
19
- require "togls/rule"
20
- require "togls/rules"
21
- require "logger"
1
+ require 'togls/version'
2
+ require 'togls/errors'
3
+ require 'togls/helpers'
4
+ require 'togls/toggle_repository_drivers'
5
+ require 'togls/toggle_repository_drivers/in_memory_driver'
6
+ require 'togls/toggle_repository_drivers/env_override_driver'
7
+ require 'togls/feature_repository_drivers'
8
+ require 'togls/feature_repository_drivers/in_memory_driver'
9
+ require 'togls/rule_repository_drivers'
10
+ require 'togls/rule_repository_drivers/in_memory_driver'
11
+ require 'togls/toggler'
12
+ require 'togls/feature_toggle_registry'
13
+ require 'togls/test_toggle_registry'
14
+ require 'togls/feature_repository'
15
+ require 'togls/rule_repository'
16
+ require 'togls/toggle_repository'
17
+ require 'togls/feature'
18
+ require 'togls/toggle'
19
+ require 'togls/null_toggle'
20
+ require 'togls/rule'
21
+ require 'togls/rules'
22
+ require 'logger'
23
+ require 'togls/release_toggle_registry_manager'
22
24
 
25
+ # Togls
26
+ #
27
+ # Togls is the primary interface to the out of the box toggle registry. It is
28
+ # the namespace the DSL is exposed under.
23
29
  module Togls
24
- def self.features(&block)
25
- if @feature_toggle_registry.nil?
26
- @feature_toggle_registry = FeatureToggleRegistry.new
27
- end
28
-
29
- if block
30
- @feature_toggle_registry.expand(&block)
31
- end
32
-
33
- return @feature_toggle_registry
34
- end
35
-
36
- def self.features=(feature_toggle_registry)
37
- @feature_toggle_registry = feature_toggle_registry
38
- end
39
-
40
- def self.feature(key)
41
- if @feature_toggle_registry.nil?
42
- @feature_toggle_registry = FeatureToggleRegistry.new
43
- end
44
-
45
- return @feature_toggle_registry.get(key)
46
- end
47
-
48
- def self.logger
49
- @logger ||= Logger.new(STDOUT)
50
- end
30
+ include ReleaseToggleRegistryManager
51
31
  end
data/togls.gemspec CHANGED
@@ -4,23 +4,29 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'togls/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "togls"
7
+ spec.name = 'togls'
8
8
  spec.version = Togls::VERSION
9
- spec.authors = ["Brian Miller", "Andrew DePonte", "Ryan Hedges"]
10
- spec.email = ["brimil01@gmail.com", "cyphactor@gmail.com", "ryanhedges@gmail.com"]
9
+ spec.authors = ['Brian Miller', 'Andrew DePonte', 'Ryan Hedges']
10
+ spec.email = ['brimil01@gmail.com', 'cyphactor@gmail.com',
11
+ 'ryanhedges@gmail.com']
11
12
 
12
- spec.summary = %q{An ultra light weight yet ridiculously powerful ruby feature toggle gem.}
13
- spec.description = %q{An ultra light weight yet ridiculously powerful ruby feature toggle gem that supports the concept of release toggles and business toggles.}
14
- spec.homepage = "http://github.com/codebreakdown/togls"
15
- spec.license = "MIT"
13
+ spec.summary = 'An ultra light weight yet ridiculously powerful' \
14
+ 'ruby feature toggle gem.'
15
+ spec.description = 'An ultra light weight yet ridiculously powerful' \
16
+ ' ruby feature toggle gem that supports the concept' \
17
+ ' of release toggles and business toggles.'
18
+ spec.homepage = 'http://github.com/codebreakdown/togls'
19
+ spec.license = 'MIT'
16
20
 
17
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- spec.bindir = "exe"
21
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
22
+ f.match(%r{^(test|spec|features)/})
23
+ end
24
+ spec.bindir = 'exe'
19
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
- spec.require_paths = ["lib"]
26
+ spec.require_paths = ['lib']
21
27
 
22
- spec.add_development_dependency "bundler", "~> 1.9"
23
- spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_development_dependency "rspec", "~> 3.2"
25
- spec.add_development_dependency "pry", "~> 0.10"
28
+ spec.add_development_dependency 'bundler', '~> 1.9'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.2'
31
+ spec.add_development_dependency 'pry', '~> 0.10'
26
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: togls
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Miller
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2015-12-14 00:00:00.000000000 Z
13
+ date: 2016-03-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -83,8 +83,9 @@ files:
83
83
  - ".rspec"
84
84
  - ".ruby-version"
85
85
  - ".travis.yml"
86
+ - CHANGELOG.md
86
87
  - CODE_OF_CONDUCT.md
87
- - ChangeLog.md
88
+ - DEVELOPMENT.md
88
89
  - Gemfile
89
90
  - LICENSE.txt
90
91
  - README.md
@@ -102,6 +103,7 @@ files:
102
103
  - lib/togls/feature_toggle_registry.rb
103
104
  - lib/togls/helpers.rb
104
105
  - lib/togls/null_toggle.rb
106
+ - lib/togls/release_toggle_registry_manager.rb
105
107
  - lib/togls/rule.rb
106
108
  - lib/togls/rule_repository.rb
107
109
  - lib/togls/rule_repository_drivers.rb
@@ -109,6 +111,7 @@ files:
109
111
  - lib/togls/rules.rb
110
112
  - lib/togls/rules/boolean.rb
111
113
  - lib/togls/rules/group.rb
114
+ - lib/togls/test_toggle_registry.rb
112
115
  - lib/togls/toggle.rb
113
116
  - lib/togls/toggle_repository.rb
114
117
  - lib/togls/toggle_repository_drivers.rb
@@ -137,8 +140,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
140
  version: '0'
138
141
  requirements: []
139
142
  rubyforge_project:
140
- rubygems_version: 2.4.5.1
143
+ rubygems_version: 2.5.1
141
144
  signing_key:
142
145
  specification_version: 4
143
- summary: An ultra light weight yet ridiculously powerful ruby feature toggle gem.
146
+ summary: An ultra light weight yet ridiculously powerfulruby feature toggle gem.
144
147
  test_files: []
148
+ has_rdoc: