简体   繁体   English

将目录添加到$ LOAD_PATH(Ruby)

[英]Adding a directory to $LOAD_PATH (Ruby)

I have seen two commonly used techniques for adding the directory of the file currently being executed to the $LOAD_PATH (or $:). 我已经看到了两种将当前正在执行的文件目录添加到$ LOAD_PATH(或$ :)中的常用技术。 I see the advantages of doing this in case you're not working with a gem. 如果您不使用gem,我会看到这样做的好处。 One seems more verbose than the other, obviously, but is there a reason to go with one over the other? 显然,一个人比另一个人更冗长,但是是否有理由将一个人放在另一个人身上?

The first, verbose method (could be overkill): 第一种冗长的方法(可能会过大):

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))

and the more straightforward, quick-and-dirty: 更直接,快捷和肮脏:

$:.unshift File.dirname(__FILE__)

Any reason to go with one over the other? 有什么理由要互相反对吗?

The Ruby load path is very commonly seen written as $: , but just because it is short, does not make it better. Ruby的加载路径通常被看成$:,但是仅仅因为它很短就不能改善它。 If you prefer clarity to cleverness, or if brevity for its own sake makes you itchy, you needn't do it just because everyone else is. 如果您更喜欢清晰而不是机灵,或者出于简洁目的让自己发痒,那么就不必因为其他所有人都那么做。 Say hello to ... 打招呼 ...

$LOAD_PATH

... and say goodbye to ... ...再见...

# I don't quite understand what this is doing...
$:

我想说的是$:.unshift File.dirname(__FILE__) ,而不是另一个,仅仅是因为我在代码中看到的使用量比$LOAD_PATH一个要$LOAD_PATH ,而且它也更短!

I'm not too fond on the 'quick-and-dirty' way. 我不太喜欢“快速而肮脏”的方式。 Anyone new to Ruby will be pondering what $:. Ruby新手都会考虑$:. is. 是。

I find this more obvious. 我发现这更加明显。

libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

Or if I care about having the full path... 或者,如果我在乎完整的路径...

libdir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

UPDATE 2009/09/10 更新 2009/09/10

As of late I've been doing the following: 到目前为止,我一直在进行以下操作:

$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
    $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

I've seen it in a whole bunch of different ruby projects while browsing GitHub. 浏览GitHub时,我在许多不同的ruby项目中都看到了它。

Seems to be the convention? 似乎是惯例?

If you type script/console in your Rails project and enter $: , you'll get an array that includes all the directories needed to load Ruby. 如果在Rails项目中键入script/console并输入$: :,则会得到一个数组,其中包含加载Ruby所需的所有目录。 The take-away from this little exercise is that $: is an array. 这个小练习的收获是$:是一个数组。 That being so, you can perform functions on it like prepending other directories with the unshift method or the << operator. 这样,您可以在其上执行功能,例如使用unshift方法或<<操作符在其他目录之前。 As you implied in your statement $: and $LOAD_PATH are the same. 正如您在语句中所暗示的$:$LOAD_PATH相同。

The disadvantage with doing it the quick and dirty way as you mentioned is this: if you already have the directory in your boot path, it will repeat itself. 如前所述,以快速,肮脏的方式执行此操作的缺点是:如果引导路径中已经有该目录,它将自动重复。

Example: 例:

I have a plugin I created called todo. 我创建了一个名为todo的插件。 My directory is structured like so: 我的目录结构如下:

/---vendor
  |
  |---/plugins
        |
        |---/todo
              |
              |---/lib
                    |
                    |---/app
                          |
                          |---/models
                          |---/controllers
              |
              |---/rails
                    |
                    |---init.rb

In the init.rb file I entered the following code: 在init.rb文件中,我输入了以下代码:

## In vendor/plugins/todo/rails/init.rb
    %w{ models controllers models }.each do |dir|
      path = File.expand_path(File.join(File.dirname(__FILE__), '../lib', 'app', dir))
      $LOAD_PATH << path
      ActiveSupport::Dependencies.load_paths << path
      ActiveSupport::Dependencies.load_once_paths.delete(path)
    end 

Note how I tell the code block to perform the actions inside the block to the strings 'models', 'controllers', and 'models', where I repeat 'models'. 注意我如何告诉代码块对字符串“ models”,“ controllers”和“ models”执行代码块内的动作,在其中重复“ models”。 (FYI, %w{ ... } is just another way to tell Ruby to hold an array of strings). (仅供参考, %w{ ... }是告诉Ruby保存字符串数组的另一种方法)。 When I run script/console , I type the following: 运行script/console ,键入以下内容:

>> puts $:

And I type this so that it is easier to read the contents in the string. 而且我键入了它,以便更轻松地读取字符串中的内容。 The output I get is: 我得到的输出是:

...
...
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/controllers
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models

As you can see, though this is as simple an example I could create while using a project I'm currently working on, if you're not careful the quick and dirty way will lead to repeated paths. 如您所见,尽管这只是我使用当前正在处理的项目时可以创建的一个简单示例,但如果您不注意,快速而肮脏的方法将导致重复的路径。 The longer way will check for repeated paths and make sure they don't occur. 较长的方法将检查重复的路径,并确保它们不会发生。

