Why relative path doesn't work in Ruby require
Asked Answered
J

3

28

I'm starting learning Ruby, one thing that I don't understand, why relative path for require directive doesn't work in ruby. It's something that works almost in every scripting language that I now (JSP, PHP...). I explain with a real example. I have a folder named shapes which contains 3 classes shape, rectangle and square. I have also another file test_shapes.rb from where I call and test my classes. When I import my classes to the main file like this:

require "./shape"
require "./rectangle"
require "./square"

I got error for files not found. When I include the name of my subfolder like this:

require "./shapes/shape"
require "./shapes/rectangle"
require "./shapes/square"

The code is perfectly working. Because I specified the whole path to the root directory of the project (the lib folder I think). When I include I include the absolute path to the hard disk, like this:

require "#{File.dirname(__FILE__)}/shape"
require "#{File.dirname(__FILE__)}/rectangle"
require "#{File.dirname(__FILE__)}/square"

It's also working perfectly.

So, I just want some explanation if know why the first import method (the relative path to the current folder) in not working.

Jerrybuilt answered 14/8, 2014 at 17:39 Comment(1)
because there is a method called require_relative for this purpose.Pajamas
L
42

Relative path is based on working dir. I assume that there is main file on the same directory. If you run ruby ./shapes/main.rb on project root, ruby try to find {project_root}/shape.rb, not {project_root}/shapes/shape.rb. It doesn't work.

You need to use require_relative like below.

# {project_root}/shapes/main.rb
require_relative './shape'
require_relative './rectangle'
require_relative './square'
Leer answered 14/8, 2014 at 17:51 Comment(0)
S
8

You are using relative path. And they are relative to the place where your script is executed. Generally it is bad idea. You should use either absolute path, either relative path to exact file where require is executed.

require File.expand_path("../shape", __FILE__)

PS: require_relative looks more laconic

Schoolmistress answered 14/8, 2014 at 17:46 Comment(0)
M
3

require(name) → true or false Loads the given name, returning true if successful and false if the feature is already loaded.

If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $LOAD_PATH ($:).

If the filename has the extension “.rb”, it is loaded as a source file; if the extension is “.so”, “.o”, or “.dll”, or the default shared library extension on the current platform, Ruby loads the shared library as a Ruby extension. Otherwise, Ruby tries adding “.rb”, “.so”, and so on to the name until found. If the file named cannot be found, a LoadError will be raised.

For Ruby extensions the filename given may use any shared library extension. For example, on Linux the socket extension is “socket.so” and require 'socket.dll' will load the socket extension.

The absolute path of the loaded file is added to $LOADED_FEATURES ($"). A file will not be loaded again if its path already appears in $". For example, require 'a'; require './a' will not load a.rb again.

require "my-library.rb" require "db-driver" Any constants or globals within the loaded source file will be available in the calling program’s global namespace. However, local variables will not be propagated to the loading environment.

require_relative(string) → true or false Ruby tries to load the library named string relative to the requiring file’s path. If the file’s path cannot be determined a LoadError is raised. If a file is loaded true is returned and false otherwise.

Ref: http://ruby-doc.org/core-2.1.2/Kernel.html#require-method

Mala answered 23/2, 2017 at 7:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.