this_feature-adapters-split_io 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dcaf0447a2c7fd42808d572a9241771599fe348aa7039f32222414d090a3330a
4
+ data.tar.gz: 786c2e46851d9beaa876fc8d9f794cd83a04be50883d9537ede712b84b1700e5
5
+ SHA512:
6
+ metadata.gz: f54b7af274a2444460df67ef67b35363736010b9d378fbc4df2e70acfb37e7c569abd62e34716e186d003f5ac970e648068388c22fce5b37c751cdf5d647f084
7
+ data.tar.gz: 77f4cc43ad5d8ad17127cd325287ad2e512efb5b202076792e68e17a50bb099511087a0fecd3b0daa8e849755bbab9ee3be71e8b3d7dd60133513fc1af8091bf
@@ -0,0 +1,128 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity
10
+ and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the
26
+ overall community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or
31
+ advances of any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email
35
+ address, without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official e-mail address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ shane.becker@hover.to.
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series
86
+ of actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or
93
+ permanent ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within
113
+ the community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.0, available at
119
+ https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120
+
121
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct
122
+ enforcement ladder](https://github.com/mozilla/diversity).
123
+
124
+ [homepage]: https://www.contributor-covenant.org
125
+
126
+ For answers to common questions about this code of conduct, see the FAQ at
127
+ https://www.contributor-covenant.org/faq. Translations are available at
128
+ https://www.contributor-covenant.org/translations.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec name: "this_feature"
4
+ gemspec name: "this_feature-adapters-flipper"
5
+ gemspec name: "this_feature-adapters-split_io"
@@ -0,0 +1,109 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ this_feature (0.4.0)
5
+ this_feature-adapters-flipper (0.4.0)
6
+ flipper (~> 0.16)
7
+ flipper-active_record (~> 0.16)
8
+ this_feature
9
+ this_feature-adapters-split_io (0.4.0)
10
+ splitclient-rb
11
+ this_feature
12
+
13
+ GEM
14
+ remote: https://rubygems.org/
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)
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)
27
+ byebug (11.1.2)
28
+ coderay (1.1.2)
29
+ concurrent-ruby (1.1.6)
30
+ connection_pool (2.2.3)
31
+ database_cleaner (1.8.4)
32
+ database_cleaner-active_record (1.8.0)
33
+ activerecord
34
+ database_cleaner (~> 1.8.0)
35
+ diff-lcs (1.3)
36
+ faraday (1.0.1)
37
+ multipart-post (>= 1.2, < 3)
38
+ flipper (0.18.0)
39
+ flipper-active_record (0.18.0)
40
+ activerecord (>= 5.0, < 7)
41
+ flipper (~> 0.18.0)
42
+ gem-release (2.1.1)
43
+ hitimes (1.3.1)
44
+ i18n (1.8.5)
45
+ concurrent-ruby (~> 1.0)
46
+ json (2.3.1)
47
+ jwt (2.2.2)
48
+ lru_redux (1.1.0)
49
+ method_source (1.0.0)
50
+ minitest (5.14.1)
51
+ multipart-post (2.1.1)
52
+ net-http-persistent (4.0.0)
53
+ connection_pool (~> 2.2)
54
+ pry (0.13.1)
55
+ coderay (~> 1.1)
56
+ method_source (~> 1.0)
57
+ pry-byebug (3.9.0)
58
+ byebug (~> 11.0)
59
+ pry (~> 0.13.0)
60
+ rake (13.0.1)
61
+ redis (4.2.1)
62
+ rspec (3.9.0)
63
+ rspec-core (~> 3.9.0)
64
+ rspec-expectations (~> 3.9.0)
65
+ rspec-mocks (~> 3.9.0)
66
+ rspec-core (3.9.1)
67
+ rspec-support (~> 3.9.1)
68
+ rspec-expectations (3.9.1)
69
+ diff-lcs (>= 1.2.0, < 2.0)
70
+ rspec-support (~> 3.9.0)
71
+ rspec-mocks (3.9.1)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.9.0)
74
+ rspec-support (3.9.2)
75
+ socketry (0.5.1)
76
+ hitimes (~> 1.2)
77
+ splitclient-rb (7.1.3)
78
+ concurrent-ruby (~> 1.0)
79
+ faraday (>= 0.8)
80
+ json (>= 1.8)
81
+ jwt (>= 2.2.1)
82
+ lru_redux
83
+ net-http-persistent (>= 2.9)
84
+ redis (>= 3.2)
85
+ socketry (~> 0.5.1)
86
+ thread_safe (>= 0.3)
87
+ sqlite3 (1.4.2)
88
+ thread_safe (0.3.6)
89
+ tzinfo (1.2.7)
90
+ thread_safe (~> 0.1)
91
+ zeitwerk (2.4.0)
92
+
93
+ PLATFORMS
94
+ ruby
95
+
96
+ DEPENDENCIES
97
+ bundler (~> 2.0)
98
+ database_cleaner-active_record
99
+ gem-release
100
+ pry-byebug
101
+ rake (~> 13.0)
102
+ rspec (~> 3.0)
103
+ sqlite3
104
+ this_feature!
105
+ this_feature-adapters-flipper!
106
+ this_feature-adapters-split_io!
107
+
108
+ BUNDLED WITH
109
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 HOVER, Inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,95 @@
1
+ # ThisFeature
2
+
3
+ The purpose of ThisFeature is to have one way to use feature flags
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's `Gemfile`:
8
+
9
+ ```ruby
10
+ gem 'this_feature'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```sh
16
+ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```sh
22
+ gem install this_feature
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ ```ruby
28
+ # config/initializers/this_feature.rb
29
+ require 'this_feature'
30
+
31
+ ThisFeature.configure do |config|
32
+ config.adapters = [ThisFeature::Adapters::Memory]
33
+ config.default_adapter = config.adapters.first
34
+ end
35
+ ```
36
+
37
+ **NOTE**: When searching for the presence of a flag, adapters are queried in order. The default adapter is the fallback adapter used when a flag isn't present in any of the adapters.
38
+
39
+
40
+ ### With Flipper
41
+
42
+ ```ruby
43
+ # config/initializers/this_feature.rb
44
+ require 'this_feature/adapters/flipper'
45
+
46
+ ThisFeature.configure do |config|
47
+ config.adapters = [ThisFeature::Adapters::Flipper]
48
+ config.default_adapter = config.adapters.first
49
+ end
50
+ ```
51
+
52
+
53
+
54
+ ## Usage
55
+
56
+ ### Flags
57
+ ```ruby
58
+ ThisFeature.flag('flag_name').on? # check if flag is turned on
59
+ ThisFeature.flag('flag_name').off? # check if flag is turned off
60
+ ThisFeature.flag('flag_name').control? # see if the adapter is using the control
61
+ ThisFeature.flag('flag_name').on! # turn on the flag
62
+ ThisFeature.flag('flag_name').off! # turn off the flag
63
+ ```
64
+
65
+ ### Context
66
+
67
+ You can also pass a context to the flag, many feature flagging systems support this.
68
+
69
+ ```ruby
70
+ ThisFeature.flag('flag_name', context: current_user).on?
71
+ ```
72
+
73
+ ### Data
74
+
75
+ In case context is not sufficient, you can also pass a data hash.
76
+
77
+ ```ruby
78
+ ThisFeature.flag('flag_name', context: context, data: { org_id: 1 }).on?
79
+ ```
80
+
81
+ ## TODO: Write documentation for the adapters (creating adapters, using memory adapter, using flipper adapter)
82
+
83
+
84
+ ## Development
85
+
86
+ The tests are a good reflection of the current development state.
87
+ You can run the tests with these commands in your Terminal:
88
+
89
+ ```
90
+ bundle install && bundle exec rspec
91
+ ```
92
+
93
+ ## License
94
+
95
+ ThisFeature is released under the [MIT License](https://choosealicense.com/licenses/mit).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "this_feature"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,37 @@
1
+ require 'this_feature/version'
2
+ require 'this_feature/adapters'
3
+ require 'this_feature/errors'
4
+ require 'this_feature/configuration'
5
+ require 'this_feature/flag'
6
+
7
+ class ThisFeature
8
+ def self.flag(flag_name, context: nil, data: {})
9
+ adapter = adapter_for(flag_name, context: nil, data: {})
10
+
11
+ Flag.new(flag_name, adapter: adapter, context: context, data: data)
12
+ end
13
+
14
+ def self.adapter_for(flag_name, context: nil, data: {})
15
+ matching_adapter = adapters.find do |adapter|
16
+ adapter.present?(flag_name)
17
+ end
18
+
19
+ matching_adapter || configuration.default_adapter
20
+ end
21
+
22
+ def self.configuration
23
+ @configuration ||= Configuration.new
24
+ end
25
+
26
+ def self.configure
27
+ @configuration = Configuration.new
28
+
29
+ yield(configuration)
30
+
31
+ configuration.init
32
+ end
33
+
34
+ def self.adapters
35
+ configuration.adapters
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ require_relative './adapters/base.rb'
2
+ require_relative './adapters/memory.rb'
3
+
4
+ class ThisFeature
5
+ module Adapters
6
+ end
7
+ end
@@ -0,0 +1,28 @@
1
+ class ThisFeature
2
+ module Adapters
3
+ class Base
4
+
5
+ def setup
6
+ raise UnimplementedError.new(self, __method__)
7
+ end
8
+
9
+ def present?(flag_name)
10
+ raise UnimplementedError.new(self, __method__)
11
+ end
12
+
13
+ def on?(flag_name, context: nil, data: {})
14
+ raise UnimplementedError.new(self, __method__)
15
+ end
16
+
17
+ def off?(flag_name, context: nil, data: {})
18
+ raise UnimplementedError.new(self, __method__)
19
+ end
20
+
21
+ # OPTIONAL method
22
+ # check to see if a control is being used
23
+ def control?(flag_name, context: nil, data: {})
24
+ false
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ require "flipper"
2
+ require "flipper/adapters/active_record"
3
+
4
+ class ThisFeature
5
+ module Adapters
6
+ class Flipper < Base
7
+ attr_reader :client
8
+
9
+ def initialize(client: nil)
10
+ @client = client || default_flipper_adapter
11
+ end
12
+
13
+ def present?(flag_name)
14
+ client[flag_name].exist?
15
+ end
16
+
17
+ def control?(flag_name, **kwargs)
18
+ !present?(flag_name)
19
+ end
20
+
21
+ def on?(flag_name, context: nil, data: {})
22
+ return unless present?(flag_name)
23
+
24
+ client[flag_name].enabled?(*[context].compact)
25
+ end
26
+
27
+ 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
33
+ end
34
+
35
+ private
36
+
37
+ def default_flipper_adapter
38
+ ::Flipper.configure do |config|
39
+ config.default do
40
+ adapter = ::Flipper::Adapters::ActiveRecord.new
41
+ ::Flipper.new(adapter)
42
+ end
43
+ end
44
+ ::Flipper
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,71 @@
1
+ class ThisFeature
2
+ module Adapters
3
+ class Memory < Base
4
+
5
+ def initialize(context_key_method: nil)
6
+ @context_key_method = context_key_method
7
+ end
8
+
9
+ def clear
10
+ storage.clear
11
+ end
12
+
13
+ def present?(flag_name)
14
+ !storage[flag_name].nil?
15
+ end
16
+
17
+ def on?(flag_name, context: nil, data: {})
18
+ return unless present?(flag_name)
19
+
20
+ flag_data = storage[flag_name]
21
+
22
+ return true if flag_data[:global]
23
+ return false if context.nil?
24
+
25
+ flag_data[:contexts] ||= {}
26
+
27
+ !!flag_data[:contexts][context_key(context)]
28
+ end
29
+
30
+ def off?(flag_name, context: nil, data: {})
31
+ on_result = on?(flag_name, context: context)
32
+
33
+ return if on_result.nil?
34
+
35
+ !on_result
36
+ end
37
+
38
+ def on!(flag_name, context: nil, data: {})
39
+ storage[flag_name] ||= {}
40
+
41
+ return storage[flag_name][:global] = true if context.nil?
42
+
43
+ storage[flag_name][:contexts] ||= {}
44
+ storage[flag_name][:contexts][context_key(context)] = true
45
+ end
46
+
47
+ def off!(flag_name, context: nil, data: {})
48
+ storage[flag_name] ||= {}
49
+
50
+ return storage[flag_name][:global] = false if context.nil?
51
+
52
+ storage[flag_name][:contexts] ||= {}
53
+ storage[flag_name][:contexts][context_key(context)] = false
54
+ end
55
+
56
+ def storage
57
+ @storage ||= {}
58
+ end
59
+
60
+ private
61
+
62
+ attr_reader :context_key_method
63
+
64
+ def context_key(context)
65
+ return context if context_key_method.nil?
66
+
67
+ context.send(context_key_method)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,52 @@
1
+ require 'splitclient-rb'
2
+
3
+ class ThisFeature
4
+ module Adapters
5
+ class SplitIo < Base
6
+ # used as treatment key when none is given, it's required by split
7
+ UNDEFINED_KEY = 'undefined_key'
8
+
9
+ def initialize(client: nil)
10
+ @client = client || default_split_client
11
+
12
+ @client.block_until_ready
13
+ end
14
+
15
+ def present?(flag_name)
16
+ !control?(flag_name)
17
+ end
18
+
19
+ def control?(flag_name, context: UNDEFINED_KEY, data: {})
20
+ treatment(flag_name, context: context, data: data).eql?('control_treatment')
21
+ end
22
+
23
+ def on?(flag_name, context: UNDEFINED_KEY, data: {})
24
+ treatment(flag_name, context: context, data: data).eql?('on')
25
+ end
26
+
27
+ def off?(flag_name, context: UNDEFINED_KEY, data: {})
28
+ treatment(flag_name, context: context, data: data).eql?('off')
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :client
34
+
35
+ 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)
45
+ end
46
+
47
+ def default_split_client
48
+ SplitIoClient::SplitFactory.new(ENV.fetch('SPLIT_IO_AUTH_KEY')).client
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,24 @@
1
+
2
+ class ThisFeature
3
+ class Configuration
4
+ attr_writer :adapters, :default_adapter
5
+
6
+ def init
7
+ validate_adapters!
8
+ end
9
+
10
+ def validate_adapters!
11
+ adapters.each do |adapter|
12
+ raise BadAdapterError.new(adapter) unless adapter.class < Adapters::Base
13
+ end
14
+ end
15
+
16
+ def adapters
17
+ @adapters ||= []
18
+ end
19
+
20
+ def default_adapter
21
+ @default_adapter ||= adapters.first
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ class ThisFeature
2
+
3
+ class Error < StandardError; end
4
+
5
+ class UnimplementedError < Error
6
+ def initialize(adapter_instance, fn_name)
7
+ super("class #{adapter_instance.class.name} doesnt implement method .#{fn_name}")
8
+ end
9
+ end
10
+
11
+ class BadAdapterError < Error
12
+ def initialize(adapter_instance)
13
+ super("adapter #{adapter_instance.class.name} doesn't inherit from #{ThisFeature::Adapters::Base.name}")
14
+ end
15
+ end
16
+
17
+ class NoWriteAdapter < Error
18
+ def initialize
19
+ super("Use the `ThisFeature.write_adapter=` setter before calling #enable or #disable")
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,24 @@
1
+ class ThisFeature
2
+ class Flag
3
+ attr_reader :flag_name, :context, :data, :adapter
4
+
5
+ def initialize(flag_name, adapter:, context: nil, data: {})
6
+ @flag_name = flag_name
7
+ @adapter = adapter
8
+ @context = context
9
+ @data = data
10
+ end
11
+
12
+ def on?
13
+ adapter.on?(flag_name, context: context, data: data)
14
+ end
15
+
16
+ def off?
17
+ adapter.off?(flag_name, context: context, data: data)
18
+ end
19
+
20
+ def control?
21
+ adapter.control?(flag_name, context: context, data: data)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ class ThisFeature
2
+ VERSION = "0.4.0"
3
+ end
data/memory ADDED
Binary file
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('../lib', __FILE__)
4
+
5
+ require 'this_feature/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'this_feature-adapters-flipper'
9
+ s.version = ThisFeature::VERSION
10
+ s.authors = ['Max Pleaner']
11
+ s.email = ['maxpleaner@gmail.com']
12
+ s.homepage = 'http://hover.to'
13
+ s.licenses = ['MIT']
14
+ s.summary = '[summary]'
15
+ s.description = '[description]'
16
+
17
+ s.files = Dir.glob('{bin/*,lib/**/*,[A-Z]*}')
18
+ s.platform = Gem::Platform::RUBY
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_runtime_dependency "this_feature"
22
+ s.add_runtime_dependency "flipper", "~> 0.16"
23
+ s.add_runtime_dependency "flipper-active_record", "~> 0.16"
24
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('../lib', __FILE__)
4
+
5
+ require 'this_feature/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'this_feature-adapters-split_io'
9
+ s.version = ThisFeature::VERSION
10
+ s.authors = ['Max Pleaner', 'Matt Fong']
11
+ s.email = ['maxpleaner@gmail.com', 'matthewjf@gmail.com']
12
+ s.homepage = 'http://hover.to'
13
+ s.licenses = ['MIT']
14
+ s.summary = '[summary]'
15
+ s.description = '[description]'
16
+
17
+ s.files = Dir.glob('{bin/*,lib/**/*,[A-Z]*}')
18
+ s.platform = Gem::Platform::RUBY
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_runtime_dependency "this_feature"
22
+ s.add_runtime_dependency "splitclient-rb"
23
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('../lib', __FILE__)
4
+
5
+ require "this_feature/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "this_feature"
9
+ spec.version = ThisFeature::VERSION
10
+ spec.authors = ["Max Pleaner"]
11
+ spec.email = ["max.pleaner@hover.to"]
12
+
13
+ spec.summary = %q{Feature flag control}
14
+ spec.description = spec.summary
15
+ spec.homepage = "https://github.com/hoverinc/this_feature"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 2.0"
30
+ spec.add_development_dependency "pry-byebug"
31
+ spec.add_development_dependency "rake", "~> 13.0"
32
+ spec.add_development_dependency "rspec", "~> 3.0"
33
+ spec.add_development_dependency "sqlite3"
34
+ spec.add_development_dependency "database_cleaner-active_record"
35
+ spec.add_development_dependency "gem-release"
36
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: this_feature-adapters-split_io
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Max Pleaner
8
+ - Matt Fong
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2020-09-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: this_feature
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: splitclient-rb
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ description: "[description]"
43
+ email:
44
+ - maxpleaner@gmail.com
45
+ - matthewjf@gmail.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - CODE_OF_CONDUCT.md
51
+ - Gemfile
52
+ - Gemfile.lock
53
+ - LICENSE
54
+ - README.md
55
+ - Rakefile
56
+ - bin/console
57
+ - bin/setup
58
+ - lib/this_feature.rb
59
+ - lib/this_feature/adapters.rb
60
+ - lib/this_feature/adapters/base.rb
61
+ - lib/this_feature/adapters/flipper.rb
62
+ - lib/this_feature/adapters/memory.rb
63
+ - lib/this_feature/adapters/split_io.rb
64
+ - lib/this_feature/configuration.rb
65
+ - lib/this_feature/errors.rb
66
+ - lib/this_feature/flag.rb
67
+ - lib/this_feature/version.rb
68
+ - memory
69
+ - this_feature-adapters-flipper.gemspec
70
+ - this_feature-adapters-split_io.gemspec
71
+ - this_feature.gemspec
72
+ homepage: http://hover.to
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.1.2
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: "[summary]"
95
+ test_files: []