From dfc3dcd4cc815aa880f921eaef238e67d4c1fc04 Mon Sep 17 00:00:00 2001 From: masahito1997 Date: Tue, 2 Feb 2021 17:14:56 +0900 Subject: [PATCH] Add signature of Timeout --- stdlib/timeout/0/timeout.rbs | 94 ++++++++++++++++++++++++++++++++++++ test/stdlib/Timeout_test.rb | 41 ++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 stdlib/timeout/0/timeout.rbs create mode 100644 test/stdlib/Timeout_test.rb diff --git a/stdlib/timeout/0/timeout.rbs b/stdlib/timeout/0/timeout.rbs new file mode 100644 index 000000000..fdaef1169 --- /dev/null +++ b/stdlib/timeout/0/timeout.rbs @@ -0,0 +1,94 @@ +# Timeout long-running blocks +# +# ## Synopsis +# +# require 'timeout' +# status = Timeout::timeout(5) { +# # Something that should be interrupted if it takes more than 5 seconds... +# } +# +# ## Description +# +# Timeout provides a way to auto-terminate a potentially long-running operation +# if it hasn't finished in a fixed amount of time. +# +# Previous versions didn't use a module for namespacing, however #timeout is +# provided for backwards compatibility. You should prefer Timeout.timeout +# instead. +# +# ## Copyright +# +# Copyright +# : (C) 2000 Network Applied Communication Laboratory, Inc. +# Copyright +# : (C) 2000 Information-technology Promotion Agency, Japan +# +module Timeout + # Perform an operation in a block, raising an error if it takes longer than + # `sec` seconds to complete. + # + # `sec` + # : Number of seconds to wait for the block to terminate. Any number may be + # used, including Floats to specify fractional seconds. A value of 0 or + # `nil` will execute the block without any timeout. + # `klass` + # : Exception Class to raise if the block fails to terminate in `sec` seconds. + # Omitting will use the default, Timeout::Error + # `message` + # : Error message to raise with Exception Class. Omitting will use the + # default, "execution expired" + # + # + # Returns the result of the block **if** the block completed before `sec` + # seconds, otherwise throws an exception, based on the value of `klass`. + # + # The exception thrown to terminate the given block cannot be rescued inside the + # block unless `klass` is given explicitly. However, the block can use ensure to + # prevent the handling of the exception. For that reason, this method cannot be + # relied on to enforce timeouts for untrusted blocks. + # + # Note that this is both a method of module Timeout, so you can `include + # Timeout` into your classes so they have a #timeout method, as well as a module + # method, so you can call it directly as Timeout.timeout(). + # + # # arglists 💪👽🚨 << Delete this section + # timeout(sec, klass = nil, message = nil) { |sec| ... } + # + def self.timeout: (Numeric? sec, ?singleton(Exception) klass, ?String message) { (Numeric sec) -> untyped } -> untyped + + private + + # Perform an operation in a block, raising an error if it takes longer than + # `sec` seconds to complete. + # + # `sec` + # : Number of seconds to wait for the block to terminate. Any number may be + # used, including Floats to specify fractional seconds. A value of 0 or + # `nil` will execute the block without any timeout. + # `klass` + # : Exception Class to raise if the block fails to terminate in `sec` seconds. + # Omitting will use the default, Timeout::Error + # `message` + # : Error message to raise with Exception Class. Omitting will use the + # default, "execution expired" + # + # + # Returns the result of the block **if** the block completed before `sec` + # seconds, otherwise throws an exception, based on the value of `klass`. + # + # The exception thrown to terminate the given block cannot be rescued inside the + # block unless `klass` is given explicitly. However, the block can use ensure to + # prevent the handling of the exception. For that reason, this method cannot be + # relied on to enforce timeouts for untrusted blocks. + # + # Note that this is both a method of module Timeout, so you can `include + # Timeout` into your classes so they have a #timeout method, as well as a module + # method, so you can call it directly as Timeout.timeout(). + # + # # arglists 💪👽🚨 << Delete this section + # timeout(sec, klass = nil, message = nil) { |sec| ... } + # + def timeout: (Numeric? sec, ?singleton(Exception) klass, ?String message) { (Numeric sec) -> untyped } -> untyped +end + +Timeout::VERSION: String diff --git a/test/stdlib/Timeout_test.rb b/test/stdlib/Timeout_test.rb new file mode 100644 index 000000000..df2c0de9e --- /dev/null +++ b/test/stdlib/Timeout_test.rb @@ -0,0 +1,41 @@ +require_relative "test_helper" +require "timeout" +require "bigdecimal" + +class TimeoutSingletonTest < Test::Unit::TestCase + include TypeAssertions + + library "timeout" + testing "singleton(::Timeout)" + + class TimeoutTestException < Exception; end # exception class for test + + def test_timeout + proc = Proc.new { |sec| sec * sec } + assert_send_type "(::Integer sec) { (::Integer sec) -> untyped } -> untyped", + Timeout, :timeout, 5, &proc + assert_send_type "(::Float sec) { (::Float sec) -> untyped } -> untyped", + Timeout, :timeout, 1.2, &proc + assert_send_type "(::Rational sec) { (::Rational sec) -> untyped } -> untyped", + Timeout, :timeout, Rational(5, 3), &proc + assert_send_type "(::BigDecimal sec) { (::BigDecimal sec) -> untyped } -> untyped", + Timeout, :timeout, BigDecimal("1.123456789123456789"), &proc + + hard_process = Proc.new { _calc_pi } + refute_send_type "(::Numeric sec) { (::Numeric sec) -> untyped } -> untyped", + Timeout, :timeout, 0.001, &hard_process + refute_send_type "(::Numeric sec, singleton(Exception) klass) { (::Numeric sec) -> untyped } -> untyped", + Timeout, :timeout, 0.001, TimeoutTestException, &hard_process + refute_send_type "(::Numeric sec, singleton(Exception) klass, String message) { (::Numeric sec) -> untyped } -> untyped", + Timeout, :timeout, 0.001, TimeoutTestException, "timeout test error", &hard_process + end + + def _calc_pi + min = [0, 0] + loop do + x = rand + y = rand + x**2 + y**2 < 1.0 ? min[0] += 1 : min[1] += 1 + end + end +end