[from BASIC to Ruby] so, what's the proper way to replace funcionality of GOTO?

I need to make few scripts for tasks I do often manually, but last time
I programmed something was almost 20 years ago in high school, we used
some BASIC dialect. Since no one uses BASIC nowdays, I decided to give a
try to Ruby (I also tried Python, but it's strict indentation is driving
me insane).

I watched Ruby Essentials Video from Lynda.com (twice), and I pretty
much understand almost all of it, but still, I'm having trouble to adapt
how to structure my programs (without using of GOTO)

Here's a simple example written in FreeBASIC (it works)

···

---------------------------------------------------------------------
Dim As Integer strKeyPress

menu_00:

CLS
PRINT "what do you desire:"
PRINT
PRINT "1 - open menu_01"
PRINT "2 - open menu_02"
PRINT "3 - open menu_03"
PRINT "4 - open menu_04"
PRINT "q - Quit"

REM is comment line, same as ' ... code for Q is 81, q = 113

Do
  strKeyPress = GetKey
Loop Until strKeyPress <> 0

'49 represents number 1 on a keybord, and so on

if strKeyPress = 49 THEN
  goto menu_01
elseif strKeyPress = 50 THEN
  goto menu_02
elseif strKeyPress = 51 THEN
  goto menu_03
elseif strKeyPress = 52 THEN
  goto menu_04
elseif strKeyPress = 81 or strKeyPress = 113 THEN
  goto programendshere
else
  print
  print "Wrong Choice, Try Again!"
  sleep 1000

menu_00_endif:
end if

goto menu_00

menu_01:
  cls
  print
  print "menu 01"
  sleep 1000
  goto menu_00_endif
menu_02:
  cls
  print
  print "menu 02"
  sleep 1000
  goto menu_00_endif
menu_03:
  cls
  print
  print "menu 03"
  sleep 1000
  goto menu_00_endif
menu_04:
  cls
  print
  print "menu 04"
  sleep 1000
  goto menu_00_endif

programendshere:

End 0
------------------------------------------------------------------

So, what would be the best practice to make this work in modern
languages, like Ruby ? Here are some ideas I have, would be nice to know
if it's good thinking or wrong:

1- make all menues part of a same Class, so I can use instance variables
(I will need to do some calculations)

2- define every menu as separate method, so you travel from root
menu_00 (method) --> menu_01 (which is separate method) --> ... etc go
back and forth ... #could this be memory demanding if there is too many
sub-menu branching ???

3- define every menu as separate method, but you DO NOT start new method
from INSIDE of other method. It goes something like this: menu_00
returns value to a loop, that value is name of sub-menu (menu_01,
separate method) ... I'd then have to use -->
method(name_of_returned_value).call()
This looks better than option #2, but my attempts to make it work so far
failed ... not sure if it is even possible to achieve at all

4- every menu is separate method, but they only have puts "enter choice"
lines, no other code, and a $global variable which I will use later in
IF loops to detect inside which menu (method) I am:

if $global == "00" and userInputChoice == "1"
  #if you are currently inside root menu 00, and user input is "1"
  menu_01()
  $global = "01"
  ... etc

I think this could easily work, though, might not look nice
.................................................................

So basically, I'd like to know which way should I go for, 2,3 or 4, or
there is maybe even something else? And, also is idea #1 ok ?

I hope this wasn't too long to read for my first question here, starting
something new is always hardest part for me

--
Posted via http://www.ruby-forum.com/.

Stu P. D'naim wrote in post #1097111:

I need to make few scripts for tasks I do often manually, but last time
I programmed something was almost 20 years ago in high school, we used
some BASIC dialect. Since no one uses BASIC nowdays, I decided to give a
try to Ruby (I also tried Python, but it's strict indentation is driving
me insane).

I watched Ruby Essentials Video from Lynda.com (twice), and I pretty
much understand almost all of it, but still, I'm having trouble to adapt
how to structure my programs (without using of GOTO)

Here's a simple example written in FreeBASIC (it works)
---------------------------------------------------------------------
Dim As Integer strKeyPres

Yes, It has. You can try "catch - throw" in Ruby's world.

Thanks

···

--
Posted via http://www.ruby-forum.com/\.

