惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
Check Point Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
WordPress大学
WordPress大学
P
Proofpoint News Feed
V
Visual Studio Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
N
Netflix TechBlog - Medium
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 聂微东
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 叶小钗
Cisco Talos Blog
Cisco Talos Blog
S
Schneier on Security
T
Threat Research - Cisco Blogs
腾讯CDC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Hacker News
The Hacker News
Google DeepMind News
Google DeepMind News
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
N
News | PayPal Newsroom
L
LINUX DO - 最新话题
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Palo Alto Networks Blog
T
Tenable Blog
S
Secure Thoughts
T
Threatpost
V2EX - 技术
V2EX - 技术
大猫的无限游戏
大猫的无限游戏
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Vercel News
Vercel News
罗磊的独立博客
P
Privacy & Cybersecurity Law Blog
Engineering at Meta
Engineering at Meta
小众软件
小众软件
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
Y
Y Combinator Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cybersecurity and Infrastructure Security Agency CISA
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
P
Privacy International News Feed
H
Heimdal Security Blog
量子位
B
Blog

Ruby on Rails: Compress the complexity of modern web apps

Safer to_i coercion, custom to_fs formats, and more! This Week in Rails: May 16, 2026 This Week in Rails: May 8, 2026 This Week in Rails: May 1, 2026 Active Record gets better every week Great big Rails World 2026 update: CFP, Corporate Support tickets, workshops Query command for database queries and more Explicit query: and body: kwargs for integration tests and more! Speedup ActiveRecord::LogSubscriber#sql_color and more! This Week in Rails: March 27, 2026 Rails Versions 8.0.5 and 8.1.3 have been released! Rails Versions 7.2.3.1, 8.0.4.1, and 8.1.2.1 have been released! This Week in Rails: March 20, 2026 Validate URI scheme in Action Text and more This Week in Rails: March 6, 2026 Planning Center is the newest Rails Foundation Contributing member Action Text gets Markdown conversion, editor links in devcontainers, and more! BARRA seeks Rails developer Joe Agliozzo is looking for a Rails developer The rise of lighttpd as the alternative web server When longer is better and more is more Snowdevil: First e-tailer on Rails Natural selection for frameworks in Ruby vs Java Address book tutorial in Portuguese Becoming a better programmer with Rails 10 Things Every Java Programmer Should Know About Ruby Really Getting Started in Rails Off the Treadmill, Onto the Rails Rails 0.9.5: A world of fixes and tweaks Rich clients with Rails and XUL Pedrosa on Rails vs WebWork: 'Language DOES matter' 'Ruby on Rails is unbelievably good' Celebrating six months anniversary! Speeding up CGI access to Gem Rails CD Baby leaves PHP behind for Ruby on Rails "I think Ruby on Rails is way over hyped" Programmer needed for JSP to Rails conversion Beyond the 10,000th gem install of Rails 'That application is so stupid' Matz takes note of Ta-da and Rails Rails tutorial on O'Reilly's ONLamp Welcome Slashdotters! Ta-da goes international with UTF-8 Make your Ta-da list today Rails 0.9.4.1: Cleaning up the mess Rails 0.9.4: Caching, filters, SQLite3... An unusual high presence of Macs Having problems running tests under 1.8.2? It\'s all about the applications But what does Rails go web services with XML-RPC prototype Rails runs through XP Cincinnati RedHanded out-evangelizes the evangelizer Rails on Lighttpd with FastCGI Have a codefest and collect cash from RubyCentral Jamis Buck is working on Basecamp S5 Presents competes with SoapBX 3,000 people are doing 10,804 things... Using the Rails to impress potential employers Brian discovers the default logging goodness SoapBX: Presentations powered by S5, Textile, Rails Road Map: The rails leading to 1.0 Tracks: A Getting Things Done implementation Nicholas presents the Directors Rails 0.9.3: Optimistic locking, dynamic finders, 1.8.2 Ruby on the German Rails 43things in 5,204 lines of Ruby on Rails Watch for huge requests on default FCGI How the redesign of the website came to be Are you watching the health of your software? "Some amazing web apps appear on Ruby on Rails" Learning Ruby on Rails with 43things The Robot Co-op takes 43things.com live! Giving up on Java for lack of love Setting up EliteJournal on TextDrive without a vhost Celebrating 219 applied patches since 0.7 Escaping Java but not its thinking "Simple design that even my grandma can understand" Rails logo remixed by Olivier Hericord Rake 0.4.14 includes fix for Ruby 1.8.2 Splitting off the research patches Running rake tests with Ruby 1.8.2 Marten opens Epilog for Trac'ing Drew McLellan predicts Rails celebrates more than 10,000 downloads Variations on a railed theme Securing your Rails: Keep it secret, keep it safe Available for hire? Collaboa and EliteJournal joins the Trac Playing Active Records on MS SQLServer and DB2 Open sourcing the Rails logo Rails: Technology of the Year #1 Reacting to customer requests in real time Extracting missing content from wiki backups Ruby on Rails has its web presence overhauled 43 things makes The Seattle Times 5.gets David Heinemeier Hansson Ruby 1.8.2 finally sees the light of day Rails 0.9: Fast development, breakpoints, validations Rails 0.9.1: Small, but important bugfix for Action Pack
Gem Packaging: Best Practices
David Heinemeier Hansson · 2009-09-01 · via Ruby on Rails: Compress the complexity of modern web apps

