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.
Add Ruby classes to a module when defined in separate files
The accepted practice in this case is to wrap every file in module
block
# a/b.rb
module A
class B
end
end
# a/c.rb
module A
class C
end
end
Btw. because of the way constant are resolved, it is advisable to use the long form I quoted above instead class A::B
(http://blog.honeybadger.io/avoid-these-traps-when-nesting-ruby-modules/).
How do I import ruby classes into the main file?
In order to include classes, modules, etc into other files you have to use require_relative
or require
(require_relative
is more Rubyish.) For example this module:
module Format
def green(input)
puts"\e[32m#{input}[0m\e"
end
end
Now I have this file:
require_relative "format" #<= require the file
include Format #<= include the module
def example
green("this will be green") #<= call the formatting
end
The same concept goes for classes:
class Example
attr_accessor :input
def initialize(input)
@input = input
end
def prompt
print "#{@input}: "
gets.chomp
end
end
example = Example.new(ARGV[0])
And now I have the main file:
require_relative "class_example"
example.prompt
In order to call any class, or module from another file, you have to require it.
I hope this helps, and answers your question.
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.
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.
Ruby - How to include classes in a Module
Im not sure what the issue is. I understand that it says uninitialized but Im not sure why. It seems it is looking for a constant instead of reading the class?
It is not clear to me what you mean by "reading the class". Yes, Ruby is looking for a constant. Variable names that begin with a capital letter are constants, ergo, HtmlBody
is a constant, HeadingTags
is a constant, and HtmlBody::HeadingTags
is the constant HeadingTags
located in a class or module that is referenced by the constant HtmlBody
.
How are you supposed to include classes located in separated files inside a module?
You namespace a class inside a module by defining the class inside the module. If you are sure that the module already exists, you can define the class like this:
class HtmlBody::HeadingTags
# …
end
However, if HtmlBody
is not defined (or is not a class or module), this will fail.
module HtmlBody
class HeadingTags
# …
end
end
This will guarantee that module HtmlBody
will be created if it doesn't exist (and simply re-opened if it already exists).
There is also a slight difference in constant lookup rules between the two, which is however not relevant to your question (but be aware of it).
The is something that Im missing in Ruby and the require/require_relative probably.
Indeed, your question stems from a fundamental misunderstanding of what Kerne#load
/ Kernel#require
/ Kernel#require_relative
does.
Here is the very complicated, detailed, in-depth explanation of all the incredibly convoluted stuff that those three methods do. Brace yourself! Are you ready? Here we go:
They run the file.
Wait … that's it? Yes, that's it! That's all there is to it. They run the file.
So, what happens when you run a file that looks like this:
class HeadingTags
# …
end
It defines a class named HeadingTags
in the top-level namespace, right?
Okay, so what happens when we now do this:
require_relative './html_body/HeadingTags'
Well, we said that require_relative
simply runs the file. And we said that running that file defines a class named HeadingTags
in the top-level namespace. Therefore, this will obviously define a class named HeadingTags
in the top-level namespace.
Now, looking at your code: what happens, when we do this:
module HtmlBody
require_relative './html_body/HeadingTags'
end
Again, we said that require_relative
simply runs the file. Nothing more. Nothing less. Just run the file. And what did we say running that file does? It defines a class named HeadingTags
in the top-level namespace.
So, what will calling require_relative
from within the module definition of HtmlBody
do? It will define a class named HeadingTags
in the top-level namespace. Because require_relative
simply runs the file, and thus the result will be exactly the same as running the file, and the result of running file is that it defines the class in the top-level namespace.
So, how do you actually achieve what you are trying to do? Well, if you want to define a class inside a module, you have to … define the class inside the module!
lib/html_body.rb
require_relative 'html_body/heading_tags'
require_relative 'html_body/anchor_tags'
require_relative 'html_body/img_tags'
module HtmlBody; end
lib/html_body/heading_tags.rb
module HtmlBody
class HeadingTags
# …
end
end
lib/html_body/anchor_tags.rb
module HtmlBody
class AnchorTags
# …
end
end
lib/html_body/img_tags.rb
module HtmlBody
class ImgTags
# …
end
end
main.rb
require_relative 'lib/html_body'
HtmlBody::HeadingTags.new
To break up Ruby class into separate files by mixins or plain definitions?
Are your support methods general enough that they might be useful for other totally unrelated classes? If so, a mixin is the proper way to do this, since it lets you easily reuse the support code.
However if your support methods are very specific to ReallyBigClass and are unlikely to work if included somewhere else, reopening the class is the way to go. Using a mixin there could give the appearance that the methods are more general than they really are, when really they should only be used with instances of a specific class.
That being said, I think your question indicates a larger design problem. If you are in the former case (general methods), you should be designing more general modules in the first place to avoid tight coupling. A module called ReallyBigClassFileB
gives off some strong code smell. In the latter case (very specific methods) if your class is so big that its file is unmanageably large you probably need to refactor something. Maybe your class is responsible for too much? Maybe it could use some subclasses (which make sense in separate files)?
Can't inherit a class defined in separate file - Ruby
Try to call require_relative
without file extension:
require_relative 'template'
You can read more about the difference between require
and require_relative
here.
Calling another ruby file that is not a gem
In 99% of all cases when a computer tells you that it couldn't find a thing, it is because the thing isn't there. So, the first thing you need to check is whether there actually is a file named TestClass.rb
somewhere on your filesystem.
In 99% of the rest of the cases, the computer is looking in the wrong place. (Well, actually, the computer is usually looking in the right place, but the thing it is looking for is in the wrong place). require
loads a file from the $LOAD_PATH
, so you have to make sure that the directory that the file TestClass.rb
is in actually is on the $LOAD_PATH
.
Alternatively, if you do not want to require
a file from the $LOAD_PATH
but rather relative to the position of the file that is doing the require
ing, then you need to use require_relative
.
Note, however, that your code won't work anyway, since say_hello
is in instance method of instances of the TestClass
class, but you are calling it on the main
object, which is an instance of Object
, not TestClass
.
Note also that standard naming conventions of Ruby files are snake_case
, in particular, the snake_case
version of the primary class/module of the file. So, in your case, the file should be named test_class.rb
. Also, require
and require_relative
figure out the correct file extension for themselves, so you should leave off the .rb
. And thirdly, standard Ruby coding style is two spaces for indentation, not four.
None of these will lead to your code not working, of course, since it is purely stylistic, but it may lead to people being unwilling to answer your questions, since it shows that you don't respect their community enough to learn even the most basic rules.
Related Topics
Error Installing Nokogiri 1.6.0 on MAC (Libxml2)
Why Are My Bigdecimal Objects Initialized with Unexpected Rounding Errors
How to Share the Factories That I Have in a Gem and Use It in Other Project
What Is the "Equals Greater Than" Operator => in Ruby
Rbenv Irb History Is Not Saving
While Executing Gem, Unknown Command
Ruby Rails - Select Only Few Columns from the Data Base
Including a Ruby Class from a Separate File
How to Create an Array in Ruby with Default Values
How to or Should I Find an Object by the Object_Id Attribute in Ruby
Getting Typed Results from Activerecord Raw SQL
How to Add MAC-Specific Gems to Bundle on MAC But Not on Linux
Match String That Doesn't Contain a Specific Word