why can I require gems which are outside from $LOAD_PATH - ruby

I installed a gem coffee-cup in my rvm gem set,ruby-2.1.1#test whose path is /Users/dingxijin/.rvm/gems/ruby-2.1.1#test/gems/coffee-cup-0.0.4.
Then I open irb,just like this:
2.1.1 :001 > puts $:
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/x86_64-darwin12.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin12.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/x86_64-darwin12.0
=> nil
2.1.1 :002 > require "coffee-cup"
NameError: uninitialized constant CoffeeCup::Rails
from /Users/dingxijin/.rvm/gems/ruby-2.1.1#test/gems/coffee-cup-0.0.4/lib/coffee-cup/engine.rb:2:in `<module:CoffeeCup>' ..........
Does ruby search gems from the $LOAD_PATH directories?
why can I require coffee-cup,it's obviously that $LOAD_PATH doesn't have its directory?

The original, “normal” behaviour of require is how you have described it: the LOAD_PATH is searched for the requested file and if it’s not found a LOAD_ERROR is raised. Rubygems modifies this behaviour by replacing the Kernel#require method. The comment to the new require method explains what happens:
When RubyGems is required, Kernel#require is replaced with our own which
is capable of loading gems on demand.
When you call require 'x', this is what happens:
If the file can be loaded from the existing Ruby loadpath, it
is.
Otherwise, installed gems are searched for a file that matches.
If it's found in gem 'y', that gem is activated (added to the
loadpath).
The normal require functionality of returning false if
that file has already been loaded is preserved.
With Rubygems included in Ruby by default, this new behaviour is now the norm.
In your example if you look at the load path again after you have required a file from a gem you should see the gems’ path has been added.

Related

How to require a Ruby gem directly from its path?

In order to work with rubyzip i installed the gems:
gem install --local rubyzip-1.1.7.gem
gem install --local zip-zip-0.3.gem
In my code i call the gems using the require method:
require 'zip/zip'
require 'zip/filesystem'
I want to use require to load the gems directly from their location on my machine.
i want somthing like this:
require 'path_to_my_zip_gem'
Where path_to_my zip_gem contains the gem files
Basically, it's because require method loads files by name from paths listed in $: or $LOAD_PATH
"If the filename does not resolve to an absolute path, it will be
searched for in the directories listed in $LOAD_PATH ($:)."
http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-require
If you want to require a gem from the "local" path then the require_relative method could help since you can specify a path relative to the requiring file’s path. Look at the official documentation for further details:
http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-require_relative
The simpliest answer is
Gem::Specification.find_by_name("GEM_NAME_HERE").full_gem_path
Example
> require File.join(Gem::Specification.find_by_name("railties").full_gem_path, "lib/rails/code_statistics.rb")
=> true

ruby adds no path to gems

I use:
rvm 1.25.19 (stable)
ruby 1.9.3p545
I install gem rake command
gem install rake
I understand that $LOAD_PATH should contain the paths:
~/.rvm/rubies/ruby1.9/gems/rake/lib
~/.rvm/rubies/ruby1.9/gems/rake/bin
I execute command:
ruby -e 'puts $LOAD_PATH'
output:
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/site_ruby/1.9.1
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/site_ruby/1.9.1/x86_64-linux
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/site_ruby
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/vendor_ruby/1.9.1
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/vendor_ruby/1.9.1/x86_64-linux
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/vendor_ruby
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/1.9.1
/home/slip/.rvm/rubies/ruby-1.9.3-p545/lib/ruby/1.9.1/x86_64-linux
why path to gem 'rake' don't add?
Installing a gem in Ruby doesn’t automatically add that gem’s files to the load path. When you require a file, first the existing load path is searched and if no matching file is found then Rubygems searches the installed gems for the file. If such a gem is found, then it is activated, which is when the gem’s lib directory is added to the load path.
Here’s an example using the Haml gem:
puts "Before:"
puts $LOAD_PATH
puts
require 'haml'
puts "After:"
puts $LOAD_PATH
This produces:
Before:
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/x86_64-darwin10.8.0
After:
/Users/matt/.rvm/gems/ruby-1.9.3-p448/gems/tilt-1.4.1/lib
/Users/matt/.rvm/gems/ruby-1.9.3-p448/gems/haml-4.0.5/lib
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/site_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/vendor_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/x86_64-darwin10.8.0
See how the lib directories for Tilt (which is a dependency of Haml) and Haml have been added to the start of the load path.
In the case of some gems, such as Rake, this is complicated by the fact they are part of the standard library and so are already on the load path. If you changed the example above to use require 'rake' then you wouldn’t see any change in the load path. In this situation you can specify you want to use the gem version with the gem method. This activates the gem in question, placing its lib directory at the start of the load path so when you later call require you will load the correct version.
For example, this script
require 'rake'
puts Rake::VERSION
produces 0.9.2.2 with Ruby 1.9.3, as that is the version of Rake included in the standard library. However this script:
gem 'rake'
require 'rake'
puts Rake::VERSION
produces 10.1.1, since that is the current highest version of the Rake gem installed on my system. You can also specify a particular gem version by providing a second argument to gem (this is the same syntax as used in Gemfiles). Note that the gem method doesn’t require any files, you have to do that as a separate step.

Strange require statement errors in Ruby?

I've got a wrapper for my Gem, socks, inside socks.rb. The entire file is made up of require statements, and a module declaration:
# lib/socks.rb
require 'socks/version'
require 'socks/base_controller'
require 'socks/templates'
require 'socks/tasks'
require 'socks/rake_tasks'
module Socks
end
However, require 'socks/tasks' and socks/rake_tasks is giving me a LoadError: no such file to load -- socks/tasks / rake_tasks error.
Is this a problem with the alignment of the require statements, or just the code?
Code is on Github: https://github.com/Beakr/socks
EDIT: require './socks/tasks' is now working, however require './socks/rake_tasks' is not.
Ruby load files using its $LOAD_PATH. This global array is changed by e.g. rubygems and bundler to allow to find libraries in various locations. In your sock.gemspec you have defined
gem.require_paths = ["lib"]
which means that rubygems will add the lib directory of your gem to ruby's $LOAD_PATH. But it odes so only if you have installed the gem and the gemspec is thus evaluated. If you don't want to install your gem, you can test your gem using
bundle exec irb
in your gem directory, or alternatively by first adapting your $LOAD_PATH in your irb session like so:
$LOAD_PATH.push "/path/to/your/gem/lib"
require 'socks'

Ruby's autoload not working in 1.8.7 or Ruby Enterprise?

I've written a gem and within a file I am doing this to autoload my main gem logic:
$:.push File.expand_path('lib', __FILE__)
require "oa-casport/version"
require 'omniauth/core'
module OmniAuth
module Strategies
autoload :Casport, 'omniauth/strategies/casport'
end
end
For Ruby versions 1.8.7 and ree, it prints out "no such file to load - omniauth/strategies/casport'
But it doesn't print out this message on version 1.9.2. Is there something off with the location of calling autoload?
The repo for the gem is located at https://github.com/stevenhaddox/oa-casport
EDIT: My gem works for Rails 2 and 3 regardless of version, but doesn't work on Sinatra when using Ruby/REE 1.8.7. Any ideas?
You're adding a wrong path to $LOAD_PATH.
File.expand_path('lib', __FILE__) will evaluate to ${GEM_PATH}/lib/oa-casport.rb/lib which obviously doesn't exist.
Instead, specify your paths in your gemspec:
Gem::Specification.new do |spec|
# ...
spec.require_paths = [ 'lib' ]
# ...
end
PS: Just to solve the initial problem: You probably meant to add the following to $LOAD_PATH: File.expand_path(File.dirname __FILE__).
I checked out the code and it looks like it loads fine with Rails 2 or Rails 3 with Ruby 1.8.7 and 1.9.2, but is only having issues with Sinatra under Ruby 1.8.7 (loads fine with 1.9.2).
I'm still not sure why the discrepancy, but I'll keep looking into it when I get a chance. The fact that it works in most of the environments above seems to tell me the $:.push line isn't really causing any problems (but it may not be necessary since you're using git to package your gem files already in the .gemspec).

require 'rubygems'

I have seen many samples of Ruby code with this line (for example, http://www.sinatrarb.com/). What is purpose of this require?
# require 'rubygems'
require 'sinatra'
get '/hi' do
"Hello world!"
end
In all cases the code works without this line.
require 'rubygems' will adjust the Ruby loadpath allowing you to successfully require the gems you installed through rubygems, without getting a LoadError: no such file to load -- sinatra.
From the rubygems-1.3.6 documentation:
When RubyGems is required, Kernel#require is replaced with our own
which is capable of loading gems on demand.
When you call require 'x', this is what happens:
If the file can be loaded from the existing Ruby loadpath, it
is.
Otherwise, installed gems are searched for a file that
matches. If it's found in gem 'y', that gem is activated
(added to the loadpath).
The normal require functionality of returning false if that file
has already been loaded is preserved.
See the documentation for Kernel#require to understand why this is necessary.
It is often superfluous. It will allow you to require specific versions of particular gems though, with the gem command.
https://guides.rubygems.org/patterns/#requiring-rubygems
As an addition to prior (and correct answers): Ruby 1.9 and newer ship with RubyGems built-in, so there is no real need to require 'rubygems'. Source here

Resources