Ruby: Require Fails To Import - Need To Set Root Directory - ruby

Forgive my inexperience with Ruby, but I am unable to run a script within a third-party project with the following structure:
˅ alpha
˅ lib
˅ bravo
golf.rb
˅ charlie
˃ delta
˅ echo
foxtrot.rb
require "charlie/delta/echo/__init"
__init.rb
require "bravo/golf"
What should my command-line be to run the script, 'foxtrot.rb', as the following generates an error:
ruby "c:\arby\lib\bravo\charlie\delta\echo\foxtrot.rb"
"'require': cannot load such file -- charlie/delta/echo/__init (LoadError)"

If this is the code inside of __init.rb, it won't work.
require "charlie/delta/echo/__init"
__init.rb
require "bravo/golf"
require tells ruby to load the code inside a ruby file. In order for it to work, the files need to be organized correctly. You can also use require_relative but they still need a relative path from the file calling them. See What is the difference between require_relative and require in Ruby?

Related

Problems with requiring files inside gem [duplicate]

What is the difference between require_relative and require in Ruby?
Just look at the docs:
require_relative complements the builtin method require by allowing you to load a file that is relative to the file containing the require_relative statement.
For example, if you have unit test classes in the "test" directory, and data for them under the test "test/data" directory, then you might use a line like this in a test case:
require_relative "data/customer_data_1"
require_relative is a convenient subset of require
require_relative('path')
equals:
require(File.expand_path('path', File.dirname(__FILE__)))
if __FILE__ is defined, or it raises LoadError otherwise.
This implies that:
require_relative 'a' and require_relative './a' require relative to the current file (__FILE__).
This is what you want to use when requiring inside your library, since you don't want the result to depend on the current directory of the caller.
eval('require_relative("a.rb")') raises LoadError because __FILE__ is not defined inside eval.
This is why you can't use require_relative in RSpec tests, which get evaled.
The following operations are only possible with require:
require './a.rb' requires relative to the current directory
require 'a.rb' uses the search path ($LOAD_PATH) to require. It does not find files relative to current directory or path.
This is not possible with require_relative because the docs say that path search only happens when "the filename does not resolve to an absolute path" (i.e. starts with / or ./ or ../), which is always the case for File.expand_path.
The following operation is possible with both, but you will want to use require as it is shorter and more efficient:
require '/a.rb' and require_relative '/a.rb' both require the absolute path.
Reading the source
When the docs are not clear, I recommend that you take a look at the sources (toggle source in the docs). In some cases, it helps to understand what is going on.
require:
VALUE rb_f_require(VALUE obj, VALUE fname) {
return rb_require_safe(fname, rb_safe_level());
}
require_relative:
VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
VALUE base = rb_current_realfilepath();
if (NIL_P(base)) {
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}
This allows us to conclude that
require_relative('path')
is the same as:
require(File.expand_path('path', File.dirname(__FILE__)))
because:
rb_file_absolute_path =~ File.expand_path
rb_file_dirname1 =~ File.dirname
rb_current_realfilepath =~ __FILE__
Summary
Use require for installed gems
Use require_relative for local files
require uses your $LOAD_PATH to find the files.
require_relative uses the current location of the file using the statement
require
Require relies on you having installed (e.g. gem install [package]) a package somewhere on your system for that functionality.
When using require you can use the "./" format for a file in the current directory, e.g. require "./my_file" but that is not a common or recommended practice and you should use require_relative instead.
require_relative
This simply means include the file 'relative to the location of the file with the require_relative statement'. I generally recommend that files should be "within" the current directory tree as opposed to "up", e.g. don't use
require_relative '../../../filename'
(up 3 directory levels) within the file system because that tends to create unnecessary and brittle dependencies. However in some cases if you are already 'deep' within a directory tree then "up and down" another directory tree branch may be necessary. More simply perhaps, don't use require_relative for files outside of this repository (assuming you are using git which is largely a de-facto standard at this point, late 2018).
Note that require_relative uses the current directory of the file with the require_relative statement (so not necessarily your current directory that you are using the command from). This keeps the require_relative path "stable" as it always be relative to the file requiring it in the same way.
From Ruby API:
require_relative complements the
builtin method require by allowing you
to load a file that is relative to the
file containing the require_relative
statement.
When you use require to load a file,
you are usually accessing
functionality that has been properly
installed, and made accessible, in
your system. require does not offer a
good solution for loading files within
the project’s code. This may be useful
during a development phase, for
accessing test data, or even for
accessing files that are "locked" away
inside a project, not intended for
outside use.
For example, if you have unit test
classes in the "test" directory, and
data for them under the test
"test/data" directory, then you might
use a line like this in a test case:
require_relative "data/customer_data_1"
Since neither
"test" nor "test/data" are likely to
be in Ruby’s library path (and for
good reason), a normal require won’t
find them. require_relative is a good
solution for this particular problem.
You may include or omit the extension
(.rb or .so) of the file you are
loading.
path must respond to to_str.
You can find the documentation at http://extensions.rubyforge.org/rdoc/classes/Kernel.html
The top answers are correct, but deeply technical. For those newer to Ruby:
require_relative will most likely be used to bring in code from another file that you wrote.
for example, what if you have data in ~/my-project/data.rb and you want to include that in ~/my-project/solution.rb? in solution.rb you would add require_relative 'data'.
it is important to note these files do not need to be in the same directory. require_relative '../../folder1/folder2/data' is also valid.
require will most likely be used to bring in code from a library someone else wrote.
for example, what if you want to use one of the helper functions provided in the active_support library? you'll need to install the gem with gem install activesupport and then in the file require 'active_support'.
require 'active_support/all'
"FooBar".underscore
Said differently--
require_relative requires a file specifically pointed to relative to the file that calls it.
require requires a file included in the $LOAD_PATH.
I just saw the RSpec's code has some comment on require_relative being O(1) constant and require being O(N) linear. So probably the difference is that require_relative is the preferred one than require.
I want to add that when using Windows you can use require './1.rb' if the script is run local or from a mapped network drive but when run from an UNC \\servername\sharename\folder path you need to use require_relative './1.rb'.
I don't mingle in the discussion which to use for other reasons.
absolute path
require './app/example_file.rb'
shortened name
require_relative 'example_file'