If you're an experienced Rails programmer, you probably have a very good idea of what you're doing and likely not make the mistake of repeating paths. 如果您是经验丰富的Rails程序员,那么您可能对自己正在做的事情非常了解,并且可能不会犯重复路径的错误。 If you're a newbie, I would go with the longer way until you understand really what you're doing. 如果您是新手,我会花更长的时间,直到您真正了解自己在做什么。

Best I have come across for adding a dir via relative path when using Rspec. 最好我遇到了使用Rspec时通过相对路径添加目录的问题。 I find it verbose enough but also still a nice one liner. 我觉得它很详细,但仍然是一个不错的选择。

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))

There is a gem which will let you setup your load path with nicer and cleaner code. 有一个gem可以让您使用更好更干净的代码来设置加载路径。 Check this out: https://github.com/nayyara-samuel/load-path . 检查一下: https : //github.com/nayyara-samuel/load-path

It also has good documentation 它也有很好的文档

I know it's been a long time since this question was first asked, but I have an additional answer that I want to share. 我知道第一次提出这个问题已经有很长时间了,但是我还有一个要分享的答案。

I have several Ruby applications that were developed by another programmer over several years, and they re-use the same classes in the different applications although they might access the same database. 我有另一位程序员几年来开发的Ruby应用程序,尽管它们可能访问相同的数据库,但它们在不同的应用程序中重用了相同的类。 Since this violates the DRY rule, I decided to create a class library to be shared by all of the Ruby applications. 由于这违反了DRY规则,因此我决定创建一个类库,以供所有Ruby应用程序共享。 I could have put it in the main Ruby library, but that would hide custom code in the common codebase which I didn't want to do. 我本可以将其放在主要的Ruby库中,但这会在我不想做的通用代码库中隐藏自定义代码。

I had a problem where I had a name conflict between an already defined name "profile.rb", and a class I was using. 我遇到了一个问题,在已经定义的名称“ profile.rb”和我使用的类之间存在名称冲突。 This conflict wasn't a problem until I tried to create the common code library. 在我尝试创建通用代码库之前,这个冲突才不是问题。 Normally, Ruby searches application locations first, then goes to the $LOAD_PATH locations. 通常,Ruby首先搜索应用程序位置,然后转到$ LOAD_PATH位置。

The application_controller.rb could not find the class I created, and threw an error on the original definition because it is not a class. application_controller.rb找不到我创建的类,并且由于它不是类,因此在原始定义上引发了错误。 Since I removed the class definition from the app/models section of the application, Ruby could not find it there and went looking for it in the Ruby paths. 由于我从应用程序的app / models部分中删除了类定义,因此Ruby在此处找不到它,并在Ruby路径中寻找它。

So, I modified the $LOAD_PATH variable to include a path to the library directory I was using. 因此,我修改了$ LOAD_PATH变量,以包括我正在使用的库目录的路径。 This can be done in the environment.rb file at initialization time. 可以在初始化时在environment.rb文件中完成此操作。

Even with the new directory added to the search path, Ruby was throwing an error because it was preferentially taking the system-defined file first. 即使将新目录添加到搜索路径中,Ruby也会抛出错误,因为它优先考虑首先使用系统定义的文件。 The search path in the $LOAD_PATH variable preferentially searches the Ruby paths first. $ LOAD_PATH变量中的搜索路径优先优先搜索Ruby路径。

So, I needed to change the search order so that Ruby found the class in my common library before it searched the built-in libraries. 因此,我需要更改搜索顺序,以便Ruby在搜索内置库之前在我的公共库中找到该类。

This code did it in the environment.rb file: 这段代码是在environment.rb文件中完成的:

Rails::Initializer.run do |config|

* * * * *

path = []
path.concat($LOAD_PATH)
$LOAD_PATH.clear
$LOAD_PATH << 'C:\web\common\lib'
$LOAD_PATH << 'C:\web\common'
$LOAD_PATH.concat(path)

* * * * *

end

I don't think you can use any of the advanced coding constructs given before at this level, but it works just fine if you want to setup something at initialization time in your app. 我认为您不能在此级别上使用之前提供的任何高级编码结构,但是如果您想在应用程序的初始化时进行设置,它就可以正常工作。 You must maintain the original order of the original $LOAD_PATH variable when it is added back to the new variable otherwise some of the main Ruby classes get lost. 将$ LOAD_PATH变量添加回新变量时,必须保持其原始顺序,否则某些主要的Ruby类会丢失。

In the application_controller.rb file, I simply use a 在application_controller.rb文件中,我只是使用

require 'profile'
require 'etc' #etc

and this loads the custom library files for the entire application, ie, I don't have to use require commands in every controller. 这会为整个应用程序加载自定义库文件,即,我不必在每个控制器中都使用require命令。

For me, this was the solution I was looking for, and I thought I would add it to this answer to pass the information along. 对我来说,这就是我一直在寻找的解决方案,我想我会将其添加到此答案中以传递信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM