Ruby: Is It Acceptable to Put More Than One Class in a File

Ruby: is it acceptable to put more than one class in a file?

Yes, it is generally acceptable because it doesn't violate any principles of the Ruby language itself but it ultimately depends on the practices of your target audience or framework. (For example, Rails likes your classes to be one-per-file.)

However, if you are grouping classes with related functionality into a single file then you should also consider making them part of the same module for a namespace.

Multiple classes in one file, Ruby Style Question

If you're asking the "ruby" way, then it is to put your classes in separate files. As some others have alluded to, placing your classes in separate files scales better. If you place multiple classes in the same file and they start to grow, then you're going to need to separate them later.

So why not have them separate from the beginning?

UPDATE

I should also mention that autoload works by expecting classes to be in their own files. For instance, if you're in a Rails environment and you don't separate classes into different files, you'll have to require the file explicitly. The best place to do this would be in the application.rb file. I know you're not in a Rails environment, but for others who may find this answer, maybe this info will be helpful.

UPDATE2

By 'autoload', I meant Rails autoload. If you configure your own autoload, you can put classes in the same file; but again, why? The Ruby and Java communities usually expect classes to be in separate files. The only exception are nested classes, but that's for more advanced design patterns.

.rb file containing multiple classes vs multiple .rb files with a single class in each

Well, you've already got one great reason: "...having them in different files would make it easier for a team to all work together or to split work up."

Another reason is organization. Suppose I want to know where the User class is defined. If there are a bunch of files and one is named user.rb, that's a pretty good clue. If there are a bunch of files and none of them is named user.rb I have to start hunting through files, or use a file search utility, and my time is wasted.

Furthermore, if I'm reading a file and it says require "user" at the top, I know automatically that this file probably needs something called User. If it says require "script" at the top, I have no idea what it's loading, or what's in there that this file needs, so I have to go digging around, and my time is wasted.

A third reason is encapsulation. Keeping code in memory has real performance implications. If there are a dozen different classes in script.rb and I do require "script", then I'm loading all of those classes, even if I only want User. Not to mention your tests—and thereby your entire workflow—run a lot faster if they only have to load the things they actually need.

Splitting a ruby class into multiple files

I often do this in my gem files to manage documentation and avoid long files.

The only issues I found (which are solvable) are:

  1. Initialization of class or module data should be thoughtfully managed. As each 'compartment' (file) is updated, the initialization data might need updating, but that data is often in a different file and we are (after all) fallible.

    In my GReactor project (edit: deprecated), I wrote a different initialization method for each section and called all of them in the main initialization method.

  2. Since each 'compartment' of the class or module is in a different file, it is easy to forget that they all share the same namespace, so more care should be taken when naming variables and methods.

  3. The code in each file is executed in the order of the files being loaded (much like it would be if you were writing one long file)... but since you 'close' the class/module between each file, than your method declaration order might be important. Care should be taken when requiring the files, so that the desired order of the code execution is preserved.

The GReactor is a good example for managing a Mega-Module with a large API by compartmentalizing the different aspects of the module in different files.

There are no other pitfalls or issues that I have experienced.

Including a Ruby class from a separate file

Modules serve a dual purpose as a holder for functions and as a namespace. Keeping classes in modules is perfectly acceptable. To put a class in a separate file, just define the class as usual and then in the file where you wish to use the class, simply put require 'name_of_file_with_class' at the top. For instance, if I defined class Foo in foo.rb, in bar.rb I would have the line require 'foo'.

If you are using Rails, this include often happens automagically

Edit: clarification of file layout

#file: foo.rb
class Foo
def initialize
puts "foo"
end
end

...

#file: bar.rb
require 'foo'

Foo.new

If you are in Rails, put these classes in lib/ and use the naming convention for the files of lowercase underscored version of the class name, e.g. Foo -> foo.rb, FooBar -> foo_bar.rb, etc.

As of ruby version 1.9 you can use require_relative, to require files relatively to the file you are editing.



Related Topics



Leave a reply



Submit