Use Ruby Class In A Different Directory

I have written a few ruby classes. However, when trying to access one from another directory I am getting the following error:
uninitialized constant Main::AppVersion
This is what the directory structure looks like:
home --> a --> app_version.rb
home --> b --> c --> lib --> main.rb (and other classes)
Everything within "lib" can see each other. However, when trying to access app_version, it fails. I added the path to app version (home/a) to the $LOAD_PATH. So it should be available from there. I have also tried "requiring" my other class, but when I do that I get the following error:
LoadError: no such file to load -- AppVersion
Any idea on what I could be doing wrong here would be highly appreciated. Thanks!
Can try using require_relative:
require_relative '../../../a/app_version'
You error is:
LoadError: no such file to load -- AppVersion
So require is looking for a file AppVersion.rb. And you said the file name is app_version.rb. Try to load it with:
require 'app_version'
after setting up the $LOAD_PATH.
When you define Main::AppVersion class it's supposed to reside in main folder (i.e. main/app_version.rb)
So it doesn't depend on $LOAD_PATH.
You will have to require the file.
LoadError: no such file to load -- AppVersion
Do you require "app_version" ? Or require "AppVersion"? (first one is correct, and consider to require_relative)
Another option is to run ruby and give the include path like
ruby -Ia -Ib/c/lib b/c/lib/main.rb
.

Ruby including files

I have a Ruby app that runs on a server with no web interface. It is run using the command line(ruby path/to/file.rb).
I have classes in different files that I want to be accessible. The files are located in the "app/classes" directory.
I put this in the application.rb file:
config.autoload_paths += Dir["#{config.root}/classes"]
and I get an uninitialized constant error.
I can put in "require_relitive 'somefile'" but I would rather not have to do this for every class that is used. How do I create an autoload path and where should it be located at?
Use require_all
See https://github.com/jarmo/require_all
It basically allows you to write this:
require 'require_all'
require_all 'app/classes'
And all ruby files in app/classes will be loaded.

How do I require a ruby file from child directory

I have the following structure
tests
specific tests
first_test.rb
more tests
second_test.rb
test_helper.rb
Now I am trying to require test_helper in both first_test and second_test. The following works
require '../test_helper.rb'
and from command line I should be under specific tests and execute
ruby first_test.rb
How can I get more flexibility ie. I want to be in any directory and execute these tests. Currently I am getting 'no such file'. This is not a rails app but in rails I could simply do require 'test_helper.rb'
Bonus points for making this work with rake.
Put your test_helper and other helpers in a separate directory like
/home/XXX/projects/test_project/lib/
or wherever you like and use base directory like
Dir["base/path/to/your/helper/*.rb"].each {|file| require file }
or from my above example
Dir["/home/XXX/projects/test_project/lib/*.rb"].each {|file| require file }
Thats it.
Now add this line to the beginning of every test you want to run separately from any directory.And forget about the directory issue.

Ruby separate large source files into multiple files

I am writing a Ruby script which was supposed to be a small thing but has grown quite large, way to large to have everything crammed into one source file. So I am trying to separate the project into different files. I have four classes and I want to put each in its own separate source file.
What I did:
I moved all of the classes into their own files so now I have this
proj/GoogleChart.rb
proj/BarChart.rb
proj/PieChart.rb
proj/GroupedBarChart.rb
Now that they are in other files I am getting uninitialized constant GoogleChart (NameError) in all of my subclasses on the line where I inherit from GoogleChart, i.e.
require 'GoogleChart'
BarChart < GoogleChart
Can anyone tell me what is wrong?
Thanks
EDIT
Using ruby version 1.8.4
Also I have tried using the absolute path:
require 'C:/Documents and Settings/proj/GoogleChart.rb' and this is still producing a NameError
In Ruby 1.8.x, the . is part of your load path. So you should at least try to debug that by including something like:
puts $:
require 'GoogleChart'
class BarChart < GoogleChart
end
and load that in an IRB session:
Open the session in your directory proj.
Enter there require 'BarChart'
Look at the result.
For me it is:
c:\apps\ruby\test\proj>irb
irb(main):001:0> require 'BarChart'
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/site_ruby/1.8
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/site_ruby/1.8/i386-msvcrt
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/site_ruby
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/vendor_ruby/1.8
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/vendor_ruby/1.8/i386-msvcrt
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/vendor_ruby
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/1.8
C:/Users/mliebelt/.pik/rubies/Ruby-187-p334/lib/ruby/1.8/i386-mingw32
.
=> true
So the require is successful for me, and the . is part of the path (as it should). As you can see, I am working with Ruby 1.8.7, I don't know if anything has changed since 1.8.4 that is relevant here.
So please describe exactly how you run your file:
Have you opened a shell to run the file?
What is the current working directory of that shell?
Do you run by double-clicking it?
It only works when you are in your proj directory and run there (with ruby in your shell path) ruby BarChart.rb.

Resources