togls 2.2.1 → 3.0.0.pre.rc.1
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 +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +107 -36
- data/README.md +12 -9
- data/lib/togls/default_feature_target_type_manager.rb +25 -0
- data/lib/togls/errors.rb +15 -4
- data/lib/togls/feature.rb +13 -1
- data/lib/togls/feature_repository.rb +28 -2
- data/lib/togls/feature_toggle_registry_manager.rb +138 -0
- data/lib/togls/helpers.rb +2 -2
- data/lib/togls/null_toggle.rb +4 -1
- data/lib/togls/rule.rb +29 -3
- data/lib/togls/rule_repository.rb +36 -3
- data/lib/togls/rule_repository_drivers/env_override_driver.rb +22 -0
- data/lib/togls/rule_type_registry.rb +38 -0
- data/lib/togls/rule_type_repository.rb +57 -0
- data/lib/togls/rule_type_repository_drivers/in_memory_driver.rb +52 -0
- data/lib/togls/rule_type_repository_drivers.rb +5 -0
- data/lib/togls/rules/boolean.rb +21 -1
- data/lib/togls/rules/group.rb +26 -0
- data/lib/togls/target_types.rb +9 -0
- data/lib/togls/toggle.rb +57 -13
- data/lib/togls/toggle_registry.rb +45 -0
- data/lib/togls/toggle_repository.rb +20 -5
- data/lib/togls/toggler.rb +6 -2
- data/lib/togls/version.rb +1 -1
- data/lib/togls.rb +11 -4
- data/togls.gemspec +1 -1
- metadata +15 -10
- data/lib/tasks/togls.rake +0 -9
- data/lib/togls/feature_toggle_registry.rb +0 -57
- data/lib/togls/release_toggle_registry_manager.rb +0 -43
- data/lib/togls/test_toggle_registry.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e15bb80dde590be56e09b63b345d321068356ed7
|
4
|
+
data.tar.gz: cf898035f7e06327aca28ba7805440fcfb123a09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 059266b27c515744c891db005dab8ac82485670a18749c3a857ee7996a2016287bba98a1ef9063a33495e937e967e3516dac505e51f5fe52f1cc499f17cb6d8d
|
7
|
+
data.tar.gz: ebe1d54110e5f27989a0f4fab4d5ebfcfc8f4c427776e5efb5fe40ce3c5e9a7716765a2c4aa75cb65db4c2be4c5f50b78533676e14660318124e88f5e1eb6a3d
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3.
|
1
|
+
2.3.1
|
data/CHANGELOG.md
CHANGED
@@ -2,55 +2,126 @@
|
|
2
2
|
|
3
3
|
The following are lists of the notable changes included with each release.
|
4
4
|
This is intended to help keep people informed about notable changes between
|
5
|
-
versions, as well as provide a rough history.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
*
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
*
|
5
|
+
versions, as well as provide a rough history. Each item is prefixed with
|
6
|
+
one of the following labels: `Added`, `Changed`, `Deprecated`,
|
7
|
+
`Removed`, `Fixed`, `Security`. We also use [Semantic
|
8
|
+
Versioning](http://semver.org) to manage the versions of this gem so
|
9
|
+
that you can set version constraints properly.
|
10
|
+
|
11
|
+
#### [Unreleased] - now
|
12
|
+
|
13
|
+
* `Changed`: The testing interface to allow for contract enforcement in tests
|
14
|
+
and allow altering existing feature rules within tests.
|
15
|
+
* `Added`: `Togls.rule` method to simplify rule construction from `type_id`
|
16
|
+
([#86](https://github.com/codebreakdown/togls/issues/86))
|
17
|
+
* `Changed`: Rule construction to require an abstract rule `type_id`
|
18
|
+
([#86](https://github.com/codebreakdown/togls/issues/86))
|
19
|
+
* `Added`: Feature repository response validation
|
20
|
+
* `Added`: validation of targets against feature target_type contract
|
21
|
+
([#78](https://github.com/codebreakdown/togls/issues/78))
|
22
|
+
* `Added`: setting a default feature target type
|
23
|
+
([#69](https://github.com/codebreakdown/togls/issues/69))
|
24
|
+
* `Added`: logging for target type mismatches/erroneous states
|
25
|
+
([#69](https://github.com/codebreakdown/togls/issues/69))
|
26
|
+
* `Changed`: in code feature rule association API to require `target_type`
|
27
|
+
([#69](https://github.com/codebreakdown/togls/issues/69))
|
28
|
+
* `Added`: rule instance target types and switch type checking over
|
29
|
+
([#67](https://github.com/codebreakdown/togls/issues/67))
|
30
|
+
* `Added`: optional target types, and target type checking
|
31
|
+
([#65](https://github.com/codebreakdown/togls/issues/65))
|
32
|
+
* `Changed`: rule type repository to store meta data
|
33
|
+
([#62](https://github.com/codebreakdown/togls/issues/62))
|
34
|
+
* `Added`: uniqueness check for rule types
|
35
|
+
([#61](https://github.com/codebreakdown/togls/issues/61)
|
36
|
+
* `Changed`: rule repository to use rule type repository
|
37
|
+
([#59](https://github.com/codebreakdown/togls/issues/59))
|
38
|
+
* `Added`: rule type registration
|
39
|
+
([#59](https://github.com/codebreakdown/togls/issues/59))
|
40
|
+
* `Changed`: driver construction to RegistryManager
|
41
|
+
([#56](https://github.com/codebreakdown/togls/issues/56))
|
42
|
+
* `Removed`: `TestToggleRegistry`
|
43
|
+
([#56](https://github.com/codebreakdown/togls/issues/56))
|
44
|
+
* `Changed`: `ReleaseToggleRegistry` to `ToggleRegistry`
|
45
|
+
([#56](https://github.com/codebreakdown/togls/issues/56))
|
46
|
+
* `Removed`: `features` rake task
|
47
|
+
([#48](https://github.com/codebreakdown/togls/issues/48))
|
48
|
+
* `Added`: `test_mode` block style method
|
49
|
+
([#44](https://github.com/codebreakdown/togls/issues/44))
|
50
|
+
* `Changed`: `Togls.features` to `Togls.release`
|
51
|
+
([#38](https://github.com/codebreakdown/togls/issues/38))
|
52
|
+
* `Changed`: Renamed `FeatureToggleRegistry` to `ReleaseToggleRegistry`
|
53
|
+
([#41](https://github.com/codebreakdown/togls/issues/41))
|
54
|
+
* `Added`: `FeatureToggleRegistryManager` methods, `enable_test_mode` &
|
55
|
+
`disable_test_mode`
|
56
|
+
* `Removed`: `features=` setter
|
57
|
+
* `Changed`: `FeatureRepository` moved from `Registry` to `RegistryManager`
|
58
|
+
([#40](https://github.com/codebreakdown/togls/issues/40))
|
59
|
+
* `Removed`: `FeatureToggleRegistry.create` and `TestToggleRegistry.create`
|
60
|
+
* `Changed`: `ReleaseToggleRegistryManager` to `FeatureToggleRegistryManager`
|
61
|
+
* `Added`: Base Error class for Togls exceptions
|
62
|
+
([#39](https://github.com/codebreakdown/togls/issues/39))
|
63
|
+
* `Added`: Exception for when a feature has already been defined in the feature
|
64
|
+
repository
|
65
|
+
([#42](https://github.com/codebreakdown/togls/issues/42))
|
66
|
+
|
67
|
+
#### [v2.2.1] - 2016-03-24
|
68
|
+
|
69
|
+
* `Added`: in-memory driver `set`, `get`, `all` Marshaling to correct a threading
|
70
|
+
reference based collision.
|
71
|
+
([#35](https://github.com/codebreakdown/togls/issues/35))
|
72
|
+
|
73
|
+
#### [v2.2.0] - 2016-03-04
|
74
|
+
|
75
|
+
* `Changed`: Togls to be thread-safe
|
76
|
+
* `Added`: `Togls::TestToggleRegistry` class for initializing test state
|
77
|
+
* `Added`: ability to create additional toggle registries
|
78
|
+
|
79
|
+
#### [v2.1.1] - 2015-12-14
|
80
|
+
|
81
|
+
* `Fixed`: env variable override wasn't falling through to in
|
23
82
|
code defined memory value.
|
83
|
+
([#24](https://github.com/codebreakdown/togls/issues/24))
|
24
84
|
|
25
|
-
|
85
|
+
#### [v2.1.0] - 2015-11-24
|
26
86
|
|
27
|
-
* Fixed
|
87
|
+
* `Fixed`: exceptions happened on evaluation after setting
|
28
88
|
`Togls.features = nil`
|
89
|
+
([#19](https://github.com/codebreakdown/togls/issues/19))
|
29
90
|
|
30
|
-
|
91
|
+
#### [v2.0.0] - 2015-11-23
|
31
92
|
|
32
|
-
*
|
33
|
-
*
|
34
|
-
*
|
35
|
-
*
|
93
|
+
* `Added`: ability to create empty feature toggle set via `Togls.features`
|
94
|
+
* `Added`: toggle definition expansion with multiple `Togls.features` blocks
|
95
|
+
* `Added`: set FeatureToggleRegistry instance, `Togls.features = toggle_registry`
|
96
|
+
* `Changed`: `Togls.features` to return FeatureToggleRegistry instance
|
36
97
|
rather than an Array of Toggle objects.
|
37
98
|
|
38
|
-
#### v1.1.0
|
99
|
+
#### [v1.1.0] - 2015-11-17
|
39
100
|
|
40
|
-
*
|
41
|
-
*
|
42
|
-
*
|
101
|
+
* `Added`: `off?` method for asking if a defined feature is off
|
102
|
+
* `Added`: feature toggle overrides
|
103
|
+
* `Changed`: Architecture to support concept of repositories and datastores allowing
|
43
104
|
further growth in the future
|
44
105
|
|
45
|
-
#### v1.0.0
|
106
|
+
#### [v1.0.0] - 2015-05-19
|
46
107
|
|
47
|
-
*
|
48
|
-
*
|
108
|
+
* `Changed`: to require human readable description to define a feature toggle
|
109
|
+
* `Added`: rake task that outputs all the feature toggles states (on, off, ? -
|
49
110
|
unknown due to Compex Rule), keys, and human readable descritpions
|
50
111
|
|
51
|
-
#### v0.1.0
|
112
|
+
#### [v0.1.0] - 2015-05-03
|
52
113
|
|
53
|
-
*
|
54
|
-
*
|
114
|
+
* `Added`: concept of Groups as a provided rule
|
115
|
+
* `Added`: concept of Rules and Custom Rules, allowing users to have more dynamic
|
55
116
|
feature toggles
|
56
|
-
*
|
117
|
+
* `Added`: basic feature toggles able to be switched on/off
|
118
|
+
|
119
|
+
[Unreleased]: https://github.com/codebreakdown/togls/compare/v2.2.1...HEAD
|
120
|
+
[v2.2.1]: https://github.com/codebreakdown/togls/compare/v2.2.0...v2.2.1
|
121
|
+
[v2.2.0]: https://github.com/codebreakdown/togls/compare/v2.1.1...v2.2.0
|
122
|
+
[v2.1.1]: https://github.com/codebreakdown/togls/compare/v2.1.0...v2.1.1
|
123
|
+
[v2.1.0]: https://github.com/codebreakdown/togls/compare/v2.0.0...v2.1.0
|
124
|
+
[v2.0.0]: https://github.com/codebreakdown/togls/compare/v1.1.0...v2.0.0
|
125
|
+
[v1.1.0]: https://github.com/codebreakdown/togls/compare/v1.0.0...v1.1.0
|
126
|
+
[v1.0.0]: https://github.com/codebreakdown/togls/compare/v0.1.0...v1.0.0
|
127
|
+
[v0.1.0]: https://github.com/codebreakdown/togls/compare/0fa2feb...v0.1.0
|
data/README.md
CHANGED
@@ -50,7 +50,7 @@ The following, `config/initializers/togls_features.rb`, is an example of
|
|
50
50
|
how one would define some basic feature toggles.
|
51
51
|
|
52
52
|
```ruby
|
53
|
-
Togls.
|
53
|
+
Togls.release do
|
54
54
|
# Set this feature to always be on
|
55
55
|
feature(:pop_up_login_form, "use pop up login instead of normal login").on
|
56
56
|
|
@@ -95,7 +95,7 @@ feature toggle in all caps with `TOGLS_` prefixed to it. For example if
|
|
95
95
|
we had the following feature toggle defined.
|
96
96
|
|
97
97
|
```ruby
|
98
|
-
Togls.
|
98
|
+
Togls.release do
|
99
99
|
# Set this feature to always be on
|
100
100
|
feature(:pop_up_login_form, "use pop up login instead of normal login").on
|
101
101
|
end
|
@@ -131,7 +131,7 @@ based on group membership.
|
|
131
131
|
alpha_testers = Togls::Rules::Group.new(["user1@email.com",
|
132
132
|
"user2@example.com"])
|
133
133
|
|
134
|
-
Togls.
|
134
|
+
Togls.release do
|
135
135
|
feature(:new_contact_form, "use new contact form").on(alpha_testers)
|
136
136
|
end
|
137
137
|
```
|
@@ -183,7 +183,7 @@ in the example above and it would look something like the following:
|
|
183
183
|
# the group.
|
184
184
|
alpha_testers = Togls::Rules::Group.new([1, 23, 42, 83])
|
185
185
|
|
186
|
-
Togls.
|
186
|
+
Togls.release do
|
187
187
|
feature(:new_contact_form, "use new contact form").on(alpha_testers)
|
188
188
|
end
|
189
189
|
```
|
@@ -207,14 +207,17 @@ including details of advanced usage in the `README.md` as to not
|
|
207
207
|
overwhelm people on first impression. For more details on some of the
|
208
208
|
more advanced features feel free to check out our
|
209
209
|
[Wiki](https://github.com/codebreakdown/togls/wiki). Just a few of the
|
210
|
-
many things it contains are
|
210
|
+
many things it contains are
|
211
|
+
[Testing with
|
212
|
+
Toggles](https://github.com/codebreakdown/togls/wiki/Testing-with-Toggles),
|
213
|
+
[Provided Rules
|
211
214
|
Reference](https://github.com/codebreakdown/togls/wiki/Provided-Rules-Reference),
|
212
215
|
[Custom
|
213
216
|
Rules](https://github.com/codebreakdown/togls/wiki/Custom-Rules),
|
214
|
-
[
|
215
|
-
|
216
|
-
[
|
217
|
-
|
217
|
+
[Organize Toggle
|
218
|
+
Definitions](https://github.com/codebreakdown/togls/wiki/Organize-Toggle-Definitions),
|
219
|
+
[Creating Additional Toggle
|
220
|
+
Registries](https://github.com/codebreakdown/togls/wiki/Create-Additional-Toggle-Registries),
|
218
221
|
etc.
|
219
222
|
|
220
223
|
## Development
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Togls
|
2
|
+
module DefaultFeatureTargetTypeManager
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def default_feature_target_type(target_type = nil)
|
9
|
+
if target_type
|
10
|
+
if @default_feature_target_type
|
11
|
+
raise Togls::DefaultFeatureTargetTypeAlreadySet, 'the default feature target type has already been set'
|
12
|
+
else
|
13
|
+
@default_feature_target_type = target_type
|
14
|
+
end
|
15
|
+
else
|
16
|
+
if @default_feature_target_type
|
17
|
+
return @default_feature_target_type
|
18
|
+
else
|
19
|
+
return Togls::TargetTypes::NOT_SET
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/togls/errors.rb
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
module Togls
|
2
|
-
class
|
3
|
-
class
|
4
|
-
class
|
5
|
-
class
|
2
|
+
class Error < StandardError; end
|
3
|
+
class NoFeaturesError < Error; end
|
4
|
+
class MissingDriver < Error; end
|
5
|
+
class InvalidDriver < Error; end
|
6
|
+
class NotImplemented < Error; end
|
7
|
+
class FeatureAlreadyDefined < Error; end
|
8
|
+
class RuleTypeAlreadyDefined < Error; end
|
9
|
+
class RuleFeatureTargetTypeMismatch < Error; end
|
10
|
+
class RuleMissingTargetType < Error; end
|
11
|
+
class DefaultFeatureTargetTypeAlreadySet < Error; end
|
12
|
+
class FeatureMissingTargetType < Error; end
|
13
|
+
class EvaluationTargetMissing < Error; end
|
14
|
+
class UnexpectedEvaluationTarget < Error; end
|
15
|
+
class RepositoryFeatureDataInvalid < Error; end
|
16
|
+
class RepositoryRuleDataInvalid < Error; end
|
6
17
|
end
|
data/lib/togls/feature.rb
CHANGED
@@ -6,13 +6,25 @@ module Togls
|
|
6
6
|
class Feature
|
7
7
|
attr_reader :key, :description
|
8
8
|
|
9
|
-
def initialize(key, description)
|
9
|
+
def initialize(key, description, target_type)
|
10
10
|
@key = key.to_s
|
11
11
|
@description = description
|
12
|
+
@target_type = target_type
|
13
|
+
raise Togls::FeatureMissingTargetType, "Feature '#{self.key}' is missing a required target type" if self.missing_target_type?
|
14
|
+
end
|
15
|
+
|
16
|
+
def target_type
|
17
|
+
return @target_type unless @target_type.nil?
|
18
|
+
return Togls::TargetTypes::NOT_SET
|
12
19
|
end
|
13
20
|
|
14
21
|
def id
|
15
22
|
@key
|
16
23
|
end
|
24
|
+
|
25
|
+
def missing_target_type?
|
26
|
+
return false if target_type && (target_type != Togls::TargetTypes::NOT_SET)
|
27
|
+
return true
|
28
|
+
end
|
17
29
|
end
|
18
30
|
end
|
@@ -22,7 +22,7 @@ module Togls
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def extract_feature_data(feature)
|
25
|
-
{ 'key' => feature.key, 'description' => feature.description }
|
25
|
+
{ 'key' => feature.key, 'description' => feature.description, 'target_type' => feature.target_type.to_s }
|
26
26
|
end
|
27
27
|
|
28
28
|
def fetch_feature_data(id)
|
@@ -34,14 +34,40 @@ module Togls
|
|
34
34
|
feature_data
|
35
35
|
end
|
36
36
|
|
37
|
+
def include?(feature_id)
|
38
|
+
result = fetch_feature_data(feature_id)
|
39
|
+
result.nil? ? false : true
|
40
|
+
end
|
41
|
+
|
37
42
|
def get(feature_id)
|
38
43
|
feature_data = fetch_feature_data(feature_id)
|
44
|
+
validate_feature_data(feature_data)
|
39
45
|
reconstitute_feature(feature_data)
|
40
46
|
end
|
41
47
|
|
42
48
|
def reconstitute_feature(feature_data)
|
43
49
|
Togls::Feature.new(feature_data['key'],
|
44
|
-
feature_data['description']
|
50
|
+
feature_data['description'],
|
51
|
+
feature_data['target_type'].to_sym)
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_feature_data(feature_data)
|
55
|
+
if feature_data.nil?
|
56
|
+
Togls.logger.debug("None of the feature repository drivers claim to have the feature")
|
57
|
+
raise Togls::RepositoryFeatureDataInvalid, "None of the feature repository drivers claim to have the feature"
|
58
|
+
end
|
59
|
+
|
60
|
+
['key', 'description', 'target_type'].each do |k|
|
61
|
+
if !feature_data.has_key? k
|
62
|
+
Togls.logger.debug("One of the feature repository drivers returned feature data that is missing the '#{k}'")
|
63
|
+
raise Togls::RepositoryFeatureDataInvalid, "One of the feature repository drivers returned feature data that is missing the '#{k}'"
|
64
|
+
end
|
65
|
+
|
66
|
+
if !feature_data[k].is_a?(String)
|
67
|
+
Togls.logger.debug("One of the feature repository drivers returned feature data with '#{k}' not being a string")
|
68
|
+
raise Togls::RepositoryFeatureDataInvalid, "One of the feature repository drivers returned feature data with '#{k}' not being a string"
|
69
|
+
end
|
70
|
+
end
|
45
71
|
end
|
46
72
|
end
|
47
73
|
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Togls
|
2
|
+
# Feature 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 FeatureToggleRegistryManager
|
7
|
+
def self.included(mod)
|
8
|
+
mod.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Feature Toggle Registry Manager Class Methods
|
12
|
+
#
|
13
|
+
# The class methods that should be extended onto the module/class when
|
14
|
+
# FeatureToggleRegistryManager is included.
|
15
|
+
module ClassMethods
|
16
|
+
def release(&block)
|
17
|
+
release_blocks << block if block
|
18
|
+
|
19
|
+
release_toggle_registry.expand(&block) if block
|
20
|
+
release_toggle_registry
|
21
|
+
end
|
22
|
+
|
23
|
+
def release_blocks
|
24
|
+
@release_blocks ||= []
|
25
|
+
end
|
26
|
+
|
27
|
+
def rule_types(&block)
|
28
|
+
rule_type_registry.expand(&block) if block
|
29
|
+
rule_type_registry
|
30
|
+
end
|
31
|
+
|
32
|
+
def rule_type(type_id)
|
33
|
+
rule_type_registry.get(type_id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def rule(type_id, data, target_type: Togls::TargetTypes::NOT_SET)
|
37
|
+
rule_type(type_id).new(type_id, data, target_type: target_type)
|
38
|
+
end
|
39
|
+
|
40
|
+
def feature(key)
|
41
|
+
Toggler.new(release_toggle_registry.instance_variable_get(:@toggle_repository), release_toggle_registry.get(key))
|
42
|
+
end
|
43
|
+
|
44
|
+
def logger
|
45
|
+
@logger ||= Logger.new(STDOUT)
|
46
|
+
end
|
47
|
+
|
48
|
+
def enable_test_mode
|
49
|
+
@previous_release_toggle_registry = @release_toggle_registry
|
50
|
+
@release_toggle_registry = test_toggle_registry
|
51
|
+
end
|
52
|
+
|
53
|
+
def disable_test_mode
|
54
|
+
@release_toggle_registry = @previous_release_toggle_registry
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_mode
|
58
|
+
enable_test_mode
|
59
|
+
yield
|
60
|
+
disable_test_mode
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def rule_type_repository
|
66
|
+
if @rule_type_repository.nil?
|
67
|
+
rule_type_repository_drivers = [RuleTypeRepositoryDrivers::InMemoryDriver.new]
|
68
|
+
@rule_type_repository = RuleTypeRepository.new(rule_type_repository_drivers)
|
69
|
+
end
|
70
|
+
@rule_type_repository
|
71
|
+
end
|
72
|
+
|
73
|
+
def rule_type_registry
|
74
|
+
if @rule_type_registry.nil?
|
75
|
+
@rule_type_registry = RuleTypeRegistry.new(rule_type_repository)
|
76
|
+
@rule_type_registry.register(:boolean, Togls::Rules::Boolean)
|
77
|
+
@rule_type_registry.register(:group, Togls::Rules::Group)
|
78
|
+
end
|
79
|
+
@rule_type_registry
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_toggle_registry
|
83
|
+
feature_repository_drivers =
|
84
|
+
[Togls::FeatureRepositoryDrivers::InMemoryDriver.new]
|
85
|
+
test_feature_repository = Togls::FeatureRepository.new(
|
86
|
+
feature_repository_drivers)
|
87
|
+
|
88
|
+
rule_repository_drivers =
|
89
|
+
[Togls::RuleRepositoryDrivers::InMemoryDriver.new]
|
90
|
+
rule_repository = Togls::RuleRepository.new(rule_type_registry, rule_repository_drivers)
|
91
|
+
|
92
|
+
toggle_repository_drivers = [
|
93
|
+
Togls::ToggleRepositoryDrivers::InMemoryDriver.new]
|
94
|
+
|
95
|
+
toggle_repository = Togls::ToggleRepository.new(
|
96
|
+
toggle_repository_drivers, test_feature_repository, rule_repository)
|
97
|
+
|
98
|
+
tr = ToggleRegistry.new(test_feature_repository, toggle_repository)
|
99
|
+
release_blocks.each do |p|
|
100
|
+
tr.expand(&p)
|
101
|
+
end
|
102
|
+
|
103
|
+
return tr
|
104
|
+
end
|
105
|
+
|
106
|
+
def release_toggle_registry
|
107
|
+
if @release_toggle_registry.nil?
|
108
|
+
rule_repository_drivers = [
|
109
|
+
Togls::RuleRepositoryDrivers::InMemoryDriver.new,
|
110
|
+
Togls::RuleRepositoryDrivers::EnvOverrideDriver.new
|
111
|
+
]
|
112
|
+
|
113
|
+
rule_repository = Togls::RuleRepository.new(rule_type_registry, rule_repository_drivers)
|
114
|
+
|
115
|
+
toggle_repository_drivers = [
|
116
|
+
Togls::ToggleRepositoryDrivers::InMemoryDriver.new,
|
117
|
+
Togls::ToggleRepositoryDrivers::EnvOverrideDriver.new
|
118
|
+
]
|
119
|
+
|
120
|
+
toggle_repository = Togls::ToggleRepository.new(
|
121
|
+
toggle_repository_drivers, feature_repository, rule_repository)
|
122
|
+
|
123
|
+
@release_toggle_registry = ToggleRegistry.new(feature_repository,
|
124
|
+
toggle_repository)
|
125
|
+
end
|
126
|
+
@release_toggle_registry
|
127
|
+
end
|
128
|
+
|
129
|
+
def feature_repository
|
130
|
+
if @feature_repository.nil?
|
131
|
+
feature_repository_drivers = [Togls::FeatureRepositoryDrivers::InMemoryDriver.new]
|
132
|
+
@feature_repository = Togls::FeatureRepository.new(feature_repository_drivers)
|
133
|
+
end
|
134
|
+
@feature_repository
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/togls/helpers.rb
CHANGED
data/lib/togls/null_toggle.rb
CHANGED
@@ -5,7 +5,7 @@ module Togls
|
|
5
5
|
# toggle found when requested to be retreived through a Toggle Repository.
|
6
6
|
class NullToggle < Togls::Toggle
|
7
7
|
def initialize
|
8
|
-
feature = Togls::Feature.new('null', 'the official null feature')
|
8
|
+
feature = Togls::Feature.new('null', 'the official null feature', Togls::TargetTypes::EITHER)
|
9
9
|
super(feature)
|
10
10
|
end
|
11
11
|
|
@@ -17,4 +17,7 @@ module Togls
|
|
17
17
|
self
|
18
18
|
end
|
19
19
|
end
|
20
|
+
|
21
|
+
class ToggleMissingToggle < NullToggle; end
|
22
|
+
class RuleFeatureMismatchToggle < NullToggle; end
|
20
23
|
end
|
data/lib/togls/rule.rb
CHANGED
@@ -4,10 +4,25 @@ module Togls
|
|
4
4
|
# The Rule is an abstract base class that is intended to act as an interface
|
5
5
|
# for other rules to be implemented against.
|
6
6
|
class Rule
|
7
|
-
attr_reader :data
|
7
|
+
attr_reader :data, :type_id
|
8
8
|
|
9
|
-
def
|
9
|
+
def self.title
|
10
|
+
raise Togls::NotImplemented, "Rule type title not implemented"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.description
|
14
|
+
raise Togls::NotImplemented, "Rule type description not implemented"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.target_type
|
18
|
+
Togls::TargetTypes::NOT_SET
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(type_id, data = nil, target_type: Togls::TargetTypes::NOT_SET)
|
22
|
+
@type_id = type_id
|
10
23
|
@data = data
|
24
|
+
@target_type = target_type
|
25
|
+
raise Togls::RuleMissingTargetType, "Rule '#{self.id}' of type '#{self.class}' is missing a required target type" if self.missing_target_type?
|
11
26
|
end
|
12
27
|
|
13
28
|
def run(key, target = nil)
|
@@ -15,7 +30,18 @@ module Togls
|
|
15
30
|
end
|
16
31
|
|
17
32
|
def id
|
18
|
-
Togls::Helpers.sha1(
|
33
|
+
Togls::Helpers.sha1(@type_id, @data, target_type)
|
34
|
+
end
|
35
|
+
|
36
|
+
def target_type
|
37
|
+
return @target_type if @target_type && @target_type != Togls::TargetTypes::NOT_SET
|
38
|
+
return self.class.target_type unless self.class.target_type.nil?
|
39
|
+
return Togls::TargetTypes::NOT_SET
|
40
|
+
end
|
41
|
+
|
42
|
+
def missing_target_type?
|
43
|
+
return false if target_type && (target_type != Togls::TargetTypes::NOT_SET)
|
44
|
+
return true
|
19
45
|
end
|
20
46
|
end
|
21
47
|
end
|
@@ -5,7 +5,7 @@ module Togls
|
|
5
5
|
# It does these by interfacing with Rule Repository Drivers which are passed
|
6
6
|
# in during construction as an Array.
|
7
7
|
class RuleRepository
|
8
|
-
def initialize(drivers)
|
8
|
+
def initialize(rule_type_registry, drivers)
|
9
9
|
unless drivers.is_a?(Array)
|
10
10
|
raise Togls::InvalidDriver, 'RuleRepository requires a valid driver'
|
11
11
|
end
|
@@ -13,6 +13,7 @@ module Togls
|
|
13
13
|
raise Togls::MissingDriver, 'RuleRepository requires a driver'
|
14
14
|
end
|
15
15
|
@drivers = drivers
|
16
|
+
@rule_type_registry = rule_type_registry
|
16
17
|
end
|
17
18
|
|
18
19
|
def store(rule)
|
@@ -23,7 +24,11 @@ module Togls
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def extract_storage_payload(rule)
|
26
|
-
{
|
27
|
+
{
|
28
|
+
'type_id' => @rule_type_registry.get_type_id(rule.class.to_s),
|
29
|
+
'data' => rule.data,
|
30
|
+
'target_type' => rule.target_type.to_s
|
31
|
+
}
|
27
32
|
end
|
28
33
|
|
29
34
|
def fetch_rule_data(id)
|
@@ -37,11 +42,39 @@ module Togls
|
|
37
42
|
|
38
43
|
def get(rule_id)
|
39
44
|
rule_data = fetch_rule_data(rule_id)
|
45
|
+
validate_rule_data(rule_data)
|
40
46
|
reconstitute_rule(rule_data)
|
41
47
|
end
|
42
48
|
|
49
|
+
def validate_rule_data(rule_data)
|
50
|
+
if rule_data.nil?
|
51
|
+
Togls.logger.debug "None of the rule repository drivers claim to have the rule"
|
52
|
+
raise Togls::RepositoryRuleDataInvalid, "None of the rule repository drivers claim to have the rule"
|
53
|
+
end
|
54
|
+
|
55
|
+
['type_id', 'data', 'target_type'].each do |k|
|
56
|
+
if !rule_data.has_key? k
|
57
|
+
Togls.logger.debug "One of the rule repository drivers returned rule data that is missing the '#{k}'"
|
58
|
+
raise Togls::RepositoryRuleDataInvalid, "One of the rule repository drivers returned rule data that is missing the '#{k}'"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
['type_id', 'target_type'].each do |k|
|
63
|
+
if !rule_data[k].is_a?(String)
|
64
|
+
Togls.logger.debug "One of the rule repository drivers returned rule data with '#{k}' not being a string"
|
65
|
+
raise Togls::RepositoryRuleDataInvalid, "One of the rule repository drivers returned rule data with '#{k}' not being a string"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
43
70
|
def reconstitute_rule(rule_data)
|
44
|
-
rule_data
|
71
|
+
if rule_data.has_key?('target_type')
|
72
|
+
@rule_type_registry.get(rule_data['type_id'])\
|
73
|
+
.new(rule_data['type_id'].to_sym, rule_data['data'],
|
74
|
+
target_type: rule_data['target_type'].to_sym)
|
75
|
+
else
|
76
|
+
@rule_type_registry.get(rule_data['type_id']).new(rule_data['type_id'].to_sym, rule_data['data'])
|
77
|
+
end
|
45
78
|
end
|
46
79
|
end
|
47
80
|
end
|