Tuesday, September 1, 2009
Posted by Josh Peek

Understand Ruby’s Load Path

<p>When you call <code>load</code> or <code>require</code> a new file, Ruby searches through the files in its load path. This allows you to require files relative to the load path without specifying the files full system path.</p>


<p>The initial load path contains paths for Ruby&#8217;s standard library. There are three aliases that point to Rubys global load path array: <code>$:, $-I, $LOAD_PATH</code>. You can append or prepend you own libraries to this list. The load path can also be modified from the command line with the <code>-I</code> flag.</p>


<p>Here is the initial load path on my Mac.</p>
  >> $LOAD_PATH
  => ["/Users/josh/.rip/active/lib",
      "/Library/Ruby/Site/1.8",
      "/Library/Ruby/Site/1.8/powerpc-darwin9.0",
      "/Library/Ruby/Site/1.8/universal-darwin9.0",
      "/Library/Ruby/Site",
      "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8",
      "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/powerpc-darwin9.0",
      "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0",
      "."]
<p>There are a few far-too-common mistakes people make with load paths.</p>


<h5>Respect the global load path</h5>


<p>When you package up your new rubygem to share with the world, you need to be careful with the files you place directly in <em>lib/</em>. Rubygems (and almost all other ruby package mangers) will add your gem&#8217;s <em>lib/</em> to the load path. This means any file placed in the top level of <em>lib/</em> will be directly requirable by anyone using the gem.</p>


