Using a method return in a string in ruby - ruby

I can't figure out how to put the return of a method into a string. I had thought it would look like this,
def cat
puts "Purrrrr..."
end
puts "The cat says #{cat}."
but this is not working. I also tried
puts "The cat says %s." % cat
and
puts "The cat says #{return.cat}."
also
puts "The cat says #{send.cat}."
I kept trying stuff and looking things up.

It is working :
def cat
"Purrrrr..."
end
puts "The cat says #{cat}."
# >> The cat says Purrrrr....
Why the below one is not giving the output as above :
def cat
puts "Purrrrr..."
end
puts "The cat says #{cat}."
# >> Purrrrr...
# >> The cat says .
This is because you used puts "Purrrrr..." inside the method #cat. Now, inside the string interpolation method #cat has been called, and puts prints the the string "Purrrrr..." and returns nil. So puts "The cat says #{cat}." became puts "The cat says #{nil}.". Which results the output as :
The cat says .
^
"#{nil}" evaluates to an empty string(""). So the output is not as expected by you.
(arup~>~)$ irb
2.0.0-p0 :001 > nil.to_s
=> ""
2.0.0-p0 :002 > "foo #{nil}"
=> "foo "
2.0.0-p0 :003 >
puts "The cat says #{return.cat}." and puts "The cat says #{send.cat}." are invalid ruby code, they will throw error. So Don't try this!
Hope it helps!

In ruby you don't have to return a value explicitly. Last line result in a method will be returned by default.
In this case, the return value of 'puts' method is nil. So the return value of method 'cat' is nil.
If you are looking for a return string, you can just put a string at the last line of the method 'cat' as #Arup suggested. That will work.

Related

Ruby is returning actual newlines instead of \n

I have a file "Foo.md", which contains three lines:
Foo
Bar
I want File.read("Foo.md") to return "Foo\n\nBar" It does this when I run it from irb in the Terminal, but when I run it from a script such as
content = File.read('Foo.md')
puts content
it returns with the lines converted to actual returns. I need that variable as a single line for what comes next in my script.
To be clear: I'm not interested in changing the number of lines, just debugging to make sure the variable content is being passed as a single line.
You are still reading "Foo\n\n\nBar". However, puts interprets the special characters.
You can use String#inspect:
puts content.inspect # => "Foo\n\n\nBar"
str =
"Foo
Bar"
#=> "Foo\n\n\nBar"
You could also do this:
str.gsub(/\n{3,}/,"\n\n")
#=> "Foo\\nnBar"
It might help you visualize what is happening by meditating on this:
str = <<EOT
Foo
Bar
EOT
str's contents look like:
str # => "Foo\n\n\nBar\n"
Inspecting it escapes the backslashes for a visual representation, but it's NOT what you'd want to use when creating a string with embedded line-ends. You'd want to define it as it's shown above.
str.inspect # => "\"Foo\\n\\n\\nBar\\n\""
inspect output varies when viewed in IRB vs. the console. Here's what you'd see in the console:
ruby -e 'puts "\n"; puts "\n".inspect'
"\n"
Printing str to the console:
puts str
# >> Foo
# >>
# >>
# >> Bar

Ruby IO - File input/output indirectly

