-
-
Notifications
You must be signed in to change notification settings - Fork 419
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add NamingStyle adapter to enforce format for added features.
- Loading branch information
Showing
2 changed files
with
112 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
module Flipper | ||
module Adapters | ||
# An adapter that enforces a naming style for added features. | ||
# | ||
# Flipper.configure do |config| | ||
# config.use Flipper::Adapters::NamingStyle, :snake # or :camel, :kebab, :screaming_snake, or a Regexp | ||
# end | ||
# | ||
class NamingStyle < Wrapper | ||
InvalidFormat = Class.new(Flipper::Error) | ||
|
||
PRESETS = { | ||
camel: /^([A-Z][a-z0-9]*)+$/, # CamelCase | ||
snake: /^[a-z0-9]+(_[a-z0-9]+)*$/, # snake_case | ||
kebab: /^[a-z0-9]+(-[a-z0-9]+)*$/, # kebab-case | ||
screaming_snake: /^[A-Z0-9]+(_[A-Z0-9]+)*$/, # SCREAMING_SNAKE_CASE | ||
} | ||
|
||
attr_reader :format | ||
|
||
def initialize(adapter, format = :snake) | ||
@format = format.is_a?(Regexp) ? format : PRESETS.fetch(format) { | ||
raise ArgumentError, "Unknown format: #{format.inspect}. Must be a Regexp or one of #{PRESETS.keys.join(', ')}" | ||
} | ||
|
||
super(adapter) | ||
end | ||
|
||
def add(feature) | ||
unless valid?(feature.key) | ||
raise InvalidFormat, "Feature key #{feature.key.inspect} does not match format #{format.inspect}" | ||
end | ||
|
||
super feature | ||
end | ||
|
||
def valid?(name) | ||
format.match?(name) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
require "flipper/adapters/naming_style" | ||
|
||
RSpec.describe Flipper::Adapters::NamingStyle do | ||
it_should_behave_like "a flipper adapter" do | ||
let(:format) { /.*/ } | ||
let(:memory) { Flipper::Adapters::Memory.new } | ||
let(:adapter) { described_class.new(memory, format) } | ||
|
||
subject { adapter } | ||
|
||
describe "#initialize" do | ||
it "accepts a regex" do | ||
expect { described_class.new(memory, format) }.not_to raise_error | ||
end | ||
|
||
it "accepts a symbol" do | ||
[:camel, :snake, :kebab, :screaming_snake].each do |format| | ||
expect { described_class.new(memory, format) }.not_to raise_error | ||
end | ||
end | ||
|
||
it "raises an error if the format is an unknown symbol" do | ||
expect { described_class.new(memory, :Pascal) }.to raise_error(ArgumentError) | ||
end | ||
end | ||
|
||
describe "#add" do | ||
{ | ||
/\A(breaker|feature)\// => { | ||
valid: %w[breaker/search feature/search], | ||
invalid: %w[search breaker_search breaker], | ||
}, | ||
camel: { | ||
valid: %w[Camel CamelCase SCREAMINGCamelCase CamelCase1 Camel1Case], | ||
invalid: %w[snake_case Camel-Kebab lowercase], | ||
}, | ||
snake: { | ||
valid: %w[lower snake_case snake_case_1], | ||
invalid: %w[CamelCase cobraCase double__underscore], | ||
}, | ||
kebab: { | ||
valid: %w[kebab kebab-case kebab-case-1 htt-party], | ||
invalid: %w[CamelCase CamelCase1 double__dash], | ||
}, | ||
screaming_snake: { | ||
valid: %w[SCREAMING SCREAMING_SNAKE SCREAMING_SNAKE_1 HTTP_THING], | ||
invalid: %w[CamelCase CamelCase1 double__underscore], | ||
} | ||
}.each do |format, examples| | ||
context "with format=#{format.inspect}" do | ||
let(:format) { format } | ||
|
||
examples[:valid].each do |feature| | ||
it "adds feature named #{feature}" do | ||
expect(subject.add(flipper[feature])).to eq(true) | ||
expect(subject.features).to eq(Set[feature]) | ||
end | ||
end | ||
|
||
examples[:invalid].each do |feature| | ||
it "raises an error for feature named #{feature}" do | ||
expect { adapter.add(flipper[feature]) }.to raise_error(Flipper::Adapters::NamingStyle::InvalidFormat) | ||
expect(subject.features).to eq(Set[]) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |