this_feature 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8812767db56e7467a7439bc73bd243e3829974f9ee8897b85e434a036d0cdff9
4
- data.tar.gz: b27419213f0bb1954a7d9c221ce315ae2229f2bb27fee13ae92b8987371d7c24
3
+ metadata.gz: 4a2e4f072c94b68b9a9e4675ac663f4d6f451d1d7c854e457079d539bd16184e
4
+ data.tar.gz: 6bbda6b3a7257f0a2e1ebd13784c3a78d4eb4ba3340727b99aa9d9df90753ea3
5
5
  SHA512:
6
- metadata.gz: cc7fe3136ed720c6eca4aed7ee10a02faf9e3eca3f39302137f7b375e408bf7be7b6259e5fa6ab7b631d9c929fa6c562c25e697cc2ff061a0d204c982dc45a73
7
- data.tar.gz: 6b7e73cead9d55c2c116c9fda04a61c789b2ab8c368d53535958f38f6fe8a7e1191842119e1c469d6d4459a55c4ad722dfdf2e24b9fb64ec95bcbcf5bc1ca36b
6
+ metadata.gz: 0c0e69e00abb16fc2e781b4fdeb63664af7705280095c1f0a12cb660c5195b886463195e0830c91382474f62cd5c9c0b777aeddb14b494f48040cc2522d238c9
7
+ data.tar.gz: 6b1e05ba21a6409f413ba5b11167f1c17e561a9c2989edde58a1b2f50d1c368c4b76fde8153db4588757d6e4bd93a0f9e36d2fa4874e7190fa8c4347699e9c53
data/Gemfile.lock CHANGED
@@ -1,39 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- this_feature (0.7.0)
5
- this_feature-adapters-flipper (0.7.0)
4
+ this_feature (0.8.0)
5
+ this_feature-adapters-flipper (0.8.0)
6
6
  flipper (~> 0.16)
7
7
  flipper-active_record (~> 0.16)
8
8
  this_feature
