How to See Required Library File Names in Ruby - ruby

How can I see the required library file name? e.g. path/to/file.rb or path/to/file.so
$ rails c
Loading development environment (Rails 4.2.7.1)
[1] pry(main)> require "readline"
=> false
I would like to make sure the exact file path that is actually required, but don't know how to confirm the file path.

Ruby has a pre-defined variable $" or $LOADED_FEATURES which contains the required modules
$LOADED_FEATURES
#=> ["enumerator.so", "thread.rb", "rational.so", ...]
You could use grep to find "readline":
$LOADED_FEATURES.grep /readline/
#=> ["/Users/sos/.rbenv/versions/2.4.0/lib/ruby/2.4.0/x86_64-darwin15/readline.bundle"]

Related

What does it mean $: in Ruby

I was reading the following tutorial.
It talked about including files in a Ruby file like require :
require(string) => true or false
Ruby tries to load the library named string, returning true if
successful. If the filename does not resolve to an absolute path, it
will be searched for in the directories listed in $:. If the file has
the extension ".rb", it is loaded as a source file; if the extension
is ".so", ".o", or ".dll", or whatever the default shared library
extension is on the current platform, Ruby loads the shared library as
a Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
to the name. The name of the loaded feature is added to the array in
$:.
I just want to know what is $: in Ruby and what does $: means.
The variable $: is one of the execution environment variables, which is an array of places to search for loaded files.
The initial value is the value of the arguments passed via the -I command-line option, followed by an installation-defined standard library location.
See Pre-defined variables, $LOAD_PATH is its alias.
Its the load path
Just open in irb terminal and type this $:
This is what you would get. Ofcourse that depends on the ruby ur using.
2.1.1 :009 > $:
=> ["/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/x86_64-darwin12.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin12.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/x86_64-darwin12.0"]
2.1.1 :010 >
In ruby $ refers to a predefined variable.
In this case, $: is short-hand for $LOAD_PATH. This is the list of directories you can require files from while giving a relative path. In other words, Ruby searches the directories listed in $:
Hope this helps.

I18n without Rails?

