Ruby argument error [duplicate] - ruby

This question already has answers here:
Kernel#gets attempts to read file instead of standard input
(2 answers)
Closed 10 years ago.
If I hard code the variable max below, my program runs with no problems. If I pass an argument in, max sets correctly but gets throws and error. Why is that?
max = ARGV[0].to_i
# Ask user for first guess
puts "I am thinking of a number between 1 and " + max.to_s + "."
print "Make your guess: "
guess = gets.chomp.to_i
Error Thrown: `gets': No such file or directory (Errno:: ENOENT)
Note: The error is fixed by changing gets to STDIN.gets but why is this needed when without the argument my program works fine?
Further, is there a way to change the default behavior of gets back to STDIN.gets for the entire file? Perhaps with one line at the top of the program?

Kernel.gets has some interesting behavior that explains your issue:
http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-gets
Specifically, it behaves differently depending on whether or not ARGV is empty, and if it is not empty then it will behave differently from STDIN.gets. If you don't want to use STDIN.gets explicitly, you might use max = ARGV.shift to remove that element before calling gets.
Addressing your last question: the best way to force gets' behavior to match STDIN.gets is probably to make sure ARGV is empty before doing anything else, and to make sure it stays that way. However, it may be wiser to continue to simply use STDIN.gets, "just to be sure". In cases like this, where unusual and surprising behavior is possible, it is almost always best to write code as explicitly as possible.

You should use:
STDIN.gets
When trying to get user input.

Related

Which is correct REPL or command-line?

when i write method missing in Object class i'm getting the output different in each interface.
the code is
class Object
def method_missing(hgh)
puts self
end
end
when i use REPL like irb, i get
when i use the command line, i get no error, any reasons would be helpful, thanks in advance
The tl;dr answer is that both are correct. Just more stuff happen in the REPL.
When you run the code from the command line like:
ruby script.rb
All that happens is that it's evaluated.
Whereas REPLs like IRB read your input, evaluate it and print it in a loop.
In this case evaluating your code literally broke the REPL and resulted in the subsequent print failing.
Now you may be a bit confused by this. "There is a print in both cases, I use puts!". The print I'm referring to here is the result that gets visualised after each evaluation. In this case the method definition result (=> :method_missing).
It might not only be the printing itself. It can be the ton of other under the hood code that the REPL has to execute to keep state like "what code was defined on which line" and so on.
Think of what you just did - you made it so that every object has every method possible to return nil. That is not just for the code you write in the REPL. It's for the code of the REPL itself as well.

'OR' Syntax in (g)Lua

I have limited knowledge of lua and would like to make an or statement.
However, I don't know the exact syntax.
Would the code below work correctly?
if text == "/teamspeak" or text == "/ts" then
If not please let me know on the correct syntax of the statement.
Yes, the statements are correct. You do not have any syntactical errors there, though you might want to check whether text contains only the command or the whole string (as is the case with ptokax). You might also want to check that the command is uppercase/lowercase or mixed-casing.
local sCmd = text:lower()
if sCmd == "/ts" or sCmd == "/teamspeak" then
...
end
Lua uses the keyword or for or statements.
I recommend reading the Lua language reference.
Your code would work correctly if you terminate the if then statement with end.
Best way is to try it yourself. If you do not have Lua installed you can use http://www.lua.org/demo.html
And please note that nil is not the same as false! Many Lua beginners have problems here.
That statement should work, though I suggest converting the string to lowercase first, as jhpotter92 already suggested.
A typical problem in cases like this is when the order the language deals with operands is not the one you'd expect; if, for example, lua were to evaluate the or before the == operator (which it doesn't, see reference) that code would not work. Therefore it is never a bad idea to write your code like this
if (text == "/teamspeak") or (text = "/ts") then <...> end
just to be sure lua does things in the correct order.
If you ever find yourself in this kind of situation again, and you don't want to wait for someone to respond to your question, you can just start lua in interactive mode (assuming you have lua installed on your system, which is very helpful for everyone who wants to learn/code in lua) and type something like
> text = "/teamspeak"
> if text == "/teamspeak" or text == "/ts" then print "true ♥" end
In this example, the console will output "true ♥". Repeat this with text="/ts" and text="some other string" and see if the line of code behaves as it should.
This shouldn't take you longer than 5 minutes (maybe +5 minutes to install lua first)

Ruby: "undefined method" error; how to use gsub more effectively?

So I'm trying to find a way to Donald Duck-ify statements inputed by users (judge me later).
This is my code so far:
puts "Wanna get Donald Duck-ified?"
print "Type some text here:"
user_input = gets.chomp
if user_input.gsub!(/s/,"th").gsub!(/ce/,"th").gsub!(/ci/,"th").gsub!(/cy/,"th")
puts "Boop - there go your s's and soft c's!"
else
puts "Dang, you didn't have any s's or soft c's!"
end
puts "#{user_input}"
Upon testing it with some input of my own ("square cycle caesar circle", specifically), I'm getting "undefined method `gsub!' for nil:NilClass" as an error.
How is gsub! undefined? If the code runs with user_input.gsub!(/s/,"th") on it own, without any other methods behind it, it works fine. Once a second method is added, the else code runs and only replacements for "s" are made. All four and I get the error above.
Does there happen to be another way of substituting multiple patterns (as named by the Ruby docs) with a single replacement? I've spent the last hours researching the problem and I still can't totally tell what the issue is.
New to Ruby. Encouraged and motivated.
Many thanks in advance.
Don't use #gsub! chained. (Actually, don't use #gsub! at all for most code.)
[gsub!] Performs the substitutions of String#gsub in place, returning str, or nil if no substitutions were performed.
Switch the code to #gsub which doesn't cause side-effects (yay!) and always returns a string (yay!) - simply compare the result with the original (unmodified) string.
Also, one could use the gsub form that accepts a hash (since Ruby 1.9.something). This has a subtle difference that replaced values will not be themselves replaced, although it doesn't matter here.
user_input.gsub(/s|ce|ci|cy/, { "s"=>"th", "ce"=>"th", "ci"=>"th", "cy"=>"th" })
# or since all are replaced with "th" (which I just noticed =^_^=) ..
user_input.gsub(/s|ce|ci|cy/, "th")
(I still recommend against gsub! because I find side effects upon strings disconcerting. However, it would work reliably when used with the non-chained forms above.)
Ruby's gsub! returns nil if it performs no substitutions. This means you can't reliably chain it like you do. If you want to verify that any of the gsubs have made any change, you can chain non-destructive gsubs (without the bang; return a new string instead of modifying the current one) instead:
input = gets.chomp
replaced = input.gsub(/s/,"th").gsub(/ce/,"th").gsub(/ci/,"th").gsub(/cy/,"th")
if input == replaced
...

