this_feature 0.5.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1ce587cdd7e38a631ec48ebec63a3de11bd96ed5c82abff3b4486a0b09c0f11
4
- data.tar.gz: 19643b3951c2483fdf3694073c24cbc71a530997a5192c58ea8a9c835b8c39cf
3
+ metadata.gz: 03e205e9b9a6a53ff76d8c93b315eb7e8cd2f05a96a9e7f4ae9ac434371155e9
4
+ data.tar.gz: 1e5e996c866d55076f205a47685e295e4b04f0373aa545d183c0192d640ac8a0
5
5
  SHA512:
6
- metadata.gz: 132cb856e2bfb0af4b334bde04a7cce7586a15a3c6a0ffc5a0dde71725cc388deef03b21fc67d1a9f174e950676c832e99b8dbcd7211f187e8864b6918f944c3
7
- data.tar.gz: 16a4c927b80d69a40b5104cb9e7d284c0da6423ddac78c89ce6a9b2394cade377f7c981c51f864c9c3fe506e119894081d6215d60f0273592912fbefa5a3892b
6
+ metadata.gz: 4ea504d76f8f435166ba50bb4643065030e40ea44626ffd4222fe60a5f80588d3242fe89dc339b14cce7b8cc1657fef016c9c59e5decdc9879f3bf64f23581b5
7
+ data.tar.gz: 523abe2a99278d2c559931e3b89ba0a946ca03f5e7a3fc92fd0e060555d0a0b25308d863f57904f4f4cc9ddb5fd93535e79bcee9164cff769b3d2ee61a6fcf0c
data/Gemfile.lock CHANGED
@@ -1,55 +1,58 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- this_feature (0.5.0)
5
- this_feature-adapters-flipper (0.5.0)
4
+ this_feature (0.6.1)
5
+ this_feature-adapters-flipper (0.6.1)
6
6
  flipper (~> 0.16)
7
7
  flipper-active_record (~> 0.16)
8
8
  this_feature
9
- this_feature-adapters-split_io (0.5.0)
9
+ this_feature-adapters-split_io (0.6.1)
10
10
  splitclient-rb
11
11
  this_feature
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- activemodel (6.0.3.2)
17
- activesupport (= 6.0.3.2)
18
- activerecord (6.0.3.2)
19
- activemodel (= 6.0.3.2)
20
- activesupport (= 6.0.3.2)
21
- activesupport (6.0.3.2)
16
+ activemodel (6.1.3)
17
+ activesupport (= 6.1.3)
18
+ activerecord (6.1.3)
19
+ activemodel (= 6.1.3)
20
+ activesupport (= 6.1.3)
21
+ activesupport (6.1.3)
22
22
  concurrent-ruby (~> 1.0, >= 1.0.2)
23
- i18n (>= 0.7, < 2)
24
- minitest (~> 5.1)
25
- tzinfo (~> 1.1)
26
- zeitwerk (~> 2.2, >= 2.2.2)
23
+ i18n (>= 1.6, < 2)
24
+ minitest (>= 5.1)
25
+ tzinfo (~> 2.0)
26
+ zeitwerk (~> 2.3)
27
27
  byebug (11.1.2)
28
28
  coderay (1.1.2)
29
- concurrent-ruby (1.1.6)
29
+ concurrent-ruby (1.1.8)
30
30
  connection_pool (2.2.3)
31
31
  database_cleaner (1.8.4)
32
32
  database_cleaner-active_record (1.8.0)
33
33
  activerecord
34
34
  database_cleaner (~> 1.8.0)
35
35
  diff-lcs (1.3)
36
- faraday (1.0.1)
36
+ faraday (1.3.0)
37
+ faraday-net_http (~> 1.0)
37
38
  multipart-post (>= 1.2, < 3)
38
- flipper (0.19.0)
39
- flipper-active_record (0.19.0)
39
+ ruby2_keywords
40
+ faraday-net_http (1.0.1)
41
+ flipper (0.20.3)
42
+ flipper-active_record (0.20.3)
40
43
  activerecord (>= 5.0, < 7)