Be careful saying "no one uses BASIC nowdays". I have no doubt there is
a subset of people out there still using BASIC. =)

···

--
Posted via http://www.ruby-forum.com/.

There is no one way to replace GOTO. GOTO is at the heart of many structured control structures. What you need to do is think about what you are trying to do and where you are trying to go when you are done.

In your code, you have: "goto menu_01". After the sequence of statements starting at the menu_01 label, you have: "goto menu_00_endif". If you returned from your sequence to the goto, you would have a subroutine. I'm not familiar with FreeBASIC, but in Commodore BASIC, you could replace your GOTO with GOSUB and the GOTO at the end of the sequence with RETURN. That would eliminate the need for the "menu_00_endif" label. This is a subroutine and can be replaced by a method in Ruby. I think in FreeBASIC, your sub may be defined as follows:

' I think "goto menu_01" may be replaced by
Menu_01()

' and the subroutine by
Sub Menu_01
   ...
End Sub

You also have a "goto menu_00" after the "End If" statement. The menu_00 and its goto can be replaced with a loop.

Using a while loop would be a good idea. The loop using goto menu_00 is an infinite loop, but you use "goto programendshere" to exit it. By setting a condition variable for the loop, you can exit the loop by changing the variable. I'm taking a guess at the FreeBASIC grammar here:

    stillChoosing = True
    Do While stillChoosing
      ...
      ElseIf strKeyPress = 81 Or strKeyPress = 113 Then
        stillChoosing = False
      Else
     ...
    Loop

It looks like your code is somewhat structured already. You just need to learn how control structures are built from gotos and other statements to properly replace them.

Finally, since all you your menus will have the same structure, it make sense that you can replace multiple subroutines with just one. You can pass the text of each menu and return the result. (In Basic, that will make it a Function rather than a Sub, I believe! But either way, it would be a Method in Ruby.)

Putting all that together in Ruby might look something like this:

# Displays a menu and gets a response back.
def showMenu menuText
  # Display the menu
  puts menuText
  puts
  # Display a prompt
  print "What do you desire? "

  # Get a string as a response. (The user will have to press enter, unlike your example.)
  # chomp removes a newline from the end of the string
  # downcase makes the string lowercase so "Q" and "q" are returned as "q"
  gets.chomp.downcase
end

# Here I am putting the menu text in a long string.
menu_00 = %q{menu 00

1 - open menu_01
2 - open menu_02
3 - open menu_03
4 - open menu_04
q - Quit}

# The same can be done for these when they are fleshed out
menu_01 = "menu 01"
menu_02 = "menu 02"
menu_03 = "menu 03"
menu_04 = "menu 04"

stillChoosing = true
while stillChoosing do
  case showMenu(menu_00)
    when "1"
      response = showMenu(menu_01)
      # do something with response here
    when "2"
      response = showMenu(menu_02)
      # do something with response here
    when "3"
      response = showMenu(menu_03)
      # do something with response here
    when "4"
      response = showMenu(menu_04)
      # do something with response here
    when "q"
      stillChoosing = false
    else
      puts "Wrong Choice, Try Again!"
      puts
  end
end

···

-----Original Message-----
From: Stu P. D'naim [mailto:lists@ruby-forum.com]
Sent: Friday, February 15, 2013 11:32 AM
To: ruby-talk ML
Subject: [from BASIC to Ruby] so, what's the proper way to replace funcionality of GOTO ?

I need to make few scripts for tasks I do often manually, but last time
I programmed something was almost 20 years ago in high school, we used
some BASIC dialect. Since no one uses BASIC nowdays, I decided to give a
try to Ruby (I also tried Python, but it's strict indentation is driving
me insane).

I watched Ruby Essentials Video from Lynda.com (twice), and I pretty
much understand almost all of it, but still, I'm having trouble to adapt
how to structure my programs (without using of GOTO)

Here's a simple example written in FreeBASIC (it works)
---------------------------------------------------------------------
Dim As Integer strKeyPress

menu_00:

CLS
PRINT "what do you desire:"
PRINT
PRINT "1 - open menu_01"
PRINT "2 - open menu_02"
PRINT "3 - open menu_03"
PRINT "4 - open menu_04"
PRINT "q - Quit"

REM is comment line, same as ' ... code for Q is 81, q = 113