Recently I've been learning Ruby.I hit a problem while I'm writing a subclass of File.
class MyFile < File
end
file_path = "text_file"
file = MyFile.open(file_path) do | file |
file.each_line do | line |
puts line
end
file.close
end
result:
line 1
line 2
line 3
If I want output by calling a method:
class MyFile < File
def foo
self.each_line do | line |
puts line
end
end
end
file_path = "text_file"
my_file = MyFile.open(file_path) do | file |
file.foo
file.close
end
Result:
/Users/veightz/Developer/RubyCode/io_error.rb:4:in `write': not opened for writing (IOError)
from /Users/veightz/Developer/RubyCode/io_error.rb:4:in `puts'
from /Users/veightz/Developer/RubyCode/io_error.rb:4:in `block in foo'
from /Users/veightz/Developer/RubyCode/io_error.rb:3:in `each_line'
from /Users/veightz/Developer/RubyCode/io_error.rb:3:in `foo'
from /Users/veightz/Developer/RubyCode/io_error.rb:20:in `block in <main>'
from /Users/veightz/Developer/RubyCode/io_error.rb:19:in `open'
from /Users/veightz/Developer/RubyCode/io_error.rb:19:in `<main>'
Then I add new method bar
class MyFile < File
def foo
self.each_line do | line |
puts line
end
end
def bar
self.each_line do | line |
p line
end
end
end
my_file = MyFile.open(file_path) do | file |
file.bar
file.close
end
Result:
"line 1\n"
"line 2\n"
"line 3\n"
So, I'm so confused about IO in Ruby.Why puts line in foo can't work well.
There is a puts method in IO and IO is a superclass of File. That means that this:
puts line
is actually self.puts rather than Kernel#puts as it is pretty much everywhere else that you use puts. Hence the "not opened for writing" error message.
You need an explicit receiver to get the same effect as Kernel#puts; Kernel#puts is equivalent to $stdout.puts so you want:
file.each_line do | line |
$stdout.puts line
end
Your p line version works fine because there is no IO#p or File#p method, p is Kernel#p just like it is everywhere else.
Keep in mind that we don't have functions in Ruby the way other languages have global functions. Methods that you use like a function are almost always methods in Kernel.
You can also use $> "the default output stream" to redirect output of methods such as Kernel#puts... Which is the sole job of $> .
def foo
self.each_line do | line |
$>.puts line
end
end
I added one more method showing how you can also borrow "require" other gems (e.g pretty-printed gem) and the use of class << slef....Hence , you said "Recently I've been learning Ruby" :|
The below works as intended.
#!/usr/bin/env ruby
require 'pp'
class MyFile < File
class << self
def foo
each_line do | line |
$>.puts line
end
end
def bar
each_line do | line |
p line
end
end
def bam
each_line do | line |
pp line
end
end
end
file_path = "/Users/path/ofdirectory_to/somefile.txt"
my_file = MyFile.open(file_path) do | file |
file.bam
file.foo
file.bar
File.close
end
Note: the use of NameOfClass << self ... wana read more SO question
What seems btter :
non-pretty-printed output by p is:
#<PP:0x81fedf0 #genspace=#<Proc:0x81feda0>, #group_queue=#<PrettyPrint::GroupQueue:0x81fed3c #queue=[[#<PrettyPrint::Group:0x81fed78 #breakables=[], #depth=0, #break=false>], []]>, #buffer=[], #newline="\n", #group_stack=[#<PrettyPrint::Group:0x81fed78 #breakables=[], #depth=0, #break=false>], #buffer_width=0, #indent=0, #maxwidth=79, #output_width=2, #output=#<IO:0x8114ee4>>
pretty-printed output by pp is:
#<PP:0x81fedf0
#buffer=[],
#buffer_width=0,
#genspace=#<Proc:0x81feda0>,
#group_queue=
#<PrettyPrint::GroupQueue:0x81fed3c
#queue=
[[#<PrettyPrint::Group:0x81fed78 #break=false, #breakables=[], #depth=0>],
[]]>,
#group_stack=
[#<PrettyPrint::Group:0x81fed78 #break=false, #breakables=[], #depth=0>],
#indent=0,
#maxwidth=79,
#newline="\n",
#output=#<IO:0x8114ee4>,
#output_width=2>
For more about pp go here Ruby-Doc

How to check ARGF is empty or not in Ruby

I want to do with ARGF like this.
# file.rb
if ARGF.???
puts ARGF.read
else
puts "no redirect."
end
$ echo "Hello world" | ruby file.rb
Hello world
$ ruby file.rb
no redirect.
I need to do without waiting user input. I tried eof? or closed? doesn't help. Any ideas?
NOTE I was misunderstood ARGF. please see comments below.
Basically you'd examine #filename. One way to do this is:
if ARGF.filename != "-"
puts ARGF.read
else
puts "no redirect."
end
And this is the more complete form:
#!/usr/bin/env ruby
if ARGF.filename != "-" or (not STDIN.tty? and not STDIN.closed?)
puts ARGF.read
else
puts "No redirect."
end
Another:
#!/usr/bin/env ruby
if not STDIN.tty? and not STDIN.closed?
puts STDIN.read
else
puts "No redirect."
end
There might be a better way, but for me I needed to read the contents of a files being passed as arguments as well as having a files contents redirected to stdin.
my_executable
#!/usr/bin/env ruby
puts ARGF.pos.zero?
Then
$ my_executable file1.txt # passed as argument
#=> true
$ my_executable < file1.txt # redirected to stdin
#=> true
$ my_executable
#=> false
So I took all three currently suggested solutions:
p (not STDIN.tty? and not STDIN.closed?)
p ARGF.filename
p ARGF.pos
and saw that none of them actually works:
$ ruby temp.rb
false
"-"
36471287
$ ruby temp.rb temp.rb
false
"temp.rb"
0
$ echo 123 | ruby temp.rb
true
"-"
temp.rb:3:in `pos': Illegal seek # rb_io_tell - <STDIN> (Errno::ESPIPE)
from temp.rb:3:in `<main>'
because to assume the ability to call the ARGF.read you want to get false/true/true.
So I suppose you have to combine them:
!STDIN.tty? && !STDIN.closed? || ARGF.filename != ?-

Ruby 'script = $0'

I was looking at a Ruby script and I came across script = $0. I have done some Googling but I have not found a definite answer as to what this does. I believe that it protects you from reading a file bigger than memory, is that correct?
Thanks, I have the full script below so you can see it in context:
# Takes the name of a file as an argument and assigns to filename
filename = ARGV.first
script = $0
puts "We're going to erase #{filename}."
puts "If you don't want that, hit CTRL-C (^C)."
puts "If you do want that, hit RETURN."
print "? "
STDIN.gets
puts "Opening the file..."
target = File.open(filename, 'w')
puts "Truncating the file. Goodbye!"
target.truncate(target.size)
puts "Now I'm going to ask you for three lines."
print "line 1: "; line1 = STDIN.gets.chomp()
print "line 2: "; line2 = STDIN.gets.chomp()
print "line 3: "; line3 = STDIN.gets.chomp()
puts "I'm going to write these to the file."
target.write(line1)
target.write("\n")
target.write(line2)
target.write("\n")
target.write(line3)
target.write("\n")
puts "And finally, we close it."
target.close()
$0 is one of Ruby's global variables. From here:
$0 -- Contains the name of the script being executed. May be assignable.
Oh the classic Zed Shaw books! lol
The $0 gets the input on the command line before the first argument. So say you were to run this through the command line using the ruby interpreter you could put "ruby (fileName) test.txt" and $0 will pick up the fileName and save it to the variable 'script'. I'm not really sure why your doing it here because you do use it later in the program, but that's it.
The way you could have tested this would be to print it on the screen using puts, perhaps add this bit of code to see it yourself somewhere in the code:
puts "The $0 has saved #{script} to it, I wonder where it got that."
and see it will name your file.

Best practices with STDIN in Ruby? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question last month and left it closed:
Original close reason(s) were not resolved
Improve this question
I want to deal with the command line input in Ruby:
> cat input.txt | myprog.rb
> myprog.rb < input.txt
> myprog.rb arg1 arg2 arg3 ...
What is the best way to do it? In particular I want to deal with blank STDIN, and I hope for an elegant solution.
#!/usr/bin/env ruby
STDIN.read.split("\n").each do |a|
puts a
end
ARGV.each do |b|
puts b
end
Following are some things I found in my collection of obscure Ruby.
So, in Ruby, a simple no-bells implementation of the Unix command
cat would be:
#!/usr/bin/env ruby
puts ARGF.read
— https://web.archive.org/web/20080725055721/http://www.oreillynet.com/ruby/blog/2007/04/trivial_scripting_with_ruby.html#comment-565558
ARGF is your friend when it comes to input; it is a virtual file that gets all input from named files or all from STDIN.
ARGF.each_with_index do |line, idx|
print ARGF.filename, ":", idx, ";", line
end
# print all the lines in every file passed via command line that contains login
ARGF.each do |line|
puts line if line =~ /login/
end
Thank goodness we didn’t get the diamond operator in Ruby, but we did
get ARGF as a replacement. Though obscure, it actually turns out to
be useful. Consider this program, which prepends copyright headers
in-place (thanks to another Perlism, -i) to every file mentioned on
the command-line:
#!/usr/bin/env ruby -i
Header = DATA.read
ARGF.each_line do |e|
puts Header if ARGF.pos - e.length == 0
puts e
end
__END__
#--
# Copyright (C) 2007 Fancypants, Inc.
#++
— http://blog.nicksieger.com/articles/2007/10/06/obscure-and-ugly-perlisms-in-ruby
Credit to:
https://web.archive.org/web/20080725055721/http://www.oreillynet.com/ruby/blog/2007/04/trivial_scripting_with_ruby.html#comment-565558
http://blog.nicksieger.com/articles/2007/10/06/obscure-and-ugly-perlisms-in-ruby
Ruby provides another way to handle STDIN: The -n flag. It treats your entire program as being inside a loop over STDIN, (including files passed as command line args). See e.g. the following 1-line script:
#!/usr/bin/env ruby -n
#example.rb
puts "hello: #{$_}" #prepend 'hello:' to each line from STDIN
#these will all work:
# ./example.rb < input.txt
# cat input.txt | ./example.rb
# ./example.rb input.txt
I am not quite sure what you need, but I would use something like this:
#!/usr/bin/env ruby
until ARGV.empty? do
puts "From arguments: #{ARGV.shift}"
end
while a = gets
puts "From stdin: #{a}"
end
Note that because ARGV array is empty before first gets, Ruby won't try to interpret argument as text file from which to read (behaviour inherited from Perl).
If stdin is empty or there is no arguments, nothing is printed.
Few test cases:
$ cat input.txt | ./myprog.rb
From stdin: line 1
From stdin: line 2
$ ./myprog.rb arg1 arg2 arg3
From arguments: arg1
From arguments: arg2
From arguments: arg3
hi!
From stdin: hi!
Something like this perhaps?
#/usr/bin/env ruby
if $stdin.tty?
ARGV.each do |file|
puts "do something with this file: #{file}"
end
else
$stdin.each_line do |line|
puts "do something with this line: #{line}"
end
end
Example:
> cat input.txt | ./myprog.rb
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb < input.txt
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb arg1 arg2 arg3
do something with this file: arg1
do something with this file: arg2
do something with this file: arg3
while STDIN.gets
puts $_
end
while ARGF.gets
puts $_
end
This is inspired by Perl:
while(<STDIN>){
print "$_\n"
}
Quick and simple:
STDIN.gets.chomp == 'YES'
You can also use STDIN.each_line, and STDIN.each_line.to_a to get it as an array.
e.g.
STDIN.each_line do |line|
puts line
end
I'll add that in order to use ARGF with parameters, you need to clear ARGV before calling ARGF.each. This is because ARGF will treat anything in ARGV as a filename and read lines from there first.
Here's an example 'tee' implementation:
File.open(ARGV[0], 'w') do |file|
ARGV.clear
ARGF.each do |line|
puts line
file.write(line)
end
end
I do something like this :
all_lines = ""
ARGV.each do |line|
all_lines << line + "\n"
end
puts all_lines
It seems most answers are assuming the arguments are filenames containing content to be cat'd to the stdin. Below everything is treated as just arguments. If STDIN is from the TTY, then it is ignored.
$ cat tstarg.rb
while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
puts a
end
Either arguments or stdin can be empty or have data.
$ cat numbers
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5

Resources