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:
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.
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.
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.
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
Error Could Not Find I18N-0.7.0 in Any of The Sources
What Is The Ruby Equivalent to This Curl Request
Sorting Hash of Hashes by Value (And Return The Hash, Not an Array)
Modifying Text Inside HTML Nodes - Nokogiri
Adding Bootstrap Icon to Button in Ruby on Rails
How to Use C# Style Enumerations in Ruby
Dynamic Role Attributes in Chef
How to Host Gem in Github and Use It
Setting Up Configuration Settings When Writing a Gem
Ruby Gem Development - How to Use Activerecord
Why Are Global Methods Allowed to Be Defined Outside of a Class in Ruby
How to Handle Serialized Edit Fields in an Active Admin Resource
Rake Cucumber and Rake Spec Always Use "Develop" Environment
How to Add Usr/Local/Bin to Path Environment Variable on Ubuntu 12.0.4