lib/much-timeout.rb in much-timeout-0.0.1 vs lib/much-timeout.rb in much-timeout-0.1.0
- old
+ new
@@ -1,4 +1,88 @@
+require 'thread'
require "much-timeout/version"
module MuchTimeout
+
+ TimeoutError = Class.new(Interrupt)
+
+ PIPE_SIGNAL = '.'
+
+ def self.timeout(seconds, klass = nil, &block)
+ if seconds.nil?
+ raise ArgumentError, 'please specify a non-nil seconds value'
+ end
+ if !seconds.kind_of?(::Numeric)
+ raise ArgumentError, "please specify a numeric seconds value " \
+ "(`#{seconds.inspect}` was given)"
+ end
+ exception_klass = klass || TimeoutError
+ reader, writer = IO.pipe
+
+ begin
+ block_thread ||= Thread.new do
+ begin
+ block.call
+ ensure
+ writer.write_nonblock(PIPE_SIGNAL) rescue false
+ end
+ end
+ if !!::IO.select([reader], nil, nil, seconds)
+ block_thread.join
+ else
+ block_thread.raise exception_klass
+ block_thread.join
+ end
+ block_thread.value
+ ensure
+ reader.close rescue false
+ writer.close rescue false
+ end
+ end
+
+ def self.optional_timeout(seconds, klass = nil, &block)
+ if !seconds.nil?
+ self.timeout(seconds, klass, &block)
+ else
+ block.call
+ end
+ end
+
+ def self.just_timeout(seconds, args)
+ args ||= {}
+ if args[:do].nil?
+ raise ArgumentError, 'you need to specify a :do block arg to call'
+ end
+ if !args[:do].kind_of?(::Proc)
+ raise ArgumentError, "you need pass a Proc as the :do arg " \
+ "(`#{args[:do].inspect}` was given)"
+ end
+ if !args[:on_timeout].nil? && !args[:on_timeout].kind_of?(::Proc)
+ raise ArgumentError, "you need pass a Proc as the :on_timeout arg " \
+ "(`#{args[:on_timeout].inspect}` was given)"
+ end
+
+ begin
+ self.timeout(seconds, &args[:do])
+ rescue TimeoutError
+ (args[:on_timeout] || proc{ }).call
+ end
+ end
+
+ def self.just_optional_timeout(seconds, args)
+ args ||= {}
+ if args[:do].nil?
+ raise ArgumentError, 'you need to specify a :do block arg to call'
+ end
+ if !args[:do].kind_of?(::Proc)
+ raise ArgumentError, "you need pass a Proc as the :do arg " \
+ "(`#{args[:do].inspect}` was given)"
+ end
+
+ if !seconds.nil?
+ self.just_timeout(seconds, args)
+ else
+ args[:do].call
+ end
+ end
+
end