togls 3.0.0.pre.rc.2 → 3.0.0.pre.rc.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/README.md +50 -10
- data/lib/togls/feature_toggle_registry_manager.rb +2 -42
- data/lib/togls/rule_manager.rb +53 -0
- data/lib/togls/rule_repository.rb +5 -5
- data/lib/togls/toggle_repository.rb +3 -4
- data/lib/togls/version.rb +1 -1
- data/lib/togls.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05024ddd358a85a71a6c2a321ca23e6dc1f1a54f
|
4
|
+
data.tar.gz: c0cffcdf9ac3c88225383dd052ebf02497a9d43e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcc5a4843465954f936decf0da23c2bdd16fd6683634a791905d700bb18753142b226653d1fcf60b8f695cef103a7f95df81e0d37afce3d9bb58bdcea1d7deff
|
7
|
+
data.tar.gz: 73bd020d13232d401c8b0dc77bcff6096a27b16674a4c5f49710cd093b2817a4287ccedca149213cce81de7ddbc3ae853ab7b874af5d015111005253a8d96f5c
|
data/CHANGELOG.md
CHANGED
@@ -10,6 +10,7 @@ that you can set version constraints properly.
|
|
10
10
|
|
11
11
|
#### [Unreleased] - now
|
12
12
|
|
13
|
+
* `Changed`: Rule and Rule Type management to be global under Togls
|
13
14
|
* `Changed`: The testing interface to allow for contract enforcement in tests
|
14
15
|
and allow altering existing feature rules within tests.
|
15
16
|
* `Added`: `Togls.rule` method to simplify rule construction from `type_id`
|
data/README.md
CHANGED
@@ -52,13 +52,28 @@ how one would define some basic feature toggles.
|
|
52
52
|
```ruby
|
53
53
|
Togls.release do
|
54
54
|
# Set this feature to always be on
|
55
|
-
feature(:pop_up_login_form, "use pop up login instead of normal login").on
|
55
|
+
feature(:pop_up_login_form, "use pop up login instead of normal login").on
|
56
56
|
|
57
57
|
# Set this feature to always be off
|
58
58
|
feature(:send_follup_email, "send the follow up email").off
|
59
59
|
end
|
60
60
|
```
|
61
61
|
|
62
|
+
The above defined feature toggles would use
|
63
|
+
[default feature target type](https://github.com/codebreakdown/togls/wiki/Abstract-Target-Types#setting-the-default-feature-target-type).
|
64
|
+
If we wanted to define them explicitly with other target types it would like as
|
65
|
+
follows.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
Togls.release do
|
69
|
+
# Set this feature to always be on
|
70
|
+
feature(:pop_up_login_form, "use pop up login instead of normal login", :user_id).on
|
71
|
+
|
72
|
+
# Set this feature to always be off
|
73
|
+
feature(:send_follup_email, "send the follow up email", :user_email_address).off
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
62
77
|
### Evaluating Feature Toggles
|
63
78
|
|
64
79
|
Once you have defined your feature toggles. The next thing you would
|
@@ -83,6 +98,28 @@ end
|
|
83
98
|
**Note:** Feature toggles that are evaluated but have **not** been
|
84
99
|
defined will default to **off**.
|
85
100
|
|
101
|
+
The above two feature toggles evaluated are written as if the feature toggle has
|
102
|
+
a target type of `Togls::TargetTypes::NONE`. If the feature toggles had a
|
103
|
+
specific target type and they were evaluted as shown above an exception would be
|
104
|
+
raised notifying you that they expect an entity of that type as the target for
|
105
|
+
evaluation. To better match the explicit target type example from Defining
|
106
|
+
Feature Toggles it would look something like the following.
|
107
|
+
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
if Togls.feature(:pop_up_login_form).on?(current_user.id)
|
111
|
+
# Use pop up login form
|
112
|
+
else
|
113
|
+
# Use normal non-pop up login form
|
114
|
+
end
|
115
|
+
|
116
|
+
...
|
117
|
+
|
118
|
+
if Togls.feature(:send_follup_email).on?(current_user.email)
|
119
|
+
# send the follow up email
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
86
123
|
### Override Feature Toggles
|
87
124
|
|
88
125
|
Toggles can be overriden using environment variables following the
|
@@ -106,7 +143,11 @@ We could override this by setting the value of the
|
|
106
143
|
to override a feature toggle to an on state you can set the
|
107
144
|
`TOGLS_POP_UP_LOGIN_FORM` environment variable to `"true"`.
|
108
145
|
|
109
|
-
|
146
|
+
**Note:** This feature is explicitly designed for use in your development
|
147
|
+
environment. If you use this feature in other environments (qa, staging,
|
148
|
+
production, etc.) it may not behave as you expect.
|
149
|
+
|
150
|
+
### Toggle Features based on Group Membership
|
110
151
|
|
111
152
|
`togls` provides out of the box support for toggling features based on
|
112
153
|
group membership. This basically allows you to have a feature **on** for
|
@@ -115,10 +156,10 @@ extremely useful if you want to enable features for a small alpha test
|
|
115
156
|
group for example.
|
116
157
|
|
117
158
|
**Note:** This is implemented using `togls` extremely robust [custom
|
118
|
-
rules](https://github.com/codebreakdown/togls/wiki/Custom-Rules) system.
|
159
|
+
rules](https://github.com/codebreakdown/togls/wiki/Custom-Rule-Types-&-Rules) system.
|
119
160
|
The following example is just one of the many powerful things you can do
|
120
161
|
with `togls` and [custom
|
121
|
-
rules](https://github.com/codebreakdown/togls/wiki/Custom-Rules).
|
162
|
+
rules](https://github.com/codebreakdown/togls/wiki/Custom-Rule-Types-&-Rules).
|
122
163
|
|
123
164
|
#### Defining Group based Feature Toggles
|
124
165
|
|
@@ -128,11 +169,10 @@ based on group membership.
|
|
128
169
|
```ruby
|
129
170
|
# Create a group rule so the feature is on if the user is a member of
|
130
171
|
# the group.
|
131
|
-
alpha_testers = Togls
|
132
|
-
"user2@example.com"])
|
172
|
+
alpha_testers = Togls.rule(:group, ["user1@email.com", "user2@example.com"], target_type: :user_email_address)
|
133
173
|
|
134
174
|
Togls.release do
|
135
|
-
feature(:new_contact_form, "use new contact form").on(alpha_testers)
|
175
|
+
feature(:new_contact_form, "use new contact form", target_type: :user_email_address).on(alpha_testers)
|
136
176
|
end
|
137
177
|
```
|
138
178
|
|
@@ -181,10 +221,10 @@ in the example above and it would look something like the following:
|
|
181
221
|
```ruby
|
182
222
|
# Create a group rule so the feature is on if the user is a member of
|
183
223
|
# the group.
|
184
|
-
alpha_testers = Togls
|
224
|
+
alpha_testers = Togls.rule(:group, [1, 23, 42, 83], :user_id)
|
185
225
|
|
186
226
|
Togls.release do
|
187
|
-
feature(:new_contact_form, "use new contact form").on(alpha_testers)
|
227
|
+
feature(:new_contact_form, "use new contact form", :user_id).on(alpha_testers)
|
188
228
|
end
|
189
229
|
```
|
190
230
|
|
@@ -213,7 +253,7 @@ Toggles](https://github.com/codebreakdown/togls/wiki/Testing-with-Toggles),
|
|
213
253
|
[Provided Rules
|
214
254
|
Reference](https://github.com/codebreakdown/togls/wiki/Provided-Rules-Reference),
|
215
255
|
[Custom
|
216
|
-
Rules](https://github.com/codebreakdown/togls/wiki/Custom-Rules),
|
256
|
+
Rules](https://github.com/codebreakdown/togls/wiki/Custom-Rule-Types-&-Rules),
|
217
257
|
[Organize Toggle
|
218
258
|
Definitions](https://github.com/codebreakdown/togls/wiki/Organize-Toggle-Definitions),
|
219
259
|
[Creating Additional Toggle
|
@@ -24,19 +24,6 @@ module Togls
|
|
24
24
|
@release_blocks ||= []
|
25
25
|
end
|
26
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
27
|
def feature(key)
|
41
28
|
Toggler.new(release_toggle_registry.instance_variable_get(:@toggle_repository), release_toggle_registry.get(key))
|
42
29
|
end
|
@@ -62,38 +49,17 @@ module Togls
|
|
62
49
|
|
63
50
|
private
|
64
51
|
|
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
52
|
def test_toggle_registry
|
83
53
|
feature_repository_drivers =
|
84
54
|
[Togls::FeatureRepositoryDrivers::InMemoryDriver.new]
|
85
55
|
test_feature_repository = Togls::FeatureRepository.new(
|
86
56
|
feature_repository_drivers)
|
87
57
|
|
88
|
-
rule_repository_drivers =
|
89
|
-
[Togls::RuleRepositoryDrivers::InMemoryDriver.new]
|
90
|
-
rule_repository = Togls::RuleRepository.new(rule_type_registry, rule_repository_drivers)
|
91
|
-
|
92
58
|
toggle_repository_drivers = [
|
93
59
|
Togls::ToggleRepositoryDrivers::InMemoryDriver.new]
|
94
60
|
|
95
61
|
toggle_repository = Togls::ToggleRepository.new(
|
96
|
-
toggle_repository_drivers, test_feature_repository
|
62
|
+
toggle_repository_drivers, test_feature_repository)
|
97
63
|
|
98
64
|
tr = ToggleRegistry.new(test_feature_repository, toggle_repository)
|
99
65
|
release_blocks.each do |p|
|
@@ -105,12 +71,6 @@ module Togls
|
|
105
71
|
|
106
72
|
def release_toggle_registry
|
107
73
|
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
74
|
|
115
75
|
toggle_repository_drivers = [
|
116
76
|
Togls::ToggleRepositoryDrivers::InMemoryDriver.new,
|
@@ -118,7 +78,7 @@ module Togls
|
|
118
78
|
]
|
119
79
|
|
120
80
|
toggle_repository = Togls::ToggleRepository.new(
|
121
|
-
toggle_repository_drivers, feature_repository
|
81
|
+
toggle_repository_drivers, feature_repository)
|
122
82
|
|
123
83
|
@release_toggle_registry = ToggleRegistry.new(feature_repository,
|
124
84
|
toggle_repository)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Togls
|
2
|
+
module RuleManager
|
3
|
+
def self.included(mod)
|
4
|
+
mod.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def rule_types(&block)
|
9
|
+
rule_type_registry.expand(&block) if block
|
10
|
+
rule_type_registry
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule_type(type_id)
|
14
|
+
rule_type_registry.get(type_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def rule(type_id, data = nil, target_type: Togls::TargetTypes::NOT_SET)
|
18
|
+
rule_type(type_id).new(type_id, data, target_type: target_type)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def rule_type_repository
|
24
|
+
if @rule_type_repository.nil?
|
25
|
+
rule_type_repository_drivers = [RuleTypeRepositoryDrivers::InMemoryDriver.new]
|
26
|
+
@rule_type_repository = RuleTypeRepository.new(rule_type_repository_drivers)
|
27
|
+
end
|
28
|
+
@rule_type_repository
|
29
|
+
end
|
30
|
+
|
31
|
+
def rule_type_registry
|
32
|
+
if @rule_type_registry.nil?
|
33
|
+
@rule_type_registry = RuleTypeRegistry.new(rule_type_repository)
|
34
|
+
@rule_type_registry.register(:boolean, Togls::Rules::Boolean)
|
35
|
+
@rule_type_registry.register(:group, Togls::Rules::Group)
|
36
|
+
end
|
37
|
+
@rule_type_registry
|
38
|
+
end
|
39
|
+
|
40
|
+
def rule_repository
|
41
|
+
if @rule_repository.nil?
|
42
|
+
rule_repository_drivers = [
|
43
|
+
Togls::RuleRepositoryDrivers::InMemoryDriver.new,
|
44
|
+
Togls::RuleRepositoryDrivers::EnvOverrideDriver.new
|
45
|
+
]
|
46
|
+
|
47
|
+
@rule_repository = Togls::RuleRepository.new(rule_repository_drivers)
|
48
|
+
end
|
49
|
+
@rule_repository
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
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(
|
8
|
+
def initialize(drivers)
|
9
9
|
unless drivers.is_a?(Array)
|
10
10
|
raise Togls::InvalidDriver, 'RuleRepository requires a valid driver'
|
11
11
|
end
|
@@ -13,7 +13,6 @@ 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
|
17
16
|
end
|
18
17
|
|
19
18
|
def store(rule)
|
@@ -25,7 +24,7 @@ module Togls
|
|
25
24
|
|
26
25
|
def extract_storage_payload(rule)
|
27
26
|
{
|
28
|
-
'type_id' =>
|
27
|
+
'type_id' => ::Togls.send(:rule_type_registry).get_type_id(rule.class.to_s),
|
29
28
|
'data' => rule.data,
|
30
29
|
'target_type' => rule.target_type.to_s
|
31
30
|
}
|
@@ -69,11 +68,12 @@ module Togls
|
|
69
68
|
|
70
69
|
def reconstitute_rule(rule_data)
|
71
70
|
if rule_data.has_key?('target_type')
|
72
|
-
|
71
|
+
::Togls.rule_type(rule_data['type_id'])\
|
73
72
|
.new(rule_data['type_id'].to_sym, rule_data['data'],
|
74
73
|
target_type: rule_data['target_type'].to_sym)
|
75
74
|
else
|
76
|
-
|
75
|
+
::Togls.rule_type(rule_data['type_id']).new(rule_data['type_id'].to_sym,
|
76
|
+
rule_data['data'])
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -3,7 +3,7 @@ module Togls
|
|
3
3
|
#
|
4
4
|
# Repository interface for storing and retrieving toggles.
|
5
5
|
class ToggleRepository
|
6
|
-
def initialize(drivers, feature_repository
|
6
|
+
def initialize(drivers, feature_repository)
|
7
7
|
unless drivers.is_a?(Array)
|
8
8
|
raise Togls::InvalidDriver, 'ToggleRepository requires a valid driver'
|
9
9
|
end
|
@@ -12,12 +12,11 @@ module Togls
|
|
12
12
|
end
|
13
13
|
@drivers = drivers
|
14
14
|
@feature_repository = feature_repository
|
15
|
-
@rule_repository = rule_repository
|
16
15
|
end
|
17
16
|
|
18
17
|
def store(toggle)
|
19
18
|
@feature_repository.store(toggle.feature)
|
20
|
-
|
19
|
+
::Togls.send(:rule_repository).store(toggle.rule)
|
21
20
|
payload = extract_storage_payload(toggle)
|
22
21
|
|
23
22
|
@drivers.each do |driver|
|
@@ -43,7 +42,7 @@ module Togls
|
|
43
42
|
end
|
44
43
|
|
45
44
|
begin
|
46
|
-
rule =
|
45
|
+
rule = ::Togls.send(:rule_repository).get(toggle_data['rule_id'])
|
47
46
|
rescue Togls::RepositoryRuleDataInvalid => e
|
48
47
|
return Togls::NullToggle.new
|
49
48
|
end
|
data/lib/togls/version.rb
CHANGED
data/lib/togls.rb
CHANGED
@@ -25,6 +25,7 @@ require 'togls/null_toggle'
|
|
25
25
|
require 'togls/rule'
|
26
26
|
require 'togls/rules'
|
27
27
|
require 'logger'
|
28
|
+
require 'togls/rule_manager'
|
28
29
|
require 'togls/feature_toggle_registry_manager'
|
29
30
|
require 'togls/default_feature_target_type_manager'
|
30
31
|
|
@@ -33,6 +34,7 @@ require 'togls/default_feature_target_type_manager'
|
|
33
34
|
# Togls is the primary interface to the out of the box toggle registry. It is
|
34
35
|
# the namespace the DSL is exposed under.
|
35
36
|
module Togls
|
37
|
+
include RuleManager
|
36
38
|
include FeatureToggleRegistryManager
|
37
39
|
include DefaultFeatureTargetTypeManager
|
38
40
|
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: 3.0.0.pre.rc.
|
4
|
+
version: 3.0.0.pre.rc.3
|
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: 2016-06-
|
13
|
+
date: 2016-06-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- lib/togls/helpers.rb
|
105
105
|
- lib/togls/null_toggle.rb
|
106
106
|
- lib/togls/rule.rb
|
107
|
+
- lib/togls/rule_manager.rb
|
107
108
|
- lib/togls/rule_repository.rb
|
108
109
|
- lib/togls/rule_repository_drivers.rb
|
109
110
|
- lib/togls/rule_repository_drivers/env_override_driver.rb
|