Print message if user does nothing for x seconds?

Hi all,

Only just started using ruby so this may be really simple to do, but here goes:

I'm trying to write a program that asks a user to enter their sex using "gets" but if the user doesn't type anything for about 5 seconds I want to print a message, like "Please enter something..." then go back to the gets prompt. I've tried using the "sleep x" method but it doesn't seem to work because once gets has been initiated it gets stuck there until something is entered.

Oh I don't have to use gets, but this is the only method of input I'm aware of at the moment

Hope this makes sense,
Ben

Ben Thomas wrote:

Hi all,

Only just started using ruby so this may be really simple to do, but here goes:

I'm trying to write a program that asks a user to enter their sex using "gets" but if the user doesn't type anything for about 5 seconds I want to print a message, like "Please enter something..." then go back to the gets prompt. I've tried using the "sleep x" method but it doesn't seem to work because once gets has been initiated it gets stuck there until something is entered.

Oh I don't have to use gets, but this is the only method of input I'm aware of at the moment

This is tricky on Windows... what platform are you on?

Hal

if you're on windows give up now. otherwise try this:

     harp:~ > cat a.rb
     require 'timeout'

     def prompt question, opts = {}
       timeout = Integer(opts['timeout'] || opts[:timeout] || 42)
       max = Integer(opts['max'] || opts[:max] || 42)
       default = opts['default'] || opts[:default]
       prod = (opts['prod'] || opts[:prod] || 'hey! wake up!').to_s

       answer = default
       prompt = "\r#{ question }: "
       prod = "\r#{ prod }"

       if prompt.size > prod.size
         prod += (' ' * (prompt.size - prod.size))
       end
       if prod.size > prompt.size
         prompt += (' ' * (prod.size - prompt.size))
       end

       max.times{
         begin
           print prompt
           STDOUT.flush
           Timeout::timeout(timeout){ answer = gets }
           break
         rescue Timeout::Error
           print prod
           STDOUT.flush
           sleep 2
         end
       }

       answer
     end

     answer = prompt 'the question', 'timeout' => 5, 'max' => 2

     p 'answer' => answer

-a

···

On Sun, 12 Nov 2006, Ben Thomas wrote:

Hi all,

Only just started using ruby so this may be really simple to do, but here goes:

I'm trying to write a program that asks a user to enter their sex using "gets" but if the user doesn't type anything for about 5 seconds I want to print a message, like "Please enter something..." then go back to the gets prompt. I've tried using the "sleep x" method but it doesn't seem to work because once gets has been initiated it gets stuck there until something is entered.

Oh I don't have to use gets, but this is the only method of input I'm aware of at the moment

Hope this makes sense,
Ben

--
my religion is very simple. my religion is kindness. -- the dalai lama

Ben Thomas wrote:

Hi all,

Only just started using ruby so this may be really simple to do, but
here goes:

I'm trying to write a program that asks a user to enter their sex using
"gets" but if the user doesn't type anything for about 5 seconds I want
to print a message, like "Please enter something..." then go back to the
gets prompt. I've tried using the "sleep x" method but it doesn't seem
to work because once gets has been initiated it gets stuck there until
something is entered.

Oh I don't have to use gets, but this is the only method of input I'm
aware of at the moment

Hope this makes sense,
Ben

Read the data in a thread, or use nonblocking io (currently crude at
best, with only eventmachine to help as a project that shown up on my
radar - and that seems to be oriented towards networking)

Also, what you describe there is a very rude thing to do to your user,
basically you're accusing them of having no attention span and the
program is attention-seeking to compensate.

David Vallner

Hal Fulton wrote:

Ben Thomas wrote:

Hi all,

Only just started using ruby so this may be really simple to do, but here goes:

I'm trying to write a program that asks a user to enter their sex using "gets" but if the user doesn't type anything for about 5 seconds I want to print a message, like "Please enter something..." then go back to the gets prompt. I've tried using the "sleep x" method but it doesn't seem to work because once gets has been initiated it gets stuck there until something is entered.

Oh I don't have to use gets, but this is the only method of input I'm aware of at the moment

This is tricky on Windows... what platform are you on?

Hal

Windows... D'oh!

Is there any better ways to get input from the user that'd make is easier?

David Vallner wrote:

Ben Thomas wrote:

Hi all,

Only just started using ruby so this may be really simple to do, but
here goes:

I'm trying to write a program that asks a user to enter their sex using
"gets" but if the user doesn't type anything for about 5 seconds I want
to print a message, like "Please enter something..." then go back to the
gets prompt. I've tried using the "sleep x" method but it doesn't seem
to work because once gets has been initiated it gets stuck there until
something is entered.

Oh I don't have to use gets, but this is the only method of input I'm
aware of at the moment

Hope this makes sense,
Ben

Read the data in a thread, or use nonblocking io (currently crude at
best, with only eventmachine to help as a project that shown up on my
radar - and that seems to be oriented towards networking)

Also, what you describe there is a very rude thing to do to your user,
basically you're accusing them of having no attention span and the
program is attention-seeking to compensate.

