Multiple choice quiz in Ruby via terminal - ruby

Is there any way to code in Ruby so that the terminal presents two options among which the user is required to select using the arrow keys and confirm using Enter?
Pseudo code:
p "What is the capital of Scotland?
user_select = gets.chomp
p "Edinburgh"
p "Glasgow"
if user_select == "Edinburgh" etc etc
I want to know if this can be achieved without the user having to type in their answer. Can the terminal behave like a GUI?

Alternatively, you could use TTY::Prompt. It will let you use the arrow keys.
Code sample
require 'tty-prompt'
prompt = TTY::Prompt.new
greeting = 'What is the capital of Scotland?'
choices = %w(Edinburgh Glasgow)
answer = prompt.select(greeting, choices)
'do something' if answer == choices[0]
Result
$ ruby quiz.rb
What is the capital of Scotland? (Use arrow keys, press Enter to select)
‣ Edinburgh
Glasgow

You could use something like Highline, though that will not let you use arrow keys:
→ ruby test.rb
1. Edinburgh
2. Glasgow
What is the capital of Scotland?
→ 1
Correct!
Code (just to get an idea):
require 'highline'
cli = HighLine.new
cli.choose do |menu|
menu.prompt = "What is the capital of Scotland?"
menu.choice("Edinburgh") { cli.say "Correct!" }
menu.choice("Glasgow") { cli.say "Wrong!" }
end
For more of a GUI, try using something like MRDialog.
Example:
require 'mrdialog'
dialog = MRDialog.new
dialog.clear = true
dialog.title = "Quiz"
question = "What is the capital of Scotland?"
answers = [['E', 'Edinburg'], ['G', 'Glasgow']]
height = 0
width = 0
menu_height = 2
selected_item = dialog.menu(question, answers, height, width, menu_height)
puts "Selected item: #{selected_item}"
Result:

Related

Text outputs as multiple separate lines instead of one paragraph with linebreaks

I have a bot that writes my message to a webpage. I want the message to be sent as one paragraph, but with the lines separated by a linebreak. However, when I actually run the code, the bot inputs and enters each line separately, instead of as one paragraph
I've tried messing with the linebreak formatting and string formatting, but the issue persists
reply_messages = []
reply_messages.push([
"FREE BABY AVOCUDDLE - Thank you for your patience!",
"To redeem your FREE avocuddle, just use the LINK IN OUR BIO and ADD TO CART - just cover shipping, no additional charges!",
"Discount AUTOMATICALLY APPLIES! Super simple, no code!",
"If you order another avocuddle in addition, we cover shipping PLUS the free baby avocuddle! :)",
"Feel free to DM us if you need anything!"
].join("\n")+"\n")
.
.
.
while true
browser.get 'https://twitter.com/messages/requests'
sleep 5
request = wait.until {
el = browser.find_element(:css, "[data-testid='conversation']")
el if el.displayed?
}
break if request.nil?
request.click
not_acceptable_link = true
na_link_index = 1
while not_acceptable_link == true
accept_btn = browser.find_element(:xpath, "//*[contains(text(), 'Accept')]")
unless accept_btn.displayed?
request_2 = wait.until {
el = browser.find_elements(:css, "[data-testid='conversation']")[na_link_index]
el if el.displayed?
}
request_2.click
else
not_acceptable_link = false
end
na_link_index += 1
end
accept_btn = browser.find_element(:xpath, "//*[contains(text(), 'Accept')]")
accept_btn.click
sleep 1
reply_input = wait.until {
el = browser.find_element(:css, "[data-testid='dmComposerTextInput']")
el if el.displayed?
}
reply_input.click
reply_input.send_keys(reply_messages)
.
.
.
I would like for the code to output the entire text as one block of text. However, instead, it outputs as separate lines.
Output currently looks like:
FREE BABY AVOCUDDLE - Thank you for your patience!
(enters this into text box)
To redeem your FREE avocuddle, just use the LINK IN OUR BIO and ADD TO CART - just cover shipping, no additional charges!
(enters this into text box)
etc.
Instead I would like for it to send as one message.

How to print unicode charaters in Command Prompt with Ruby

I was wondering how to print unicode characters, such as Japanese or fun characters like 📦.
I can print hearts with:
hearts = "\u2665"
puts hearts.encode('utf-8')
How can I print more unicode charaters with Ruby in Command Prompt?
My method works with some characters but not all.
Code examples would be greatly appreciated.
You need to enclose the unicode character in { and } if the number of hex digits isn't 4 (credit : /u/Stefan) e.g.:
heart = "\u2665"
package = "\u{1F4E6}"
fire_and_one_hundred = "\u{1F525 1F4AF}"
puts heart
puts package
puts fire_and_one_hundred
Alternatively you could also just put the unicode character directly in your source, which is quite easy at least on macOS with the Emoji & Symbols menu accessed by Ctrl + Command + Space by default (a similar menu can be accessed on Windows 10 by Win + ; ) in most applications including your text editor/Ruby IDE most likely:
heart = "♥"
package = "📦"
fire_and_one_hundred = "🔥💯"
puts heart
puts package
puts fire_and_one_hundred
Output:
♥
📦
🔥💯
How it looks in the macOS terminal:

How can I read the arrow keys in a Ruby curses application?