Do
  strKeyPress = GetKey
Loop Until strKeyPress <> 0

'49 represents number 1 on a keybord, and so on

if strKeyPress = 49 THEN
  goto menu_01
elseif strKeyPress = 50 THEN
  goto menu_02
elseif strKeyPress = 51 THEN
  goto menu_03
elseif strKeyPress = 52 THEN
  goto menu_04
elseif strKeyPress = 81 or strKeyPress = 113 THEN
  goto programendshere
else
  print
  print "Wrong Choice, Try Again!"
  sleep 1000

menu_00_endif:
end if

goto menu_00

menu_01:
  cls
  print
  print "menu 01"
  sleep 1000
  goto menu_00_endif
menu_02:
  cls
  print
  print "menu 02"
  sleep 1000
  goto menu_00_endif
menu_03:
  cls
  print
  print "menu 03"
  sleep 1000
  goto menu_00_endif
menu_04:
  cls
  print
  print "menu 04"
  sleep 1000
  goto menu_00_endif

programendshere:

End 0
------------------------------------------------------------------

So, what would be the best practice to make this work in modern
languages, like Ruby ? Here are some ideas I have, would be nice to know
if it's good thinking or wrong:

1- make all menues part of a same Class, so I can use instance variables
(I will need to do some calculations)

2- define every menu as separate method, so you travel from root
menu_00 (method) --> menu_01 (which is separate method) --> ... etc go
back and forth ... #could this be memory demanding if there is too many
sub-menu branching ???

3- define every menu as separate method, but you DO NOT start new method
from INSIDE of other method. It goes something like this: menu_00
returns value to a loop, that value is name of sub-menu (menu_01,
separate method) ... I'd then have to use -->
method(name_of_returned_value).call()
This looks better than option #2, but my attempts to make it work so far
failed ... not sure if it is even possible to achieve at all

4- every menu is separate method, but they only have puts "enter choice"
lines, no other code, and a $global variable which I will use later in
IF loops to detect inside which menu (method) I am:

if $global == "00" and userInputChoice == "1"
  #if you are currently inside root menu 00, and user input is "1"
  menu_01()
  $global = "01"
  ... etc

I think this could easily work, though, might not look nice
.................................................................

So basically, I'd like to know which way should I go for, 2,3 or 4, or
there is maybe even something else? And, also is idea #1 ok ?

I hope this wasn't too long to read for my first question here, starting
something new is always hardest part for me

--
Posted via http://www.ruby-forum.com/.

hash inside hash menus, interesting, same as Robert Klemme's example ...
thank you all guys, now I have more than enough ideas how to start my
script

···

--
Posted via http://www.ruby-forum.com/.

Love U Ruby: I'm really not sure what you meant by that response, but
it's irrelevant and inaccurate (there is no catch in Ruby, it's rescue)...

To answer the OP's question, you'd probably want to first pick up a good
book on Ruby (or one of the many tutorials online). You're probably
going to want to look into first creating methods where you normally had
headers in your BASIC code and replacing the GOTO declarations with just
the method name. I'd also take a look at the "case...when" syntax to
replace your if statements. Switching to an object oriented language
from BASIC is tough but not impossible, especially if you're just
replacing some utility scripts. I'm sure there's a "menu" gem out there
too somewhere.

Hopefully that cleared up at least something,
Ryan Victory

···

On 2/15/13 10:37 AM, Love U Ruby wrote:

Stu P. D'naim wrote in post #1097111:

I need to make few scripts for tasks I do often manually, but last time
I programmed something was almost 20 years ago in high school, we used
some BASIC dialect. Since no one uses BASIC nowdays, I decided to give a
try to Ruby (I also tried Python, but it's strict indentation is driving
me insane).

I watched Ruby Essentials Video from Lynda.com (twice), and I pretty
much understand almost all of it, but still, I'm having trouble to adapt
how to structure my programs (without using of GOTO)

Here's a simple example written in FreeBASIC (it works)
---------------------------------------------------------------------
Dim As Integer strKeyPres

Yes, It has. You can try "catch - throw" in Ruby's world.

Thanks

Charles Caldwell wrote in post #1097135:

Be careful saying "no one uses BASIC nowdays". I have no doubt there is
a subset of people out there still using BASIC. =)

