Including a Ruby Class from a Separate File

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:

  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.

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 requireing, 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



Leave a reply



Submit