“require File.dirname(__FILE__)” — how to safely u

2020-05-19 04:54发布

Some Ruby librararies I'm using use require statements like this:

require File.dirname(__FILE__) + '/specification_helper.rb'

lib_dir = File.expand_path(File.join(File.dirname(__FILE__), "lib"))

require File.join(File.dirname(__FILE__), 'lib/tools', 'version')

require File.expand_path(File.join(File.dirname(__FILE__), 'datautils', 'conn'))

Doesn't this format make your code needlessly dependent on the structure of the file system?

Why did the author do it this way?

Would it be possible to (safely) alter this code to remove this dependency on the filesystem?

1条回答
姐就是有狂的资本
2楼-- · 2020-05-19 05:37

I actually use this scheme in production code.

Requiring files relative to the current source location has several advantages :

  • the source tree can be moved around as a whole and remains usable since we require sources relatively to each other.
  • since we use full paths, we avoid accidental collisions (loading a source with the same name in another library, or reloading the same source twice)
  • the code can be used without having to modify ruby's search path

Should you prefer to use a modified ruby search path, you can do it in multiple ways :

  1. adding -I options on the ruby command line
  2. modifying the $LOAD_PATH variable within the sources
  3. playing with the environment variable RUBYLIB

Solution 1 implies controlling how ruby is invoked. You'll need a script to start the program, such as:

@echo off
REM my_script.cmd
set srcdir=%~dp0\..\path\to\source
ruby -I %srcdir% %srcdir%\my_script.rb

Or:

#!/bin/sh
srcdir=$(cd $(dirname $0)/../path/to/source && pwd)
exec ruby -I $srcdir $srcdir/my_script.rb

Solution 2 is workable but does not avoid collisions. You'll typically do something like :

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))

Solution 3 is unadvisable, the less dependencies you'll have toward environment variables, the better you will be.

查看更多
登录 后发表回答