How to use cbreak mode in Ruby terminal application? - ruby

In a small Ruby application, I'd like user input to be accepted without having to wait for a carriage return. My understanding is that cbreak mode needs to be enabled in order for the terminal to feed user input directly into the script.
I tried simply running x%[cbreak()] at the top of my script but that didn't work. I've also seen that it's possible to use (n)curses to achieve the same results, although that seems like overkill.
Does anybody have a suggestion on how to implement this?
Thanks

cbreak is a curses function call, so %x definitely doesn't apply (that is for executing shell commands). cbreak is defined in the standard curses library, so that would probably be your best bet.
See:
http://ruby-doc.org/stdlib/libdoc/curses/rdoc/classes/Curses.html#M000280
Edit: you might also check out Curses.getch

One solution which avoids having to use curses (which I find difficult to implement) is to use the shell's read command via %x. It doesn't feel right dipping into the shell to do something that seems like Ruby's STDIN should be responsible for, but it's simple and it works.
#! /usr/bin/ruby
puts "Please enter your first initial"
str = %x[read -s -n1 keypress; echo $keypress]
puts "Your first inital is " + str

Related

How to run Ruby file on Sublime Text

I have a file named add_and_power.rb as below, and want to run it on Sublime Text.
def add_and_power a,b
(a+b)**(a+b)
end
puts "First number please? "
input1 = gets
puts "Second number please? "
input2 = gets
puts "The result is: ", add_and_power(input1.to_i, input2.to_i)
I run cmd+b, but it just displays,
First number please?
Second number please?
The result is:
1
[Finished in 0.9s]
I want to input 2 and 3 to get the answer. How can I make Sublime Text 2 ask for inputs and give back an answer?
If you want to run code within ST2, check out the SublimeREPL plugin, available through Package Control. You can either use IRB or pry, which is a lot more powerful. You can use it as a classic REPL (think Clojure or LISP), and you can also transfer your code from one tab into the running REPL in another tab by selection, line range, or block.
In some of my tests the pry REPL doesn't handle input through gets very well, but I haven't played around with it that much. YMMV - Edit - As AGS mentions below, use my_var = $stdin.gets for interactive input within SublimeREPL Ruby.
I highly highly recommend SublimeREPL, as it's a really powerful tool, and is self-contained within ST2, so you don't have to keep flipping back and forth to your terminal, saving and reloading your programs.
It is possible to run your programs when you need to have user input from the keyboard, but it isn't very nice.
When I do so, I need to input from a terminal that opens when I run Sublime, while also reading the response from the program at the bottom of the editor.
It is simply easier to run the program from the console/terminal.
So, the answer is, while it is possible to do so, there are concerns. You may need to use STDOUT.sync = true or STDOUT.flush to help manage the buffer with the OS, you have two thing to look at, while doing so... yuck.
It may not be the answer you are looking for, but as a developer, you should be comfortable running things from the console/terminal.

Passing shell commands parameters securely with %x[] in Ruby

Let's say I have in a Rails controller:
dir = params[:dir]
output = %x[ls #{dir}]
This is a HUGE security hole if somebody posts dir="foo; rm -rf /"
So I need to secure the parameter. I know I could do
system "ls", dir
But this method does not capture stdout !
So, how can I securely pass parameters to %x[] ?
The problem is that %x() basically hands a string to the shell to be parsed so you'd have to escape everything that the shell could possibly interpret. So %x is pretty much out the window if you need to deal with anything that you haven't built yourself (and event then it is suspect).
One solution is to use Open3.capture3:
out, err, status = Open3.capture3('/bin/ls', dir)
and then deal with the standard output (out) and standard error (err) returns as needed. There are a few other things in Open3 that might serve your needs better.
Have you looked at Ruby's safe levels?
http://www.ruby-doc.org/docs/ProgrammingRuby/html/taint.html
For levels >= 2 it says "Can't change, make, or remove directories, or use chroot."
There also used to be a sandbox gem, but I'm not sure if that's still active. You also could have a look at the source of "Try Ruby!" there has to be some kind of sandboxing in there.

Program running not in order

I tried running this simple code:
puts 4
i = gets
puts i
It's "working", but the console asks for a string and just then it prints 4 and i
Add a flush call before gets:
$stdout.flush
Instead of explicitly calling $stdout.flush:
$stdout.sync = true
Works in order for me using ruby 1.8.7, 1.9.2 and ree. What version of ruby and operating system are you on?
What are you hoping to accomplish here ?
Normally the interpreter gathers all data before presenting you with the output. It's simply isnt bash :)
I guess you may be hit by output buffering. But your code example does not show how the program might "ask" for input, so I guess that you type answer just before ruby starts. Then your ruby program reads the input from input buffers, as the data is not read directly from the keyboard.
Are you sure that your problem is caused by exactly this code you have shown us?
Usually problems with data shown on terminal in wrong order are caused by using two different output streams: STDIN and STDERR for example. Each stream may decide to flush its data at different times.
if you want to make sure the text is displayed before something happens (as in this example) use the 'flush' command, as Yossi suggests.

How would one implement bash-like tab completion?

I'm trying to determine how the system prints characters to standard input -- that is, how it prints characters which the user can delete and which are considered input if the user hits "Enter."
I happen to be using C, but I would be very surprised if the solution were language-dependent.
Thanks for any insights! : D
As iny says, bash uses readline for its input. The source is available here, and there's a file called complete.c.
To answer your question, I don't think they're actually printed to standard input. Readline contains some kind of buffer for the contents of the line the user is editing, and completion prints into this. When the user presses enter, the contents of the buffer are sent to whatever program wanted to read a line, and in the case of bash, passed along into standard input. (Readline doesn't do this - other programs which use readline might simply store the value into a string for later use.)
Several people have pointed out that bash uses readline, which is true, but I think what you're really asking is how is it able to see what you've typed before you hit enter.
The answer is that ttys (ie: terminals) can be switched into "raw mode", where input processing of the terminal is disabled, and then you'll see every character as it comes in. This also disables automatic echoing of typed characters.
See this guide on Reading a single character from a file or a terminal for more info.
It uses readline library to handle the input and readline provides the history and the completion.
To actually implement completion, access to the keyboard input handling is needed. The completion must be able to modify the buffer used by it. After that it is just about looking at the current input and checking what completions is found. The actual completion logic can work in many ways.
Here's a C snippet that implements tab completion via readline:
http://github.com/rupa/el

Capturing keycodes in shell?

I am writing my own shell and need to implement a history feature where up and down arrow keys show history of commands executed. I need to find out when up and down keys are pressed.
How do i do this?
you want to be capturing input in raw mode. this can get kinda complicated, but here's an example that should get you on the right path:
http://docs.linux.cz/programming/c/unix_examples/raw.html
i'm assuming you're writing your shell in c. if you're using a more high-level language, there might be an easy way to get raw input. in python, for instance, i would use the ncurses module.

Resources