Feature #8781

Use require_relative() instead of require() if possible

Added by Koichi Sasada 8 months ago. Updated 7 months ago.

[ruby-core:56569]
Status:Open
Priority:Normal
Assignee:-
Category:lib
Target version:next minor

Description

I wrote a attached small script rrc.rb, stand for "RequireRelativeChecker".

This small script points out that require() can be replaced with require_relative().

"Detecting replace-able require()" algorithm is easy (and not perfect):
(1) If loaded file is at sub (or same) directory of requiring file.
(2) If requiring file foo.rb is at $LOAD_PATH, then check only foo/*.
See attached script for details.

This is a part of output.

####
/home/ko1/tmp/trunk/lib/ruby/2.1.0/cgi.rb:294: WARNING: Use requirerelative() to require /home/ko1/tmp/trunk/lib/ruby/2.1.0/cgi/core.rb.
/home/ko1/tmp/trunk/lib/ruby/2.1.0/cgi.rb:295: WARNING: Use require
relative() to require /home/ko1/tmp/trunk/lib/ruby/2.1.0/cgi/cookie.rb.
/home/ko1/tmp/trunk/lib/ruby/2.1.0/date.rb:4: WARNING: Use requirerelative() to require /home/ko1/tmp/trunk/lib/ruby/2.1.0/date/format.rb.
/home/ko1/tmp/trunk/lib/ruby/2.1.0/net/http.rb:1541: WARNING: Use require
relative() to require /home/ko1/tmp/trunk/lib/ruby/2.1.0/net/http/exceptions.rb.
/home/ko1/tmp/trunk/lib/ruby/2.1.0/net/http.rb:1543: WARNING: Use requirerelative() to require /home/ko1/tmp/trunk/lib/ruby/2.1.0/net/http/header.rb.
/home/ko1/tmp/trunk/lib/ruby/2.1.0/net/http.rb:1545: WARNING: Use require
relative() to require /home/ko1/tmp/trunk/lib/ruby/2.1.0/net/http/generic_request.rb.
###

(all of warnings are attached)

How about to replace require() with require_relative() if it is possible?

Advantage:
* require_relative() is faster than require() especially with many gems.
* Easy to detect which file is loaded.

Disadvantage (incompatibility)
* We can't replace loading file with $LOAD_PATH trick.
(But I believe nobody expect such behavior)

(I also recommend other gem authors to use require_relative)

Any comments?

rrc.rb Magnifier (841 Bytes) Koichi Sasada, 08/12/2013 03:35 PM

log (145 KB) Koichi Sasada, 08/12/2013 03:35 PM

History

#1 Updated by Benoit Daloze 8 months ago

Strongly agreed, and it would ensure a whole library is loaded, not by accident a part of it and some other files which happen to have the same structure above in $LOAD_PATH.

#2 Updated by Rodrigo Rosenfeld Rosas 8 months ago

+1

#3 Updated by Steve Klabnik 8 months ago

Isn't require_relative generally considered worse because it makes your file structure more brittle? From a code design standpoint, not from a speed standpoint.

#4 Updated by Thomas Sawyer 8 months ago

requirerelative makes sense for "packages", i.e. where you have a main file that loads a bunch of subordinate files. In other words, the subordinate files could have all been in the main file, but are split out for better organization. So the brittleness you speak of is not an issue here. A much worse brittleness that requirerelative helps prevent is when two libraries clobber each other by using the same absolute library path --it shouldn't happen in a well structured project, but people don't always follow the proper conventions.

#5 Updated by Rodrigo Rosenfeld Rosas 8 months ago

Steve, from my point of view, using require_relative helps us to structure our projects rather than the opposite. That's actually the main reason for my +1, not the speed improvements one.

It helps us avoiding issues that might happen by using a different $LOAD_PATH in some scenarios.

#6 Updated by Eric Hodel 8 months ago

Following an IRC conversation with Koichi I don't believe this bug proposes to eliminate requirerelative outright, instead it is for investigating if requirerelative should be used more in the standard library and in gems. The optimization is useful for libraries with many files as it eliminates repeated $LOAD_PATH lookups.

Regarding the $LOADPATH trick restriction of requirerelative:

For a gem it is not overly restrictive. I typically replace whole libraries as it is easier and more convenient that replacing just one file.

1) gem unpack foo or git clone git@...:foo
2) edit files
3) ruby -I foo/lib …

Is easier than

1) mkdir new/path/to/dir
2) cp {old,new}/path/to/dir/foo.rb
3) edit file
4) ruby -Ilib …

For the second case, a need to edit multiple files and possibly create a patch makes the first option much more convenient..

For files in the standard library, replacing a file loaded by requirerelative that is not part of a gem is more difficult. To alter net/http/request.rb loaded by requirerelative you must duplicate the tree of files that requirerelative it in order to use the $LOADPATH trick. I see adding features of the standard library as default gems a workaround for this restriction.

How is requirerelative more brittle that require? If a file is removed from a gem it can be loaded from the wrong path (via -I if in a gem or vice versa). Using requirerelative the error is immediate and obvious. It seems to eliminate this class of error entirely.

I would like to note that autoload can't benefit from this optimization as it always uses $LOAD_PATH. Koichi suggested adding a relative: true keyword argument to support this.

#7 Updated by Koichi Sasada 8 months ago

(2013/08/13 2:25), drbrain (Eric Hodel) wrote:

For files in the standard library, replacing a file loaded by requirerelative that is not part of a gem is more difficult. To alter net/http/request.rb loaded by requirerelative you must duplicate the tree of files that requirerelative it in order to use the $LOADPATH trick. I see adding features of the standard library as default gems a workaround for this restriction.

I think this proposal depends on that how many people want to do such a
replacement.

Before reading comments, I had believed that there are no case to
replace only a file such as lib/net/http/request.rb required from
lib/net/http.rb. It depends on a version strictly and we can add/modify
behavior by monkey patching. However, I'm not a heavy user of Ruby :p.

If there are many such cases, I need to withdraw this proposal. (without
Eric's "default gem" proposal)

How is requirerelative more brittle that require? If a file is
removed from a gem it can be loaded from the wrong path (via -I if in a
gem or vice versa). Using require
relative the error is immediate and
obvious. It seems to eliminate this class of error entirely.

+1 from design perspective.

--
// SASADA Koichi at atdot dot net

#8 Updated by Eric Hodel 8 months ago

Even if a switch from require to requirerelative is unsuitable for the standard library, we certainly can update the documentation for require and requirerelative with recommended use and caveats.

#9 Updated by Benoit Daloze 8 months ago

ko1 (Koichi Sasada) wrote:

(2013/08/13 2:25), drbrain (Eric Hodel) wrote:

For files in the standard library, replacing a file loaded by requirerelative that is not part of a gem is more difficult. To alter net/http/request.rb loaded by requirerelative you must duplicate the tree of files that requirerelative it in order to use the $LOADPATH trick. I see adding features of the standard library as default gems a workaround for this restriction.

I think this proposal depends on that how many people want to do such a
replacement.

I doubt many users do this.

For my part I always track the project under some version control and edit the file directly
(except for the smallest change when the editor undo feature is enough).

Making the structure is probably even easier with
cp -R lib/net edited than
mkdir -p edited/net/http && cp lib/net/http/request.rb edited/net/http.

#10 Updated by Koichi Sasada 8 months ago

(2013/08/12 15:35), ko1 (Koichi Sasada) wrote:

Advantage:
* require_relative() is faster than require() especially with many gems.

FYI: with Akira (Matsuda-san), we compare performance of require and
require_relative to load thousands of files.

Without Bundler, requirerelative is good performance.
However, with Bundler, require
relative does not help so much.
Maybe most of Ruby user == Rails programmer use Bundler.

So we can concentrate to discuss about "which is a good design?".

--
// SASADA Koichi at atdot dot net

#11 Updated by Thomas Sawyer 8 months ago

On Tue, Aug 13, 2013 at 6:14 AM, SASADA Koichi ko1@atdot.net wrote:

(2013/08/12 15:35), ko1 (Koichi Sasada) wrote:

Advantage:
* require_relative() is faster than require() especially with many gems.

FYI: with Akira (Matsuda-san), we compare performance of require and
require_relative to load thousands of files.

Without Bundler, requirerelative is good performance.
However, with Bundler, require
relative does not help so much.
Maybe most of Ruby user == Rails programmer use Bundler.

Does anyone know why performance degrades with Bundler?

Also, I have wondered before about require_relative performance. In my
tests it seemed like it was slower than it should be. That was about a year
ago. Has any work been done to optimize it --is there room to optimize it?

#12 Updated by Rodrigo Rosenfeld Rosas 8 months ago

Actually, to be completely honest, I use none of them in my Rails projects since they don't play well in development mode with auto-reloading. That's why most people using Rails nowadays will use requiredependency (from activesupport/dependencies) or won't require anything and follow Rails locations conventions and let Rails handle their requires automatically...

#13 Updated by Koichi Sasada 8 months ago

(2013/08/13 19:25), Trans wrote:

FYI: with Akira (Matsuda-san), we compare performance of require and
require_relative to load thousands of files.

Without Bundler, require_relative is good performance.
However, with Bundler, require_relative does not help so much.
Maybe most of Ruby user == Rails programmer use Bundler.

Does anyone know why performance degrades with Bundler?

Also, I have wondered before about require_relative performance. In my
tests it seemed like it was slower than it should be. That was about a
year ago. Has any work been done to optimize it --is there room to
optimize it?

I'm sorry, it was a bad description.

This is not a degration of "require_relative()" with bundler.
Performance improvement of "require()" with Bundler.

Test do:
(1) require some gems
(2-1) require many files
(2-2) require_relative many files

We compared (2-1) and (2-2).

                require() require_relative()

without Bundler about 7sec about 1~2sec
with Bundler about 1~2sec about 1~2sec (* prepare a Gemfile)

# test code:
#
require 'bundler/setup' # with Gemfile or not
require 'haml'
require 'psych'
require 'atomic'
require 'RedCloth'
require 'rspec'

N = 5_000

unless File.exist?("test-files")
Dir.mkdir("test-files")
N.times{|i|
open("test-files/test#{i}.rb", 'w')
}
end

$: << Dir.pwd + "/test-files"
p [$:.size, $:]

N.times{|i|
# require_relative "test-files/test#{i}"
require "test#{i}"
}

--
// SASADA Koichi at atdot dot net

#14 Updated by Aaron Patterson 8 months ago

On Tue, Aug 13, 2013 at 07:38:01AM +0900, SASADA Koichi wrote:

(2013/08/13 2:25), drbrain (Eric Hodel) wrote:

For files in the standard library, replacing a file loaded by requirerelative that is not part of a gem is more difficult. To alter net/http/request.rb loaded by requirerelative you must duplicate the tree of files that requirerelative it in order to use the $LOADPATH trick. I see adding features of the standard library as default gems a workaround for this restriction.

I think this proposal depends on that how many people want to do such a
replacement.

Before reading comments, I had believed that there are no case to
replace only a file such as lib/net/http/request.rb required from
lib/net/http.rb. It depends on a version strictly and we can add/modify
behavior by monkey patching. However, I'm not a heavy user of Ruby :p.

If there are many such cases, I need to withdraw this proposal. (without
Eric's "default gem" proposal)

How is requirerelative more brittle that require? If a file is
removed from a gem it can be loaded from the wrong path (via -I if in a
gem or vice versa). Using require
relative the error is immediate and
obvious. It seems to eliminate this class of error entirely.

+1 from design perspective.

If you move the file, then all calls to require_relative in that file
must be changed. If you had just used require, the file can be moved
without changes.

--
Aaron Patterson
http://tenderlovemaking.com/

#15 Updated by Koichi Sasada 8 months ago

(2013/08/16 14:21), Aaron Patterson wrote:

If you move the file, then all calls to require_relative in that file
must be changed. If you had just used require, the file can be moved
without changes.

Which case?

For example, there are files:
foo.rb
foo/bar/a.rb

And foo.rb has "require 'foo/bar/a'".

If you move foo/bar/a.rb to foo/bar/b.rb, then you need to rewrite to
"require 'foo/bar/b'".

If you move foo/bar/a.rb to foo/baz/a.rb, then you need to rewrite to
"require 'foo/baz/a'".

--
// SASADA Koichi at atdot dot net

#16 Updated by Aaron Patterson 8 months ago

On Fri, Aug 16, 2013 at 03:00:59PM +0900, SASADA Koichi wrote:

(2013/08/16 14:21), Aaron Patterson wrote:

If you move the file, then all calls to require_relative in that file
must be changed. If you had just used require, the file can be moved
without changes.

Which case?

For example, there are files:
foo.rb
foo/bar/a.rb

And foo.rb has "require 'foo/bar/a'".

If you move foo/bar/a.rb to foo/bar/b.rb, then you need to rewrite to
"require 'foo/bar/b'".

If you move foo/bar/a.rb to foo/baz/a.rb, then you need to rewrite to
"require 'foo/baz/a'".

Yes, you changed the files that depend on the source for 'foo/bar/a',
but 'foo/bar/a.rb' itself did not change.

If something you depend on changes location, then yes, you should
change your code.

Here is an example with require_relative:

$ mkdir -p lib/foo/bar
$ touch lib/foo.rb
$ echo "requirerelative '../../foo'" > lib/foo/bar/baz.rb
$ ruby -I lib -r'foo/bar/baz' -e 0
$ mv lib/foo/bar/baz.rb lib/foo/
$ ruby -I lib -r'foo/baz' -e 0
/Users/aaron/git/example/lib/foo/baz.rb:1:in require_relative': cannot load such file -- /Users/aaron/git/example/foo (LoadError)
from /Users/aaron/git/example/lib/foo/baz.rb:1:in
'
from /Users/aaron/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems/core
ext/kernel_require.rb:45:in require'
from /Users/aaron/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in
require'
$

In the above example, "foo.rb" did not change location, yet I have to
change the call to require_relative.

foo/bar/baz.rb depends on foo.rb. foo.rb did not change locations, so
why do I have to change my code?

Let's take the same example, "foo/bar/baz.rb" that depends on "foo.rb",
but instead use require:

$ mkdir -p lib/foo/bar
$ echo "require 'foo'" > lib/foo/bar/baz.rb
$ touch lib/foo.rb
$ ruby -I lib -r'foo/bar/baz' -e 0
$ mv lib/foo/bar/baz.rb lib/foo/
$ ruby -I lib -r'foo/baz' -e 0
$

My dependency, "foo.rb", did not change locations, so I don't need to
change my code. "foo/bar/baz.rb" works as-is, no matter where it is on
the filesystem. :-)

--
Aaron Patterson
http://tenderlovemaking.com/

#17 Updated by Rodrigo Rosenfeld Rosas 8 months ago

Since we were discussing the design perspective, you just demonstrated how the design of using require can become much worse than using requirerelative. When you're reading code you can be sure where to look for the files being loaded as expected while when using require you will always have to check $LOADPATH to be sure. I don't really think using require to allow such hacks is a good enough reason to favor require instead of require_relative... After all, Ruby already allows you to override code by monkey patching. Why would you need to override a full file?

#18 Updated by Steve Klabnik 8 months ago

Thank you, Aaron, that was what I was trying to say, but put much better. <3

#19 Updated by Thomas Sawyer 8 months ago

$ echo "require_relative '../../foo'" > lib/foo/bar/baz.rb

Seriously? That is not a real use case. Proper use of require_relative is downward, not upward.

#20 Updated by Aaron Patterson 8 months ago

On Sat, Aug 17, 2013 at 07:17:50AM +0900, trans (Thomas Sawyer) wrote:

Issue #8781 has been updated by trans (Thomas Sawyer).

$ echo "require_relative '../../foo'" > lib/foo/bar/baz.rb

Seriously? That is not a real use case. Proper use of require_relative is downward, not upward.

sigh

First, it is a real use case (as in, people actually use it in real
projects):

[aaron@higgins ruby (trunk)]$ git grep require_relative | grep '..' | wc -l
45
[aaron@higgins ruby (trunk)]$

If Ruby's source code isn't enough examples for you, try a GitHub seach:

https://github.com/search?q=require_relative+..&type=Code&ref=searchresults

It's not up to you what is "proper" use.

Second, my point remains valid whether you go down or up. Let's do
another example.

"foo.rb" depends on "foo/bar/baz.rb".

$ mkdir -p lib/foo/bar
$ touch lib/foo/bar/baz.rb
$ echo "requirerelative 'foo/bar/baz'" > lib/foo.rb
$ ruby -I lib -rfoo -e 0
$ mv lib/foo.rb lib/foo/
$ ruby -I lib -rfoo/foo -e 0
/Users/aaron/git/example/lib/foo/foo.rb:1:in require_relative': cannot load such file -- /Users/aaron/git/example/lib/foo/foo/bar/baz (LoadError)
from /Users/aaron/git/example/lib/foo/foo.rb:1:in
'
from /Users/aaron/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems/core
ext/kernel_require.rb:45:in require'
from /Users/aaron/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in
require'
$

If we move "foo.rb", we still have to change the call to
"require_relative" even though the file we depend on did not change.

Here is the same example just using require:

$ mkdir -p lib/foo/bar
$ echo "require 'foo/bar/baz'" > lib/foo.rb
$ touch lib/foo/bar/baz.rb
$ ruby -I lib -rfoo -e 0
$ mv lib/foo.rb lib/foo/
$ ruby -I lib -rfoo/foo -e 0
$

Again, "foo.rb" is completely independent of the filesystem. The files
it depends on did not change, so it did not have to change.

I am uncertain how to make the coupling between "require_relative" and
the filesystem more clear than this.

--
Aaron Patterson
http://tenderlovemaking.com/

#21 Updated by Aaron Patterson 8 months ago

On Fri, Aug 16, 2013 at 09:35:04AM -0300, Rodrigo Rosenfeld Rosas wrote:

Em 16-08-2013 03:24, Aaron Patterson escreveu:

On Fri, Aug 16, 2013 at 03:00:59PM +0900, SASADA Koichi wrote:

(2013/08/16 14:21), Aaron Patterson wrote:

If you move the file, then all calls to require_relative in that file
must be changed. If you had just used require, the file can be moved
without changes.
Which case?

For example, there are files:
foo.rb
foo/bar/a.rb

And foo.rb has "require 'foo/bar/a'".

If you move foo/bar/a.rb to foo/bar/b.rb, then you need to rewrite to
"require 'foo/bar/b'".

If you move foo/bar/a.rb to foo/baz/a.rb, then you need to rewrite to
"require 'foo/baz/a'".
Yes, you changed the files that depend on the source for 'foo/bar/a',
but 'foo/bar/a.rb' itself did not change.

If something you depend on changes location, then yes, you should
change your code.

Here is an example with require_relative:

$ mkdir -p lib/foo/bar
$ touch lib/foo.rb
$ echo "requirerelative '../../foo'" > lib/foo/bar/baz.rb
$ ruby -I lib -r'foo/bar/baz' -e 0
$ mv lib/foo/bar/baz.rb lib/foo/
$ ruby -I lib -r'foo/baz' -e 0
/Users/aaron/git/example/lib/foo/baz.rb:1:in require_relative': cannot load such file -- /Users/aaron/git/example/foo (LoadError)
from /Users/aaron/git/example/lib/foo/baz.rb:1:in
'
from /Users/aaron/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems/core
ext/kernel_require.rb:45:in require'
from /Users/aaron/.rbenv/versions/2.0.0-p247/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in
require'
$

In the above example, "foo.rb" did not change location, yet I have to
change the call to require_relative.

foo/bar/baz.rb depends on foo.rb. foo.rb did not change locations, so
why do I have to change my code?

Let's take the same example, "foo/bar/baz.rb" that depends on "foo.rb",
but instead use require:

$ mkdir -p lib/foo/bar
$ echo "require 'foo'" > lib/foo/bar/baz.rb
$ touch lib/foo.rb
$ ruby -I lib -r'foo/bar/baz' -e 0
$ mv lib/foo/bar/baz.rb lib/foo/
$ ruby -I lib -r'foo/baz' -e 0
$

My dependency, "foo.rb", did not change locations, so I don't need to
change my code. "foo/bar/baz.rb" works as-is, no matter where it is on
the filesystem. :-)

Since we were discussing the design perspective, you just
demonstrated how the design of using require can become much worse
than using requirerelative. When you're reading code you can be
sure where to look for the files being loaded as expected while when
using require you will always have to check $LOAD
PATH to be sure.

Use $LOADED_FEATURES:

[aaron@higgins example]$ touch foo.rb
[aaron@higgins example]$ irb -I .
irb(main):001:0> x = $LOADEDFEATURES.dup; nil
=> nil
irb(main):002:0> require 'foo'
=> true
irb(main):003:0> $LOADED
FEATURES - x
=> ["/Users/aaron/git/example/foo.rb"]
irb(main):004:0>

I don't really think using require to allow such hacks is a good
enough reason to favor require instead of require_relative... After
all, Ruby already allows you to override code by monkey patching.
Why would you need to override a full file?

Simply requiring a file will execute code. There are times (especially
in tests) where you do not want ANY of the code to be executed (maybe it
connects to a database, or network, etc).

--
Aaron Patterson
http://tenderlovemaking.com/

#22 Updated by Thomas Sawyer 8 months ago

But it doesn't matter if it is downward, b/c it is relative to the internal structure. If I move something around in my internal structure, that I might have alter a require statement is to be expected. In your example, if we move foo/bar/baz we'll still break a require, regardless of where foo.rb resides. Worse still, if an external program had depended on the location of foo.rb, moving foo.rb would break their program. In practice, the foo.rb of your example rarely moves, by its very design. It represents a component and the things under foo/ are its subcomponents. Some code in the file might move but not the file itself.

I feel like you are making something of a strawman argument against using requirerelative b/c it is doing exactly what requirerelative is supposed to do. Meanwhile ignoring its benefits. I really don't understand the objection to it. Used judiciously (better than "properly"?) it works quite well.

As for "proper" use, two dollars to a donut most of those uses of ../ relative requires will be in test scripts. I don't even have to look. That's okay b/c it's localized to building the project. I'd still recommend removing it, for example adding test directory to the $LOAD_PATH when running tests. The usage I am talking about is within lib where we are structuring our programs from top level structures to low level structures. It's just the common pattern that we've all used:

module MyApp -> myapp/
class Foo -> foo.rb and foo/
class Bar -> foo/bar.rb

So in foo.rb we require 'foo/bar.rb' not the other way around. That's all I mean by "proper".

Hey, let me make one other interesting point. I would be totally supportive of not using require_relative --requiring relative to the current file, if we could require relative to the current library's base directory. The load system I created actually has this feature. I think it is really the most "proper" solution of all, but it requires that Ruby have some notion of a library as having a base directory. (To clarify, in your example code lib/foo/ is the base directory of the library.)

#23 Updated by Nobuyoshi Nakada 8 months ago

(13/08/17 13:13), Aaron Patterson wrote:

First, it is a real use case (as in, people actually use it in real
projects):

[aaron@higgins ruby (trunk)]$ git grep require_relative | grep '..' | wc -l
45
[aaron@higgins ruby (trunk)]$

It's only in test directory, and almost is test/ruby/envutil.rb.

I agree that require_relative fits something but may not other.
That example tells us that envutil.rb shouldn't be bound in test/ruby.

Again, "foo.rb" is completely independent of the filesystem. The files
it depends on did not change, so it did not have to change.

I am uncertain how to make the coupling between "require_relative" and
the filesystem more clear than this.

But I don't think your point enough to prohibit to use require_relative.
Why move a file but not edit it?
An author can use it when one thinks it is useful, it's the author's choice.
This proposal is just a proposal, but not mandatory.

--
Nobu Nakada

#24 Updated by Rodrigo Rosenfeld Rosas 8 months ago

Em 17-08-2013 01:16, Aaron Patterson escreveu:

...

I don't really think using require to allow such hacks is a good
enough reason to favor require instead of require_relative... After
all, Ruby already allows you to override code by monkey patching.
Why would you need to override a full file?
Simply requiring a file will execute code. There are times (especially
in tests) where you do not want ANY of the code to be executed (maybe it
connects to a database, or network, etc).

Now I finally understand how people are using this trick. I believe this
is mostly used for mocking domain classes (Rails models, for instance)
when using ActiveRecord or Sequel, given their metaprogramming tricks on
initialization to fetch the tables meta-data.

But I don't see how this ticket would affect such environments. If I
understand correctly, what Koichi proposed is to replace require with
require_relative on Ruby stdlibs and core classes only. Do you see any
reason you'd like to execute those files? I believe they won't touch any
database or network so they shouldn't slow down any tests, right?

Cheers,
Rodrigo.

#25 Updated by Aaron Patterson 8 months ago

On Sat, Aug 17, 2013 at 09:00:34PM +0900, Nobuyoshi Nakada wrote:

(13/08/17 13:13), Aaron Patterson wrote:

First, it is a real use case (as in, people actually use it in real
projects):

[aaron@higgins ruby (trunk)]$ git grep require_relative | grep '..' | wc -l
45
[aaron@higgins ruby (trunk)]$

It's only in test directory, and almost is test/ruby/envutil.rb.

I agree that require_relative fits something but may not other.
That example tells us that envutil.rb shouldn't be bound in test/ruby.

Again, "foo.rb" is completely independent of the filesystem. The files
it depends on did not change, so it did not have to change.

I am uncertain how to make the coupling between "require_relative" and
the filesystem more clear than this.

But I don't think your point enough to prohibit to use require_relative.

I don't think it should be prohibited. I am pointing out why I don't
use it (namely LOAD_PATH hacking).

Why move a file but not edit it?

I am using "file moving" as a way to demonstrate how require_relative
couples your file to its location on the file system. require does
not have this coupling.

An author can use it when one thinks it is useful, it's the author's choice.
This proposal is just a proposal, but not mandatory.

Yes. I think it's fine, I just don't want to use it. Are there no more
ways to speed up require?

--
Aaron Patterson
http://tenderlovemaking.com/

#26 Updated by Akira Matsuda 8 months ago

FYI: For those of you who wants to estimate how a "real use case" looks
like, here I made tons of require_relatives on Rails
https://github.com/amatsuda/rails/compare/require_relative
Here I replaced all requires to require_relative.
I confirmed it actually works, and as Ko1 said, we confirmed that it's not
at all faster than the current require version, because Bundler already
made require faster in a different way.

Yes. I think it's fine, I just don't want to use it. Are there no more
ways to speed up require?

  1. Use Bundler

  2. Avoid scanning through all installed gems before falling back to the
    originalrequire:
    https://github.com/ruby/ruby/blob/c106d19/lib/rubygems/core
    ext/kernelrequire.rb#L41
    This is the reason every require call performs significantly slower than
    require
    relative.

  3. Reduce number of installed gems in your box...

    On Sun, Aug 18, 2013 at 5:58 AM, Aaron Patterson
    tenderlove@ruby-lang.orgwrote:

    On Sat, Aug 17, 2013 at 09:00:34PM +0900, Nobuyoshi Nakada wrote:

    (13/08/17 13:13), Aaron Patterson wrote:

    First, it is a real use case (as in, people actually use it in real
    projects):

    [aaron@higgins ruby (trunk)]$ git grep require_relative | grep '..'
    | wc -l
    45
    [aaron@higgins ruby (trunk)]$

    It's only in test directory, and almost is test/ruby/envutil.rb.

    I agree that require_relative fits something but may not other.
    That example tells us that envutil.rb shouldn't be bound in test/ruby.

    Again, "foo.rb" is completely independent of the filesystem. The files
    it depends on did not change, so it did not have to change.

    I am uncertain how to make the coupling between "require_relative" and
    the filesystem more clear than this.

    But I don't think your point enough to prohibit to use require_relative.

    I don't think it should be prohibited. I am pointing out why I don't
    use it (namely LOAD_PATH hacking).

    Why move a file but not edit it?

    I am using "file moving" as a way to demonstrate how require_relative
    couples your file to its location on the file system. require does
    not have this coupling.

    An author can use it when one thinks it is useful, it's the author's
    choice.
    This proposal is just a proposal, but not mandatory.

    Yes. I think it's fine, I just don't want to use it. Are there no more
    ways to speed up require?

    Aaron Patterson
    http://tenderlovemaking.com/

    Akira Matsudaronnie@dio.jp

#27 Updated by Martin Dürst 8 months ago

On 2013/08/18 5:58, Aaron Patterson wrote:

I am using "file moving" as a way to demonstrate how require_relative
couples your file to its location on the file system. require does
not have this coupling.

On the other hand, 'require' has a tighter coupling to the file name
than 'reqirerelative'. It's no problem to have two different files of
the same name with 'require
relative', but it won't work with 'require'.

This reminds me of absolute vs. relative links in Web pages. Both have
their advantages, but none of them is perfect.

Regards, Martin.

#28 Updated by Koichi Sasada 7 months ago

  • Target version changed from 2.1.0 to next minor

No conclusion.

Also available in: Atom PDF