41
- flipper (~> 0.19.0)
42
- gem-release (2.1.1)
44
+ flipper (~> 0.20.3)
45
+ gem-release (2.2.1)
43
46
  hitimes (1.3.1)
44
- i18n (1.8.5)
47
+ i18n (1.8.9)
45
48
  concurrent-ruby (~> 1.0)
46
- json (2.3.1)
49
+ json (2.5.1)
47
50
  jwt (2.2.2)
48
51
  lru_redux (1.1.0)
49
52
  method_source (1.0.0)
50
- minitest (5.14.1)
53
+ minitest (5.14.4)
51
54
  multipart-post (2.1.1)
52
- net-http-persistent (4.0.0)
55
+ net-http-persistent (4.0.1)
53
56
  connection_pool (~> 2.2)
54
57
  pry (0.13.1)
55
58
  coderay (~> 1.1)
@@ -58,7 +61,7 @@ GEM
58
61
  byebug (~> 11.0)
59
62
  pry (~> 0.13.0)
60
63
  rake (13.0.1)
61
- redis (4.2.2)
64
+ redis (4.2.5)
62
65
  rspec (3.9.0)
63
66
  rspec-core (~> 3.9.0)
64
67
  rspec-expectations (~> 3.9.0)
@@ -72,23 +75,24 @@ GEM
72
75
  diff-lcs (>= 1.2.0, < 2.0)
73
76
  rspec-support (~> 3.9.0)
74
77
  rspec-support (3.9.2)
78
+ ruby2_keywords (0.0.4)
75
79
  socketry (0.5.1)
76
80
  hitimes (~> 1.2)
77
- splitclient-rb (7.1.3)
81
+ splitclient-rb (7.2.3)
78
82
  concurrent-ruby (~> 1.0)
79
83
  faraday (>= 0.8)
80
84
  json (>= 1.8)
81
85
  jwt (>= 2.2.1)
82
86
  lru_redux
83
87
  net-http-persistent (>= 2.9)
84
- redis (>= 3.2)
88
+ redis (>= 4.2.2)
85
89
  socketry (~> 0.5.1)
86
90
  thread_safe (>= 0.3)
87
91
  sqlite3 (1.4.2)
88
92
  thread_safe (0.3.6)
89
- tzinfo (1.2.7)
90
- thread_safe (~> 0.1)
91
- zeitwerk (2.4.0)
93
+ tzinfo (2.0.4)
94
+ concurrent-ruby (~> 1.0)
95
+ zeitwerk (2.4.2)
92
96
 
93
97
  PLATFORMS
94
98
  ruby
data/README.md CHANGED
@@ -63,7 +63,7 @@ These adapters do behave slightly differently, so make sure to read the followin
63
63
 
64
64
  - [Flipper adapter](./docs/flipper.md)
65
65
  - [Split.io adapter](./docs/splitio.md)
66
- - [Memory adapter](./docs/memory.md) - **very helpful to use in tests**
66
+ - [Memory adapter](./docs/memory.md) - **designed for use in tests**
67
67
 
68
68
  ## Development
69
69
 
data/docs/memory.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # ThisFeature - Memory Adapter
2
2
 
3
+ ## Synopsis
4
+
5
+ Under the hood, the memory adapter stores data in a dictionary like so:
6
+
7
+ ```ruby
8
+ {
9
+ some_flag_name: {
10
+ global: false,
11
+ contexts: {
12
+ User1: true,
13
+ User2: false
14
+ }
15
+ }
16
+ }
17
+ ```
18
+
19
+ Since it doesn't require actual DB lookups, it's faster, and works well for use
20
+ in test suites.
21
+
3
22
  ## Installation
4
23
 
5
24
  This adapter is included with the core gem:
@@ -16,18 +35,19 @@ require 'this_feature'
16
35
  require 'this_feature/adapters/memory'
17
36
 
18
37
  ThisFeature.configure do |config|
19
- adapter = ThisFeature::Adapters::Memory.new
20
- config.adapters = [adapter]
21
- config.default_adapter = adapter
38
+ config.test_adapter = ThisFeature::Adapters::Memory.new
39
+ config.adapters = [config.test_adapter]
40
+ config.default_adapter = config.test_adapter
22
41
  end
