New to Ruby - While Loop Issues in Irb

New to Ruby - While loop issues in IRB

i++ is not valid ruby. You need to do i += 1.

Edit:
See Mladen's comment as to what the parser is seeing.

Why isn't my variable getting defined, and ending this loop?

Whether or not a variable is defined depends upon not only the scope, but also on its location within the ruby script. That is, a variable is defined only if it has been defined previously within the parse, not the execution.

Here's an example:

begin
puts "Is foo defined? #{defined?(foo).inspect}" # foo is never defined here
foo ||= 1
puts "but now foo is #{foo}" # foo is always defined here
foo += 1
end while foo <= 3

Output:

Is foo defined? nil
but now foo is 1
Is foo defined? nil
but now foo is 2
Is foo defined? nil
but now foo is 3

Because foo has not been defined previously within the script on the first line of the loop, it is undefined at that point, and remains undefined, even if it is assigned to and the same line is returned to at a later point during execution.

This is why foo in the while condition of the question is always undefined:

while defined?(foo).nil? # foo is always undefined
foo = 1
end

and will loop forever. In contrast, this loop only executes once:

begin
foo = 1
end while defined?(foo).nil? # foo is defined

because foo is assigned to previously in the parse.


Edit:

Only loops that require a block seem to isolate its local variables from living outside of it. E.g. loop, upto, each, inject, map, times, etc. These all require use of the keyword do and end, or curly braces, which delimit the block. In contrast, while, until, and for do not, and so variables defined within them continue to live outside of them. This is demonstrated here:

while true
foo_while = 1
break
end
puts "foo_while: #{defined?(foo_while).inspect}"

until false
foo_until = 1
break
end
puts "foo_until: #{defined?(foo_until).inspect}"

for i in 0..2
foo_for = 1
break
end
puts "foo_for: #{defined?(foo_for).inspect}"

loop do
foo_loop = 1
break
end
puts "foo_loop: #{defined?(foo_loop).inspect}"

1.upto(2) do |i|
foo_upto = 1
break
end
puts "foo_upto: #{defined?(foo_upto).inspect}"

[1,2,3].each do |i|
foo_each = 1
break
end
puts "foo_each: #{defined?(foo_each).inspect}"

[1,2,3].inject do |i,j|
foo_inject = 1
break
end
puts "foo_inject: #{defined?(foo_inject).inspect}"

[1,2,3].map do |i|
foo_map = 1
break
end
puts "foo_map: #{defined?(foo_map).inspect}"

3.times do
foo_times = 1
break
end
puts "foo_times: #{defined?(foo_times).inspect}"

Output:

foo_while: "local-variable"
foo_until: "local-variable"
foo_for: "local-variable"
foo_loop: nil
foo_upto: nil
foo_each: nil
foo_inject: nil
foo_map: nil
foo_times: nil

Confusion with IRB output in Ruby when object#initialize is overloaded

What exactly are you trying to do? You just redefined Object.new, so there is no surprise you make everything go haywire.

You can basically get the same effect by just:

>> def Object.new
>> end
>> [press enter]
KABOOM

The reason "hi" is printed is that someone just called Object.new, probably the irb REPL loop, and it expected an object, but instead it gets gobledygook.

You can also try this:

def Object.new *args
p args
end

And you will see funny stuff. However you won't be able to quit irb or do anything useful with it after that. Again: you just broke Object.

To make some sense of it you should read this:

In Ruby, what's the relationship between 'new' and 'initialize'? How to return nil while initializing?

And then you can try this:

class Object
class << self
alias :old_new :new
end
end

Now you can do:

def Object.new *args
p args
old_new *args
end

This won't break new because you are still calling the old version of it. However you will now be printing out stuff every time someone calls new.

Ruby Loop failing to break when using gets

Just use the String#chomp method which will return the string without the new line separator:


gets_var.chomp == "stop"

https://ruby-doc.org/core-2.2.0/String.html#method-i-chomp

You can check it out manually in irb:


irb(main):011:0> gets_var = gets
test
=> test

irb(main):012:0> pp gets_var
"test\n"
=> test

There's a new line (\n) character at the end of the string. It appears always when you're using gets.

Could gets be a loop condition?

The problem that in you sample while loop will break when line is null, but gets.chomp will return empty string when empty line is given.

Simplest solution to use loop with explicit break

lines = []
loop do
line = gets.chomp
break if line.empty?

lines << line
end

If you would use ActiveSupport library(included with Rails) you can do one liner with presence method

lines << line while line = gets.chomp.presence


Related Topics



Leave a reply



Submit