togls 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: