Hey you! Stop using relative requires!

I

Intransition

I recently came across two different programs that had this line in a
bin/ executable:

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../
lib"))

This stuff makes me sad. The use of RubyGems is masking some bad
practices here. The above code would not work with a traditional site
installation.

I imagine this sort of thing has probably trickled down form Rails,
where programmers are accustom to deploying apps rather than releasing
them.

So here are the general rules (that I can think of off the top of my
head):

* Don't mess with the $LOAD_PATH. PERIOD.
* Use relative lookup only when you must, eg. using bundled HTML
templates.
* Any relative paths you do use must remain within the confines of
their main directory (eg. lib/)
* Don't use a relative lookup for any ,rb or .so/.dll loading. PERIOD.
* Oh, and it should never need to necessary to require 'rubygems'.

These rules do not apply to building, eg. your Rakefile, running tests
and such. But try to follow them as much as possible anyway.

~Trans
 
L

Leslie Viljoen

I recently came across two different programs that had this line in a
bin/ executable:

=A0$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../
lib"))

This stuff makes me sad. The use of RubyGems is masking some bad
practices here. The above code would not work with a traditional site
installation.

Why? require_relative has just been added to Ruby 1.9 and I wish it
had been there from the start. How else can you bundle some
application specific library code with an app?

If I don't require rubygems, none of my programs work.

I don't understand any of your points, so can you give some reasons?
 
L

Louis-Philippe

[Note: parts of this message were removed to make it a legal post.]

for further clarification read:
http://gist.github.com/54177

<http://gist.github.com/54177>and

http://www.untilnil.com/2009/02/25/require-principle_of_least_surprise

<http://www.untilnil.com/2009/02/25/require-principle_of_least_surprise>

2009/10/14 Anthony Metcalf said:
Intransition said:
* Don't mess with the $LOAD_PATH. PERIOD.
* Use relative lookup only when you must, eg. using bundled HTML
templates.
* Any relative paths you do use must remain within the confines of
their main directory (eg. lib/)
* Don't use a relative lookup for any ,rb or .so/.dll loading. PERIOD.
* Oh, and it should never need to necessary to require 'rubygems'.
Ok, I just finished "packaging"[1] my first app, and the only way I
could find that described how to do it, including the pickaxe book (for
ruby 1.9), breaks all but the last of those rules.

Care to enlighten me?

I have a structure of:

App
|----> bin -> app.rb
|----> initdb.rb
|----> lib
|----> models -> *.rb
|----> views -> *.rb
|----> controllers -> *.rb
|----> config -> database.yaml
|----> db -> *.sqlite

I'm using wxRuby for the gui, ActiveRecord for the DB access, and
obviously, sqlite for the db.

How do I :

1) Make it so that I can call ruby <path to bin>/app.rb from anywhere in
the filesystem and have my app work?
2) Make 1) true for Linux, Windows and MacOSX?

Regards

Anthony


[1] because it isn't actually packaged yet, just internally consistent....
 
L

Leslie Viljoen


Ah, this helps a little - I will stop requiring rubygems.

Of course, the correct thing:
require File.join( File.dirname( File.expand_path(__FILE__)), 'lib',
'helpers', 'precious')
..is also a relative require!

And I don't understand:
* Don't use a relative lookup for any ,rb or .so/.dll loading. PERIOD.
 
R

Robert Klemme

2009/10/14 Intransition said:
I recently came across two different programs that had this line in a
bin/ executable:

=A0$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../
lib"))

This stuff makes me sad. The use of RubyGems is masking some bad
practices here. The above code would not work with a traditional site
installation.

I am not sure I understand why this is an issue. If it is in an
executable I write locally then I know where libraries reside (of
course, I would set RUBYLIB appropriately but for special tests or so
this might be necessary nevertheless).

If it is an executable which is part of a distribution, paths might be
as well known.

The only situation which could be problematic is an executable which
is deployed on arbitrary systems without modification. Hm...
I imagine this sort of thing has probably trickled down form Rails,
where programmers are accustom to deploying apps rather than releasing
them.

So here are the general rules (that I can think of off the top of my
head):

* Don't mess with the $LOAD_PATH. PERIOD.
* Use relative lookup only when you must, eg. using bundled HTML
templates.
* Any relative paths you do use must remain within the confines of
their main directory (eg. lib/)
* Don't use a relative lookup for any ,rb or .so/.dll loading. PERIOD.
* Oh, and it should never need to necessary to require 'rubygems'.

These rules do not apply to building, eg. your Rakefile, running tests
and such. But try to follow them as much as possible anyway.

As far as I can see we would need at least two different sets of rules

1. requiring in library files
2. requiring in "main" files (executables)

