Variable scopes with code blocks

Hello!

Novice here. I’m reading Beginning Ruby and Beginning Rails by Apres and
building both applications they walk you through. Additionally, I’m
taking courses at lynda dot com and attempting to build a simple
application myself.

That said, I’m aware of the limits you have with local variable being
incapable of accessing variables defined inside of a code block, but is
there any exception to this rule?

Example:


1.times do
File.open(“text.txt”).each {|a| puts a}
end

puts a

This where I get my error.


Is there anything I can do to ‘puts a’ that will allow it to return the
content it was passed inside of the code block?

Ultimately, I’d like to store the ‘text.txt’ as an array so I can call
.uniq! on it… But we don’t need to get into that in this thread.

I hope my question makes sense.

Thank you in advanced,
Aaron

Aaron G. wrote in post #1001620:

Hello!

Novice here. I’m reading Beginning Ruby and Beginning Rails by Apres and
building both applications they walk you through. Additionally, I’m
taking courses at lynda dot com and attempting to build a simple
application myself.

That said, I’m aware of the limits you have with local variable being
incapable of accessing variables defined inside of a code block, but is
there any exception to this rule?

Example:


1.times do
File.open(“text.txt”).each {|a| puts a}
end

puts a

This where I get my error.


Is there anything I can do to ‘puts a’ that will allow it to return the
content it was passed inside of the code block?

Code blocks can see variables in the surrounding scope:

arr = []

IO.open(‘text.txt’) do |f|
f.each do |line|
puts line
arr << line #push() the line onto the end of the array
end
end

p arr #show the array as an array, rather than outputting
#each element of the array on a separate line–
#which is what puts() does.

Note that the IO.open block will automatically close the file.

Ultimately, I’d like to store the ‘text.txt’ as an array so I can call
.uniq! on it… But we don’t need to get into that in this thread.

f = File.open(‘text.txt’)
arr = f.readlines
f.close

7stud,

Yes! Thank you. I see the logic and it works. However, it returns my
array with an unusual mark at the end of each object within… ‘/n’

The code you provided returns the following:

[“text1\n”, “text2\n”, “text3\n”]

Where is the ‘/n’ coming from?

Aaron

Aaron G. wrote in post #1001635:

7stud,

Yes! Thank you. I see the logic and it works. However, it returns my
array with an unusual mark at the end of each object within… ‘/n’

It’s a “\n” not “/n”. Whenever you hit return on your keyboard, an
invisible ‘newline’ is entered in your file. For instance, if you type:

text1

…then the file will contain:

text1\n

If you want to remove the newline, use chomp():

line.chomp! #modifies the string in the variable line

or

str = line.chomp #creates a new string with the newline removed

Also, about this:

IO.open(‘text.txt’) do |f|
f.each do |line|
puts line
arr << line #push() the line onto the end of the array
end
end

My favorite automatic-close-file block is the succinct:

IO.foreach(‘text.txt’) do |line|
puts line
end

Now something to ponder: how do ruby’s file reading methods know where
the lines in a file end?

That should have been obvious to me, as I used that method to create the
simple programs described in Chris P.s book. One of the first things
he describes is ‘gets’ and how it requires chomp to eliminate the line
break from user input.

About that…

IO.open(‘text.txt’) do |f|
f.each do |line|
puts line
arr << line #push() the line onto the end of the array
end
end

IO.open isn’t working for me, but the script runs flawlessly when I use
File.open instead. When I use IO in the code it returns this error:
`initialize’: can’t convert String into Integer (TypeError)

Is there enough of a benefit when using IO instead of File to justify
adapting the code to make it work? As I said, it works fine with
File.open.

Thanks for the stimulating conversation! I’m not sure how ruby’s file
reading methods know where the line ends. I’m not even sure how it know
where it begins yet.

Aaron G. wrote in post #1001647:

That should have been obvious to me, as I used that method to create the
simple programs described in Chris P.s book. One of the first things
he describes is ‘gets’ and how it requires chomp to eliminate the line
break from user input.

About that…

IO.open(‘text.txt’) do |f|
f.each do |line|
puts line
arr << line #push() the line onto the end of the array
end
end

IO.open isn’t working for me, but the script runs flawlessly when I use
File.open instead. When I use IO in the code it returns this error:
`initialize’: can’t convert String into Integer (TypeError)

My mistake. It should be File.open(). I was trying to come up with the
IO.foreach() block, but I couldn’t remember how to do it.

I’m not sure how ruby’s file
reading methods know where the line ends. I’m not even sure how it know
where it begins yet.

A line begins at the current position of the file pointer; when you open
a file, the pointer is at position 0. As you read characters from the
file, the file pointer moves to position 1, 2, 3, etc.

A line ends whenever ruby encounters a newline when reading the file.
Actually, a line ends whenever ruby encounters the string stored in the
variable $/, which is the “input record separator”. By default, $/ has
a value of “\n”. However, you can change that to anything you want.
Try this:

$/ = ‘HELLO WORLD’

and then read this file:

line 1
line HELLO WORLD 2
line 3
HELLO WORLD line 4
line 5 HELLO WORLD