David Vallner

Yeah, I'd never even think of doing it normally, it was just put in a small program specification for uni. It's not an assignment or anything so I'll probably just leave that part out if it's hard to implement.

The part of the specification was:

  3. Keep the program running until the user shouts “BYE”. If, while the program is running, nothing is happening Grandma should shout “WHAT? CAT GOT YOUR TONGUE? SPEAK UP, I SAY!"

I'll just leave the "cat got your tongue" part out for now. Managed to keep the program running until the user shouts "BYE" easy enough, just the second part causing problems.

Thanks for the help.

Nice! May I suggest adding an optional validation block?
I hope you don't mind if I slightly modify your code:

def prompt question, opts = {}, &validation
   timeout = Integer(opts['timeout'] || opts[:timeout] || 42)
   max = Integer(opts['max'] || opts[:max] || 42)
   default = opts['default'] || opts[:default]
   prod = (opts['prod'] || opts[:prod] || 'hey! wake up!').to_s
   invalid = (opts['invalid'] || opts[:invalid] || 'try again').to_s

   answer = default
   prompt = "\r#{ question }: "
   prod = "\r#{ prod }"

   if prompt.size > prod.size
     prod += (' ' * (prompt.size - prod.size))
   end
   if prod.size > prompt.size
     prompt += (' ' * (prod.size - prompt.size))
   end

   max.times{
     begin
       print prompt
       STDOUT.flush
       Timeout::timeout(timeout){ answer = gets }
       if validation && !validation.call(answer)
         answer = default
         puts invalid
       else
         break
       end
     rescue Timeout::Error
       print prod
       STDOUT.flush
       sleep 2
     end
   }

   answer
end

answer = prompt('the question', 'timeout' => 5, 'max' => 2) { |s| s == "valid input\n" }

···

On 11/nov/06, at 21:07, ara.t.howard@noaa.gov wrote:

if you're on windows give up now. otherwise try this:

    harp:~ > cat a.rb
    require 'timeout'

    def prompt question, opts = {}
      timeout = Integer(opts['timeout'] || opts[:timeout] || 42)
      max = Integer(opts['max'] || opts[:max] || 42)
      default = opts['default'] || opts[:default]
      prod = (opts['prod'] || opts[:prod] || 'hey! wake up!').to_s

      answer = default
      prompt = "\r#{ question }: "
      prod = "\r#{ prod }"

      if prompt.size > prod.size
        prod += (' ' * (prompt.size - prod.size))
      end
      if prod.size > prompt.size
        prompt += (' ' * (prod.size - prompt.size))
      end

      max.times{
        begin
          print prompt
          STDOUT.flush
          Timeout::timeout(timeout){ answer = gets }
          break
        rescue Timeout::Error
          print prod
          STDOUT.flush
          sleep 2
        end
      }

      answer
    end

    answer = prompt 'the question', 'timeout' => 5, 'max' => 2

    p 'answer' => answer

--
Gabriele Marrone

Thanks for the reply. Unfortunately I am on windows.

···

ara.t.howard@noaa.gov wrote:

On Sun, 12 Nov 2006, Ben Thomas wrote:

Hi all,

Only just started using ruby so this may be really simple to do, but here goes:

I'm trying to write a program that asks a user to enter their sex using "gets" but if the user doesn't type anything for about 5 seconds I want to print a message, like "Please enter something..." then go back to the gets prompt. I've tried using the "sleep x" method but it doesn't seem to work because once gets has been initiated it gets stuck there until something is entered.

Oh I don't have to use gets, but this is the only method of input I'm aware of at the moment

Hope this makes sense,
Ben

if you're on windows give up now. otherwise try this:

    harp:~ > cat a.rb
    require 'timeout'

    def prompt question, opts = {}
      timeout = Integer(opts['timeout'] || opts[:timeout] || 42)
      max = Integer(opts['max'] || opts[:max] || 42)
      default = opts['default'] || opts[:default]
      prod = (opts['prod'] || opts[:prod] || 'hey! wake up!').to_s

      answer = default
      prompt = "\r#{ question }: "
      prod = "\r#{ prod }"

      if prompt.size > prod.size
        prod += (' ' * (prompt.size - prod.size))
      end
      if prod.size > prompt.size
        prompt += (' ' * (prod.size - prompt.size))
      end

      max.times{
        begin
          print prompt
          STDOUT.flush
          Timeout::timeout(timeout){ answer = gets }
          break
        rescue Timeout::Error
          print prod
          STDOUT.flush
          sleep 2
        end
      }

      answer
    end

    answer = prompt 'the question', 'timeout' => 5, 'max' => 2

    p 'answer' => answer

-a

Ben Thomas wrote:

Thanks for the reply. Unfortunately I am on windows.

Actually I think this should partially work on Windows.

As I recall, I found that as long as the user typed
*nothing*, timeout was possible. But if the user
typed a character or more and just didn't finish, it
wouldn't time out.

Hal