Question

I am using Ruby 2.0 and I have two files: hello.rb & assets/display.rb.

hello.rb:

class Hello
  def self.run_it(name)
    ui = Display.new(name)
    ui.say_hi
  end
end

require_relative "assets/display"

Hello.run_it("Someone")

assets/display.rb:

class Hello::Display
  def initialize(name = "World")
    @name = name
  end

  def say_hi  
    puts "Hello #{@name}"  
  end
end

If in hello.rb I move require_relative "assets/display" before class Hello (1st line), ruby hello.rb outputs an uninitialized constant error. Why is that? What is the best practice when requiring external files and is require_relative the correct method (vs require and require "./some_file") in this short example ?

Was it helpful?

Solution

The standard practice is to put all or most of the require statements at the top of the file. Files should be designed so there is as little dependency as possible to other files.

The problem you have is that you have designed the file display.rb to be dependent on the class Hello.

When you say this:

class Hello::Display
end

It is the same as:

class Hello
  class Display
  end
end

But the difference is that in the first case Hello needs to be defined before you can say Hello::Display. Since Hello has not been defined when you put the require at the top of the file you will get the error.

You can fix it like this:

class Hello
   class Display
     # ..your Display code here..
   end
end

Or like this:

# Predefine Hello as a class name
class Hello
end

class Hello::Display
  # ..your Display code here..
end

OTHER TIPS

If you include the file display.rb at the beginning of hello.rb, when ruby interpreter encounter class Hello::Display, it expects Hello to defined somewhere before. But at this time, class Hello has not been defined, so you see the error.

The reason of this error is that you are trying to define a class inside Hello class, which is not defined yet at this point. Simply split the name into two classes:

class Hello
  class Display
    def initialize(name = "World")
      @name = name
    end

    def say_hi  
      puts "Hello #{@name}"  
    end
  end
end

That way you define both classes at once (and you can later on open Hello class)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top