Maybe more.

Kind regards

robert


PS: Why the changed name? Are you moving?

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
R

Robert Klemme

2009/10/14 Anthony Metcalf said:
Thanks for the links. They are interesting.

Does make the require statements a wee bit wacky though, do people
really use

require File.join( File.dirname( File.expand_path(__FILE__)), 'lib',
'helpers', 'precious')

rather than

require 'lib/helpers/precious'

I believe there is a mistake: the second require should read

# file /mygem/lib/helpers.rb
require File.join( File.dirname( File.expand_path(__FILE__)),
'helpers', 'precious')

i.e. the "lib" is superfluous since helpers.rb does reside in lib already.

Whether people use that much I can't say. I believe usually require
'helpers/precious' is safe because if the load path is such that the
initial helpers.rb is found then it will also find the correct
precious.rb with the relative path. I do believe though that the
absolute path is more robust especially when using an explicit path to
require the library root file.

Kind regards

robert
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

Don't use a relative lookup for any ,rb or .so/.dll loading. PERIOD.

As someone who wrote a dependency-resolving code loading gem, I am extremely
dubious that one can always avoid code loading using relative paths.

How would you ordinarily go about loading some .rb files in a subdirectory
beneath the directory in which the current file is located?
 
I

Intransition

As someone who wrote a dependency-resolving code loading gem, I am extrem= ely
dubious that one can always avoid code loading using relative paths.

How would you ordinarily go about loading some .rb files in a subdirector= y
beneath the directory in which the current file is located?

After reading your and previous comments and a brief bit of
unsuccessful googling, I decided it best if I wrote a blog entry on
the matter:

http://proutils.github.com/2009/10/proper-require.html

Hope it helps.

Note the blog itself isn't quite "fully operational" -- no rss feed,
comments, and so forth yet, sorry. So please comment here.
 
J

James Edward Gray II

I decided it best if I wrote a blog entry on the matter:

http://proutils.github.com/2009/10/proper-require.html

Hope it helps.

Note the blog itself isn't quite "fully operational" -- no rss feed,
comments, and so forth yet, sorry. So please comment here.

Quoting from that page:

=95 Don't mess with the $LOAD_PATH. PERIOD.

My rule for rules:

* Don't make rules that can never be broken. Period.

There are totally viable reasons to use $LOAD_PATH. For example, a =20
Rails project is a self contained chunk of code that works together =20
and it makes total sense to add certain portions of that project to =20
the $LOAD_PATH, just as Rails does.

James Edward Gray II=
 
R

Robert Klemme

Quoting from that page:

• Don't mess with the $LOAD_PATH. PERIOD.

My rule for rules:

* Don't make rules that can never be broken. Period.

Don't make rules without proof reading them. :)

SCNR

I think I agree to what you intended (if that is what you intended):
rules should be checked against reality - if you cannot adhere to them
under all conditions rather make them guidelines than rules - if at all.

Cheers

robert
 
T

Thomas Sawyer

James said:
Quoting from that page:

� Don't mess with the $LOAD_PATH. PERIOD.

My rule for rules:

* Don't make rules that can never be broken. Period.

There are totally viable reasons to use $LOAD_PATH. For example, a
Rails project is a self contained chunk of code that works together
and it makes total sense to add certain portions of that project to
the $LOAD_PATH, just as Rails does.

Tried to respond a few times, Google Groups is acting up it seems, so if
I ultimately triple post, my apologies.

To be brief, you are correct in that these rules do not apply to Rails
apps. I'm talking about Ruby projects. I made a note of it in the post
to clarify that fact.

Thanks.
 
J

James Edward Gray II

Tried to respond a few times, Google Groups is acting up it seems, =20
so if
I ultimately triple post, my apologies.

To be brief, you are correct in that these rules do not apply to Rails
apps. I'm talking about Ruby projects. I made a note of it in the post
to clarify that fact.

I'm pretty sure we can come up with non-Rails applications scenarios =20
where they don't apply. I vote we just reject the dogma and focus on =20=

the problems it can cause.

I'm not saying you're wrong about the issue. I'm just saying that =20
telling us to never do something, is just a turn off.

James Edward Gray II=
 
T

Thomas Sawyer

James said:
I'm pretty sure we can come up with non-Rails applications scenarios
where they don't apply. I vote we just reject the dogma and focus on
the problems it can cause.

I'm not saying you're wrong about the issue. I'm just saying that
telling us to never do something, is just a turn off.

Ok. But I think maybe you are missing my point. I'm not pushing a dogma.
I am making an emphasis: There is no reason to use relative loading at
all in those cases. To re-phase... I'm not telling you not to do it. I
am telling you there is absolutely no need for you to do it.