Actually I like FreeBASIC, it's cross-platform, syntax I'm somewhat
familiar with ... but it lacks tutorials, books, videos etc .. also,
Ruby has
much more string manipulation methods (which I need for my script).

And I know there is not GOTO in Ruby, I was asking for advice how should
I re-write code I posted above in a Ruby way ? Looks like no one read
entire original post :frowning: ... (but I don't blame you, it's really long)

···

--
Posted via http://www.ruby-forum.com/\.

WILLS, JAMAL A wrote in post #1097138:

def showMenu menuText
  puts menuText
  puts
  print "What do you desire? "

menu_00 = %q{menu 00

1 - open menu_01
2 - open menu_02
3 - open menu_03
4 - open menu_04
q - Quit}

Firstly, I know what are Functions/Methods, but I find GOTO much easier
to follow (and also more powrfull, because I can RETURN wherever I want
- in GOSUB, and Functions, you always return to the point you started
from)

Secondly, this is great idea, to put entire menu in one long string. I
wouldn't have thought of that !! Thanks !

I had idea (as described in original post at #2) to write code something
like this:

···

------------------------------------------------
class Mymenus

  attr_acessor :over100variablesIintendtoUse

  def initialize
  #initialize every variable
  end

  def menu_00 #root menu
    system("cls")
    puts "Select something:"
    puts
    puts "1 - open menu_1"
    puts "2 - open menu_2"
    puts "3 - open menu_3"
    puts "4 - open menu_4"
    puts "q - Quit"
  end

  def menu_1
  system("cls")
  puts "enter choice:"
  puts
  puts "1 - open menu_11"
  puts "2 - open menu_12"
  puts "3 - open menu_13"
  puts "4 - open menu_14"
  puts "b - Back"
  end

  def menu_2
  system("cls")
  puts "enter choice:"
  puts
  puts "1 - open menu_21"
  puts "2 - open menu_22"
  puts "b - Back"
  end

... etc ... etc
---------------------------------------------------------
... and then probably put loop, starting with root menu, when you select
number, you call new method (submenu) ... but your way seems easier, and
with less methods involved

--
Posted via http://www.ruby-forum.com/\.

hash inside hash menus, interesting, same as Robert Klemme's example ...

There is one difference: I created a class while the other example
uses nested Hashes. Frankly, since with Ruby it is so easy to create
classes, I do not understand why people go about to suggest creating
nested structures of Hash and Array combinations. Look at this
example:

@commands = {
  '1' => {
    :menu => "Thing 1",
    :action => lambda {thing1}},
  '2' => {
    :menu => "Thing 2",
    :action => lambda {thing2}},
  '0' => {
    :menu => "Quit",
    :action => lambda { :done }}

}

It shows quite obviously that there are "things" which always have a
"menu" (or rather a name) and an "action". Why then not just create a
class for that?

Thing = Struct.new :menu, :action

etc.

thank you all guys, now I have more than enough ideas how to start my
script

Good!

Kind regards

robert

···

On Sat, Feb 16, 2013 at 2:03 PM, Stu P. D'naim <lists@ruby-forum.com> wrote:
On Sat, Feb 16, 2013 at 8:30 AM, tamouse mailing lists <tamouse.lists@gmail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Ryan Victory wrote in post #1097114:

Love U Ruby: I'm really not sure what you meant by that response, but
it's irrelevant and inaccurate (there is no catch in Ruby, it's
rescue)...

before going to challenge other you should "GOOGLE" - here I did for
you.

Please read it : http://www.devalot.com/articles/2012/03/ruby-goto

···

--
Posted via http://www.ruby-forum.com/\.

Baseline - you are certainly free to move to classes or any other concepts
you want to add on - but this would be a starting point

#!/usr/bin/ruby

def handle1
  puts 'Got 01'
end

def handle2
  puts 'Got 02'
end

def handleq
  @cont = 0
end

@cont = 1

while @cont == 1
  puts 'Pick an option'
  choice = gets.strip
  case choice
  when '1'
    handle1
  when '2'
    handle2
  when 'q'
    handleq
  end
end

John

P.S. Probably the trickiest thing in there for you is the gets.strip - ruby
will give you back the newline character when the person hits enter #strip
removes the last character from the string (newline character).

