4
0.upto(9) do
    STDOUT.print "Flash!"
    sleep 0.5
    STDOUT.print "\b\b\b\b\b\b" # (6 backspaces, the length of "Flash!")
    sleep 0.5
end

This code doesn't work. It prints Flash! to the screen, but it doesn't flash. It just stays there, as though the backspaces aren't taking effect. But I do this:

0.upto(9) do
    STDOUT.print "Flash!"
    sleep 0.5
    STDOUT.print "\b\b\b\b\b" # (5 backspaces, the length of "Flash! - 1")
    sleep 0.5
end

and it almost works. It prints this: FFFFFFFFFFlash!(after 9 loops) Why do the backspaces stop taking effect when their number is equal to the length of the string they're deleting?

How can I overcome this problem and create a flashing message, only using libraries that are part of rails?

I tried a workaround like this:

0.upto(9) do
    STDOUT.print " Flash!"
    sleep 0.5
    STDOUT.print "\b\b\b\b\b\b"
    sleep 0.5

end

(Note the space in " Flash!"), but what happens is the message appears to crawl across the screen! An interesting effect, but not what I want.

I'm using Command Prompt with Ruby and Rails in Windows 7

Starkers
  • 10,273
  • 21
  • 95
  • 158
  • 1
    Interesting code.. I am keep running it.. and enjoying the output :) – Arup Rakshit Oct 10 '13 at 17:41
  • 6
    You probably want to use a library for doing this, like [curses](http://ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/), or at the very least the [ANSI library](https://github.com/rubyworks/ansi). Also be sure `STDOUT.sync = true` is set. It's not necessary to specify `STDOUT.print` as `print` would do exactly that by default. – tadman Oct 10 '13 at 17:42
  • Sorry if this is a beginner question, but can I require curses without installing a gem? Is it part of ruby by default? – Starkers Oct 10 '13 at 17:54
  • It isn't necessary to use `STDOUT.print`. By default `print` and `puts` both output to STDOUT. – the Tin Man Oct 10 '13 at 18:03
  • 1
    Before printing fancy stuff, make sure that [`$stdout.isatty`](http://ruby-doc.org/core-2.0.0/IO.html#method-i-isatty) :) – Stefan Oct 10 '13 at 18:37

4 Answers4

5

Typically this would be written something like:

0.upto(9) do
  STDOUT.print "\rFlash!"
  sleep 0.5
  STDOUT.print "\r      " # Send return and six spaces
  sleep 0.5
end

Back in the days when we'd talk to TTY and dot-matrix printers, we'd rapidly become used to the carriage-control characters, like "\r", "\n", "\t", etc. Today, people rarely do that to start, because they want to use the web, and browsers; Learning to talk to devices comes a lot later.

"\r" means return the carriage to its home position, which, on a type-writer moved the roller all the way to the right so we could start typing on the left margin again. Printers with moving heads reversed that and would move the print-head all the way to the left, but, in either case, printing started on the left-margin again. With the console/telnet/video-TTY, it moves the cursor to the left margin. It's all the same, just different technology.


A little more usable routine would be:

msg = 'Flash!'

10.times do
  print "\r#{ msg }"
  sleep 0.5
  print "\r#{ ' ' * msg.size }" # Send return and however many spaces are needed.
  sleep 0.5
end

Change msg to what you want, and the code will automatically use the right number of spaces to overwrite the characters.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • Darn. Much cleaner than mine! – Starkers Oct 10 '13 at 18:08
  • It's not my first time doing it. :-) It's possible to do this more simply using a VT-52 (or newer) terminal emulator, such as most consoles, and the built-in [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code) "blink". See "[Colorized Ruby Output](http://stackoverflow.com/questions/1489183/colorized-ruby-output)" for additional information. – the Tin Man Oct 10 '13 at 18:17
2

Anyway, it looks like backspace (at least in windows) just positions the cursor back, you need/want to overwrite the character with a space at that point (or 6 of them) to "blank" the text out.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
2

Or, you can just use this

def text_flasher(text)
    puts "\e[5m#{text}\e[0m"
end

use text_flasher in the console and you'll see the magic :)

Gaurav Manchanda
  • 544
  • 5
  • 22
1

Right, based on @rogerdpack 's input I have devised a solution:

def flashing_output(output)
    message = output
    backspace = "\b"
    space = " "

    backspace_array = []
    space_array = []  

    length = message.length

    length.times do
        backspace_array << backspace
        space_array << space
    end    

    0.upto(9) do
        print message
        sleep 0.5
        print backspace_array.join.to_s + space_array.join.to_s + backspace_array.join.to_s + backspace_array.join.to_s
        sleep 0.5
    end
end

flashing_output("Flashing Foobars! (not a euphemism)")
Starkers
  • 10,273
  • 21
  • 95
  • 158