Bill Bisco
Bill Bisco

Reputation: 129

Dynamic 'case' 'when' conditions

The following function iterates over an array MASTER_INVENTORY, and presents choices to buy. Typing 1 buys Item #1, Typing 2 buys Item #2, Typing 34 buys Item #34.

def buy_menu()
  choices = ['Go [B]ack']
  i = 1
  MASTER_INVENTORY.each do |obj| 
    choices << "[#{i}] Buy #{obj.name} Price: #{obj.price}"
    i += 1
  end
  choicemap = choices.map { |c| "  #{c}\n" }.join
  puts choicemap
  input = gets.chomp
  case input
  when "b","B"
    main_menu
  when "1"
    buy_item_index(1)
    buy_menu
  when "2"
    buy_item_index(2)
    buy_menu            
  when ...
    ...
  else
    puts "Not a valid input"
    buy_menu
  end        
end

How can I dynamically increment case when options instead of hard-coding them like I did above?

Upvotes: 0

Views: 538

Answers (3)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

case input.to_i
when 1..choices.count-1
  buy_item_index(input.to_i)
else
  puts "Not a valid input" unless input.downcase == 'b'
end
buy_menu

or:

if (1..choices.count-1).cover? input.to_i
  buy_item_index(input.to_i)
elsif input.downcase != 'b'
  puts "Not a valid input"
end
buy_menu

Update: one case for all:

case input
when 'b', 'B'
  main_menu
when ->(i) { (1..choices.count-1).cover? i.to_i }
  buy_item_index(input.to_i)
  buy_menu
else
  puts "Not a valid input"
  buy_menu
end

Upvotes: 2

BernardK
BernardK

Reputation: 3734

There are many ways to do things in Ruby. This is one solution :

O  = Struct.new(:name, :price)
o1 = O.new('a', 1)
o2 = O.new('b', 2)
o3 = O.new('c', 3)
o4 = O.new('d', 4)
o5 = O.new('e', 5)
MASTER_INVENTORY = [o1, o2, o3, o4, o5]

def buy_item_index(p)
    puts "-----buy #{p}"
end

def main_menu
    puts '-----Main Menu'
end

def prepare_buy_menu_and_case
    choices = ['Go [B]ack']
    i = 1
    MASTER_INVENTORY.each do |obj| 
        choices << "[#{i}] Buy #{obj.name} Price: #{obj.price}"
        i += 1
    end
    @choice_map = choices.join("\n")

    @case_body = ''
    MASTER_INVENTORY.size.times do | number0 |
        number = number0 + 1
        @case_body <<
            "when '#{number}'
                buy_item_index(#{number})
                buy_menu\n"
        puts "when #{number} generated"
    end
    puts "@case_body=#{@case_body}"
end

def buy_menu
    puts @choice_map
    input = gets.chomp

    eval("
    case input
    when 'b', 'B'
        main_menu
    #{@case_body}
    else
        puts 'Not a valid input'
        buy_menu
    end
    ")
end

prepare_buy_menu_and_case
buy_menu

Execution :

$ ruby -w t.rb 
t.rb:40: warning: assigned but unused variable - input
when 1 generated
when 2 generated
when 3 generated
when 4 generated
when 5 generated
@case_body=when '1'
                buy_item_index(1)
                buy_menu
when '2'
...
Go [B]ack
[1] Buy a Price: 1
[2] Buy b Price: 2
[3] Buy c Price: 3
[4] Buy d Price: 4
[5] Buy e Price: 5
2
-----buy 2
Go [B]ack
[1] Buy a Price: 1
[2] Buy b Price: 2
[3] Buy c Price: 3
[4] Buy d Price: 4
[5] Buy e Price: 5
5
-----buy 5
Go [B]ack
[1] Buy a Price: 1
[2] Buy b Price: 2
[3] Buy c Price: 3
[4] Buy d Price: 4
[5] Buy e Price: 5
6
Not a valid input
Go [B]ack
[1] Buy a Price: 1
[2] Buy b Price: 2
[3] Buy c Price: 3
[4] Buy d Price: 4
[5] Buy e Price: 5
b
-----Main Menu
$

This time, the warning about assigned but unused variable can be ignored.

Preparing the menu and the case code separately in prepare_buy_menu_and_case avoids to recompute them each time buy_menu is called.

The initial puts are for my comfort and can of course be removed.

Upvotes: 1

Rots
Rots

Reputation: 5586

when 1..99
  send("buy_item_index",  input)
end

https://repl.it/repls/ChillyPaltryHippopotamus

Upvotes: 1

Related Questions