···

On Fri, Feb 15, 2013 at 9:49 AM, Stu P. D'naim <lists@ruby-forum.com> wrote:

And I know there is not GOTO in Ruby, I was asking for advice how should
I re-write code I posted above in a Ruby way ? Looks like no one read
entire original post :frowning: ... (but I don't blame you, it's really long)

--

Posted via http://www.ruby-forum.com/\.

Firstly, I know what are Functions/Methods, but I find GOTO much easier
to follow (and also more powrfull, because I can RETURN wherever I want
- in GOSUB, and Functions, you always return to the point you started
from)

Where's the difference? With a GOSUB the RETURN will also take you to
the calling site. That's the whole point of GOSUB vs. GOTO. What
makes GOSUB worse than functions is that you do not get a new scope
and do not have function arguments. So you always risk messing up the
caller's scope. Granted, more modern dialects of BASIC might have
mechanisms to deal with that (it's been a while I worked with BASIC -
and I wouldn't got back unless for experimental purposes).

I had idea (as described in original post at #2) to write code something
like this:
------------------------------------------------
class Mymenus

  attr_acessor :over100variablesIintendtoUse

  def initialize
  #initialize every variable
  end

  def menu_00 #root menu
    system("cls")
    puts "Select something:"
    puts
    puts "1 - open menu_1"
    puts "2 - open menu_2"
    puts "3 - open menu_3"
    puts "4 - open menu_4"
    puts "q - Quit"
  end

  def menu_1
  system("cls")
  puts "enter choice:"
  puts
  puts "1 - open menu_11"
  puts "2 - open menu_12"
  puts "3 - open menu_13"
  puts "4 - open menu_14"
  puts "b - Back"
  end

  def menu_2
  system("cls")
  puts "enter choice:"
  puts
  puts "1 - open menu_21"
  puts "2 - open menu_22"
  puts "b - Back"
  end

... etc ... etc
---------------------------------------------------------
... and then probably put loop, starting with root menu, when you select
number, you call new method (submenu) ... but your way seems easier, and
with less methods involved

I do not know what your menus will do eventually but I would certainly
make this more data driven. In this example the structure of the code
is identical for all menu entries. There is no if else cascade or
case statement. The proper item is just determined via the position
in the Array:

Menu = Struct.new :name, :code

# convenience method to create a Menu instance
def menu(name, &b)
  Menu.new name, b
end

menus = [
  menu("Configuration") do
    print "Starting configuration..."
    sleep 5
    puts " done."
  end ,

  menu("Reset everything") do
    puts "back to square one"
  end,

  menu("Quit") do
    puts "quitting"
    exit 0
  end,
]

loop do
  puts "Enter your choice:"

  menus.each_with_index do |m, idx|
    printf "%2d %s\n", idx, m.name
  end

  print "> "
  input = gets.chomp

  begin
    m = menus[Integer(input)]

    if m
      m.code.call
    else
      puts "Wrong choice. Try again"
    end
  rescue ArgumentError
    puts "Not numeric: #{input}"
  end
end

Kind regards

robert

···

On Fri, Feb 15, 2013 at 7:17 PM, Stu P. D'naim <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

You're wrong.

···

On Feb 15, 2013, at 08:46 , Ryan Victory <ryan@raptormail.net> wrote:

Love U Ruby: I'm really not sure what you meant by that response, but
it's irrelevant and inaccurate (there is no catch in Ruby, it's rescue)...

All very true. My initial thought was to refrain from jumping directly
Classes, but it's probably just as well.

···

On Sat, Feb 16, 2013 at 8:20 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

On Sat, Feb 16, 2013 at 2:03 PM, Stu P. D'naim <lists@ruby-forum.com> wrote:

hash inside hash menus, interesting, same as Robert Klemme's example ...

There is one difference: I created a class while the other example
uses nested Hashes. Frankly, since with Ruby it is so easy to create
classes, I do not understand why people go about to suggest creating
nested structures of Hash and Array combinations. Look at this
example:

On Sat, Feb 16, 2013 at 8:30 AM, tamouse mailing lists > <tamouse.lists@gmail.com> wrote:

@commands = {
  '1' => {
    :menu => "Thing 1",
    :action => lambda {thing1}},
  '2' => {
    :menu => "Thing 2",
    :action => lambda {thing2}},
  '0' => {
    :menu => "Quit",
    :action => lambda { :done }}

}

It shows quite obviously that there are "things" which always have a
"menu" (or rather a name) and an "action". Why then not just create a
class for that?

Thing = Struct.new :menu, :action

etc.

thank you all guys, now I have more than enough ideas how to start my
script

Good!

Kind regards

robert

I did consider jokingly showing the "enable jokes" compiler flag that
turned on the __goto__ method...I'm actually slightly horrified that
Ruby has anything resembling goto for hopping around in code. I'll
concede that I did not know about this, however I'll stand by the idea
that it's terrible coding practice (except for in very particular
circumstances where goto is the most elegant solution).

