0

In the code below:

module UserInterface

    @main_menu_options = { 1 => "Display Task List", 2 => "Add New Task", 3 => "Edit A Task", 4 => "Delete A Task", "Q" => "Quit" }

    def main_menu(string="")
        @main_menu_options.each_value { |v| puts v }
        if @main_menu_options == nil then puts "NOTHING THERE" end
    end

end

I've created a module variable and put a standard Ruby hash inside it.

But the first line of the main_menu method can't display the values.

When I comment out the first line of that method, the second line always displays "NOTHING THERE", which tells me that the method thinks the class variable contains nil.

I also tried recreating that exact same hash in the method body, and that line of code could display its values perfectly fine, so I don't see how it can be the statement in the method. I think the problem must be the module class variable.

Why does that module method think there's nothing in my @main_menu_options module class variable when it clearly has something in it?

C. Ball
  • 643
  • 1
  • 8
  • 18
  • I assume you invoked `main_menu` from an instance of a class that included that module. Correct? – Cary Swoveland Feb 08 '18 at 21:44
  • Yes that's correct. I know what I need to do now. I need to make that module variable a constant so that it can be accessed at the module level and by anything that includes that module. – C. Ball Feb 08 '18 at 21:50
  • You could retrieve (or set) the module instance variable directly: `module M; @m = 99; end; M.instance_variable_get("@a") #=> 99` (or `..._get(:@a)`). – Cary Swoveland Feb 09 '18 at 00:32

1 Answers1

3

The first @main_menu_options is not the same as the @main_menu_options referenced in the mixin method. The second method operates in the context of whatever called include.

If you want these both on the same page you'll need to redefine that method to be in the same scope:

module UserInterface
  @main_menu_options = {
    1 => "Display Task List",
    2 => "Add New Task",
    3 => "Edit A Task",
    4 => "Delete A Task",
    "Q" => "Quit"
  }

  # Module-level method has access to module-level defined variables
  def self.main_menu(string = "")
    @main_menu_options.each_value { |v| puts v }

    if @main_menu_options == nil then puts "NOTHING THERE" end
  end
end

This misses the bigger problem. Since those options never change you really should be defining this as a constant:

module UserInterface
  MAIN_MENU_OPTIONS = {
    1 => "Display Task List",
    2 => "Add New Task",
    3 => "Edit A Task",
    4 => "Delete A Task",
    "Q" => "Quit"
  }

  def main_menu(string = "")
    MAIN_MENU_OPTIONS.each_value { |v| puts v }

    if MAIN_MENU_OPTIONS == nil then puts "NOTHING THERE" end
  end
end

You'll need to fix your if since that's not really functional code. When writing Ruby try to avoid one-liners like that, skip the then to avoid clutter.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • I don't see the point of the last line in `def main_menu`. If `MAIN_MENU_OPTIONS` is nill then the line above would have raised a NoMethodError. – max pleaner Feb 08 '18 at 21:02
  • Oh never mind I see you just copied this from the question – max pleaner Feb 08 '18 at 21:02
  • Thank you very much @tadman. And thanks for your advice about the if statement. So just to be clear, if I make that variable a constant, I don't need to add "self." before the method name? – C. Ball Feb 08 '18 at 21:14
  • Constants are available to both the module level context and the mixin level at the same time, they're more "universal" that way, so yes. Same principle applies in a class. – tadman Feb 08 '18 at 21:32