I have a Ruby curses application in which I'd like to trap for the arrow keys and function keys. The problem is that some keystrokes generate multiple values when using STDIN.getch. When I type a 'regular' key like a-z I get a single value back. When I type a [F]key or arrow key I get three values back.
Is there a gem designed for handling keyboard input or a better way to accomplish reading keystrokes?
#!/usr/bin/ruby
require 'curses'
require 'io/console'
Curses.noecho
Curses.init_screen
main_window = Curses::Window.new(24, 40, 1, 0)
num_keys = 0
loop do
ch = STDIN.getch
num_keys = num_keys + 1
main_window.addstr(' key:' + ch.inspect + ' count:' + num_keys.to_s)
main_window.refresh
break if ch == 'q'
end
Curses.close_screen
Trying enabling the keypad on the window right after you instantiate it.
main_window = Curses::Window.new(24, 40, 1, 0)
main_window.keypad = true
and then instead of using STDIN.getch there's a getch method on the window as well you can use, so try changing
ch = STDIN.getch
to
ch = main_window.getch
now when I run your program, I get
key: 259 count: 1
when I hit the up arrow instead of
key:"\e" count 1 key:"[" count:2 key:"A" count:3

Better way to write this code

I am designing a user interface for a menu project. I tried using a for-loop such as:
for i in 0..8
i=i
end
for k in 0..7
k=k
end
if #selection==i && #unlock==k && $switches[(what do I do here?)]==?????
do thing
Whenever the user presses the Y key, it will turn off a function; if #selection==1 is highlighted and the user presses the "Y" key, the corresponding switch at that specific location should be turned off. #unlock is just used as a way of saying that, unless this global boolean is set to true, the user can press "Y" and turn this switch on or off.
First thing, you could change each if else to something like this:
BITMAP_PATH = "Graphics/Pictures/Input Map/switch"
if #selection==1 && #unlock1
pbSEPlay("BW2MenuChoose",65)
bitmap_switch = $switches[310] ? 'off' : 'on' # sets path to off/on
#graphics["switch"].setBitmap(BITMAP_PATH + bitmap_switch)
!$switches[310] # it changes value of boolean to opposite value
end
And the selections that only have one condition could be written like this:
if #selection==0 && #unlock0
pbSEPlay("buzzer",65)
end
You could also try writing a case expression for #selection. Probably you could dry it even more, but I do not really understand what each #unlock is used for.
Edit:
BITMAP_PATH = "Graphics/Pictures/Input/switch"
SELECTION_SWITCHES = [nil, 310, 300, 339, 338, 330, 318]
def pbChangeSwitch
case
when 0
case #selection
when 0,7
pbSEPlay("buzzer",65) if instance_variable_get("#unlock#{#selection}")
when 1..6
if instance_variable_get("#unlock#{#selection}")
pbSEPlay("BW2MenuChoose",65)
bitmap_switch = $switches[SELECTION_SWITCHES[#selection]] ? 'off' : 'on'
#sprites["switch"].setBitmap(BITMAP_PATH + bitmap_switch)
index = SELECTION_SWITCHES[#selection]
$switches[index] = !$switches[index]
end
end
Graphics.update
Please add $ to the last line. bitmap_switch can not be true or false, because you add it to BITMAP_PATH, so it has to be 'off' or 'on'.

Cucumber and variables internal to methods called indirectly

Please note: I am new to TDD & cucumber, so the answer may be very easy.
I am creating a basic image editor for a test (the image is just a sequence of letters).
I have written a Cucumber story:
Scenario Outline: edit commands
Given I start the editor
And a 3 x 3 image is created
When I type the command <command>
Then the image should look like <image>
The step
Scenarios: colour single pixel
| command | image |
| L 1 2 C | OOOCOOOOO |
always fails, returning
expected: "OOOCOOOOO"
got: " OOOOOOOO" (using ==) (RSpec::Expectations::ExpectationNotMetError)
This is the step code:
When /^I type the command (.*)$/ do |command|
#editor.exec_cmd(command).should be
end
The function exec_cmd in the program recognizes the command and launches the appropriate action. In this case it will launch the following
def colorize_pixel(x, y, color)
if !#image.nil?
x = x.to_i
y = y.to_i
pos = (y - 1) * #image[:columns] + x
#image[:content].insert(pos, color).slice!(pos - 1)
else
#messenger.puts "There's no image. Create one first!"
end
end
However, this always fails unless I hardcode the values of the two local variables (pos and color) in the function in the program itself.
Why? It doesn's seem I'm doing anything wrong in the program itself: the function does what it's supposed to do and those two variables are only useful locally. So I'd think this is a problem with my use of cucumber. How do I properly test this?
---edit---
def exec_cmd(cmd = nil)
if !cmd.nil?
case cmd.split.first
when "I" then create_image(cmd[1], cmd[2])
when "S" then show_image
when "C" then clear_table
when "L" then colorize_pixel(cmd[1], cmd[2], cmd[3])
else
#messenger.puts "Incorrect command. " + "Commands available: I C L V H F S X."
end
else
#messenger.puts "Please enter a command."
end
end
When /^I type the command (.*)$/ do |command|
#output = #editor.exec_cmd(command)
end
Then /^the image should look like (.)*$/ do |expected_image|
#output.should == expected_image
end
Hope this may help you.
It's not a cucumber issue.
The problem was that, in exec_cmd, split was called only in the "case" clause, not in the "when"s. This meant that, since the command's format was "a 1 2 b", cmd[1] in the "when" would call the second character of the string, a space, not the second value of the array, and the other functions would convert that to_i, returning 0.
I changed exec_cmd like this:
def exec_cmd(cmd = nil)
if !cmd.nil?
cmd = cmd.split
case cmd.first
when "I" then create_image(cmd[1], cmd[2])
[...]
end
which fixed the issue.

Resources