diff --git a/lib/literal/array.rb b/lib/literal/array.rb index feb1038..3720238 100644 --- a/lib/literal/array.rb +++ b/lib/literal/array.rb @@ -327,6 +327,23 @@ def minmax(...) __with__(@__value__.minmax(...)) end + def narrow(type) + return self if __type__ == type + + unless Literal.subtype?(type, of: @__type__) + raise ArgumentError.new("Cannot narrow #{@__type__} to #{type}") + end + + @__value__.each do |item| + Literal.check(actual: item, expected: type) do |c| + c.fill_receiver(receiver: self, method: "#narrow") + end + end + + @__type__ = type + self + end + def one?(...) @__value__.one?(...) end diff --git a/test/array.test.rb b/test/array.test.rb index 2ac42b1..34a29f4 100644 --- a/test/array.test.rb +++ b/test/array.test.rb @@ -442,3 +442,33 @@ expect(Literal::Array(Integer).new(1, 2, 3).sum) == 6 expect(Literal::Array(String).new("1", "2", "3").sum(&:to_i)) == 6 end + +test "#narrow" do + array = Literal::Array(Numeric).new(1, 2, 3) + + refute Literal::Array(Integer) === array + array.narrow(Integer) + assert Literal::Array(Integer) === array +end + +test "#narrow with same type" do + array = Literal::Array(Numeric).new(1, 2, 3) + + assert Literal::Array(Numeric) === array +end + +test "#narrow with wrong value" do + array = Literal::Array(Numeric).new(1, 2, 3.456) + + expect { + array.narrow(Integer) + }.to_raise(Literal::TypeError) +end + +test "#narrow with wrong type" do + array = Literal::Array(Integer).new(1, 2, 3) + + expect { + array.narrow(Numeric) + }.to_raise(ArgumentError) +end