Question

When using class files in Ruby, do you put the 'requires' statements at the top of the file, or inside the class definition?

Was it helpful?

Solution

Technically, it doesn't really matter. require is just a normal method call, and the scope it's called in doesn't affect how it works. The only difference placement makes is that it will be executed when whatever code it's placed in is evaluated.

Practically speaking, you should put them at top so people can see the file's dependencies at a glance. That's the traditional place for it.

OTHER TIPS

at the top.

require 'rubygems'
require 'fastercsv'

class MyClass
  # Do stuff with FasterCSV
end

I can see a possible reason for not putting a require at the top of the file: where it's expensive to load and not always executed. One case that occurs to me is where, for example, code and its tests are in the same file, which is something I like to do from time to time for small library code in particular. Then I can run the file from my editor and the tests run. In this case when the file is required in from elsewhere, I don't want test/unit to be loaded.

Something a little like this:

def some_useful_library_function()
  return 1
end

if __FILE__ == $0
  require 'test/unit'
  class TestUsefulThing < Test::Unit::TestCase
    def test_it_returns_1
      assert_equal 1, some_useful_library_function()
    end
  end
end

It doesn't really matter where you put them, but if you put them inside a class or module expression, then it looks like you are importing whatever is in the required file into the class's namespace, which is not true: everything ends up in the global namespace (or whatever namespaces are defined in the library).

So, better put them at the top to avoid any confusion.

At the top of the file, the majority (but not all) languages handle imports this way. I find it much cleaner and easier to handle them this way.

I think it only makes sense this way really... like you get mid way in a file then:

class Foo
  def initialize(init_value)
    @instance_var = init_value

# some 500 lines of code later....

  end
end

class Bar
# oh look i need an import now!
require 'breakpoint'

as you can see, it would be very hard to track them. Not to mention if you wanted to use the imported functions earlier in your code, you would probably have to backtrack and include it again because the other import would be specific to that class. Importing the same files would create a lot of overhead during runtime as well.

I feel that the require statement belongs inside the class. Using classes means that we are accepting a basic tenet of OOP, namely objects should be as loosely coupled as possible. To me that implies minimizing external dependencies. If I later move a class to its own file, I don't want to have it break because I didn't track down all the necessary require statements that the class consumes.

It doesn't cause any problems to have duplicate require statements in a file and it simplifies the refactoring that inevitably is going to take place by the next programmer that inherit your code.

Most answers recommend putting the require statements at the top of the file. However when requiring nested classes/modules you might want to consider putting them in the class instead (at the top). Have a look at this example:

# foo.rb
require './foo/bar'

class Foo < Struct.new(:name, :description)
  def bar
    Bar.new(self)
  end
end

# foo/bar.rb
class Foo
  class Bar < Struct.new(:foo)
  end
end

irb:

require './foo'
# ...
# TypeError (superclass mismatch for class Foo)

This happens because Bar is nested inside Foo and it will need to defined as such by nesting the Bar class inside the Foo class. However since Foo is not yet defined it is now being defined by the nested structure. After Bar is successfully required we now try to define the Foo class that inherits from another class. This fails due to the fact that Foo is already defined (by the nested structure) and inheritance can only occur on the initial definition of the class. Thus raising:

TypeError (superclass mismatch for class Foo)

This issue can be resolved by simply moving the require statement inside the Foo class.

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