diff --git a/lib/async/variable.rb b/lib/async/variable.rb index 9dffc55..f9efa96 100644 --- a/lib/async/variable.rb +++ b/lib/async/variable.rb @@ -30,24 +30,40 @@ def resolve(value = true) condition.signal(value) end + + def reject(error) + @error = error + condition = @condition + @condition = nil + + self.freeze + + condition.signal # signal without value + end # Alias for {#resolve}. def value=(value) self.resolve(value) end - + # Whether the value has been resolved. # # @returns [Boolean] Whether the value has been resolved. def resolved? - @condition.nil? + @condition.nil? && @error.nil? + end + + def rejected? + @condition.nil? && !!@error end # Wait for the value to be resolved. # # @returns [Object] The resolved value. + # @raises [Exception] The error with which this Variable was rejected def wait @condition&.wait + raise @error if @error return @value end diff --git a/test/async/variable.rb b/test/async/variable.rb index b8cdfd9..797a537 100644 --- a/test/async/variable.rb +++ b/test/async/variable.rb @@ -21,6 +21,14 @@ variable.resolve(value) end + + it "can wait for the value to be resolved using setter" do + Async do + expect(variable.wait).to be == value + end + + variable.value = value + end it "can't resolve it a 2nd time" do variable.resolve(value) @@ -28,6 +36,22 @@ variable.resolve(value) end.to raise_exception(FrozenError) end + + it "can reject with an exception" do + variable.reject RuntimeError.new('boom') + expect(variable).not.to be(:resolved?) + expect(variable).to be(:rejected?) + end + + it "can wait for a rejection with an error" do + Async do + expect do + variable.wait + end.to raise_exception(RuntimeError) + end + + variable.reject(RuntimeError.new) + end end include Sus::Fixtures::Async::ReactorContext