-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from nevinera/nev-5--implement-integer-ranges
Implement `ENV.integer_range`
- Loading branch information
Showing
5 changed files
with
167 additions
and
1 deletion.
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
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
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 EnvironmentHelpers | ||
module RangeHelpers | ||
def integer_range(name, default: nil, required: false) | ||
check_default_type(:integer_range, default, Range) | ||
check_range_endpoint(:integer_range, default.begin) if default | ||
check_range_endpoint(:integer_range, default.end) if default | ||
|
||
text = fetch_value(name, required: required) | ||
range = parse_range_from(text) | ||
return range if range | ||
return default unless required | ||
fail(InvalidRangeText, "Required Integer Range environment variable #{name} had inappropriate content '#{text}'") | ||
end | ||
|
||
private | ||
|
||
def check_range_endpoint(context, value) | ||
return if value.is_a?(Integer) | ||
fail(BadDefault, "Invalid endpoint for default range of #{context} - must be Integer") | ||
end | ||
|
||
def parse_range_bound_from(text) | ||
return nil if text.nil? | ||
return nil if text.empty? | ||
text.to_i | ||
end | ||
|
||
def parse_range_from(text) | ||
text =~ /\A(\d*)(-|\.\.|\.\.\.)(\d*)\z/ | ||
lower_bound = parse_range_bound_from($1) | ||
separator = $2 | ||
upper_bound = parse_range_bound_from($3) | ||
|
||
return nil if lower_bound.nil? || upper_bound.nil? | ||
if separator == "..." | ||
(lower_bound...upper_bound) | ||
else | ||
(lower_bound..upper_bound) | ||
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 |
---|---|---|
@@ -1,3 +1,3 @@ | ||
module EnvironmentHelpers | ||
VERSION = "1.0.1" | ||
VERSION = "1.1.0" | ||
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,118 @@ | ||
RSpec.describe EnvironmentHelpers::RangeHelpers do | ||
subject(:env) { ENV } | ||
|
||
describe "#integer_range" do | ||
let(:name) { "FOO" } | ||
let(:options) { {} } | ||
subject(:integer_range) { ENV.integer_range(name, **options) } | ||
|
||
context "when required: true" do | ||
let(:options) { {required: true} } | ||
|
||
context "and the key is supplied" do | ||
with_env("FOO" => "52-63") | ||
it { is_expected.to eq((52..63)) } | ||
|
||
context "but has invalid content" do | ||
with_env("FOO" => "hello") | ||
|
||
it "raises a MissingVariableError" do | ||
expect { integer_range }.to raise_error( | ||
EnvironmentHelpers::InvalidRangeText, | ||
/inappropriate content/ | ||
) | ||
end | ||
end | ||
end | ||
|
||
context "and the environment variable is not supplied" do | ||
before { expect(ENV["FOO"]).to be_nil } | ||
|
||
it "raises a MissingVariableError" do | ||
expect { integer_range }.to raise_error( | ||
EnvironmentHelpers::MissingVariableError, | ||
/not supplied/ | ||
) | ||
end | ||
end | ||
end | ||
|
||
context "without a default specified" do | ||
let(:options) { {} } | ||
|
||
context "when the environment variable is present" do | ||
with_env("FOO" => "58..61") | ||
it { is_expected.to eq((58..61)) } | ||
end | ||
|
||
context "when the environment variable is not present" do | ||
before { expect(ENV["FOO"]).to be_nil } | ||
it { is_expected.to be_nil } | ||
end | ||
end | ||
|
||
context "with a default specified" do | ||
let(:options) { {default: (91..93)} } | ||
|
||
context "but of the wrong type" do | ||
let(:options) { {default: "91"} } | ||
|
||
it "raises a BadDefault error" do | ||
expect { integer_range }.to raise_error( | ||
EnvironmentHelpers::BadDefault, | ||
/inappropriate default/i | ||
) | ||
end | ||
end | ||
|
||
context "with the wrong type of endpoint" do | ||
let(:options) { {default: ("a".."c")} } | ||
|
||
it "raises a BadDefault error" do | ||
expect { integer_range }.to raise_error( | ||
EnvironmentHelpers::BadDefault, | ||
/invalid endpoint for default range/i | ||
) | ||
end | ||
end | ||
|
||
context "when the environment variable is present" do | ||
with_env("FOO" => "58..62") | ||
it { is_expected.to eq((58..62)) } | ||
|
||
context "but not actually an integer" do | ||
with_env("FOO" => "hello") | ||
it { is_expected.to eq((91..93)) } | ||
end | ||
end | ||
|
||
context "when the environment variable is not present" do | ||
before { expect(ENV["FOO"]).to be_nil } | ||
it { is_expected.to eq((91..93)) } | ||
end | ||
end | ||
|
||
context "for various formats" do | ||
context "with a dash" do | ||
with_env("FOO" => "3-5") | ||
it { is_expected.to eq((3..5)) } | ||
end | ||
|
||
context "with two dots" do | ||
with_env("FOO" => "3..5") | ||
it { is_expected.to eq((3..5)) } | ||
end | ||
|
||
context "with three dots" do | ||
with_env("FOO" => "3...5") | ||
it { is_expected.to eq((3...5)) } | ||
it { is_expected.not_to be_cover(5) } | ||
end | ||
|
||
context "with missing bound" do | ||
with_env("FOO" => "3..") | ||
it { is_expected.to be_nil } | ||
end | ||
end | ||
end | ||
end |