9
- this_feature-adapters-split_io (0.7.0)
9
+ this_feature-adapters-split_io (0.8.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 (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)
16
+ activemodel (7.0.3.1)
17
+ activesupport (= 7.0.3.1)
18
+ activerecord (7.0.3.1)
19
+ activemodel (= 7.0.3.1)
20
+ activesupport (= 7.0.3.1)
21
+ activesupport (7.0.3.1)
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
- zeitwerk (~> 2.3)
27
26
  byebug (11.1.2)
28
27
  coderay (1.1.2)
29
- concurrent-ruby (1.1.8)
28
+ concurrent-ruby (1.1.10)
30
29
  connection_pool (2.2.5)
31
30
  database_cleaner (1.8.4)
32
31
  database_cleaner-active_record (1.8.0)
33
32
  activerecord
34
33
  database_cleaner (~> 1.8.0)
35
34
  diff-lcs (1.3)
36
- faraday (1.5.0)
35
+ faraday (1.7.0)
37
36
  faraday-em_http (~> 1.0)
38
37
  faraday-em_synchrony (~> 1.0)
39
38
  faraday-excon (~> 1.1)
@@ -41,6 +40,7 @@ GEM
41
40
  faraday-net_http (~> 1.0)
42
41
  faraday-net_http_persistent (~> 1.1)
43
42
  faraday-patron (~> 1.0)
43
+ faraday-rack (~> 1.0)
44
44
  multipart-post (>= 1.2, < 3)
45
45
  ruby2_keywords (>= 0.0.4)
46
46
  faraday-em_http (1.0.0)
@@ -48,21 +48,22 @@ GEM
48
48
  faraday-excon (1.1.0)
49
49
  faraday-httpclient (1.0.1)
50
50
  faraday-net_http (1.0.1)
51
- faraday-net_http_persistent (1.1.0)
51
+ faraday-net_http_persistent (1.2.0)
52
52
  faraday-patron (1.0.0)
53
- flipper (0.22.0)
54
- flipper-active_record (0.22.0)
55
- activerecord (>= 4.2, < 7)
56
- flipper (~> 0.22.0)
53
+ faraday-rack (1.0.0)
54
+ flipper (0.25.0)
55
+ flipper-active_record (0.25.0)
56
+ activerecord (>= 4.2, < 8)
57
+ flipper (~> 0.25.0)
57
58
  gem-release (2.2.1)
58
59
  hitimes (1.3.1)
59
- i18n (1.8.9)
60
+ i18n (1.11.0)
60
61
  concurrent-ruby (~> 1.0)
61
62
  json (2.5.1)
62
63
  jwt (2.2.3)
63
64
  lru_redux (1.1.0)
64
65
  method_source (1.0.0)
65
- minitest (5.14.4)
66
+ minitest (5.16.2)
66
67
  multipart-post (2.1.1)
67
68
  net-http-persistent (4.0.1)
68
69
  connection_pool (~> 2.2)
@@ -73,7 +74,7 @@ GEM
73
74
  byebug (~> 11.0)
74
75
  pry (~> 0.13.0)
75
76
  rake (13.0.1)
76
- redis (4.3.1)
77
+ redis (4.4.0)
77
78
  rspec (3.9.0)
78
79
  rspec-core (~> 3.9.0)
79
80
  rspec-expectations (~> 3.9.0)
@@ -87,10 +88,10 @@ GEM
87
88
  diff-lcs (>= 1.2.0, < 2.0)
88
89
  rspec-support (~> 3.9.0)
89
90
  rspec-support (3.9.2)
90
- ruby2_keywords (0.0.4)
91
+ ruby2_keywords (0.0.5)
91
92
  socketry (0.5.1)
92
93
  hitimes (~> 1.2)
93
- splitclient-rb (7.2.3)
94
+ splitclient-rb (7.3.1)
94
95
  concurrent-ruby (~> 1.0)
95
96
  faraday (>= 0.8)
96
97
  json (>= 1.8)
@@ -104,7 +105,6 @@ GEM
104
105
  thread_safe (0.3.6)
105
106
  tzinfo (2.0.4)
106
107
  concurrent-ruby (~> 1.0)
107
- zeitwerk (2.4.2)
108
108
 
109
109
  PLATFORMS
110
110
  ruby
@@ -122,4 +122,4 @@ DEPENDENCIES
122
122
  this_feature-adapters-split_io!
123
123
 
124
124
  BUNDLED WITH
125
- 2.1.4
125
+ 2.3.21
data/docs/splitio.md CHANGED
@@ -32,4 +32,31 @@ The SplitIo adapter supports the public API of `ThisFeature`.
32
32
 
33
33
  Both `context` and `data` are supported.
34
34
 
35
- `control` is a native Split feature, so we perform a query to Split to get this info.
35
+ `control` is a native Split feature, so we perform a query to Split to get this info.
36
+
37
+ We've also added `record`, which is a helper to easily and consistently add
38
+ attributes to the `data` hash. To take advantage of this, the application must
39
+ set a `base_data_lambda` in the config. An example—
40
+ ```ruby
41
+ ThisFeature.configure do |config|
42
+ config.base_data_lambda = -> (record) do
43
+ case record
44
+ when Org
45
+ {
46
+ org_id: record.id,
47
+ org_name: record.name
48
+ }
49
+ when User
50
+ {
51
+ org_id: record.org.id,
52
+ org_name: record.org.name,
53
+ user_email: record.email,
54
+ user_id: record.id,
55
+ user_name: record.name,
56
+ }
57
+ end
58
+ end
59
+ end
60
+ ```
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.
@@ -5,11 +5,11 @@ class ThisFeature
5
5
  raise UnimplementedError.new(self, __method__)
6
6
  end
7
7
 
8
- def on?(flag_name, context: nil, data: {})
8
+ def on?(flag_name, context: nil, data: {}, record: nil)
9
9
  raise UnimplementedError.new(self, __method__)
10
10
  end
11
11
 
12
- def off?(flag_name, context: nil, data: {})
12
+ def off?(flag_name, context: nil, data: {}, record: nil)
13
13
  raise UnimplementedError.new(self, __method__)
14
14
  end
15
15
 
@@ -18,11 +18,11 @@ class ThisFeature
18
18
  !present?(flag_name)
19
19
  end
20
20
 
21
- def on?(flag_name, context: nil, data: {})
21
+ def on?(flag_name, context: nil, data: {}, record: nil)
22
22
  client[flag_name].enabled?(*[context].compact)
23
23
  end
24
24
 
25
- def off?(flag_name, context: nil, data: {})
25
+ def off?(flag_name, context: nil, data: {}, record: nil)
26
26
  !on?(flag_name, context: context)
27
27
  end
28
28
 
@@ -14,7 +14,7 @@ class ThisFeature
14
14
  !storage[flag_name].nil?
15
15
  end
16
16
 
17
- def on?(flag_name, context: nil, data: {})
17
+ def on?(flag_name, context: nil, data: {}, record: nil)
18
18
  return false unless present?(flag_name)
19
19
 
20
20
  flag_data = storage[flag_name]
@@ -27,7 +27,7 @@ class ThisFeature
27
27
  !!flag_data[:contexts][context_key(context)]
28
28
  end
29
29
 
30
- def off?(flag_name, context: nil, data: {})
30
+ def off?(flag_name, context: nil, data: {}, record: nil)
31
31
  !on?(flag_name, context: context, data: data)
32
32
  end
33
33
 
@@ -3,8 +3,9 @@ require 'splitclient-rb'
3
3
  class ThisFeature
4
4
  module Adapters
5
5
  class SplitIo < Base
6
- # used as treatment key when none is given, it's required by split
7
- UNDEFINED_KEY = 'undefined_key'
6
+ # Used as the context key when none is given. This arg is required by
7
+ # Split, but it's nice not to have to pass it when the context is empty.
8
+ EMPTY_CONTEXT = 'undefined_key'
8
9
 
9
10
  def initialize(client: nil, context_key_method: nil)
10
11
  @client = client || default_split_client
@@ -17,28 +18,29 @@ class ThisFeature
17
18
  !control?(flag_name)
18
19
  end
19
20
 
20
- def control?(flag_name, context: UNDEFINED_KEY, data: {})
21
- treatment(flag_name, context: context, data: data).include?('control')
21
+ def control?(flag_name, context: EMPTY_CONTEXT, data: {}, record: nil)
22
+ treatment(flag_name, context: context, data: data, record: record).include?('control')
22
23
  end
23
24
 
24
- def on?(flag_name, context: UNDEFINED_KEY, data: {})
25
- treatment(flag_name, context: context, data: data).eql?('on')
25
+ def on?(flag_name, context: EMPTY_CONTEXT, data: {}, record: nil)
26
+ treatment(flag_name, context: context, data: data, record: record).eql?('on')
26
27
  end
27
28
 
28
- def off?(flag_name, context: UNDEFINED_KEY, data: {})
29
- treatment(flag_name, context: context, data: data).eql?('off')
29
+ def off?(flag_name, context: EMPTY_CONTEXT, data: {}, record: nil)
30
+ treatment(flag_name, context: context, data: data, record: record).eql?('off')
30
31
  end
31
32
 
32
33
  private
33
34
 
34
35
  attr_reader :client, :context_key_method
35
36
 
36
- def treatment(flag_name, context: UNDEFINED_KEY, data: {})
37
- client.get_treatment(context_key(context), flag_name, data)
37
+ def treatment(flag_name, context: EMPTY_CONTEXT, data: {}, record: nil)
38
+ base_data = record ? ThisFeature.base_data_lambda.call(record) : {}
39
+ client.get_treatment(context_key(context), flag_name, base_data.merge(data))
38
40
  end
39
41
 
40
42
  def context_key(context)
41
- return UNDEFINED_KEY if context.nil? || context.eql?(UNDEFINED_KEY)
43
+ return EMPTY_CONTEXT if context.nil? || context.eql?(EMPTY_CONTEXT)
42
44
  return context.send(context_key_method) unless context_key_method.nil?
43
45
  return context.to_s if context.respond_to?(:to_s)
44
46
 
@@ -1,6 +1,6 @@
1
1
  class ThisFeature
2
2
  class Configuration
3
- attr_writer :adapters, :default_adapter, :test_adapter
3
+ attr_writer :adapters, :default_adapter, :test_adapter, :base_data_lambda
4
4
 
5
5
  def init
6
6
  validate_adapters!
@@ -25,5 +25,9 @@ class ThisFeature
25
25
  def test_adapter
26
26
  @test_adapter ||= Adapters::Memory.new
27
27
  end
28
+
29
+ def base_data_lambda
30
+ @base_data_lambda ||= -> (record) { {} }
31
+ end
28
32
  end
29
33
  end
@@ -1,24 +1,25 @@
1
1
  class ThisFeature
2
2
  class Flag
3
- attr_reader :flag_name, :context, :data, :adapter
3
+ attr_reader :flag_name, :context, :data, :adapter, :record
4
4
 
5
- def initialize(flag_name, adapter:, context: nil, data: {})
5
+ def initialize(flag_name, adapter:, context: nil, data: {}, record: nil)
6
6
  @flag_name = flag_name
7
7
  @adapter = adapter
8
8
  @context = context
9
9
  @data = data
10
+ @record = record
10
11
  end
11
12
 
12
13
  def on?
13
- adapter.on?(flag_name, context: context, data: data)
14
+ adapter.on?(flag_name, context: context, data: data, record: record)
14
15
  end
15
16
 
16
17
  def off?
17
- adapter.off?(flag_name, context: context, data: data)
18
+ adapter.off?(flag_name, context: context, data: data, record: record)
18
19
  end
19
20
 
20
21
  def control?
21
- adapter.control?(flag_name, context: context, data: data)
22
+ adapter.control?(flag_name, context: context, data: data, record: record)
22
23
  end
23
24
  end
24
25
  end
@@ -1,3 +1,3 @@
1
1
  class ThisFeature
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
data/lib/this_feature.rb CHANGED
@@ -5,13 +5,13 @@ require 'this_feature/configuration'
5
5
  require 'this_feature/flag'
6
6
 
7
7
  class ThisFeature
8
- def self.flag(flag_name, context: nil, data: {})
9
- adapter = adapter_for(flag_name, context: nil, data: {})
8
+ def self.flag(flag_name, context: nil, data: {}, record: nil)
9
+ adapter = adapter_for(flag_name)
10
10
 
11
- Flag.new(flag_name, adapter: adapter, context: context, data: data)
11
+ Flag.new(flag_name, adapter: adapter, context: context, data: data, record: record)
12
12
  end
13
13
 
14
- def self.adapter_for(flag_name, context: nil, data: {})
14
+ def self.adapter_for(flag_name)
15
15
  matching_adapter = adapters.find do |adapter|
16
16
  adapter.present?(flag_name)
17
17
  end
@@ -38,4 +38,8 @@ class ThisFeature
38
38
  def self.test_adapter
39
39
  configuration.test_adapter
40
40
  end
41
+
42
+ def self.base_data_lambda
43
+ configuration.base_data_lambda
44
+ end
41
45
  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.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Pleaner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-09 00:00:00.000000000 Z
11
+ date: 2023-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler