this_feature 0.8.0 → 0.10.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 +4 -4
- data/.github/workflows/linter-rubocop.yml +19 -0
- data/.github/workflows/test.yml +6 -21
- data/.gitignore +2 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +100 -0
- data/.ruby-version +1 -0
- data/Gemfile +17 -4
- data/Gemfile.lock +80 -45
- data/README.md +6 -7
- data/Rakefile +3 -3
- data/bin/console +3 -7
- data/docs/flipper.md +1 -1
- data/docs/memory.md +50 -2
- data/docs/splitio.md +5 -5
- data/docs/writing_an_adapter.md +3 -3
- data/lib/this_feature/adapters/flipper.rb +2 -2
- data/lib/this_feature/adapters/memory.rb +20 -1
- data/lib/this_feature/adapters/split_io.rb +14 -1
- data/lib/this_feature/adapters.rb +2 -2
- data/lib/this_feature/configuration.rb +3 -3
- data/lib/this_feature/errors.rb +2 -4
- data/lib/this_feature/flag.rb +8 -0
- data/lib/this_feature/version.rb +1 -1
- data/this_feature-adapters-flipper.gemspec +26 -20
- data/this_feature-adapters-split_io.gemspec +25 -19
- data/this_feature.gemspec +26 -22
- metadata +20 -107
- data/docs/flipper.html +0 -1087
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7a1fb53b4ceabfd85df7c059b02331d419259b23d7f0de2d90c942528bab1bbc
|
|
4
|
+
data.tar.gz: 81f8b34041e14e8d02c455c9c427c760b5d02ddf50531f016867f91bb7668368
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8eb7586c9d9b39cabe35d29257e79352f4eb807104f685fd23286717a6b358435c724bc194997b01bd8270d13de743374f763c6e32e4be355fa1db3c46caceb3
|
|
7
|
+
data.tar.gz: 3b0f23e8392bb6eb1eb52bf3858fb064aad0e59d5c5ef535e15ccb95acf88a974c64ae2ad32d0ee925e37b34ff55bf6b499e459593c656c7a01c5fee55712498
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
on: [push]
|
|
2
|
+
|
|
3
|
+
name: Ruby linter (Rubocop)
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
linter_rubocop:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
|
|
9
|
+
steps:
|
|
10
|
+
- name: Checkout
|
|
11
|
+
uses: actions/checkout@main
|
|
12
|
+
|
|
13
|
+
- name: Set up Ruby
|
|
14
|
+
uses: ruby/setup-ruby@v1
|
|
15
|
+
with:
|
|
16
|
+
bundler-cache: true
|
|
17
|
+
|
|
18
|
+
- name: Run Rubocop
|
|
19
|
+
run: bundle exec rubocop --parallel
|
data/.github/workflows/test.yml
CHANGED
|
@@ -1,34 +1,19 @@
|
|
|
1
1
|
on: [push]
|
|
2
2
|
|
|
3
|
-
name:
|
|
3
|
+
name: Tests
|
|
4
4
|
|
|
5
5
|
jobs:
|
|
6
|
-
|
|
6
|
+
test:
|
|
7
7
|
runs-on: ubuntu-latest
|
|
8
8
|
|
|
9
9
|
steps:
|
|
10
10
|
- name: Checkout
|
|
11
|
-
uses: actions/checkout@
|
|
11
|
+
uses: actions/checkout@main
|
|
12
12
|
|
|
13
13
|
- name: Set up Ruby
|
|
14
|
-
uses:
|
|
14
|
+
uses: ruby/setup-ruby@master
|
|
15
15
|
with:
|
|
16
|
-
ruby-version: '2.7.x'
|
|
17
16
|
bundler-cache: true
|
|
18
17
|
|
|
19
|
-
- name:
|
|
20
|
-
|
|
21
|
-
with:
|
|
22
|
-
path: vendor/bundle
|
|
23
|
-
key: ${{ runner.os }}-gems-${{ hashFiles('Gemfile.lock') }}
|
|
24
|
-
restore-keys: |
|
|
25
|
-
${{ runner.os }}-gems-
|
|
26
|
-
|
|
27
|
-
- name: Install Ruby gems
|
|
28
|
-
run: |
|
|
29
|
-
bundle config path vendor/bundle
|
|
30
|
-
bundle install
|
|
31
|
-
|
|
32
|
-
- name: Run Rspec
|
|
33
|
-
run: |
|
|
34
|
-
bundle exec rspec
|
|
18
|
+
- name: Run RSpec
|
|
19
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- rubocop-md
|
|
3
|
+
- rubocop-performance
|
|
4
|
+
- rubocop-rake
|
|
5
|
+
- rubocop-rspec
|
|
6
|
+
- rubocop-thread_safety
|
|
7
|
+
|
|
8
|
+
inherit_from: .rubocop_todo.yml
|
|
9
|
+
|
|
10
|
+
AllCops:
|
|
11
|
+
NewCops: enable
|
|
12
|
+
|
|
13
|
+
RSpec/NestedGroups:
|
|
14
|
+
Max: 4
|
|
15
|
+
|
|
16
|
+
Style/Documentation:
|
|
17
|
+
Enabled: false
|
|
18
|
+
|
|
19
|
+
Style/FrozenStringLiteralComment:
|
|
20
|
+
EnforcedStyle: never
|
|
21
|
+
|
|
22
|
+
Style/HashSyntax:
|
|
23
|
+
EnforcedStyle: ruby19
|
|
24
|
+
EnforcedShorthandSyntax: never
|
|
25
|
+
|
|
26
|
+
Style/WordArray:
|
|
27
|
+
Exclude:
|
|
28
|
+
- spec/support/schema.rb
|
|
29
|
+
|
|
30
|
+
Style/NumericLiterals:
|
|
31
|
+
Exclude:
|
|
32
|
+
- 'spec/support/schema.rb'
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2023-05-31 05:59:25 UTC using RuboCop version 1.51.0.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Configuration parameters: AllowComments, AllowEmptyLambdas.
|
|
11
|
+
Lint/EmptyBlock:
|
|
12
|
+
Exclude:
|
|
13
|
+
- 'spec/this_feature_spec.rb'
|
|
14
|
+
|
|
15
|
+
# Offense count: 3
|
|
16
|
+
Lint/MissingSuper:
|
|
17
|
+
Exclude:
|
|
18
|
+
- 'lib/this_feature/adapters/flipper.rb'
|
|
19
|
+
- 'lib/this_feature/adapters/memory.rb'
|
|
20
|
+
- 'lib/this_feature/adapters/split_io.rb'
|
|
21
|
+
|
|
22
|
+
# Offense count: 23
|
|
23
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
24
|
+
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods.
|
|
25
|
+
Lint/UnusedMethodArgument:
|
|
26
|
+
Exclude:
|
|
27
|
+
- '**/*.md'
|
|
28
|
+
- '**/*.markdown'
|
|
29
|
+
- 'lib/this_feature/adapters/base.rb'
|
|
30
|
+
- 'lib/this_feature/adapters/flipper.rb'
|
|
31
|
+
- 'lib/this_feature/adapters/memory.rb'
|
|
32
|
+
|
|
33
|
+
# Offense count: 1
|
|
34
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
|
35
|
+
Metrics/AbcSize:
|
|
36
|
+
Max: 19
|
|
37
|
+
|
|
38
|
+
# Offense count: 1
|
|
39
|
+
RSpec/AnyInstance:
|
|
40
|
+
Exclude:
|
|
41
|
+
- 'spec/this_feature/adapters/split_io_adapter_spec.rb'
|
|
42
|
+
|
|
43
|
+
# Offense count: 10
|
|
44
|
+
# Configuration parameters: CountAsOne.
|
|
45
|
+
RSpec/ExampleLength:
|
|
46
|
+
Max: 12
|
|
47
|
+
|
|
48
|
+
# Offense count: 4
|
|
49
|
+
# Configuration parameters: Max.
|
|
50
|
+
RSpec/IndexedLet:
|
|
51
|
+
Exclude:
|
|
52
|
+
- 'spec/this_feature/adapters/memory_adapter_spec.rb'
|
|
53
|
+
|
|
54
|
+
# Offense count: 3
|
|
55
|
+
# Configuration parameters: .
|
|
56
|
+
# SupportedStyles: have_received, receive
|
|
57
|
+
RSpec/MessageSpies:
|
|
58
|
+
EnforcedStyle: receive
|
|
59
|
+
|
|
60
|
+
# Offense count: 23
|
|
61
|
+
RSpec/MultipleExpectations:
|
|
62
|
+
Max: 12
|
|
63
|
+
|
|
64
|
+
# Offense count: 72
|
|
65
|
+
# Configuration parameters: AllowSubject.
|
|
66
|
+
RSpec/MultipleMemoizedHelpers:
|
|
67
|
+
Max: 10
|
|
68
|
+
|
|
69
|
+
# Offense count: 9
|
|
70
|
+
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
|
|
71
|
+
# SupportedStyles: always, named_only
|
|
72
|
+
RSpec/NamedSubject:
|
|
73
|
+
Exclude:
|
|
74
|
+
- 'spec/this_feature/adapters/flipper_adapter_spec.rb'
|
|
75
|
+
- 'spec/this_feature/adapters/memory_adapter_spec.rb'
|
|
76
|
+
- 'spec/this_feature_spec.rb'
|
|
77
|
+
|
|
78
|
+
# Offense count: 1
|
|
79
|
+
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
|
|
80
|
+
RSpec/VerifiedDoubles:
|
|
81
|
+
Exclude:
|
|
82
|
+
- 'spec/this_feature_spec.rb'
|
|
83
|
+
|
|
84
|
+
# Offense count: 3
|
|
85
|
+
Style/MultilineBlockChain:
|
|
86
|
+
Exclude:
|
|
87
|
+
- 'spec/this_feature/adapters/base_adapter_spec.rb'
|
|
88
|
+
- 'spec/this_feature_spec.rb'
|
|
89
|
+
|
|
90
|
+
# Offense count: 15
|
|
91
|
+
Style/OpenStructUse:
|
|
92
|
+
Exclude:
|
|
93
|
+
- 'spec/this_feature/adapters/flipper_adapter_spec.rb'
|
|
94
|
+
- 'spec/this_feature/adapters/memory_adapter_spec.rb'
|
|
95
|
+
- 'spec/this_feature/adapters/split_io_adapter_spec.rb'
|
|
96
|
+
|
|
97
|
+
# Offense count: 2
|
|
98
|
+
ThreadSafety/InstanceVariableInClassMethod:
|
|
99
|
+
Exclude:
|
|
100
|
+
- 'lib/this_feature.rb'
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.2.2
|
data/Gemfile
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
source
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
|
-
gemspec name:
|
|
4
|
-
gemspec name:
|
|
5
|
-
gemspec name:
|
|
3
|
+
gemspec name: 'this_feature'
|
|
4
|
+
gemspec name: 'this_feature-adapters-flipper'
|
|
5
|
+
gemspec name: 'this_feature-adapters-split_io'
|
|
6
|
+
|
|
7
|
+
gem 'bundler'
|
|
8
|
+
gem 'database_cleaner-active_record'
|
|
9
|
+
gem 'gem-release'
|
|
10
|
+
gem 'rake'
|
|
11
|
+
gem 'rspec'
|
|
12
|
+
gem 'rubocop'
|
|
13
|
+
gem 'rubocop-md'
|
|
14
|
+
gem 'rubocop-performance'
|
|
15
|
+
gem 'rubocop-rake'
|
|
16
|
+
gem 'rubocop-rspec'
|
|
17
|
+
gem 'rubocop-thread_safety'
|
|
18
|
+
gem 'sqlite3'
|
data/Gemfile.lock
CHANGED
|
@@ -1,37 +1,36 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
this_feature (0.
|
|
5
|
-
this_feature-adapters-flipper (0.
|
|
6
|
-
flipper
|
|
7
|
-
flipper-active_record
|
|
4
|
+
this_feature (0.10.0)
|
|
5
|
+
this_feature-adapters-flipper (0.10.0)
|
|
6
|
+
flipper
|
|
7
|
+
flipper-active_record
|
|
8
8
|
this_feature
|
|
9
|
-
this_feature-adapters-split_io (0.
|
|
9
|
+
this_feature-adapters-split_io (0.10.0)
|
|
10
10
|
splitclient-rb
|
|
11
11
|
this_feature
|
|
12
12
|
|
|
13
13
|
GEM
|
|
14
14
|
remote: https://rubygems.org/
|
|
15
15
|
specs:
|
|
16
|
-
activemodel (7.0.
|
|
17
|
-
activesupport (= 7.0.
|
|
18
|
-
activerecord (7.0.
|
|
19
|
-
activemodel (= 7.0.
|
|
20
|
-
activesupport (= 7.0.
|
|
21
|
-
activesupport (7.0.
|
|
16
|
+
activemodel (7.0.5)
|
|
17
|
+
activesupport (= 7.0.5)
|
|
18
|
+
activerecord (7.0.5)
|
|
19
|
+
activemodel (= 7.0.5)
|
|
20
|
+
activesupport (= 7.0.5)
|
|
21
|
+
activesupport (7.0.5)
|
|
22
22
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
23
23
|
i18n (>= 1.6, < 2)
|
|
24
24
|
minitest (>= 5.1)
|
|
25
25
|
tzinfo (~> 2.0)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
concurrent-ruby (1.1.10)
|
|
26
|
+
ast (2.4.2)
|
|
27
|
+
concurrent-ruby (1.2.2)
|
|
29
28
|
connection_pool (2.2.5)
|
|
30
29
|
database_cleaner (1.8.4)
|
|
31
30
|
database_cleaner-active_record (1.8.0)
|
|
32
31
|
activerecord
|
|
33
32
|
database_cleaner (~> 1.8.0)
|
|
34
|
-
diff-lcs (1.
|
|
33
|
+
diff-lcs (1.5.0)
|
|
35
34
|
faraday (1.7.0)
|
|
36
35
|
faraday-em_http (~> 1.0)
|
|
37
36
|
faraday-em_synchrony (~> 1.0)
|
|
@@ -51,43 +50,73 @@ GEM
|
|
|
51
50
|
faraday-net_http_persistent (1.2.0)
|
|
52
51
|
faraday-patron (1.0.0)
|
|
53
52
|
faraday-rack (1.0.0)
|
|
54
|
-
flipper (0.
|
|
55
|
-
|
|
53
|
+
flipper (0.28.0)
|
|
54
|
+
concurrent-ruby (< 2)
|
|
55
|
+
flipper-active_record (0.28.0)
|
|
56
56
|
activerecord (>= 4.2, < 8)
|
|
57
|
-
flipper (~> 0.
|
|
57
|
+
flipper (~> 0.28.0)
|
|
58
58
|
gem-release (2.2.1)
|
|
59
59
|
hitimes (1.3.1)
|
|
60
|
-
i18n (1.
|
|
60
|
+
i18n (1.13.0)
|
|
61
61
|
concurrent-ruby (~> 1.0)
|
|
62
62
|
json (2.5.1)
|
|
63
63
|
jwt (2.2.3)
|
|
64
64
|
lru_redux (1.1.0)
|
|
65
|
-
|
|
66
|
-
minitest (5.16.2)
|
|
65
|
+
minitest (5.18.0)
|
|
67
66
|
multipart-post (2.1.1)
|
|
68
67
|
net-http-persistent (4.0.1)
|
|
69
68
|
connection_pool (~> 2.2)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
pry (~> 0.13.0)
|
|
76
|
-
rake (13.0.1)
|
|
69
|
+
parallel (1.23.0)
|
|
70
|
+
parser (3.2.2.1)
|
|
71
|
+
ast (~> 2.4.1)
|
|
72
|
+
rainbow (3.1.1)
|
|
73
|
+
rake (13.0.6)
|
|
77
74
|
redis (4.4.0)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
rspec-
|
|
82
|
-
|
|
83
|
-
rspec-
|
|
84
|
-
rspec-
|
|
75
|
+
regexp_parser (2.8.0)
|
|
76
|
+
rexml (3.2.5)
|
|
77
|
+
rspec (3.12.0)
|
|
78
|
+
rspec-core (~> 3.12.0)
|
|
79
|
+
rspec-expectations (~> 3.12.0)
|
|
80
|
+
rspec-mocks (~> 3.12.0)
|
|
81
|
+
rspec-core (3.12.2)
|
|
82
|
+
rspec-support (~> 3.12.0)
|
|
83
|
+
rspec-expectations (3.12.3)
|
|
85
84
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
86
|
-
rspec-support (~> 3.
|
|
87
|
-
rspec-mocks (3.
|
|
85
|
+
rspec-support (~> 3.12.0)
|
|
86
|
+
rspec-mocks (3.12.5)
|
|
88
87
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
89
|
-
rspec-support (~> 3.
|
|
90
|
-
rspec-support (3.
|
|
88
|
+
rspec-support (~> 3.12.0)
|
|
89
|
+
rspec-support (3.12.0)
|
|
90
|
+
rubocop (1.51.0)
|
|
91
|
+
json (~> 2.3)
|
|
92
|
+
parallel (~> 1.10)
|
|
93
|
+
parser (>= 3.2.0.0)
|
|
94
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
95
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
96
|
+
rexml (>= 3.2.5, < 4.0)
|
|
97
|
+
rubocop-ast (>= 1.28.0, < 2.0)
|
|
98
|
+
ruby-progressbar (~> 1.7)
|
|
99
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
100
|
+
rubocop-ast (1.28.1)
|
|
101
|
+
parser (>= 3.2.1.0)
|
|
102
|
+
rubocop-capybara (2.18.0)
|
|
103
|
+
rubocop (~> 1.41)
|
|
104
|
+
rubocop-factory_bot (2.23.1)
|
|
105
|
+
rubocop (~> 1.33)
|
|
106
|
+
rubocop-md (1.2.0)
|
|
107
|
+
rubocop (>= 1.0)
|
|
108
|
+
rubocop-performance (1.18.0)
|
|
109
|
+
rubocop (>= 1.7.0, < 2.0)
|
|
110
|
+
rubocop-ast (>= 0.4.0)
|
|
111
|
+
rubocop-rake (0.6.0)
|
|
112
|
+
rubocop (~> 1.0)
|
|
113
|
+
rubocop-rspec (2.22.0)
|
|
114
|
+
rubocop (~> 1.33)
|
|
115
|
+
rubocop-capybara (~> 2.17)
|
|
116
|
+
rubocop-factory_bot (~> 2.22)
|
|
117
|
+
rubocop-thread_safety (0.5.1)
|
|
118
|
+
rubocop (>= 0.90.0)
|
|
119
|
+
ruby-progressbar (1.13.0)
|
|
91
120
|
ruby2_keywords (0.0.5)
|
|
92
121
|
socketry (0.5.1)
|
|
93
122
|
hitimes (~> 1.2)
|
|
@@ -103,23 +132,29 @@ GEM
|
|
|
103
132
|
thread_safe (>= 0.3)
|
|
104
133
|
sqlite3 (1.4.2)
|
|
105
134
|
thread_safe (0.3.6)
|
|
106
|
-
tzinfo (2.0.
|
|
135
|
+
tzinfo (2.0.6)
|
|
107
136
|
concurrent-ruby (~> 1.0)
|
|
137
|
+
unicode-display_width (2.4.2)
|
|
108
138
|
|
|
109
139
|
PLATFORMS
|
|
110
140
|
ruby
|
|
111
141
|
|
|
112
142
|
DEPENDENCIES
|
|
113
|
-
bundler
|
|
143
|
+
bundler
|
|
114
144
|
database_cleaner-active_record
|
|
115
145
|
gem-release
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
146
|
+
rake
|
|
147
|
+
rspec
|
|
148
|
+
rubocop
|
|
149
|
+
rubocop-md
|
|
150
|
+
rubocop-performance
|
|
151
|
+
rubocop-rake
|
|
152
|
+
rubocop-rspec
|
|
153
|
+
rubocop-thread_safety
|
|
119
154
|
sqlite3
|
|
120
155
|
this_feature!
|
|
121
156
|
this_feature-adapters-flipper!
|
|
122
157
|
this_feature-adapters-split_io!
|
|
123
158
|
|
|
124
159
|
BUNDLED WITH
|
|
125
|
-
2.
|
|
160
|
+
2.4.13
|
data/README.md
CHANGED
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
ThisFeature can be used to more easily migrate from one feature flag service to another
|
|
6
6
|
|
|
7
|
-
If your code uses ThisFeature,
|
|
8
|
-
then you can just swap out the vendor adapter without needing to do a bunch of find-and-replace in your codebase
|
|
9
|
-
from one vendor's class/method signature to the another's.
|
|
7
|
+
If your code uses ThisFeature, then you can just swap out the vendor adapter without needing to do a bunch of find-and-replace in your codebase from one vendor's class/method signature to the another's.
|
|
10
8
|
|
|
11
9
|
## Installation
|
|
12
10
|
|
|
@@ -68,7 +66,7 @@ ThisFeature.flag('flag_name', context: context, data: { org_id: 1 }).on?
|
|
|
68
66
|
|
|
69
67
|
### Avoid Pitfalls
|
|
70
68
|
|
|
71
|
-
1. If your flag has context-specific rules (e.g. on for some orgs, off for others), make sure that the code does a context-specific check. `ThisFeature.flag("flag_name").on?` may return true, while `ThisFeature.flag("flag_name", context: Org.first).on?` would return false.
|
|
69
|
+
1. If your flag has context-specific rules (e.g. on for some orgs, off for others), make sure that the code does a context-specific check. `ThisFeature.flag("flag_name").on?` may return true, while `ThisFeature.flag("flag_name", context: Org.first).on?` would return false.
|
|
72
70
|
2. Related to the previous bullet point, if you are checking whether a flag is "globally enabled" (and thus may be removed from the codebase), do not just use `ThisFeature.flag("flag_name").on?`, it won't tell you the whole story. Go to the vendor console and check whether there are context-specific rules enabled.
|
|
73
71
|
|
|
74
72
|
## Available Adapters
|
|
@@ -100,9 +98,10 @@ bundle install && bundle exec rspec
|
|
|
100
98
|
|
|
101
99
|
To write a new adapter, check the [Guide](./docs/writing_an_adapter.md).
|
|
102
100
|
|
|
103
|
-
##
|
|
104
|
-
|
|
105
|
-
ThisFeature is released under the [MIT License](https://choosealicense.com/licenses/mit).
|
|
101
|
+
## Deployment
|
|
106
102
|
|
|
103
|
+
If you are working at Hover, see [this confluence doc](https://hoverinc.atlassian.net/wiki/spaces/EN/pages/3149266988/deploying+this+feature+gem)
|
|
107
104
|
|
|
105
|
+
## License
|
|
108
106
|
|
|
107
|
+
ThisFeature is released under the [MIT License](https://choosealicense.com/licenses/mit).
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'this_feature'
|
|
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.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
# require "pry"
|
|
11
|
-
# Pry.start
|
|
12
|
-
|
|
13
|
-
require "irb"
|
|
9
|
+
require 'irb'
|
|
14
10
|
IRB.start(__FILE__)
|
data/docs/flipper.md
CHANGED
data/docs/memory.md
CHANGED
|
@@ -12,6 +12,13 @@ Under the hood, the memory adapter stores data in a dictionary like so:
|
|
|
12
12
|
User1: true,
|
|
13
13
|
User2: false
|
|
14
14
|
}
|
|
15
|
+
},
|
|
16
|
+
some_flag_name_with_treatments: {
|
|
17
|
+
treatment_contexts: {
|
|
18
|
+
User1: 'treatment_name_1',
|
|
19
|
+
User2: 'treatment_name_2',
|
|
20
|
+
User3: 'treatment_name_3'
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
}
|
|
17
24
|
```
|
|
@@ -24,7 +31,7 @@ in test suites.
|
|
|
24
31
|
This adapter is included with the core gem:
|
|
25
32
|
|
|
26
33
|
```ruby
|
|
27
|
-
gem 'this_feature
|
|
34
|
+
gem 'this_feature'
|
|
28
35
|
```
|
|
29
36
|
|
|
30
37
|
## Configuration
|
|
@@ -50,7 +57,7 @@ For example:
|
|
|
50
57
|
# of a context object (e.g. imagine this module is included onto User)
|
|
51
58
|
module FeatureFlaggable
|
|
52
59
|
def this_feature_id
|
|
53
|
-
"#{self.class}-#{
|
|
60
|
+
"#{self.class}-#{id}"
|
|
54
61
|
end
|
|
55
62
|
end
|
|
56
63
|
|
|
@@ -79,6 +86,47 @@ ThisFeature.test_adapter.on!(:flag_name, context: user) # with context
|
|
|
79
86
|
ThisFeature.test_adapter.off!(:flag_name) # without context
|
|
80
87
|
```
|
|
81
88
|
|
|
89
|
+
### **#enable_treatment!**
|
|
90
|
+
|
|
91
|
+
This method is useful when you need to enable a feature flag with a treatment (or multiple treatments), and not just `"on"` and `"off"`.
|
|
92
|
+
|
|
93
|
+
Usage example of these:
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
# If you have configured the in-memory adapter as the default
|
|
97
|
+
ThisFeature.test_adapter.enable_treatment!(:flag_name, treatment: 'treatment_name', context: user)
|
|
98
|
+
```
|
|
99
|
+
#### This method requires 3 arguments:
|
|
100
|
+
1. `flag_name`: String or Symbol (not a named argument)
|
|
101
|
+
2. `treatment`: String
|
|
102
|
+
3. `context`: User or Org object
|
|
103
|
+
|
|
104
|
+
Per flag name, there can only be one treatment per `context_key` (the ID of object that is provided as `context`). So multiple calls with the same `context`, but different treatment names, will be overwritten.
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
ThisFeature.test_adapter.enable_treatment!('flag_a', treatment: 'treatment_1', context: user1)
|
|
108
|
+
ThisFeature.test_adapter.storage # => { 'flag_a' => { :treatment_contexts => { 'User1': 'treatment_1' } } }
|
|
109
|
+
|
|
110
|
+
ThisFeature.test_adapter.enable_treatment!(:flag_a, treatment: 'treatment_2', context: user1)
|
|
111
|
+
ThisFeature.test_adapter.storage # => { 'flag_a' => { :treatment_contexts => { 'User1': 'treatment_2' } } }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### **#treatment_value**
|
|
115
|
+
|
|
116
|
+
You can retrieve the flag's treatment name for a specific context.
|
|
117
|
+
|
|
118
|
+
Usage example of these:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
# If you have configured the in-memory adapter as the default
|
|
122
|
+
ThisFeature.test_adapter.treatment_value(:flag_name, context: user)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### This method requires 2 arguments:
|
|
126
|
+
1. `flag_name`: String or Symbol (not a named argument)
|
|
127
|
+
2. `context`: User or Org object
|
|
128
|
+
|
|
129
|
+
When the Memory storage does not contain the given flag_name or if there is no provided `context`, `"control"` is returned. This is meant to mimic what SplitIO would return in the case of no configured treatment for the given `context`.
|
|
82
130
|
### **#clear**
|
|
83
131
|
|
|
84
132
|
Since the memory adapter stores flags in memory, it won't automatically get cleaned up in your tests. You can use this method to reset the memory adapter state.
|
data/docs/splitio.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Installation
|
|
4
4
|
|
|
5
5
|
```ruby
|
|
6
|
-
gem 'this_feature-adapters-split-io
|
|
6
|
+
gem 'this_feature-adapters-split-io'
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## Configuration
|
|
@@ -39,7 +39,7 @@ attributes to the `data` hash. To take advantage of this, the application must
|
|
|
39
39
|
set a `base_data_lambda` in the config. An example—
|
|
40
40
|
```ruby
|
|
41
41
|
ThisFeature.configure do |config|
|
|
42
|
-
config.base_data_lambda =
|
|
42
|
+
config.base_data_lambda = lambda { |record|
|
|
43
43
|
case record
|
|
44
44
|
when Org
|
|
45
45
|
{
|
|
@@ -52,11 +52,11 @@ ThisFeature.configure do |config|
|
|
|
52
52
|
org_name: record.org.name,
|
|
53
53
|
user_email: record.email,
|
|
54
54
|
user_id: record.id,
|
|
55
|
-
user_name: record.name
|
|
55
|
+
user_name: record.name
|
|
56
56
|
}
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
}
|
|
59
59
|
end
|
|
60
60
|
```
|
|
61
61
|
Then `ThisFeature.flag("my-flag", record: user).on?` will automatically include
|
|
62
|
-
org_id, org_name, user_email, user_id, and user_name in the data attributes.
|
|
62
|
+
org_id, org_name, user_email, user_id, and user_name in the data attributes.
|
data/docs/writing_an_adapter.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
Look at [lib/this_feature/adapters/base.rb](../lib/this_feature/adapters/base.rb) to see the methods that your class should implement.
|
|
1
|
+
Look at [lib/this_feature/adapters/base.rb](../lib/this_feature/adapters/base.rb) to see the methods that your class should implement.
|
|
2
2
|
|
|
3
|
-
Make sure your class inherits from `ThisFeature::Adapters::Base` - this is a requirement.
|
|
3
|
+
Make sure your class inherits from `ThisFeature::Adapters::Base` - this is a requirement.
|
|
4
4
|
|
|
5
|
-
You may define a custom `initialize` method - this isn't used by `this_feature` internals because we require an already-constructed instance to be passed into `ThisFeature.configure`.
|
|
5
|
+
You may define a custom `initialize` method - this isn't used by `this_feature` internals because we require an already-constructed instance to be passed into `ThisFeature.configure`.
|
|
6
6
|
|
|
7
7
|
For an example, look at one of the existing adapters: [lib/this_feature/adapters/](../lib/this_feature/adapters/)
|
|
8
8
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
class ThisFeature
|
|
2
2
|
module Adapters
|
|
3
3
|
class Memory < Base
|
|
4
|
-
|
|
5
4
|
def initialize(context_key_method: nil)
|
|
6
5
|
@context_key_method = context_key_method
|
|
7
6
|
end
|
|
@@ -35,6 +34,26 @@ class ThisFeature
|
|
|
35
34
|
!present?(flag_name)
|
|
36
35
|
end
|
|
37
36
|
|
|
37
|
+
def treatment_value(flag_name, context: nil, data: {}, record: nil)
|
|
38
|
+
return 'control' if !present?(flag_name) || context.nil?
|
|
39
|
+
|
|
40
|
+
flag_data = storage[flag_name][:treatment_contexts]
|
|
41
|
+
context_registered = flag_data&.key?(context_key(context))
|
|
42
|
+
|
|
43
|
+
return 'control' if !flag_data || !context_registered
|
|
44
|
+
|
|
45
|
+
flag_data ||= {}
|
|
46
|
+
flag_data[context_key(context)]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def enable_treatment!(flag_name, treatment: nil, context: nil)
|
|
50
|
+
return false if treatment.nil? || flag_name.nil? || context.nil?
|
|
51
|
+
|
|
52
|
+
storage[flag_name] ||= {}
|
|
53
|
+
storage[flag_name][:treatment_contexts] ||= {}
|
|
54
|
+
storage[flag_name][:treatment_contexts][context_key(context)] = treatment
|
|
55
|
+
end
|
|
56
|
+
|
|
38
57
|
def on!(flag_name, context: nil, data: {})
|
|
39
58
|
storage[flag_name] ||= {}
|
|
40
59
|
|