<h6>Bad gem example:</h6>
  `-- lib
      |-- foo
      |   `-- cgi.rb
      |-- foo.rb
      |-- erb.rb
      `-- set.rb
<p>It may seem harmless to call files whatever you&#8217;d like in your package because you are &#8220;namespaced&#8221; in your own package. But if <em>lib/</em> is prepended to <code>$LOAD_PATH</code> it will clobber Ruby&#8217;s built in <em>erb</em> and <em>set</em> libs. <code>require 'erb'</code> would no longer require Ruby&#8217;s builtin erb library, but this package&#8217;s version of it.</p>


<p>The safe (and correct) way would be to namespace your files under another directory. Its conventional to create a folder within lib with the same name as your gem. Then we would put all our dependency files under <em>lib/foo/</em> instead of at <em>lib/</em> root.</p>


<p>This is sort of a gray area. There is no strict rule that you <strong>must</strong> put all your files under a folder with your package name. It is okay to have multiple files at your root lib directory as long as you intend for people to require them separately. Namespace internal dependency files that you don&#8217;t expect for people to require directly.</p>


<h5>Requiring other files relative to each other</h5>
  require File.join(File.dirname(__FILE__), "foo", "bar")
  # or
  require File.expand_path(File.join(File.dirname(__FILE__), "foo", "bar"))
<p>If you&#8217;re using <code>File.dirname(__FILE__)</code> with require, you&#8217;re doing something wrong.</p>


<p>The fix is simple, require files relative to the load path.</p>
  require "foo/bar" 
<p>Its interesting that the 3 previous <code>require</code> examples are totally different. Ruby is only able to track which files it has required by the exact path you gave it. The first is relative your current directory (<em>&#8221;./lib/foo/bar&#8221;</em>), the second is the full expanded system path (<em>&#8221;/usr/local/lib/ruby/gems/foo/lib/foo/bar&#8221;</em>), and the third is relative to the load path (<em>&#8221;foo/bar&#8221;</em>). <code>require</code> treats each as a different file, so it may end up loading the file multiple times.</p>


<h5>Depending on files outside the load path</h5>


<p>This is a more severe case of the previous example.</p>
  module Rack
    module Test
      VERSION = ::File.read(::File.join(::File.dirname(__FILE__), "..", "..", "VERSION")).strip
      # ...
    end
  end
<p>Your gem&#8217;s folders may be separated and reorganized on install. If someone wants to &#8220;vendor&#8221; your library, they should only have to copy everything under <em>lib/</em>. Everything outside <em>lib/</em> is not important for running the code. Never expect your <em>lib</em> or <em>test</em> folders to be one level up. A minimalist installer, such as <a href="http://hellorip.com/">rip</a>, will only install your <em>bin</em> and <em>lib</em> directories. Any file your package needs to access should be under <em>lib</em> and properly namespaced in a folder to avoid collisions. If you try install this version of rack-test with rip, <code>require 'rack/test'</code> will fail because ../VERSION doesn&#8217;t exist.</p>


<h5>Libs don&#8217;t need to mange $LOAD_PATH</h5>


<p>Its not the package&#8217;s responsibility to setup and manage the load path. Instead rely on the package manger to set it up for. When rubygems activates a gem, it adds your package&#8217;s <em>lib</em> folder to the <code>$LOAD_PATH</code> ready to be required normally by another lib or application. Its safe to assume you can relative <code>require</code> any file in your <em>lib</em> folder.</p>
  unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
    $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
  end
<p>It should be safe to remove code like that.</p>


<h5>TIP: Setup your test runner to configure your paths for local development</h5>


<p>If your trying to develop your lib locally, dealing with all this load path stuff seems like a pain in the ass. This is where rake tests come in handy.</p>


<p>Rake&#8217;s test task will automatically push <em>lib</em> into your path when your test unit tests. So you don&#8217;t need File.join(File.dirname(<i>FILE</i>), &#8221;..&#8221;, &#8220;lib&#8221;, &#8220;foo&#8221;) anywhere in your tests. You may want to consider adding the test directory to your path if you have &#8220;test_helper&#8221; that you need to require.</p>
  Rake::TestTask.new do |t|
    t.libs << 'test'
  end
<p>Unfortunately Rspec doesn&#8217;t even add <em>lib</em> to your path for you. You can fix this with:</p>
  Spec::Rake::SpecTask.new do |t|
    t.libs << 'lib'
  end
<p>If you want to run a single test, you can add <em>lib</em> to the <code>$LOAD_PATH</code> with a command line flag. <em>(This started a <a href="http://github.com/rails/rails/commit/e8170805df1a32119db9d328daee1239b338ac71">long debate</a> when the change was made to Rails)</em></p>
  ruby -Ilib test/test_foo.rb
<h5>Provide a <span class="caps">VERSION</span> constant</h5>


<p>If you release the Awesome gem, provide Awesome::VERSION. When using Rubygems, it&#8217;s possible to ask Rubygems for the version of the gem you&#8217;re using, but when using an alternate package manager, the only way to find out what version is loaded is by introspection into the Ruby code itself.</p>


<h4>Don&#8217;t depend on <code>rubygems</code></h4>


<blockquote>
	<p>When I use your library, deploy your app, or run your tests I may not want to use rubygems. When you &#8220;require &#8216;rubygems&#8217;&#8221; in your code, you remove my ability to make that decision. I cannot unrequire rubygems, but you can not require it in the first place. &#8211; Ryan Tomayko</p>
</blockquote>


<p>Its safe to <strong>remove <code>require "rubygems"</code></strong> from your lib since code loading it probably did this already. It makes it harder (but not impossible) for people to use alternative ways of setting up the load path because there is no way to &#8220;unrequire&#8221; rubygems. There are many other package management solutions out there, like <a href="http://hellorip.com/">rip</a>, <a href="http://github.com/wycats/bundler">bundler</a>, or managing <code>$LOAD_PATH</code> by hand.</p>


<p>Avoid declaring rubygem dependencies in <em>lib/</em>. This means <strong>removing <code>gem "foo"</code></strong>. This creates a hard dependency on Rubygems when you should be specifying you gem dependencies in your gemspec. Rubygems already hooks into <code>require</code> and will automatically resolve these dependencies at runtime. A simple require will trigger the lookup via rubygems, or will just require it if it&#8217;s been added to the load path by another system. Moving dependency specification outside the lib is more flexible for other package managers can do so at install time.</p>


<p>In addition to removing <code>gem</code>, do not wrap your load checks with <code>rescue Gem::LoadError</code> or <code>rescue Gem::Exception</code>. If you need to gracefully skip over load errors, <code>Gem::LoadError</code> inherits from <code>LoadError</code> so replacing it with <code>rescue LoadError</code> will work.</p>
  # Bad
  begin
    gem "rack" 
    require "rack" 
  rescue Gem::LoadError
    puts "Could not load 'rack'" 
    exit
  end

  # Good
  begin
    require "rack" 
  rescue LoadError
    puts "Could not load 'rack'" 
    exit
  end
<h4>Why should I care?</h4>


<p>I wasn&#8217;t aware of any of these issues until Ryan wrote up his <a href="http://gist.github.com/54177">post on why requiring rubygems is wrong</a> at the beginning of 2009. And I feel many other rubyists have just overlooked these issues since rubygems has been our only solution. The foundation of Ruby library management is built on the load path system and its important for every ruby gem author to understand how it works.</p>


<h4>We&#8217;re working on it</h4>


<p>Fixing every ruby library is easier said than done <em>(There are 12,000+ hosted on RubyForge at the time of posting)</em>. Rails is currently in violation of a few of these rules. But we&#8217;re working hard to fix them. We also need to fix all the gems that we depend on. Ideally, we&#8217;d like Rails 3 to boot w/o rubygems and allow you use to whatever package management strategy you&#8217;d like.</p>


<h4>Further reading</h4>


<p><a href="http://yehudakatz.com/2009/07/24/rubygems-good-practice/">Rubygems Good Practice « Katz Got Your Tongue?</a><br /><a href="http://gist.github.com/54177">Why require &#8216;rubygems&#8217; In Your Library/App/Tests Is Wrong</a></p>