Inputting string using (gets.chomp) and producing a histogram - ruby

I'm having struggles understanding ruby. I wish to have a program in which a user can input a set of text and it come back with asterisks. So far I was able to do it via a .txt file. Can anyone explain where I went wrong? I am struggling with ruby a lot.
Image of outcome when I run it
print "Please enter any length of text:"
user_input = String(gets.chomp)
h = Hash.new
f = user_input
f.each_line { |line|
letters = line.split(//)
letters.each { |w|
if h.has_key?(w)
h[w] = h[w] + 1
else
h[w] = 1
end
}
}
# sort the hash by
h.sort{|a,b| a[1]<=>b[1]}.each { |elem|
puts "\"#{elem[0]}\": " + '*' * elem[1]
}
Error message I encountered
Undefined method `chomp' for nil:NilClass (NoMethodError)

In the script runner of Atom where you are currently running your Ruby program, you can not read from standard input using gets. It appears that the script-runner package can extend this to provide a real terminal to the script where you can then also use STDIN.
Alternatively, you could also run your program from a real console. For that, you have run it from a command line window, e.g. with ruby name_of_program.rb instead of starting it from Atom.

The gets method must be called alone. Try it in your second line:
user_input = gets.chomp
without String.
I hope it useful for you. :)

Your code is working as intended. You went wrong by running the code in your text editor instead of through the console. The Kernal#gets method requires user input, which would need to be mocked in order to run within your text-editor. Because your editor is returning nil instead of user input in string format, the chomp method is raising your NoMethodError.
Essentially your code is fine, but your are trying to run it in a limited environment. As a beginner, if your code requires user input, it's easier to test the code by running your ruby file through the console/terminal with ruby <filename.rb>.

Related

Console keeps waiting for input right after executing without doing anything prior the gets statement in Ruby

I'm new to ruby and this issue is bugging me for a while . Whenever i use gets to take user input , my gets statement is executed right after i run the file .I'm using git Bash to run my file.rb file ,
puts "some unnecessary text"
puts "Hello world"
puts "now you should input something"
x = gets.chomp
puts 36
puts "your input is " + x + " right?"
the program should print the first 3 lines before waiting for an input but it waits for the input right after i run it
$ruby file.rb
|
it waits for eternity unless I press enter . If i write something,
$ ruby file.rb
myInput
some unnecessary text
Hello world
now you should input something
36
your input is myInput right?
it runs okay . So I'm forced to write my input at the beginning .
It's not much of a problem right now but it'll cause a lot if headaches when i write bigger and more complex code . Any solutions ?
ps: It seems the problem only occurs with git Bash (windows) . Powershell works just fine .
It seems that the standard output is buffered.
Try to put at the beginning of the file (first two lines) old_sync = $stdout.sync $stdout.sync = true and a the end of the file (last line) $stdout.sync = old_sync.
The call to the IO#sync= method set the sync mode to true. This cause that all output is immediately flushed, at the end of the script we restore its value to its original old value, see Ruby documentation for details.
In summary:
old_sync = $stdout.sync # cache old value
$stdout.sync = true # set mode to true
# your scripting staff
$stdout.sync = old_sync # restore old value
If this trick works at least you know the reason for the weird behaviour. You can find some explanation also in this SO post.

Not able to get result for def using ruby on mac osx

This is just a sample method I have created for testing purpose using Ruby on Mac OSX 10.12 but I don't get the desired output: Can anyone suggest please? I tried getting the result using both paranthesis and without (). It doesn't even throw any error.
def hi
puts "Hello World"
End
hi
hi()
hi("Hello Matz")`
Try this:
def hi
puts "Hello World"
end
hi
hi()
And this:
def greet(greeting)
puts greeting
end
greet("Hello Matz")
Note that in this line:
hi("Hello Matz")`
you have a tick mark at the end, so that is an error:
1.rb:5: syntax error, unexpected tXSTRING_BEG, expecting end-of-input
It doesn't even throw any error.
Then you aren't running that program.
I suggest you open a Terminal window (Applications/Utilities/Terminal.app), and type in:
$ vimtutor
vim is a free computer programming editor that comes with your Mac. Do the tutorial and learn how to use vim. To run a ruby program, you enter your code into a file, then save it as, say, my_prog.rb. Then you need to give that file to ruby to execute it. You execute a ruby program like this:
$ ruby my_prog.rb
You can create a directory for all your ruby programs like this:
$ mkdir ruby_programs
$ cd ruby_programs
To create a new file inside that directory, use vim:
~/ruby_programs$ vi my_prog.rb
Once you are done typing in your code, save the file, which will put you back at the prompt in Terminal, then you can run your program:
~/ruby_programs$ ruby my_prog.rb
Once you get comfortable with vim, and you feel confident running your ruby programs, consider installing macvim with the vivid chalk color scheme:
It's nicer to look at than plain vim.
Try editing your file so that it reads:
def hi
puts "Hello World"
end
hi
Some important differences to note: def and end are both case-sensitive. The inside of the function definition is indented by two spaces. Since the function takes no arguments, no parentheses are necessary on the call to hi on line 4.
Depending on your filename, enter the command ruby FILENAME and you should see the output Hello World
Ruby keywords are case sensitive. Your code uses End and you probably wanted to use end to mark the end of the hi method.
Because End is not the same as end (and End is not a keyword), irb keeps waiting for input and treats the other three lines as part of the hi method. As far as it can tell, its definition is not complete until it reaches the end keyword (all non-capital letters.)
The correct way to define the method is:
def hi
puts "Hello World"
end
Then you can call it using either hi or hi().
Calling it as hi("Hello Matz") (or hi "Hello Matz") throws an ArgumentError exception with the message wrong number of arguments (given 1, expected 0) because it is called with one argument but the definition of method hi doesn't specify anything about arguments (by its definition, the method hi doesn't accept any argument).

Ruby - STDIN.read

I'm trying to read from a file, and because my more complex code doesn't work, I came back to basics to see whether it even reads properly.
My code:
MyParser.new(STDIN.read).run.lines.each do |line|
p line.chomp
end
I use
ruby program
(it's placed in a bin directory and I saved it without .rb )
Now program is waiting for me to write something. I type:
../examples/file.txt
and use CTRL + Z (I'm on Windows 10). It produces ^Z and I hit enter.
Now I have an error:
Invalid argument # rb_sysopen - ../examples/file.txt (Errno::EINVAL)
MyParser class and its whole logic works fine. I'll be grateful for any hints.
Without knowing, what your MyParser expect, it is hard to know, what you need.
But maybe this helps:
MyParser.new(STDIN.gets.strip).run.lines.each do |line|
p line.chomp
end
I would extend it by a message what you need:
puts "Please enter the filename"
STDOUT.flush
MyParser.new(STDIN.gets.strip).run.lines.each do |line|
p line.chomp
end
With STDOUT.flush the user gets the message, before STDIN.getswaits for a message.
In your case I would take a look on ARGV and call the program with:
ruby program ../examples/file.txt
Your program should then use:
MyParser.new(ARGV.first).run.lines.each do |line|
p line.chomp
end

RubyFiddle issue - NameError: undefined local variable or method 'gets' for #

class SqrrtProg
def hello
puts "Hello! Welcome to the square root program."
puts "\n Please enter a number: "
number = gets
puts number
end
def Sqrrt
end
end
object = SqrrtProg.new
object.hello
I am simply trying to use 'gets' to get user input. I had read that it might be because, by default, gets tries to read information from a file. I have tried name = $stdin.gets and name = &stdin.gets.chomp etc... However, I end up at the same error.
I am going to answer my own question as it has been solved. The code is fine when run from a terminal. This problem apparently stems from a limitation in RubyFiddle. Hopefully this question can help someone who comes across the same problem with the RubyFiddle enviornment :)

How to read an open file in Ruby

I want to be able to read a currently open file. The test.rb is sending its output to test.log which I want to be able to read and ultimately send via email.
I am running this using cron:
*/5 * * * /tmp/test.rb > /tmp/log/test.log 2>&1
I have something like this in test.rb:
#!/usr/bin/ruby
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
When I run this code, it only gives me this output:
Start
End
I would expect the output to be something like this:
Start
Start (from the reading of the test.log since it should have the word start already)
End
Ok, you're trying to do several things at once, and I suspect you didn't systematically test before moving from one step to the next.
First we're going to clean up your code:
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
can be replaced with:
puts "Start"
puts File.read("./test.log")
puts "End"
It's plain and simple; There's no need for a method or anything complicated... yet.
Note that for ease of testing I'm working with a file in the current directory. To put some content in it I'll simply do:
echo "foo" > ./test.log
Running the test code gives me...
Greg:Desktop greg$ ruby test.rb
Start
foo
End
so I know the code is reading and printing correctly.
Now we can test what would go into the crontab, before we deal with its madness:
Greg:Desktop greg$ ruby test.rb > ./test.log
Greg:Desktop greg$
Hmm. No output. Something is broken with that. We knew there was content in the file previously, so what happened?
Greg:Desktop greg$ cat ./test.log
Start
End
Cat'ing the file shows it has the "Start" and "End" output of the code, but the part that should have been read and output is now missing.
What happening is that the shell truncated "test.log" just before it passed control to Ruby, which then opened and executed the code, which opened the now empty file to print it. In other words, you're asking the shell to truncate (empty) it just before you read it.
The fix is to read from a different file than you're going to write to, if you're trying to do something with the contents of it. If you're not trying to do something with its contents then there's no point in reading it with Ruby just to write it to a different file: We have cp and/or mv to do those things for us witout Ruby being involved. So, this makes more sense if we're going to do something with the contents:
ruby test.rb > ./test.log.out
I'll reset the file contents using echo "foo" > ./test.log, and cat'ing it showed 'foo', so I'm ready to try the redirection test again:
Greg:Desktop greg$ ruby test.rb > ./test.log.out
Greg:Desktop greg$ cat test.log.out
Start
foo
End
That time it worked. Trying it again has the same result, so I won't show the results here.
If you're going to email the file you could add that code at this point. Replacing the puts in the puts File.read('./test.log') line with an assignment to a variable will store the file's content:
contents = File.read('./test.log')
Then you can use contents as the body of a email. (And, rather than use Ruby for all of this I'd probably do it using mail or mailx or pipe it directly to sendmail, using the command-line and shell, but that's your call.)
At this point things are in a good position to add the command to crontab, using the same command as used on the command-line. Because it's running in cron, and errors can happen that we'd want to know about, we'd add the 2>&1 redirect to capture STDERR also, just as you did before. Just remember that you can NOT write to the same file you're going to read from or you'll have an empty file to read.
That's enough to get your app working.
class FileLineRead
File.open("file_line_read.txt") do |file|
file.each do |line|
phone_number = line.gsub(/\n/,'')
user = User.find_by_phone_number(line)
user.destroy unless user.nil?
end
end
end
open file
read line
DB Select
DB Update
In the cron job you have already opened and cleared test.log (via redirection) before you have read it in the Ruby script.
Why not do both the read and write in Ruby?
It may be a permissions issue or the file may not exist.
f = File.open("test","r")
puts f.read()
f.close()
The above will read the file test. If the file exists in the current directory
The problem is, as I can see, already solved by Slomojo. I'll only add:
to read and print a text file in Ruby, just:
puts File.read("/tmp/log/test.log")

Resources