views:

69

answers:

2

I have a more conceptual question in Rails... or Ruby for that matter:

Is it best to call a require right before the method that needs it, group my requires at the beginning of the class or somewhere in an initializer when Rails boots?

Does it matter from a performance point of view? From a readability point of view? Does it make a difference if I'm using Rails 3?

Thanks!

+2  A: 

If you're concerned about performance then you should require things in the context of where they are needed so that if that portion of your code is not exercised, the library is not loaded. Any subsequent calls to require have no effect as that file has already been loaded. This ends up looking like something along the lines of:

if (user.using_openid?)
  require 'openid'

  # ... Do OpenID stuff
end

While this is more efficient in terms of resources, it can make it very difficult to determine the dependencies of your application. Declaring these up-front makes it clear to other people maintaining the software. Keep in mind that "other people" always includes your future self when you've forgotten about some details of your application.

You're technically allowed to require anything at any time, late or early, but declaring your requirements up front is better from a design perspective. If you find that there is an element that is used only intermittently and takes an unusual amount of time or memory to load, then you should probably document that up front in your requirements file. For example:

require 'library1'
require 'library2'
require 'library3'
require 'library4'
require 'library5'

# Other libraries loaded as required:
#  * slowimagelibrary
#  * slowencryptionlibrary
#  * openid

Arguably this is less of an issue with bundler because you can have your gems declared up front more formally and the actual require call can come later.

tadman
Thanks tadman, this is in line with what I was thinking. Conclusion: readability is more important than performance except when using heavy requires.
Cimm
+1  A: 

If you consider vanilla Ruby, 'require' is mostly used in the first lines, because you then are sure you have access to what you need, and it is easier to find and read what dependency you need.

There are a few cases when you want to load a gem only in a method, because this is not really needed for your script to work (e.g.: a optional visualization).

With Rails, I believe it depends on what you want to do.

If you use Bundler, you can assume your gem has been 'required' (you can of course override what is required with the :require option).

If it is some stuff you want to autoload when the server start (like validators or form builders), then you should look how to do with the config (autoload_paths and eager_load_paths).

require can also be used to load only a part of a gem, like an extension to it. Then it is of course required where the configuration is.

You might be concerned if you work in a multi-threaded environment, as they are some problems with that. You must then ensure everything is loaded before having your threads running. (Something like the class constant is loaded, but the methods not yet, there was a good article but I can not find it anymore).

You might also want to try {Module,Kernel}.autoload, Rails extensively use it to load only what is necessary when accessed (but it looks rather ugly).

You can also hack it yourself with const_missing (so this can do plain lazy-loading, if you accept a structure). This is a simple example (will not be appropriate for nested classes).

def Object.const_missing c
  if (file = Dir["#{c.downcase}.rb"]).size == 1 
    require_relative(file)
  end
  if const_defined? c
    const_get c
  else
    super # Object < Module
  end
end

About performance, a call to require is relatively expensive, so if you know you are going to use it, do it only once if possible. However, to manage complex dependencies within your project, you might need to require relative files. Then require_relative is the way to go in 1.9.

Lastly, for a project, I would recommend to require all in the main file in lib/, with some Dir["**/*.rb"] expression. You would then rarely need to require_relative, because it is only needed if you reference in the body of the class another constant (all the contents of the methods are not resolved, so there is no problem with that).

Another solution would be to define these constants in your main file, it would also give you an idea of the structure.

eregon