23
42
  ```
24
43
 
25
- The initializer takes an optional `context_key_method` argument. This is only relevant when using `context` -
44
+ The initializer takes an optional `context_key_method` argument. This is only relevant when using `context` -
26
45
  it specifies a method name which should be called on the context object to determine its identity.
27
46
  For example:
28
47
 
29
- ```
30
- # Say you have this method which you want to use as the "identity" of a context object:
48
+ ```ruby
49
+ # Say you have this method which you want to use as the "identity"
50
+ # of a context object (e.g. imagine this module is included onto User)
31
51
  module FeatureFlaggable
32
52
  def this_feature_id
33
53
  "#{self.class}-#{self.id}"
@@ -40,26 +60,29 @@ ThisFeature::Adapters::Memory.new(context_key_method: :this_feature_id)
40
60
 
41
61
  If this option is ommitted, then the context object uses its `self` as its "identity".
42
62
 
63
+ **See below for example of how to use on! and off! from tests**
64
+
43
65
  ## API
44
66
 
45
67
  The Memory adapter supports the public API of `ThisFeature`.
46
68
 
47
- The `context` argument is supported, but not `data`.
69
+ ### **#on? / #off?**
48
70
 
49
- Read the following notes as well:
71
+ If passed a `context` argument, uses the aformentioned logic
72
+ (`context_key_method`) to determine how it's handled.
50
73
 
51
- - **on?** / **off?**: Under the hood, calls `flipper_id` method on the `context`, if one was given.
74
+ Usage example of these:
52
75
 
53
- - **control?** is not yet implemented
76
+ ```ruby
77
+ # If you have configured the in-memory adapter as the default
78
+ ThisFeature.test_adapter.on!(:flag_name, context: user) # with context
79
+ ThisFeature.test_adapter.off!(:flag_name) # without context
80
+ ```
54
81
 
55
- We also support two additional methods here that aren't present on the main adapter yet:
82
+ ### **#clear**
56
83
 
57
- - **on!** / **off!**
84
+ 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.
58
85
 
59
- Usage example of these:
60
-
61
- ```
62
- # If you have configured the in-memory adapter as the default
63
- ThisFeature.default_adapter.on!(:flag_name, context: user) # with context
64
- ThisFeature.default_adapter.off!(:flag_name) # without context
86
+ ```ruby
87
+ ThisFeature.test_adapter.clear
65
88
  ```
