i discovered a problem when cron tries to run a ruby script which uses some library.
require "library"
#do some stuff
it complains about not being able to find library.rb
so i was wondering if i could do something like require "/var/dir/library.rb"
Yes, you can do that. You could also simply add the directory where your files are to the list of paths in $:, either with the -I argument, the RUBYLIB environment variable or just by doing $: << 'some_directory'.
if you're using 1.9
require_relative is your friend
Related
The latest changesets to Ruby 1.9.2 no longer make the current directory . part of your LOAD_PATH. I have a non-trivial number of Rakefiles that assume that . is part of the LOAD_PATH, so this broke them (they reported "no such file to load" for all require statements that based off the project path). Was there a particular justification for doing this?
As for a fix, adding $: << "." everywhere works, but seems incredibly hacky and I don't want to do that. What's the preferred way to make my Rakefiles 1.9.2+ compatible?
It was deemed a "security" risk.
You can get around it by using absolute paths
File.expand_path(__FILE__) et al
or doing
require './filename' (ironically).
or by using
require_relative 'filename'
or adding an "include" directory
ruby -I . ...
or the same, using irb;
$irb -I .
There's two reasons:
robustness and
security
Both are based on the same underlying principle: in general, you simply cannot know what the current directory is, when your code is run. Which means that, when you require a file and depend on it being in the current directory, you have no way of controlling whether that file will even be there, or whether it is the file that you actually expect to be there.
As others answers point out, it's a security risk because . in your load path refers to the present working directory Dir.pwd, not the directory of the current file being loaded. So whoever is executing your script can change this simply by cding to another directory. Not good!
I've been using full paths constructed from __FILE__ as an alternative.
require File.expand_path(File.join(File.dirname(__FILE__), 'filename'))
Unlike require_relative, this is backward compatible with Ruby 1.8.7.
Use require_relative 'file_to_require'
Throw this in your code to make require_relative work in 1.8.7:
unless Kernel.respond_to?(:require_relative)
module Kernel
def require_relative(path)
require File.join(File.dirname(caller.first), path.to_str)
end
end
end
'.' in your path has long been considered a bad thing in the Unix world (see, for example, http://www.faqs.org/faqs/unix-faq/faq/part2/section-13.html). I assume the Ruby folks have been persuaded of the wisdom of not doing that.
I found this to be a confounding change until I realized a couple of things.
You can set RUBYLIB in your .profile (Unix) and go on with life as you did before:
export RUBYLIB="."
But as mentioned above, it's long been considered unsafe to do so.
For the vast majority of cases you can avoid problems by simply calling your Ruby scripts with a prepended '.' e.g. ./scripts/server.
As Jörg W Mittag pointed out, I think what you want to be using is require_relative so the file you require is relative to the source file of the require declaration and not the current working dir.
Your dependencies should be relative to your rake build file.
I have a Ruby code with different classes in a few files. In one file, I start the execution. This file requires my other files.
Is this a good way to start a ruby code?
When I run the code from a symbolic link, for example DIR2/MyRubyCode is a link to the main file DIR1/MyRubyCode.rb, then my requires will fail. I solved the problem by adding the path DIR1 to $LOAD_PATH before the require, but I think there would be much better ways to do it. Do you have any suggestions about that?
If you're using Ruby 1.9 or greater, user require_relative for your dependencies.
require_relative 'foo_class'
require_relative 'bar_module'
If you want to check if a Ruby file is being 'require'ed or executed with 'ruby MyRubyCode.rb', check the __FILE__ constant.
# If the first argument to `ruby` is this file.
if $0 == __FILE__
# Execute some stuff.
end
As far as the require/$LOAD_PATH issue, you could always use the relative path in the require statement. For example:
# MyRubyCode.rb
require "#{File.dirname(__FILE__)}/foo_class"
require "#{File.dirname(__FILE__)}/bar_module"
Which would include the foo_class.rb and bar_module.rb files in the same directory as MyRubyCode.rb.
I know this is an old question, but there is an updated answer to it, and I wanted to post it:
Starting in a more recent version of Ruby (I'm not sure when), you can require files in the same directory by using the following:
require './foo_class'
require './bar_module'
and it'll load files called foo_class.rb and bar_module.rb in the same directory.
For checking if your file is being required or ran normally, check the other answer.
I have a folder full of ruby files, and when I try and require one file in another that is in the same directory using require 'file' I get a LoadError but when I use require './file' everything works fine. Can somebody explain to me why this happens and if there is any way I can require a file without adding a ./ onto the file?
(Picture of directory):
If you want to require a file not from the system $LOAD_PATH but rather relative to the directory of the file you are requireing from, you should use require_relative. (Which, as you can see, isn't exactly extensively documented.)
You don't have current directory in your loadpath.
Check the contents of the $LOAD_PATH variable
Though it is very old post I think some extra information will be very useful to beginner.
The best way to think of require is in relation to the UNIX $PATH variable. Just by way of a refresher, the $PATH variable in UNIX is a list of directories where executables can be found. So when you type the name of a program on any UNIX terminal, your computer is looking through the executable files in the directories specified in your $PATH variable. require does something very similar. When, for example, you write require 'set' at the top of your Ruby file, you are telling Ruby to look through a bunch of directories for a library called set.rb (Ruby's set library).
So where does Ruby look for set.rb? Well, once again, Ruby has something very similar to UNIX's $PATH variable. It is the global variable $LOAD_PATH also sometimes known by it's ugly and undescriptive alias $: (which I don't suggest using by the way--short though it may be). It is an array of directory names where Ruby looks when it comes across a require.
There is nice informative post here where you can get more information about require, load and require_relative
The latest changesets to Ruby 1.9.2 no longer make the current directory . part of your LOAD_PATH. I have a non-trivial number of Rakefiles that assume that . is part of the LOAD_PATH, so this broke them (they reported "no such file to load" for all require statements that based off the project path). Was there a particular justification for doing this?
As for a fix, adding $: << "." everywhere works, but seems incredibly hacky and I don't want to do that. What's the preferred way to make my Rakefiles 1.9.2+ compatible?
It was deemed a "security" risk.
You can get around it by using absolute paths
File.expand_path(__FILE__) et al
or doing
require './filename' (ironically).
or by using
require_relative 'filename'
or adding an "include" directory
ruby -I . ...
or the same, using irb;
$irb -I .
There's two reasons:
robustness and
security
Both are based on the same underlying principle: in general, you simply cannot know what the current directory is, when your code is run. Which means that, when you require a file and depend on it being in the current directory, you have no way of controlling whether that file will even be there, or whether it is the file that you actually expect to be there.
As others answers point out, it's a security risk because . in your load path refers to the present working directory Dir.pwd, not the directory of the current file being loaded. So whoever is executing your script can change this simply by cding to another directory. Not good!
I've been using full paths constructed from __FILE__ as an alternative.
require File.expand_path(File.join(File.dirname(__FILE__), 'filename'))
Unlike require_relative, this is backward compatible with Ruby 1.8.7.
Use require_relative 'file_to_require'
Throw this in your code to make require_relative work in 1.8.7:
unless Kernel.respond_to?(:require_relative)
module Kernel
def require_relative(path)
require File.join(File.dirname(caller.first), path.to_str)
end
end
end
'.' in your path has long been considered a bad thing in the Unix world (see, for example, http://www.faqs.org/faqs/unix-faq/faq/part2/section-13.html). I assume the Ruby folks have been persuaded of the wisdom of not doing that.
I found this to be a confounding change until I realized a couple of things.
You can set RUBYLIB in your .profile (Unix) and go on with life as you did before:
export RUBYLIB="."
But as mentioned above, it's long been considered unsafe to do so.
For the vast majority of cases you can avoid problems by simply calling your Ruby scripts with a prepended '.' e.g. ./scripts/server.
As Jörg W Mittag pointed out, I think what you want to be using is require_relative so the file you require is relative to the source file of the require declaration and not the current working dir.
Your dependencies should be relative to your rake build file.
Sorry if this question is very easy, but I can't find the answer anywhere. How do you refer to an external ruby file in a ruby script if, for example, the file you want is in the same folder as the one you are writing?
Thanks in advance.
You just do a require like this require "filename". Ruby will look in each of the paths in the $LOAD_PATH variable to find the file.
Have a look at $LOAD_PATH and you should get something like this:
irb(main):001:0> puts $LOAD_PATH
/usr/local/lib/ruby/site_ruby/1.8
/usr/local/lib/ruby/site_ruby/1.8/i686-darwin10.0.0
/usr/local/lib/ruby/site_ruby
/usr/local/lib/ruby/vendor_ruby/1.8
/usr/local/lib/ruby/vendor_ruby/1.8/i686-darwin10.0.0
/usr/local/lib/ruby/vendor_ruby
/usr/local/lib/ruby/1.8
/usr/local/lib/ruby/1.8/i686-darwin10.0.0
.
You can see that the last entry is the current directory.
You can also give a path specifically like require "lib/filename.rb"
require "YOUR_EXTERNAL_FILE_NAME_WITHOUT_DOT_RB_EXTENSION"
For example, if you have two files, 'file0.rb' and 'file1.rb' and want to include 'file0.rb' from 'file1.rb' (and both files are in the same folder), your 'file1.rb' should have following statement:
require 'file0'