togls 2.2.1 → 3.0.0.pre.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|