this_feature 0.7.0 → 0.8.0

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: 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