Print editable to console in Ruby [duplicate] - ruby

This question already has answers here:
What will give me something like ruby readline with a default value?
(6 answers)
Closed 6 years ago.
Let's say I have the following code in Ruby:
print("Enter a filename:")
editableprint("untitled.txt")
filename = gets.chomp!
What would be the function "editableprint" so that "untitled.txt" is part of the input of the user for the gets function? (thus the user can edit the "untitled.txt" string or simply leave it as is")

There are similar questions here and here
However, the solutions there don't seem to work as expected, so it looks this is ruby version or platform dependent?
For example, this does not work for me, but also does not throw an error.
require "readline"
filename = Readline.insert_text("untitled.txt").readline("Enter a filename:")
print filename
But since it looks much better, and should work according to the documentation for ruby >= 2, I am leaving it there for now.
The following works on my system (ruby 2.3.1, OS X)
require "readline"
require 'rb-readline'
module RbReadline
def self.prefill_prompt(str)
#rl_prefill = str
#rl_startup_hook = :rl_prefill_hook
end
def self.rl_prefill_hook
rl_insert_text #rl_prefill if #rl_prefill
#rl_startup_hook = nil
end
end
RbReadline.prefill_prompt("untitled.txt")
str = Readline.readline("Enter a filename:", true)
puts "You entered: #{str}"

I would use vim to edit the file. Vim will save edited files in ~/.viminfo. The last edited file is marked with '0. The pattern of a file entry is 'N N N filename where N stands for a integer.
def editableprint(filename)
system "vi #{filename}"
regex = /(?<='0\s{2}\d\s{2}\d\s{2}).*/
viminfo = File.expand_path("~/.viminfo")
File.read(viminfo).scan(regex).first
end
In order to make this to work you would have to change your code
print("Enter a filename:")
filename = gets.chomp!
filename = "untitled.txt" if filename.emtpy?
edited_filename = editableprint("untitled.txt")

Related

Garbage Base64 decoded string [duplicate]

This question already has answers here:
p vs puts in Ruby
(8 answers)
Closed 3 years ago.
Could somebody explain me, why there are two various outputs?
CODE IN IRB(Interactive ruby shell):
irb(main):001:0> require 'base64'
=> true
irb(main):002:0> cookie = "YXNkZmctLTBEAiAvi95NGgcgk1W0pyUKXFEo6IuEvdxhmrfLqNVpskDv5AIgVn8wfIWf0y41cb%2Bx9I0ah%2F4BIIeRJ54nX2qGcxw567Y%3D"
=> "YXNkZmctLTBEAiAvi95NGgcgk1W0pyUKXFEo6IuEvdxhmrfLqNVpskDv5AIgVn8wfIWf0y41cb%2Bx9I0ah%2F4BIIeRJ54nX2qGcxw567Y%3D"
irb(main):003:0> decoded_cookie = Base64.urlsafe_decode64(URI.decode(cookie))
=> "asdfg--0D\x02 /\x8B\xDEM\x1A\a \x93U\xB4\xA7%\n\\Q(\xE8\x8B\x84\xBD\xDCa\x9A\xB7\xCB\xA8\xD5i\xB2#\xEF\xE4\x02 V\x7F0|\x85\x9F\xD3.5q\xBF\xB1\xF4\x8D\x1A\x87\xFE\x01 \x87\x91'\x9E'_j\x86s\x1C9\xEB\xB6"
Code from Linux terminal:
asd#asd:~# ruby script.rb
asdfg--0D /��M� �U��%
\Q(苄��a��˨�i�#�� V0|���.5q������ ��'�'_j�s9�
Script:
require 'base64'
require 'ecdsa'
cookie = "YXNkZmctLTBEAiAvi95NGgcgk1W0pyUKXFEo6IuEvdxhmrfLqNVpskDv5AIgVn8wfIWf0y41cb%2Bx9I0ah%2F4BIIeRJ54nX2qGcxw567Y%3D"
def decode_cookie(cookie)
decoded_cookie = Base64.urlsafe_decode64(URI.decode(cookie))
end
puts (decode_cookie(cookie))
How can i get the same output in terminal?
I need the output:
"asdfg--0D\x02 /\x8B\xDEM\x1A\a \x93U\xB4\xA7%\n\Q(\xE8\x8B\x84\xBD\xDCa\x9A\xB7\xCB\xA8\xD5i\xB2#\xEF\xE4\x02 V\x7F0|\x85\x9F\xD3.5q\xBF\xB1\xF4\x8D\x1A\x87\xFE\x01 \x87\x91'\x9E'_j\x86s\x1C9\xEB\xB6"
In Linux terminal.
A string like "\x8B" is a representation of character, not the literal \x8B. Ruby uses such representation if it's missing the font to display the character or if it messes with whitespacing (for example "\n" is a newline and not \ followed by a n).
The reason you get another output in irb is because you don't print the string using puts (like you do in your script). Simply calling decoded_cookie will return the string representation, not the actual content.
You can display the actual content by simply printing it to an output.
require 'base64'
cookie = "YXNkZmctLTBEAiAvi95NGgcgk1W0pyUKXFEo6IuEvdxhmrfLqNVpskDv5AIgVn8wfIWf0y41cb%2Bx9I0ah%2F4BIIeRJ54nX2qGcxw567Y%3D"
decoded_cookie = Base64.urlsafe_decode64(URI.decode(cookie))
puts decoded_cookie
# asdfg--0D /��M �U��%
# \Q(苄��a��˨�i�#�� V0|���.5q����� ��'�'_j�s9�
#=> nil
You can find more info about the "\xnn" representation here.
If you'd like the script to display the string representation use p instead of puts, or use puts decoded_cookie.inspect.

Toggling true/false: editing a file in ruby

I have some code that tries to change 'false' to 'true' in a ruby file, but it only works once while the script is running.
toggleto = true
text = File.read(filename)
text.gsub!("#{!toggleto}", "#{toggleto}")
File.open(filename, 'w+') {|file| file.write(text); file.close}
As far as I know, as long as I close a file, i should be able to read it it afterwards with what I previously wrote and thus change it back and forth no matter how many times.
Larger Context:
def toggleAutoAction
require "#{#require_path}/options"
filename = "#{#require_path}/options.rb"
writeToggle(filename, !OPTIONS[:auto])
0
end
def writeToggle(filename, toggleto)
text = File.read(filename)
text.gsub!(":auto => #{!toggleto}", ":auto => #{toggleto}")
File.open(filename, 'w+') {|file| file.write(text); file.close}
end
def exitOrMenu
puts "Are you done? (y/n)"
prompt
if gets.chomp == 'n'
whichAction
else
exit
end
end
def whichAction
if action == 5
toggleAutoAction
else
puts "Sorry, that isn't an option...returning"
return 1
end
exitOrMenu
end
The problem lays within this method:
def toggleAutoAction
require "#{#require_path}/options" # here
filename = "#{#require_path}/options.rb"
writeToggle(filename, !OPTIONS[:auto])
0
end
Ruby will not load the options.rb a second time (i.e. with the exact same path name), hence your !OPTIONS[:auto] will only be evaluated once (otherwise you would get a constant-already-defined-warning, provided OPTIONS is defined in options.rb). See Kernel#require docs.
You could, of course, do crazy stuff like
eval File.read("#{#require_path}/options.rb")
but I would not recommend that (performance wise).
As noted above, reading/writing from/to YAML files is less painful ;-)

Pre-Filled Prompt in Ruby [duplicate]

This question already has answers here:
What will give me something like ruby readline with a default value?
(6 answers)
Closed 6 years ago.
I am using to Ruby to write a small command line utility to search Pubmed. Right now, I prompt the user for a query and display the results, and the user has the option of appending to the query or entering an entirely new query. I would like to add the ability to edit the current query; i.e. the prompt should come pre-filled with an editable version of the previous query, like so:
Enter query: <PREVIOUS QUERY HERE>
It's easy enough to print out the previous query next to the prompt, but how do I make this output editable, as if the user had typed it herself?
#casper:
Thank you for the response Casper. I tried the code that you supplied below, and it does indeed work on its own. Strangely enough, it doesn't seem to work when I try to use it in a gem. My gem is called db_hippo. I added rb-readline as a dependency in my gemspec, and I put the extension to RbReadline in lib/db_hippo/rb-readline.rb
module DbHippo
module RbReadline
<CASPER'S EXTENSION HERE>
end
end
I wish to use the functionality in another submodule of DbHippo, DbHippo::Source. In DbHippo::Source I added at the top:
require 'rb-readline'
require 'db_hippo/rb-readline'
Then in one of the methods of DbHippo::Source, I have:
RbReadline.prefill_prompt(query)
query = Readline.readline("Query: ", true)
The query variable is definitely not empty, but for some reason in this context the prompt doesn't get prefilled. I also notice that if I put the extension in the same file (lib/db_hippo/rb-readline) without making it a submodule of DbHippo, I get the error: uninitialized constant DbHippo::Source::Readline (NameError) on the line:
query = Readline.readline("Query: ", true)
This all seems to have something to do with proper naming of modules, require statements, and gems. This is the first gem I've tried to build. Any idea what's going wrong here?
Maybe googlers will find this useful.
With plain Readline on Ruby 2.1 you could use:
def ask(prompt, default=nil)
if default
Readline.pre_input_hook = -> {
Readline.insert_text(default)
Readline.redisplay
# prevent re-trigger on every `readline`
Readline.pre_input_hook = nil
}
end
data = Readline.readline("#{prompt}: ")
return data.chomp
end
ask("MOAR...?", "COMPUTARS!") # displays: MOAR...? COMPUTARS!
At the prompt the text COMPUTARS! will be editable
You can do it with RbReadline:
require 'rubygems'
require 'rb-readline'
module RbReadline
def self.prefill_prompt(str)
#rl_prefill = str
#rl_startup_hook = :rl_prefill_hook
end
def self.rl_prefill_hook
rl_insert_text #rl_prefill if #rl_prefill
#rl_startup_hook = nil
end
end
RbReadline.prefill_prompt("Previous query")
str = Readline.readline("Enter query: ", true)
puts "You entered: #{str}"

Strange number conversion while reading a csv file with ruby

i've got a strange problem in ruby on rails
There is a csv file, made with Excel 2003.
5437390264172534;Mark;5
I have a page with upload input and i read the file like this:
file = params[:upload]['datafile']
file.read.split("\n").each do |line|
num,name,type = line.split(";")
logger.debug "row: #{num} #{name} #{type}"
end
etc
So. finally i've got the following:
num = 5437...2534
name = Mark
type = 5
Why num has so strange value?
Also i tried to do like this:
str = file.read
csv = CSV.parse(str)
csv.each do |line|
RAILS_DEFAULT_LOGGER.info "######## #{line.to_yaml}"
end
but again i got
######## ---
- !str:CSV::Cell "5437...2534;Mark;5"
The csv file in win1251 (i can't change file encoding)
ruby file in UTF8
ruby version 1.8.4
rails version 2.0.2
If it indeed has a strange value, it probably has to to do with the code you didn't post. Edit your question, and include the smallest bit of code that will run independently and still produce your questionable output.
split() returns an array of strings. So the first value of your CSV file is a String, not a Bignum. Maybe you need num.to_i, or a test like num.is_a?(Bignum) somewhere in your code.
file = File.open("test.csv", "r")
# Just getting the first line
line = file.gets
num,name,type = line.split(";")
# split() returns an array of String
puts num.class
puts num
# Make num a number
puts num.to_i.class
puts num.to_i
file.close
Running that file here gives me this:
$ ruby test.rb
String
5437390264172534
Bignum
5437390264172534

Ruby unable to use require

This is a newbie question as I am attempting to learn Ruby by myself, so apologies if it sounds like a silly question!
I am reading through the examples of why's (poignant) guide to ruby and am in chapter 4. I typed the code_words Hash into a file called wordlist.rb
I opened another file and typed the first line as require 'wordlist.rb' and the rest of the code as below
#Get evil idea and swap in code
print "Enter your ideas "
idea = gets
code_words.each do |real, code|
idea.gsub!(real, code)
end
#Save the gibberish to a new file
print "File encoded, please enter a name to save the file"
ideas_name = gets.strip
File::open( 'idea-' + ideas_name + '.txt', 'w' ) do |f|
f << idea
end
When I execute this code, it fails with the following error message:
C:/MyCode/MyRubyCode/filecoder.rb:5: undefined local variable or method `code_words' for main:Object (NameError)
I use Windows XP and Ruby version ruby 1.8.6
I know I should be setting something like a ClassPath, but not sure where/how to do so!
Many thanks in advance!
While the top-level of all files are executed in the same context, each file has its own script context for local variables. In other words, each file has its own set of local variables that can be accessed throughout that file, but not in other files.
On the other hand, constants (CodeWords), globals ($code_words) and methods (def code_words) would be accessible across files.
Some solutions:
CodeWords = {:real => "code"}
$code_words = {:real => "code"}
def code_words
{:real => "code"}
end
An OO solution that is definitely too complex for this case:
# first file
class CodeWords
DEFAULT = {:real => "code"}
attr_reader :words
def initialize(words = nil)
#words = words || DEFAULT
end
end
# second file
print "Enter your ideas "
idea = gets
code_words = CodeWords.new
code_words.words.each do |real, code|
idea.gsub!(real, code)
end
#Save the gibberish to a new file
print "File encoded, please enter a name to save the file"
ideas_name = gets.strip
File::open( 'idea-' + ideas_name + '.txt', 'w' ) do |f|
f << idea
end
I think the problem might be that the require executes the code in another context, so the runtime variable is no longer available after the require.
What you could try is making it a constant:
CodeWords = { :real => 'code' }
That will be available everywhere.
Here is some background on variable scopes etc.
I was just looking at the same example and was having the same problem.
What I did was change the variable name in both files from code_words to $code_words .
This would make it a global variable and thus accesible by both files right?
My question is: wouldn't this be a simpler solution than making it a constant and having to write CodeWords = { :real => 'code' } or is there a reason not to do it ?
A simpler way would be to use the Marshal.dump feature to save the code words.
# Save to File
code_words = {
'starmonkeys' => 'Phil and Pete, those prickly chancellors of the New Reich',
'catapult' => 'chucky go-go', 'firebomb' => 'Heat-Assisted Living',
'Nigeria' => "Ny and Jerry's Dry Cleaning (with Donuts)",
'Put the kabosh on' => 'Put the cable box on'
}
# Serialize
f = File.open('codewords','w')
Marshal.dump(code_words, f)
f.close
Now at the beginning of your file you would put this:
# Load the Serialized Data
code_words = Marshal.load(File.open('codewords','r'))
Here's the easy way to make sure you can always include a file that's in the same directory as your app, put this before the require statement
$:.unshift File.dirname(__FILE__)
$: is the global variable representing the "CLASSPATH"

Resources