Code Quiver

Let me preface this by saying I’m sure that there are actual industry terms for everything that I am going to say, but as a junior developer in training I don’t know what they are. At least not yet!

DC’s Green Arrow. Source: http://dc.wikia.com/

The Green Arrow

Now, in my humble opinion, Green Arrow was never an A-list hero. So let me fill in the important points. The Green Arrow, aka Oliver Queen is a master archer, but what makes him unique is his arrows, and quiver. He carries a variety of arrows, each one with its own purpose. Tips that stun, freeze, break apart or simply have a blunt end to punch out the average 1960's villain. To keep them straight, his quiver served up the right arrow at the right time.

Menus and Sub-Menus (pure Ruby)

The assignment, create a simple command line app that allows you to create, edit and delete projects. To better track your projects, you can associate tasks to them. This requires a menu for project management and a sub-menu for task management.

https://gist.github.com/postazure/948fb0dcf8cf84a8a764

This is the most straight forward solution, but it’s not very useful. If you were to add more options or another menu, sooner or later this is going to turn into one unmanageable piece of code.

So my thought was instead of hard-coding all of our options what if we instead created a method that could interpret a hash and pull out the right options for the menu level we wanted. This would help remove the ‘sub’ from sub-menu. After all we are not actually dealing with a main menu and a sub-menu, in fact we have two menus. One that handles projects and another that handles tasks. This might be a hard concept because we want to believe that tasks belong to projects, and they do. However, the association of tasks to projects is part of the ‘model’ and not the ‘controller/router’.

The Quiver

https://gist.github.com/postazure/af4968d341fc75e694be

The method ‘menu’ expects an array of all possible descriptions for the user to chose from. Based on the key (by default :project_menu) it sets a menu_level. Then the instructions are displayed to the user, and the program waits for a valid input from the user. If user_input == “quit” then the loop ends and the program exits. Next the user input is assigned an identifier based on the current menu. If the this string is a valid (it must be represented by a key in the menu hash) then the method contained in the hash’s value is called.

The Arrows

https://gist.github.com/postazure/2270c279fc738b85aca7

Here are the hashes mentioned above. “@instructions” hold a hash where the key is the menu name, and the value is the list of strings (instructions) displayed to the user. “@actions” holds a hash where the key is the concatenation of the user_input and the menu_level. For example, ‘list’ + ‘_p’ would be ‘list_p”, method list from the project’s (_p) menu.

If your wondering about the lambda{}, which I hope you are, here’s what going on. Without this, Ruby starts reading this hash as soon as the class is created (I put it in the initialize method after all) so naturally it tries to run these methods right away. That is not what we intended. We want to call these methods at the time we need them. So, lambda tells Ruby to wait. Lambdas are anonymous functions, if you want more you should go to RubyMonk. They have a very concise description and a very helpful example.

So…

Now I’m not sure how practical or useful this is, but I think it’s pretty cool. I wanted to separate out the menus and make the code both more readable and maintainable. I do feel as though I lost some of the obvious insight into the menu/submenu interplay. However, when viewing the code as a whole it should still make sense.