Ruby 'script = $0' - ruby

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.

Related

Reading a file after writing on it

I am doing exercise 16 at learnrubythehardway.org.
The name of a file is passed as argument to the following script, which asks the user to write three lines to the file:
filename = ARGV.first
puts "Opening the file..."
target = open(filename, 'w+')
puts "Now I am 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 am 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 "Here is your new file:"
print target.read
puts "And finally we close it"
target.close
Just before closing the file I would like the user be given the opportunity to see the content of the new file, however that part of the code is not processed. Why is that?
You have to rewind the file, if you want to read what you have just written.
target.write(line3)
target.write("\n")
target.rewind
target.read
Bonus content
Use puts, it writes the newline for you.
target.puts(line3)

Reading files and asking for an input on a new line

I understand how to open and then print the content of the file. I would like to understand how to ask a second question on a new line after the txt file has been printed.
The code below prints the output of the text file, then on the same line, asks "Type the file name again:"
filename = ARGV.first
txt = open(filename)
puts "Here's your file #{filename}:"
print txt.read
print "Type the filename again: "
file_again = $stdin.gets.chomp
txt_again = open(file_again)
print txt_again.read
I would like this question to be printed on a new line after the txt file has been read.
You should use puts and not print.
The difference is that puts add a new line at the end of the output.
filename = ARGV.first
txt = open(filename)
puts "Here's your file #{filename}:"
puts txt.read // Changed Line
print "Type the filename again: "
file_again = $stdin.gets.chomp
txt_again = open(file_again)
puts txt_again.read //Changed Line

Printing $0 in different ways

Among the following ways to print $0, the first one works, yet the second one doesn't. Why?
Directly
puts "current $0 is #{$0}"
Constructing $0 variable name (motivated by javascript)
1.times {|i| puts "current $#{i} is #{$i}"}
Because the second one is looking for a variable called "$i" not "$0"
If you want to build the variable name dynamically you'd need to do something like ...
1.times {|i| puts "current $#{i} is #{eval '$'+i.to_s}"}

How do i create line breaks in ruby?

How would i put line breaks in between lines like this:
print "Hi"
print "Hi"
Because it would just output this:
HiHi
Use puts since it will automatically add a newline for you:
puts "Hi"
puts "Hi"
If you want to make an explicit newline character then you'll need to know what kind of system(s) on which your program will run:
print "Hi\n" # For UNIX-like systems including Mac OS X.
print "Hi\r\n" # For Windows.
Use line break character:
print "Hi\n"
print "Hi"
puts "\n" works also on Win/Ruby ruby 2.4.2p198
and even "\n"*4 for multiplication of new rows (by 4)
You can create a space by adding a string with only a space in it between the 2 other strings. For example:
print "Hi" + " " + "Hi"
You could avoid the two print statements and instead only use one line.
print "Hi\r\nHi"
Or if you want to use two lines then
print "Hi\r\n"
print "Hi"

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