just having troubles to make I18n to work without Rails environment:
irb> require 'i18n'
=> true
irb> I18n.load_path=Dir['/usr/lib/ruby/gems/1.9.1/gems/rails-i18n-0.6.6/rails/locale/en.yml']
=> ["/usr/lib/ruby/gems/1.9.1/gems/rails-i18n-0.6.6/rails/locale/en.yml"]
irb> I18n.load_path+=Dir['/usr/lib/ruby/gems/1.9.1/gems/rails-i18n-0.6.6/rails/locale/sk.yml']
=> ["/usr/lib/ruby/gems/1.9.1/gems/rails-i18n-0.6.6/rails/locale/en.yml", "/usr/lib/ruby/gems/1.9.1/gems/rails-i18n-0.6.6/rails/locale/sk.yml"]
irb> I18n.locale=:sk
=> :sk
irb> I18n.default_locale=:sk
=> :sk
irb> I18n.l Time.now
I18n::MissingTranslationData: translation missing:
sk.time.formats.default
from /usr/lib/ruby/gems/1.9.1/gems/i18n-0.6.1/lib/i18n.rb:289:in
`handle_exception'
from /usr/lib/ruby/gems/1.9.1/gems/i18n-0.6.1/lib/i18n.rb:159:in
`translate'
from
/usr/lib/ruby/gems/1.9.1/gems/i18n-0.6.1/lib/i18n/backend/base.rb:55:in
`localize'
from /usr/lib/ruby/gems/1.9.1/gems/i18n-0.6.1/lib/i18n.rb:236:in
`localize'
from (irb):11
from /usr/bin/irb:12:in `<main>'
irb>
What am I doing wrong ? The sk.yml DOES contain sk.time.formats.default
element !!
In addition what's the I18n's default load_path(s) so I won't be
bothered to supply full paths to every translation YAML/Ruby file ?
Thanks.
You already set the search path for the language definitions with I18n.load_path.
It seems, this is enough when using rails. Without rails, you must also load the language definitions with I18n.backend.load_translations.
In summary, you need two steps:
I18n.load_path = Dir['*.yml']
I18n.backend.load_translations
The dictionaries are defined with language key, e.g. like:
en:
hello: "Hello world"
If you prefer to define your en.yml without language key, you may load them via
I18n.backend.store_translations(:en , YAML.load(File.read('en.yml')))
(You may also use a here-document or direct a ruby-hash).
It seems like your load_path is not being set correctly.
Try including the whole directory and if it's successful, you should see your :sk and :en files by calling I18n.load_path.
I18n.load_path = Dir['/usr/lib/ruby/gems/1.9.1/gems/rails-i18n-0.6.6/rails/locale/*yml']
Setting the files paths directly can be a bit confusing since I18n won't raise an error if the file doesn't exist.
As a side note, I'd advise against including translations from the rails-i18n gem as the path may be different from one machine to another with different ruby versions etc.. a file local to the project would be better.
You'll need to install rails-i18n gem just to get localization data.
With this gem install, one can e.g. print month names in sk localization with:
require 'rails-i18n'
I18n.load_path += $LOADED_FEATURES
.select {|f| "rails-i18n.rb".in? f }
.collect {|f| f.sub('lib/rails-i18n.rb', 'rails/locale/sk.yml') }
I18n.locale = :sk
puts I18n.t('date.month_names').compact
This yields:
Január
Február
Marec
Apríl
Máj
Jún
Júl
August
September
Október
November
December

What does $:<< "." do to Ruby's require path?

I don't understand the meaning of $:<< "." in Ruby.
I upgraded Ruby to 1.9.1, but a program was not working. My classmate told me that I am supposed to add $:<< "."
What does $:<< "." do?
$: is the variable that holds an array of paths that make up your Ruby's load path
<< appends an item to the end of the array
. refers to the current directory
1 2 3
| | |
V V V
$: << "."
So you are adding the current directory to Ruby's load path
References:
Can be found in the Execution Environment Variables section of of this page from The Pragmatic Programmers Guide
An array of strings, where each string specifies a directory to be searched for Ruby scripts and binary extensions used by the load and require methods. The initial value is the value of the arguments passed via the -I command-line option, followed by an installation-defined standard library location, followed by the current directory (“.”)[Obviously this link is for an older version of Ruby as this is still in there]. This variable may be set from within a program to alter the default search path; typically, programs use $: << dir to append dir to the path.
Can be found in the docs for array at ruby-doc.org.
Append—Pushes the given object on to the end of this array. This expression returns the array itself, so several appends may be chained together.
Since version 1.9, Ruby doesn't look for required files in the current working directory AKA .. The $LOAD_PATH or $: global variable is an array of paths where Ruby looks for files you require.
By adding $:<< "." to your files, you are actually telling Ruby to include your current directory in the search paths. That overrides new Ruby behavior.
In your example you add working directory (".") to ruby load path ($:).
Working directory (".") was removed from load path (global variable $: or $-I or $LOAD_PATH) in Ruby 1.9 because it was considered a security risk:
Your working directory may be any folder, and your script will require files from this folder if these files have appropriate names. For example you have 2 files in Project1 folder main.rb and init.rb:
==Project1/main1.rb:
$: << "."
require 'init'
==Project1/init.rb:
puts 'init 1'
And you have alike project:
==Project2/main2.rb:
$: << "."
require 'init'
==Project2/init.rb:
puts 'init 2'
If you run Project1 from Project2 folder, then main1.rb will require Project2/init.rb, not Project1/init.rb:
~/Projects/Project2$ ruby ../Project1/main1.rb
init 2 # may be unexpected an dangerous
~/Projects/Project2$ ruby main2.rb
init 2
You can change your working directory in your code, e.g. using Dir.chdir:
ruby-1.9.2-p290 :002 > puts File.expand_path('.')
=> /home/alex/Projects
ruby-1.9.2-p290 :003 > Dir.chdir('..')
ruby-1.9.2-p290 :004 > puts File.expand_path('.')
=> /home/alex
I recommend you to use the following techniques instead of $: << '.':
require_relative (Ruby 1.9 only)
Add folder of the file to the working directory (common approach because it is compatible with Ruby 1.8): $: << File.expand_path('..', __FILE__) etc.. __FILE__ is a reference to the current file name. File.expand_path converts a pathname to an absolute pathname.

Rails irb default directory

I'm trying to include a source code file when I run irb but irb is unable to find it.
For example, say I am in the following directory in terminal:
/dan/rubyapp/
Assume I have a file named "firstapp.rb" in /dan/rubyapp/
I startup irb and from the irb prompt I type
> require "firstapp.rb"
but the file can't be found. If I type "Dir.pwd" it shows as
/dan/rubyapp/
The only way I can get "require" to work is if I include the full path like so
> require "/dan/rubyapp/firstapp.rb"
Is that the only way I can get this to work? All the tutorials I see online simply do "require file_name" so I assumed it would work.
here is the output from $: at irb
ruby-1.9.2-p0 > $:
=> ["/Users/Daniel/.rvm/gems/ruby-1.9.2-p0/gems/wirble-0.1.3/bin",
"/Users/Daniel/.rvm/gems/ruby-1.9.2-p0/gems/wirble-0.1.3/lib",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/site_ruby/1.9.1",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.4.0",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/site_ruby",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/vendor_ruby/1.9.1",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.4.0",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/vendor_ruby",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1",
"/Users/Daniel/.rvm/rubies/ruby-
1.9.2-p0/lib/ruby/1.9.1/x86_64-darwin10.4.0"]
The problem is that the current working directory is no longer in your path (as of Ruby 1.9.2). There are a few different ways around the problem.
1) In a ruby file itself, you can use the method require_relative instead of require. This will load a file relative to the loaction of the file containing the require_relative method:
http://extensions.rubyforge.org/rdoc/classes/Kernel.html
require_relative 'firstapp.rb'
This, however, will not work in irb.
2) Your other option is to include the current path in your argument to the require method. This will work in irb or in a ruby file. For instance:
require './firstapp.rb'
The reason this was implemented in ruby was to avoid inadvertently requiring the wrong file if there are different files with the same name in different directories in the path (similar to how *nix does not include the current directory "." in its path)
A couple of things to try:
1) Drop the .rb from the end of your require so you have:
require 'firstapp'
You don't normally add the .rb to a require (only to a load) - have a look here for more details:
http://www.fromjavatoruby.com/2008/10/require-vs-load.html
2) Failing that, make sure the current directory is on your load path - in irb execute:
p $:
and it will print out your ruby load path - check for an entry for "." (mine is the last entry)

Ruby path management

What is the best way to manage the require paths in a ruby program?
Let me give a basic example, consider a structure like:
\MyProgram
\MyProgram\src\myclass.rb
\MyProgram\test\mytest.rb
If in my test i use require '../src/myclass' then I can only call the test from \MyProgram\test folder, but I want to be able to call it from any path!
The solution I came up with is to define in all source files the following line:
ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(ROOT) and then always use require "#{ROOT}/src/myclass"
Is there a better way to do it?
As of Ruby 1.9 you can use require_relative to do this:
require_relative '../src/myclass'
If you need this for earlier versions you can get it from the extensions gem as per this SO comment.
Here is a slightly modified way to do it:
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "src"))
By prepending the path to your source to $LOAD_PATH (aka $:) you don't have to supply the root etc. explicitly when you require your code i.e. require 'myclass'
The same, less noisy IMHO:
$:.unshift File.expand_path("../../src", __FILE__)
require 'myclass'
or just
require File.expand_path "../../src/myclass", __FILE__
Tested with ruby 1.8.7 and 1.9.0 on (Debian) Linux - please tell me if it works on Windows, too.
Why a simpler method (eg. 'use', 'require_relative', or sg like this) isn't built into the standard lib? UPDATE: require_relative is there since 1.9.x
Pathname(__FILE__).dirname.realpath
provides a the absolute path in a dynamic way.
Use following code to require all "rb" files in specific folder (=> Ruby 1.9):
path='../specific_folder/' # relative path from current file to required folder
Dir[File.dirname(__FILE__) + '/'+path+'*.rb'].each do |file|
require_relative path+File.basename(file) # require all files with .rb extension in this folder
end
sris's answer is the standard approach.
Another way would be to package your code as a gem. Then rubygems will take care of making sure your library files are in your path.
This is what I ended up with - a Ruby version of a setenv shell script:
# Read application config
$hConf, $fConf = {}, File.expand_path("../config.rb", __FILE__)
$hConf = File.open($fConf) {|f| eval(f.read)} if File.exist? $fConf
# Application classpath
$: << ($hConf[:appRoot] || File.expand_path("../bin/app", __FILE__))
# Ruby libs
$lib = ($hConf[:rubyLib] || File.expand_path("../bin/lib", __FILE__))
($: << [$lib]).flatten! # lib is string or array, standardize
Then I just need to make sure that this script is called once before anything else, and don't need to touch the individual source files.
I put some options inside a config file, like the location of external (non-gem) libraries:
# Site- and server specific config - location of DB, tmp files etc.
{
:webRoot => "/srv/www/myapp/data",
:rubyLib => "/somewhere/lib",
:tmpDir => "/tmp/myapp"
}
This has been working well for me, and I can reuse the setenv script in multiple projects just by changing the parameters in the config file. A much better alternative than shell scripts, IMO.

Resources