Either way, your original suggestion is just bad advice. I'll stand by that.

-Ryan

···

On 2/15/13 10:56 AM, Love U Ruby wrote:

Ryan Victory wrote in post #1097114:

Love U Ruby: I'm really not sure what you meant by that response, but
it's irrelevant and inaccurate (there is no catch in Ruby, it's
rescue)...

before going to challenge other you should "GOOGLE" - here I did for
you.

Please read it : http://www.devalot.com/articles/2012/03/ruby-goto

Yeah, I realized that...still doesn't make him right :slight_smile:

-Ryan

···

On 2/15/13 3:47 PM, Ryan Davis wrote:

On Feb 15, 2013, at 08:46 , Ryan Victory <ryan@raptormail.net> wrote:

Love U Ruby: I'm really not sure what you meant by that response, but
it's irrelevant and inaccurate (there is no catch in Ruby, it's rescue)...

You're wrong.

Ruby | zenspider.com | by ryan davis

Ryan Victory wrote in post #1097118:

I did consider jokingly showing the "enable jokes" compiler flag that
turned on the __goto__ method...I'm actually slightly horrified that
Ruby has anything resembling goto for hopping around in code. I'll
concede that I did not know about this, however I'll stand by the idea
that it's terrible coding practice (except for in very particular
circumstances where goto is the most elegant solution).

Either way, your original suggestion is just bad advice. I'll stand by
that.

-Ryan

OP asked is it there? I have given the reference to him- yes Ruby has. i
didn't advice him to use that. So please don't need to stand by. You
didn't aware what Ruby has, so now you got it. That's good.

chill...

···

--
Posted via http://www.ruby-forum.com/\.

I think GOTO gets a bad rap. Actually, I find the COMEFROM command far more terrifying. It's mentioned in the comments...

Jamal

···

-----Original Message-----
From: Ryan Victory [mailto:ryan@raptormail.net]
Sent: Friday, February 15, 2013 12:03 PM
To: ruby-talk ML
Subject: Re: so, what's the proper way to replace funcionality of GOTO ?

I did consider jokingly showing the "enable jokes" compiler flag that
turned on the __goto__ method...I'm actually slightly horrified that
Ruby has anything resembling goto for hopping around in code. I'll
concede that I did not know about this, however I'll stand by the idea
that it's terrible coding practice (except for in very particular
circumstances where goto is the most elegant solution).

Either way, your original suggestion is just bad advice. I'll stand by that.

-Ryan
On 2/15/13 10:56 AM, Love U Ruby wrote:

Ryan Victory wrote in post #1097114:

Love U Ruby: I'm really not sure what you meant by that response, but
it's irrelevant and inaccurate (there is no catch in Ruby, it's
rescue)...

before going to challenge other you should "GOOGLE" - here I did for
you.

Please read it : http://www.devalot.com/articles/2012/03/ruby-goto

Actually this makes him pretty much the definition of right.

···

--
Matma Rex

Well, considering the OP's question was "What's the /proper/ way to
replace functionality of GOTO" (emphasis mine), I'd say that pretty much
any rubyist would agree that a goto like structure doesn't belong in
ruby code unless it truly is the most elegant solution (escaping
multiple nested loops for example). Not that it really matters either
way, this question has been answered by somebody else and I believe the
OP is satisfied.

-Ryan

···

On 2/15/13 5:59 PM, Bartosz Dziewoński wrote:

Actually this makes him pretty much the definition of right.