data/docs/splitio.md CHANGED
@@ -0,0 +1,35 @@
1
+ # ThisFeature - Split Adapter
2
+
3
+ ## Installation
4
+
5
+ ```ruby
6
+ gem 'this_feature-adapters-split-io
7
+ ```
8
+
9
+ ## Configuration
10
+
11
+ ```ruby
12
+ # config/initializers/this_feature.rb
13
+ require 'this_feature'
14
+ require 'this_feature/adapters/split_io'
15
+
16
+ ThisFeature.configure do |config|
17
+ adapter = ThisFeature::Adapters::SplitIo.new
18
+ config.adapters = [adapter]
19
+ config.default_adapter = adapter
20
+ end
21
+ ```
22
+
23
+ An existing Split client can be optionally passed to the initializer:
24
+
25
+ ```
26
+ ThisFeature::Adapters::SplitIo.new(client: my_existing_client)
27
+ ```
28
+
29
+ ## API
30
+
31
+ The SplitIo adapter supports the public API of `ThisFeature`.
32
+
33
+ Both `context` and `data` are supported.
34
+
35
+ `control` is a native Split feature, so we perform a query to Split to get this info.
@@ -1 +1,9 @@
1
- todo
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
+
3
+ Make sure your class inherits from `ThisFeature::Adapters::Base` - this is a requirement.
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`.
6
+
7
+ For an example, look at one of the existing adapters: [lib/this_feature/adapters/](../lib/this_feature/adapters/)
8
+
9
+ If you want to include your adapter in our README, just open up a PR.
@@ -19,17 +19,11 @@ class ThisFeature
19
19
  end
20
20
 
21
21
  def on?(flag_name, context: nil, data: {})
22
- return unless present?(flag_name)
23
-
24
22
  client[flag_name].enabled?(*[context].compact)
25
23
  end
26
24
 
27
25
  def off?(flag_name, context: nil, data: {})
28
- on_result = on?(flag_name, context: context)
29
-
30
- return if on_result.nil?
31
-
32
- !on_result
26
+ !on?(flag_name, context: context)
33
27
  end
34
28
 
35
29
  private
@@ -15,7 +15,7 @@ class ThisFeature
15
15
  end
16
16
 
17
17
  def on?(flag_name, context: nil, data: {})
18
- return unless present?(flag_name)
18
+ return false unless present?(flag_name)
19
19
 
20
20
  flag_data = storage[flag_name]
21
21
 
@@ -28,11 +28,11 @@ class ThisFeature
28
28
  end
29
29
 
30
30
  def off?(flag_name, context: nil, data: {})
31
- on_result = on?(flag_name, context: context)
32
-
33
- return if on_result.nil?
31
+ !on?(flag_name, context: context, data: data)
32
+ end
34
33
 
35
- !on_result
34
+ def control?(flag_name, **kwargs)
35
+ !present?(flag_name)
36
36
  end
37
37
 
38
38
  def on!(flag_name, context: nil, data: {})
@@ -6,8 +6,9 @@ class ThisFeature
6
6
  # used as treatment key when none is given, it's required by split
7
7
  UNDEFINED_KEY = 'undefined_key'
8
8
 
9
- def initialize(client: nil)
9
+ def initialize(client: nil, context_key_method: nil)
10
10
  @client = client || default_split_client
11
+ @context_key_method = context_key_method
11
12
 
12
13
  @client.block_until_ready
13
14
  end
@@ -30,18 +31,18 @@ class ThisFeature
30
31
 
31
32
  private
32
33
 
33
- attr_reader :client
34
+ attr_reader :client, :context_key_method
34
35
 
35
36
  def treatment(flag_name, context: UNDEFINED_KEY, data: {})
36
- key = if context.nil?
37
- UNDEFINED_KEY
38
- elsif context.respond_to?(:to_s)
39
- context.to_s
40
- else
41
- context
42
- end
43
-
44
- client.get_treatment(key, flag_name, data)
37
+ client.get_treatment(context_key(context), flag_name, data)
38
+ end
39
+
40
+ def context_key(context)
41
+ return UNDEFINED_KEY if context.nil? || context.eql?(UNDEFINED_KEY)
42
+ return context.send(context_key_method) unless context_key_method.nil?
43
+ return context.to_s if context.respond_to?(:to_s)
44
+
45
+ context
45
46
  end
46
47
 
47
48
  def default_split_client
@@ -7,6 +7,8 @@ class ThisFeature
7
7
  end
8
8
 
9
9
  def validate_adapters!
10
+ raise(NoAdaptersError.new) unless adapters.any?
11
+
10
12
  adapters.each do |adapter|
11
13
  raise BadAdapterError.new(adapter) unless adapter.class < Adapters::Base
12
14
  end
@@ -14,9 +14,9 @@ class ThisFeature
14
14
  end
15
15
  end
16
16
 
17
- class NoWriteAdapter < Error
17
+ class NoAdaptersError < Error
18
18
  def initialize
19
- super("Use the `ThisFeature.write_adapter=` setter before calling #enable or #disable")
19
+ super("No adapters configured.")
20
20
  end
21
21
  end
22
22
 
@@ -1,3 +1,3 @@
1
1
  class ThisFeature
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: this_feature
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Pleaner
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-25 00:00:00.000000000 Z
11
+ date: 2021-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -150,7 +150,7 @@ licenses: []
150
150
  metadata:
151
151
  homepage_uri: https://github.com/hoverinc/this_feature
152
152
  source_code_uri: https://github.com/hoverinc/this_feature
153
- post_install_message:
153
+ post_install_message:
154
154
  rdoc_options: []
155
155
  require_paths:
156
156
  - lib
@@ -165,8 +165,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  requirements: []
168
- rubygems_version: 3.0.3
169
- signing_key:
168
+ rubygems_version: 3.1.2
169
+ signing_key:
170
170
  specification_version: 4
171
171
  summary: Feature flag control
172
172
  test_files: []