Learn Ruby the Hard Way ex17 extra credit 3 - consolidating to one line

For exercise 17, through searching other responses I was able to condense the following into one line (as asked in the extra credit #3)
from_file, to_file = ARGV
script = $0
input = File.open(from_file)
indata = input.read()
output = File.open(to_file, 'w')
output.write(indata)
output.close()
input.close()
I was able to condense it into:
from_file, to_file = ARGV
script = $0
File.open(to_file, 'w') {|f| f.write IO.read(from_file)}
Is there a better/different way to condense this into 1 line?
Can someone help explain the line I created? I created this from various questions/answers unrelated to this question. I have tried looking up exactly what I did but I am still a little lost and want a full understanding of it.
Similar to using IO::read to simplify "just read the whole file into a string", you can use IO::write to "just write the string to the file":
from_file, to_file = ARGV
IO.write(to_file, IO.read(from_file))
Since you don't use script, it can be removed. If you really want to get things down to one line, you can do:
IO.write(ARGV[1], IO.read(ARGV[0]))
I personally find this just as comprehensible, and the lack of error checking is equivalent.
You're using File#open with a block to open to_file in write-only mode ('w'). Inside the block you have access to the open file as f, and the file will be closed for you when the block terminates. IO::read reads the entire contents of from_file, which you then pass to IO#write on f (File is a subclass of IO), writing those contents to f (which is the open, write-only File for to_file).
There are always different ways of doing things:
Using File.open with a block is a good approach here. I like that to_file and from_file are declared in variables. So I think this is a good and readable solution that is not overly verbose.
The basic approach here is swapping out open/close operations with the more-clean File.open method with a block. File.open with a block will open a file, run the block, and then close the file, which is exactly what is needed here. Because the method automatically opens and closes the file, we are able to remove the boilerplate code that appears in the initial example. IO.read is another shortcut method that allows us to open/read/close the file without all of the open/close boilerplate. This is an exercise to learn more about Ruby's standard File/IO library, and in this case swapping out the more verbose methods is sufficient to reduce things to a single line.
I'm just a complete beginner, but this works for me:
open(ARGV[1], 'w').write(open(ARGV[0]).read)
It doesn't look elegant for me, but it works.
Edit: This is my attempt to put the entire script into one line if it's not clear.

Ruby gets() not returning correct string [duplicate]

This question already has answers here:
Ruby: String Comparison Issues
(5 answers)
Closed 3 years ago.
I decided to give Ruby a go today after hearing all of the great things about it, but so far it has only been giving me a hard time. A long time ago I made a "search engine" while learning Python that just stores data in an array and checks if the search keyword is in it, and I've been trying to do the same thing in Ruby.
Although it wasn't as intuitive as it was in Python, I got the search functionality working. I'm having trouble working with user input, though. I want to check if the input equals insert, search, and quit, but it just doesn't work. I don't really know how to use gets, so I'm assuming the issue is gets-related.
while true
puts 'What do you want to do?'
choice = $stdin.gets
puts choice # => quit
if choice == 'quit'
break
end
end
The if statement doesn't work. What the heck am I doing wrong? This is trivial in C++ for God's sake!
I would really appreciate some help. Ruby is so foreign to me... thanks!
I think the gets includes the newline at the end of the input. try using gets.chomp instead
irb(main):001:0> input = $stdin.gets
hello
=> "hello\n"
irb(main):002:0> input = $stdin.gets.chomp
hello
=> "hello"
davidrac is correct, you need to chop off the \n
Quoting the answer from here
The problem is you are getting a newline character on your input from the user. while they are entering "y" you are actually getting "y\n". You need to chomp the newline off using the "chomp" method on string to get it to work as you intend

Resources