this_feature 0.7.0 → 0.9.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 +88 -53
- data/README.md +2 -7
- data/Rakefile +3 -3
- data/bin/console +3 -7
- data/docs/flipper.md +1 -1
- data/docs/memory.md +2 -2
- data/docs/splitio.md +29 -2
- data/docs/writing_an_adapter.md +3 -3
- data/lib/this_feature/adapters/base.rb +2 -2
- data/lib/this_feature/adapters/flipper.rb +4 -4
- data/lib/this_feature/adapters/memory.rb +2 -3
- data/lib/this_feature/adapters/split_io.rb +13 -11
- data/lib/this_feature/adapters.rb +2 -2
- data/lib/this_feature/configuration.rb +7 -3
- data/lib/this_feature/errors.rb +2 -4
- data/lib/this_feature/flag.rb +6 -5
- data/lib/this_feature/version.rb +1 -1
- data/lib/this_feature.rb +8 -4
- data/this_feature-adapters-flipper.gemspec +27 -20
- data/this_feature-adapters-split_io.gemspec +26 -19
- data/this_feature.gemspec +26 -22
- metadata +20 -107
- data/docs/flipper.html +0 -1087
@@ -3,8 +3,9 @@ require 'splitclient-rb'
|
|
3
3
|
class ThisFeature
|
4
4
|
module Adapters
|
5
5
|
class SplitIo < Base
|
6
|
-
#
|
7
|
-
|
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'.freeze
|
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:
|
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:
|
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:
|
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:
|
37
|
-
|
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
|
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,16 +1,16 @@
|
|
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!
|
7
7
|
end
|
8
8
|
|
9
9
|
def validate_adapters!
|
10
|
-
raise
|
10
|
+
raise NoAdaptersError unless adapters.any?
|
11
11
|
|
12
12
|
adapters.each do |adapter|
|
13
|
-
raise BadAdapterError
|
13
|
+
raise BadAdapterError, adapter unless adapter.class < Adapters::Base
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -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
|
data/lib/this_feature/errors.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
class ThisFeature
|
2
|
-
|
3
2
|
class Error < StandardError; end
|
4
3
|
|
5
4
|
class UnimplementedError < Error
|
6
5
|
def initialize(adapter_instance, fn_name)
|
7
|
-
super("class #{adapter_instance.class.name}
|
6
|
+
super("class #{adapter_instance.class.name} doesn't implement method .#{fn_name}")
|
8
7
|
end
|
9
8
|
end
|
10
9
|
|
@@ -16,8 +15,7 @@ class ThisFeature
|
|
16
15
|
|
17
16
|
class NoAdaptersError < Error
|
18
17
|
def initialize
|
19
|
-
super(
|
18
|
+
super('No adapters configured.')
|
20
19
|
end
|
21
20
|
end
|
22
|
-
|
23
21
|
end
|
data/lib/this_feature/flag.rb
CHANGED
@@ -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
|
data/lib/this_feature/version.rb
CHANGED
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
|
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
|
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
|
@@ -1,24 +1,31 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
$:.unshift File.expand_path('../lib', __FILE__)
|
1
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
4
2
|
|
5
3
|
require 'this_feature/version'
|
6
4
|
|
7
|
-
Gem::Specification.new do |
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'this_feature-adapters-flipper'
|
7
|
+
spec.version = ThisFeature::VERSION
|
8
|
+
|
9
|
+
spec.required_ruby_version = '>= 3.2'
|
10
|
+
|
11
|
+
spec.authors = ['Max Pleaner', 'Matt Fong']
|
12
|
+
spec.email = ['maxpleaner@gmail.com', 'matthewjf@gmail.com']
|
13
|
+
spec.homepage = 'http://hover.to'
|
14
|
+
|
15
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
16
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
17
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
18
|
+
|
19
|
+
spec.licenses = ['MIT']
|
20
|
+
spec.summary = 'A ThisFeature adapter to Flipper'
|
21
|
+
spec.description = ''
|
22
|
+
spec.homepage = 'https://github.com/hoverinc/this_feature'
|
23
|
+
|
24
|
+
spec.files = Dir.glob('{bin/*,lib/**/*,[A-Z]*}')
|
25
|
+
spec.platform = Gem::Platform::RUBY
|
26
|
+
spec.require_paths = ['lib']
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'flipper'
|
29
|
+
spec.add_runtime_dependency 'flipper-active_record'
|
30
|
+
spec.add_runtime_dependency 'this_feature'
|
24
31
|
end
|
@@ -1,23 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
$:.unshift File.expand_path('../lib', __FILE__)
|
1
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
4
2
|
|
5
3
|
require 'this_feature/version'
|
6
4
|
|
7
|
-
Gem::Specification.new do |
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'this_feature-adapters-split_io'
|
7
|
+
spec.version = ThisFeature::VERSION
|
8
|
+
|
9
|
+
spec.required_ruby_version = '>= 3.2'
|
10
|
+
|
11
|
+
spec.authors = ['Max Pleaner', 'Matt Fong']
|
12
|
+
spec.email = ['maxpleaner@gmail.com', 'matthewjf@gmail.com']
|
13
|
+
spec.homepage = 'http://hover.to'
|
14
|
+
|
15
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
16
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
17
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
18
|
+
|
19
|
+
spec.licenses = ['MIT']
|
20
|
+
spec.summary = 'A ThisFeature adapter to Split.io'
|
21
|
+
spec.description = ''
|
22
|
+
spec.homepage = 'https://github.com/hoverinc/this_feature'
|
23
|
+
|
24
|
+
spec.files = Dir.glob('{bin/*,lib/**/*,[A-Z]*}')
|
25
|
+
spec.platform = Gem::Platform::RUBY
|
26
|
+
spec.require_paths = ['lib']
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'splitclient-rb'
|
29
|
+
spec.add_runtime_dependency 'this_feature'
|
23
30
|
end
|
data/this_feature.gemspec
CHANGED
@@ -1,34 +1,38 @@
|
|
1
|
-
lib = File.expand_path(
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require
|
3
|
+
require 'this_feature/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name
|
7
|
-
spec.version
|
8
|
-
spec.authors = ["Max Pleaner"]
|
9
|
-
spec.email = ["max.pleaner@hover.to"]
|
6
|
+
spec.name = 'this_feature'
|
7
|
+
spec.version = ThisFeature::VERSION
|
10
8
|
|
11
|
-
spec.
|
12
|
-
spec.description = spec.summary
|
13
|
-
spec.homepage = "https://github.com/hoverinc/this_feature"
|
9
|
+
spec.required_ruby_version = '>= 3.2'
|
14
10
|
|
15
|
-
|
16
|
-
|
11
|
+
contributors = {
|
12
|
+
'Max Pleaner' => 'max.pleaner@hover.to',
|
13
|
+
'Matt Fong' => 'matt.fong@hover.to',
|
14
|
+
'Shane Becker' => 'shane.becker@hover.to',
|
15
|
+
'Daniel Deutsch' => 'daniel.deutsch@hover.to'
|
16
|
+
}
|
17
|
+
spec.authors = contributors.keys
|
18
|
+
spec.email = contributors.values
|
19
|
+
|
20
|
+
spec.licenses = ['MIT']
|
21
|
+
spec.summary = 'A common interface to interact with many feature flag providers'
|
22
|
+
spec.description = ''
|
23
|
+
spec.homepage = 'https://github.com/hoverinc/this_feature'
|
24
|
+
|
25
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
26
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
27
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
17
28
|
|
18
29
|
# Specify which files should be added to the gem when it is released.
|
19
30
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
-
spec.files
|
31
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
32
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
33
|
end
|
23
|
-
spec.bindir = "exe"
|
24
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
-
spec.require_paths = ["lib"]
|
26
34
|
|
27
|
-
spec.
|
28
|
-
spec.
|
29
|
-
spec.
|
30
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
31
|
-
spec.add_development_dependency "sqlite3"
|
32
|
-
spec.add_development_dependency "database_cleaner-active_record"
|
33
|
-
spec.add_development_dependency "gem-release"
|
35
|
+
spec.bindir = 'exe'
|
36
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
37
|
+
spec.require_paths = ['lib']
|
34
38
|
end
|
metadata
CHANGED
@@ -1,123 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: this_feature
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Pleaner
|
8
|
+
- Matt Fong
|
9
|
+
- Shane Becker
|
10
|
+
- Daniel Deutsch
|
8
11
|
autorequire:
|
9
12
|
bindir: exe
|
10
13
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '2.0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '2.0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: pry-byebug
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '13.0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '13.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rspec
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '3.0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '3.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: sqlite3
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: database_cleaner-active_record
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: gem-release
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
description: Feature flag control
|
14
|
+
date: 2023-05-31 00:00:00.000000000 Z
|
15
|
+
dependencies: []
|
16
|
+
description: ''
|
112
17
|
email:
|
113
18
|
- max.pleaner@hover.to
|
19
|
+
- matt.fong@hover.to
|
20
|
+
- shane.becker@hover.to
|
21
|
+
- daniel.deutsch@hover.to
|
114
22
|
executables: []
|
115
23
|
extensions: []
|
116
24
|
extra_rdoc_files: []
|
117
25
|
files:
|
26
|
+
- ".github/workflows/linter-rubocop.yml"
|
118
27
|
- ".github/workflows/test.yml"
|
119
28
|
- ".gitignore"
|
120
29
|
- ".rspec"
|
30
|
+
- ".rubocop.yml"
|
31
|
+
- ".rubocop_todo.yml"
|
32
|
+
- ".ruby-version"
|
121
33
|
- ".travis.yml"
|
122
34
|
- CODE_OF_CONDUCT.md
|
123
35
|
- Gemfile
|
@@ -127,7 +39,6 @@ files:
|
|
127
39
|
- Rakefile
|
128
40
|
- bin/console
|
129
41
|
- bin/setup
|
130
|
-
- docs/flipper.html
|
131
42
|
- docs/flipper.md
|
132
43
|
- docs/memory.md
|
133
44
|
- docs/splitio.md
|
@@ -146,10 +57,12 @@ files:
|
|
146
57
|
- this_feature-adapters-split_io.gemspec
|
147
58
|
- this_feature.gemspec
|
148
59
|
homepage: https://github.com/hoverinc/this_feature
|
149
|
-
licenses:
|
60
|
+
licenses:
|
61
|
+
- MIT
|
150
62
|
metadata:
|
151
63
|
homepage_uri: https://github.com/hoverinc/this_feature
|
152
64
|
source_code_uri: https://github.com/hoverinc/this_feature
|
65
|
+
rubygems_mfa_required: 'true'
|
153
66
|
post_install_message:
|
154
67
|
rdoc_options: []
|
155
68
|
require_paths:
|
@@ -158,15 +71,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
158
71
|
requirements:
|
159
72
|
- - ">="
|
160
73
|
- !ruby/object:Gem::Version
|
161
|
-
version: '
|
74
|
+
version: '3.2'
|
162
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
76
|
requirements:
|
164
77
|
- - ">="
|
165
78
|
- !ruby/object:Gem::Version
|
166
79
|
version: '0'
|
167
80
|
requirements: []
|
168
|
-
rubygems_version: 3.
|
81
|
+
rubygems_version: 3.4.13
|
169
82
|
signing_key:
|
170
83
|
specification_version: 4
|
171
|
-
summary:
|
84
|
+
summary: A common interface to interact with many feature flag providers
|
172
85
|
test_files: []
|