Back to the designated point with anchor - ruby

How can i do stuff like that in ruby:
# => ANCHOR GO BACK HERE
...some code
f = 0
while f == 0
... some code
f = 1
end
# if [condition] => ANCHOR FROM HERE
It's sth like goto in pascal i belive, but i'm not sure.
I want to go back to the "Anchor" in code when certain condition happen.
Could somebody help me with that?

One way to do this is with a loop:
loop do
# ...some code
f = 0
while f == 0
... some code
f = 1
end
break unless some_condition
end
So, the loop will continue unless the condition is met.

Related

The syntax about While loop in Ruby

I'm practicing the While Loop in Ruby and got a basic example as below
i = 3
while i > 0 do
print i
i -= 1
end
My question is why I can't interchange do..end with {} as if I rewrite the above code as below it doesn't work anymore
i = 3
while i > 0 {
print i
i -= 1
}
However, it seems to work without the first "do"
i = 3
while i > 0
print i
i -= 1
end
Could anyone explain the rule or redirect me to the right resource? Thx!
As you said do is optional for while loop. While keyword is enough to define a block which is finished with end like any other block in ruby. In addition, end is mandatory for while block.
If you want to use while on just one line you can do such as below:
i = 0
i += 1 while i < 10
While mandatory needs end in Ruby.
Syntax example
do is optional and can be omitted.
So, it is not the case where pair do - end can be replaced with {}

What's the difference between `until` and `until do` loops in Ruby?

c = 5
until c == 0 do
print c
c -= 1
end
/break
c = 5
until c == 0
print c
c -= 1
end
What's the difference?
Both of them display 54321 as output.
do is optional. It indicates the beginning of the block of code to be repeatedly executed.
In your example it makes no difference. However if you try re-writing the code in one line, you can see why its needed:
c = 5
until c == 0 do print c; c -= 1 end
# 54321 => nil
Now try this without do:
c = 5
until c == 0 print c; c -= 1 end
# SyntaxError: (irb):115: syntax error, unexpected tIDENTIFIER, expecting keyword_do_cond or ';' or '\n'
As you can see there is no clear beginning for block, Ruby will throw a SyntaxError.
There is no difference between until and until do. Do is optional and both will show same output. If want to get some more idea about this while and while do
There is absolutely no difference. It is like the while [condition] [block] end vs while [condition] do [block] end or if [condition] [block] end vs if [condition] then [block] end.
In Ruby, often there are tons of ways of doing the same thing - the important is to be consistent, either way.

Ruby Multiple AND Evaluations For Integer Value

I have, on a few occasions, found myself needing to write a rather verbose if statement in some ruby scripts.
The statement would look something like this:
if long_var_name == 0 && very_different_name == 0 && other_third_var == 0 && additional_variable == 0 && name_five == 0 && longest_variable_name_six == 0
# (possibly even more conditions)
# do stuff here...
end
It seems like there has to be a more elegant way to do this.
The problem is, if and and aren't exactly easy to research with google, as basic english words. So I've come up empty-handed.
Does anyone know a way to shorten this kind of situation?
It can become a nightmare to read when you have even more of them.
Sometimes variable renaming isn't an option.
The names are sometimes vastly different.
Note: I found a clever solution for similar situations with OR:
Ruby Multiple OR Evaluations For String Value
If you have an array and are specifically testing for zero, you can do:
vars1 = [0,0,3,0,0]
vars2 = [0,0,0,0,0]
vars1.all?(&:zero?) # false
vars2.all?(&:zero?) # true
EDIT: Based on OP's added conditions of having different names for the values:
if [long_var_name_1,long_var_name_2,long_var_name_3].all?(&:zero?)
# do stuff here...
end
In your specific case, I would write
if [a, b, c, d, e, f].all? { |var| var == 0 }
There's noting wrong about chaining and conditions IMHO.
Have you thought of breaking it up into logic expressions? Basically break it up into smaller bits of logical groupings and its easier to read e.g.
grp_1_zero = var_1 == 0 && var_2 == 0 && var_3 == 0
grp_2_zero = var_a == 0 && var_b == 0 && var_c == 0
grp_3_zero = var_z == 0 && var_x == 0 && var_y == 0
if grp_1_zero && grp_2_zero && grp_3_zero
#code here
end
Another, for array a:
a == Array.new(a.size,0)
You can use Enumerable#all? and the Symbol#to_proc utilisation of the Fixnum#zero? method.
foo = 0
bar = 0
baz = 0
[foo, bar, baz].all? &:zero?
# => true
one = 1
two = 2
[foo, one, two].any? &:zero?
#=> true
Note that you can also provide any anonymous function for the test.
owns_peanuts = ->(person){ person.inventory.contains :peanuts }
[bill, david, mike].any? &owns_peanuts

Reservation System

Can anyone please tell me what I should be using and why this method isn't correct? The code doesn't work, I know, I just want to know how I can interface with the array for this type of thing.
Thank you.
Code:
$i = 1
$f = 0
$c = 0
answer = ""
loop do
puts "Welcome\n"
puts "If you'd like to fly in first class, Press 1. For coach, Push 2."
answer = STDIN.gets
answer.chop!
break if answer =~ /1|2/
if answer == 1 then
$i += 1.each
$available.at(0..4)
end
if answer == 2 then
$i += 1.each
$available.at(5..19)
else
puts "Invalid number, enter 1 or 2."
Console_Screen.pause
end
end
puts "Here is your boarding pass. You are in seat " + $i.to_s
For first class, you can do something like this:
next_first = (0..4).find { |i| $available[i] != 1 }
If that gives you a next_available that is nil then first class is full, otherwise you have the index of the next available first class seat.
Similarly for coach:
next_coach = (5..19).find { |i| $available[i] != 1 }
Then once you have the index, have checked that it isn't nil, and stored it in $i, just $available[$i] = 1 to reserve the seat.
And an extra hint for free, this:
answer = STDIN.gets
answer.chop!
leaves a string in answer so answer == 1 will always be false.
References:
Enumerable#find
The problem seems to be here:
break if answer =~ /1|2/
This means "stop and leave the loop entirely if if we get a 1 or 2"
ie it means that none of your code that does seat-allocation gets executed if the person actually enters something valid (ie a 1 or 2).
After that comes the errors pointed out by #mu_is_too_short above.

