JmanxC JmanxC - 1 year ago 33
Ruby Question

Modules and Accessing Variables from Modules (Ruby Language)

I have the following Module which has 1 variable which contains a string for the first day of a hypothetical year, 1 method which outputs a string and another method which also outputs a string:

module Week
first_day = "Sunday"

def weeks_in_month
puts "There are 4 weeks in a month"

def weeks_in_year
puts "There are 52 weeks in a year"

I now have a class who's only purpose is to print out the variable located in the module.(this is just for testing purposes)

class Decade
include Week

def firstday
puts Week::first_day

I now instantiate Decade and access the methods located in the module using Decades object. My program runs into a problem when calling the firstday method

z =

z.firstday #Errors here

The error I get is:

undefined method `first_day' for Week:Module (NoMethodError)

I am new to Ruby and am just getting used to Modules, so any help would be appreciated.

Answer Source

When writing a module the convention is to declare constants like this:

module Week
  FIRST_DAY = 'Sunday'

Note that they're in ALL_CAPS. Anything that begins with a capital letter is treated as a constant. Lower-case names of that sort are treated as local variables.

Generally it's bad form to access the constants of another module, it limits your ability to refactor how those are stored. Instead define a public accessor method:

module Week
  def first_day

Now you can call that externally:


Note you can also change how that's implemented:

module Week
  DAYS = %w[

  def first_day

  extend self # Makes methods callable like Week.first_day

The nice thing about that is the first_day method does exactly the same thing, no other code has to change. This makes refactoring significantly easier. Imagine if you had to track down and replace all those instances to Week::FIRST_DAY.

There's some other things to note here. The first is that any time you call include on a module then you get the methods and constants loaded in locally. The second thing is when you define a mix-in module, be careful with your names to avoid potential conflict with the target class.

Since you've mixed it in, you don't need the namespace prefix, just calling first_day should do it.