I'm very much doubt there are any outlay cases. But if there are, I'd be
more than ready to amend these "rules".

Also, let me just note that I actually like relative loading, b/c I like
folder based packaging (I'm a fan of GoboLinux for instance). But
without the major distro's embrace it's not something that can be
completely relied upon (hence the bin/ example). If it were, I think
Ruby would have better support for it too. I mean really, doesn't

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) +
"/../lib"))

give off just a little code smell? ;)
 
M

Michael W. Ryder

Thomas said:
Ok. But I think maybe you are missing my point. I'm not pushing a dogma.
I am making an emphasis: There is no reason to use relative loading at
all in those cases. To re-phase... I'm not telling you not to do it. I
am telling you there is absolutely no need for you to do it.

I'm very much doubt there are any outlay cases. But if there are, I'd be
more than ready to amend these "rules".

Also, let me just note that I actually like relative loading, b/c I like
folder based packaging (I'm a fan of GoboLinux for instance). But
without the major distro's embrace it's not something that can be
completely relied upon (hence the bin/ example). If it were, I think
Ruby would have better support for it too. I mean really, doesn't

What would you suggest in the case of multiple versions of a module for
testing purposes? If everything is "hard coded" to go to a specific
directory than all versions would use the same code and defeat the
purpose of having the different versions.
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

Ok. But I think maybe you are missing my point. I'm not pushing a dogma.
I am making an emphasis: There is no reason to use relative loading at
all in those cases. To re-phase... I'm not telling you not to do it. I
am telling you there is absolutely no need for you to do it.

I'm very much doubt there are any outlay cases. But if there are, I'd be
more than ready to amend these "rules".

Just a general description of how you handle code loading within a gem
that's "under development" (i.e. all code lives in a directory somewhere,
not in a gem) while requiring minimal/no changes to a "released" gem (one
which loads through a RubyGems-defined LOAD_PATH) would be helpful.

Or for that matter, how about selectively pulling in files which require the
toplevel gem but exist under subdirectories within the gem, and need to load
the gem in order to function? How would you handle that?

If there's some magic tricks I'm missing to solving these sorts of
conundrums, I'm certainly interested in hearing them. I think for the most
part something like require_all/require_rel takes care of a lot of the
problems of code loading, and certainly isn't my own solution, just my
implementation, but I'm curious how people solve these sorts of problems
without it.
 
I

Intransition

What would you suggest in the case of multiple versions of a module for
testing purposes? =A0If everything is "hard coded" to go to a specific
directory than all versions would use the same code and defeat the
purpose of having the different versions.

Testing is a build issue and a separate matter. In that case you want
to simulate the Ruby environment locally, so you would add lib/ to the
$LOAD_PATH in your *helper* script. Or on the command line of your
test runner. Eg.

$ testrb -Ilib test/**/*.rb
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

* Don't mess with the $LOAD_PATH. PERIOD.

Testing is a build issue and a separate matter. In that case you want
to simulate the Ruby environment locally, so you would add lib/ to the
$LOAD_PATH in your *helper* script.

Lol, I have no idea what to do anymore. Practical Ruby Gems decreased to $4
since I last logged onto Amazon, I think I'll push that purchase through and
defer to it's expertise.
 
M

Michal Suchanek

2009/10/14 Intransition said:
I recently came across two different programs that had this line in a
bin/ executable:

=C2=A0$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../
lib"))

This stuff makes me sad. The use of RubyGems is masking some bad
practices here. The above code would not work with a traditional site
installation.

It's not for site installation.

It's for packaged applications.

I wrote a pure ruby application that you can just unpack and run, no
need to "install" it on your system, and it uses the exact code you
show except it does not use the "/../".

This is ideal for situations when you do not want to require the users
to have a development environment ready to "install" the application.
Just having a ruby interpreter preinstalled from a binary package
suffices.

Thanks

Michal
 
I

Intransition

It's not for site installation.

It's for packaged applications.

I wrote a pure ruby application that you can just unpack and run, no
need to "install" it on your system, and it uses the exact code you
show except it does not use the "/../".

This is ideal for situations when you do not want to require the users
to have a development environment ready to "install" the application.
Just having a ruby interpreter preinstalled from a binary package
suffices.

Thanks

Hi Michal

I've seen equivalent code in quite a few projects. Maybe they all have
the same reasoning, though I suspect they are just copying form one
another. Which is really why I wrote that blog post --so people at
least are aware.

I've thought about it further and I think maybe something "larger
picture" is actually taking place. I wrote a follow up post:

http://proutils.github.com/2009/10/fhs-revolt.html

Thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top