Is there a "do ... while" loop in Ruby?

I'm using this code to let the user enter in names while the program stores them in an array until they enter an empty string (they must press enter after each name):
people = []
info = 'a' # must fill variable with something, otherwise loop won't execute
while not info.empty?
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end
This code would look much nicer in a do ... while loop:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
In this code I don't have to assign info to some random string.
Unfortunately this type of loop doesn't seem to exist in Ruby. Can anybody suggest a better way of doing this?
CAUTION:
The begin <code> end while <condition> is rejected by Ruby's author Matz. Instead he suggests using Kernel#loop, e.g.
loop do
# some code here
break if <condition>
end
Here's an email exchange in 23 Nov 2005 where Matz states:
|> Don't use it please. I'm regretting this feature, and I'd like to
|> remove it in the future if it's possible.
|
|I'm surprised. What do you regret about it?
Because it's hard for users to tell
begin <code> end while <cond>
works differently from
<code> while <cond>
RosettaCode wiki has a similar story:
During November 2005, Yukihiro Matsumoto, the creator of Ruby, regretted this loop feature and suggested using Kernel#loop.
I found the following snippet while reading the source for Tempfile#initialize in the Ruby core library:
begin
tmpname = File.join(tmpdir, make_tmpname(basename, n))
lock = tmpname + '.lock'
n += 1
end while ##cleanlist.include?(tmpname) or
File.exist?(lock) or File.exist?(tmpname)
At first glance, I assumed the while modifier would be evaluated before the contents of begin...end, but that is not the case. Observe:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
As you would expect, the loop will continue to execute while the modifier is true.
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
While I would be happy to never see this idiom again, begin...end is quite powerful. The following is a common idiom to memoize a one-liner method with no params:
def expensive
#expensive ||= 2 + 2
end
Here is an ugly, but quick way to memoize something more complex:
def expensive
#expensive ||=
begin
n = 99
buf = ""
begin
buf << "#{n} bottles of beer on the wall\n"
# ...
n -= 1
end while n > 0
buf << "no more bottles of beer"
end
end
Originally written by Jeremy Voorhis. The content has been copied here because it seems to have been taken down from the originating site. Copies can also be found in the Web Archive and at Ruby Buzz Forum. -Bill the Lizard
Like this:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
Reference: Ruby's Hidden do {} while () Loop
How about this?
people = []
until (info = gets.chomp).empty?
people += [Person.new(info)]
end
Here's the full text article from hubbardr's dead link to my blog.
I found the following snippet while reading the source for Tempfile#initialize in the Ruby core library:
begin
tmpname = File.join(tmpdir, make_tmpname(basename, n))
lock = tmpname + '.lock'
n += 1
end while ##cleanlist.include?(tmpname) or
File.exist?(lock) or File.exist?(tmpname)
At first glance, I assumed the while modifier would be evaluated before the contents of begin...end, but that is not the case. Observe:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
As you would expect, the loop will continue to execute while the modifier is true.
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
While I would be happy to never see this idiom again, begin...end is quite powerful. The following is a common idiom to memoize a one-liner method with no params:
def expensive
#expensive ||= 2 + 2
end
Here is an ugly, but quick way to memoize something more complex:
def expensive
#expensive ||=
begin
n = 99
buf = ""
begin
buf << "#{n} bottles of beer on the wall\n"
# ...
n -= 1
end while n > 0
buf << "no more bottles of beer"
end
end
This works correctly now:
begin
# statment
end until <condition>
But, it may be remove in the future, because the begin statement is counterintuitive. See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745
Matz (Ruby’s Creator) recommended doing it this way:
loop do
# ...
break if <condition>
end
From what I gather, Matz does not like the construct
begin
<multiple_lines_of_code>
end while <cond>
because, it's semantics is different than
<single_line_of_code> while <cond>
in that the first construct executes the code first before checking the condition,
and the second construct tests the condition first before it executes the code (if ever). I take it Matz prefers to keep the second construct because it matches one line construct of if statements.
I never liked the second construct even for if statements. In all other cases, the computer
executes code left-to-right (eg. || and &&) top-to-bottom. Humans read code left-to-right
top-to-bottom.
I suggest the following constructs instead:
if <cond> then <one_line_code> # matches case-when-then statement
while <cond> then <one_line_code>
<one_line_code> while <cond>
begin <multiple_line_code> end while <cond> # or something similar but left-to-right
I don't know if those suggestions will parse with the rest of the language. But in any case
I prefere keeping left-to-right execution as well as language consistency.
a = 1
while true
puts a
a += 1
break if a > 10
end
Here's another one:
people = []
1.times do
info = gets.chomp
unless info.empty?
people += [Person.new(info)]
redo
end
end
ppl = []
while (input=gets.chomp)
if !input.empty?
ppl << input
else
p ppl; puts "Goodbye"; break
end
end

Resources