Skip to content

Commit

Permalink
feat: add integer and float specific resolver methods (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
mschoenlaub authored Apr 22, 2024
1 parent a6c789d commit eea9d17
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 10 deletions.
2 changes: 1 addition & 1 deletion lib/open_feature/sdk/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module SDK
# TODO: Write documentation
#
class Client
RESULT_TYPE = %i[boolean string number object].freeze
RESULT_TYPE = %i[boolean string number integer float object].freeze
SUFFIXES = %i[value details].freeze

attr_reader :metadata, :evaluation_context
Expand Down
12 changes: 10 additions & 2 deletions lib/open_feature/sdk/provider/in_memory_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,15 @@ def fetch_string_value(flag_key:, default_value:, evaluation_context: nil)
end

def fetch_number_value(flag_key:, default_value:, evaluation_context: nil)
fetch_value(allowed_classes: [Integer, Float], flag_key:, default_value:, evaluation_context:)
fetch_value(allowed_classes: [Numeric], flag_key:, default_value:, evaluation_context:)
end

def fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)
fetch_value(allowed_classes: [Integer], flag_key:, default_value:, evaluation_context:)
end

def fetch_float_value(flag_key:, default_value:, evaluation_context: nil)
fetch_value(allowed_classes: [Float], flag_key:, default_value:, evaluation_context:)
end

def fetch_object_value(flag_key:, default_value:, evaluation_context: nil)
Expand All @@ -52,7 +60,7 @@ def fetch_value(allowed_classes:, flag_key:, default_value:, evaluation_context:
return ResolutionDetails.new(value: default_value, error_code: ErrorCode::FLAG_NOT_FOUND, reason: Reason::ERROR)
end

if allowed_classes.include?(value.class)
if allowed_classes.any? { |klass| value.is_a?(klass) }
ResolutionDetails.new(value:, reason: Reason::STATIC)
else
ResolutionDetails.new(value: default_value, error_code: ErrorCode::TYPE_MISMATCH, reason: Reason::ERROR)
Expand Down
8 changes: 8 additions & 0 deletions lib/open_feature/sdk/provider/no_op_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ def fetch_number_value(flag_key:, default_value:, evaluation_context: nil)
no_op(default_value)
end

def fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)
no_op(default_value)
end

def fetch_float_value(flag_key:, default_value:, evaluation_context: nil)
no_op(default_value)
end

def fetch_object_value(flag_key:, default_value:, evaluation_context: nil)
no_op(default_value)
end
Expand Down
14 changes: 11 additions & 3 deletions spec/open_feature/sdk/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,21 @@
expect(client).to respond_to(:fetch_number_value)
end

context "Condition 1.3.2 - The implementation language differentiates between floating-point numbers and integers." do
it do
expect(client.fetch_number_value(flag_key: flag_key, default_value: 4)).is_a?(Integer)
end

it do
expect(client.fetch_number_value(flag_key: flag_key, default_value: 95.5)).is_a?(Float)
end

context "Condition 1.3.3 - The implementation language differentiates between floating-point numbers and integers." do
it do
expect(client.fetch_number_value(flag_key: flag_key, default_value: 4)).is_a?(Integer)
expect(client.fetch_integer_value(flag_key: flag_key, default_value: 4)).is_a?(Integer)
end

it do
expect(client.fetch_number_value(flag_key: flag_key, default_value: 95.5)).is_a?(Float)
expect(client.fetch_float_value(flag_key: flag_key, default_value: 95.5)).is_a?(Float)
end
end
end
Expand Down
81 changes: 77 additions & 4 deletions spec/open_feature/sdk/provider/in_memory_provider_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
{
"bool" => true,
"str" => "testing",
"num" => 1,
"int" => 1,
"float" => 1.0,
"struct" => {"more" => "config"}
}
)
Expand Down Expand Up @@ -103,12 +104,18 @@
describe "#fetch_number_value" do
context "when flag is found" do
context "when type matches" do
it "returns value as static" do
fetched = provider.fetch_number_value(flag_key: "num", default_value: 0)
it "returns int as static" do
fetched = provider.fetch_number_value(flag_key: "int", default_value: 0)

expect(fetched.value).to eq(1)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::STATIC)
end
it "returns float as static" do
fetched = provider.fetch_number_value(flag_key: "float", default_value: 0.0)

expect(fetched.value).to eq(1.0)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::STATIC)
end
end

context "when type does not match" do
Expand All @@ -133,6 +140,72 @@
end
end

describe "#fetch_integer_value" do
context "when flag is found" do
context "when type matches" do
it "returns value as static" do
fetched = provider.fetch_integer_value(flag_key: "int", default_value: 0)

expect(fetched.value).to eq(1)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::STATIC)
end
end

context "when type does not match" do
it "returns default as type mismatch" do
fetched = provider.fetch_integer_value(flag_key: "float", default_value: 0)

expect(fetched.value).to eq(0)
expect(fetched.error_code).to eq(OpenFeature::SDK::Provider::ErrorCode::TYPE_MISMATCH)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::ERROR)
end
end
end

context "when flag is not found" do
it "returns default as flag not found" do
fetched = provider.fetch_number_value(flag_key: "not here", default_value: 0)

expect(fetched.value).to eq(0)
expect(fetched.error_code).to eq(OpenFeature::SDK::Provider::ErrorCode::FLAG_NOT_FOUND)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::ERROR)
end
end
end

describe "#fetch_integer_value" do
context "when flag is found" do
context "when type matches" do
it "returns value as static" do
fetched = provider.fetch_float_value(flag_key: "float", default_value: 0.0)

expect(fetched.value).to eq(1.0)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::STATIC)
end
end

context "when type does not match" do
it "returns default as type mismatch" do
fetched = provider.fetch_float_value(flag_key: "int", default_value: 0.0)

expect(fetched.value).to eq(0)
expect(fetched.error_code).to eq(OpenFeature::SDK::Provider::ErrorCode::TYPE_MISMATCH)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::ERROR)
end
end
end

context "when flag is not found" do
it "returns default as flag not found" do
fetched = provider.fetch_number_value(flag_key: "not here", default_value: 0)

expect(fetched.value).to eq(0)
expect(fetched.error_code).to eq(OpenFeature::SDK::Provider::ErrorCode::FLAG_NOT_FOUND)
expect(fetched.reason).to eq(OpenFeature::SDK::Provider::Reason::ERROR)
end
end
end

describe "#fetch_object_value" do
context "when flag is found" do
context "when type matches" do
Expand All @@ -146,7 +219,7 @@

context "when type does not match" do
it "returns default as type mismatch" do
fetched = provider.fetch_object_value(flag_key: "num", default_value: {})
fetched = provider.fetch_object_value(flag_key: "int", default_value: {})

expect(fetched.value).to eq({})
expect(fetched.error_code).to eq(OpenFeature::SDK::Provider::ErrorCode::TYPE_MISMATCH)
Expand Down

0 comments on commit eea9d17

Please sign in to comment.