Reviewing old code: Practical use of blocks and Proc

In my journey of getting the best Ruby style code of an old video game I programmed, I have found a good example for the use of Ruby's blocks and Proc, I'm not 100% sure if using blocks it's the best way for handling this problem but I find the most rubyesque way of solving it.

Let's first see what problem do I have.

I have defined a class called Menu.rb that I use for holding and drawing items stacked in a menu for displaying in the screen. Now this is how I am defining the menu

@menu = Menu.new(window,220,50,'Main Menu',resource_manager.font,resource_manager.cursor_sound)
  @menu.add_item('Quick Race',nil)
  @menu.add_item('Story Mode',nil)   
  @menu.add_item('Options',nil)   
  @menu.add_item('Credits',nil)   
  @menu.add_item('Exit',nil)   

I first define the menu, with it's position, padding, title, font, and moving cursor sound. And then I start adding items. Those items are added by specifying the text tag that will show, and a second parameter that represents the value associated, this is useful for displaying things in an options menu like 'Volume 100' or 'Difficulty 8', but as this is the main menu all the items have a nil value.

Obviously, these options are intended to fire actions, and for now I was managing it this way:

if input["action"] then
  @accept_fx.play(false)
   case @menu.selected
   when 0
     @finished = 2 
   when 1
     @finished = 2 
   when 2
     @current_state = 1
   when 3
     @credits.reset
     @current_state = 2
   when 4
     @finished = -1
   end

I have a public variable that I access from the outside of the Menu class, and then, depending on it's value using this big case I write the statements that firing that action cause. This is working but I think it could be more elegant with the use of Ruby's blocks. These are chunks of code, that can be passed as an argument to a method for a later execution.

Then, those statements can be passed to the add_item method for expressing something like Add this item, with this text tag, this value, and does this when fired. Then, later in the code we will just have to call item.fire and the item will do it's thing.

The menu creation will now look like this:

@menu = Menu.new(window,220,50,'Main Menu',resource_manager.font,resource_manager.cursor_sound)
@menu.add_item('Quick Race',nil) { @finished = 2 }
@menu.add_item('Story Mode',nil) { @finished = 3 }
@menu.add_item('Options',nil) { @current_state = 1 }
@menu.add_item('Credits',nil) { @credits.reset; @current_state = 2 }
@menu.add_item('Exit',nil) { @finished = -1 }

Now the add_item method has to be rewritten this way:

def add_item(name,value,&action
  @items.push({"name" => name,
  			 "value" => value,
               "action" => action}
end

And then I will create a new method for firing this action from the outside of the Menu class like this:

def select
  @items[@selected]["action"].call unless  @actions[@selected]["action"].nil?
end

That's it, now we can rewrite the whole case written before just like this:

@menu.select if input["action"]

Very nice!