How can I tell which file is being required here? [duplicate] - ruby

This question already has answers here:
What happens technically when a file is required in Ruby?
(3 answers)
Closed 5 years ago.
I'm reading through the codebase of the Homebrew repo, specifically the file here:
https://github.com/Homebrew/brew/blob/8518ffdee19c0c985e8631e836b78624e4926c7f/Library/Homebrew/brew.rb
I see many 'require' statements scattered throughout the file, for instance on line 104 (require 'tap'). The problem is that I see 3 files named tap.rb in the codebase:
Library/Homebrew/tap.rb
Library/Homebrew/cmd/tap.rb
Library/Homebrew/compat/tap.rb
Further down in the code I see Tap.fetch..., and in Library/Homebrew/tap.rb which contains a class named Tap with a class method named fetch, so I'm confident this is the correct file that's being included. But conceivably, there could be dozens of files with the same filename, and more than one of those could have identical class methods. My question is, is there a way to tell which Tap class is being loaded without looking through each of the files?
UPDATE: I think I have the answer to my question (see below).

If you put a binding.pry before the require and execute $: that will be the list of directories in which the require will look up the 'tap.rb' files.
See definition of require:
If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $:.

I found this great explanation of how require works in Ruby:
https://github.com/ericmathison/articles/blob/master/understaning-require-in-ruby.md
Essentially, it works by looking at the Ruby $LOAD_PATH method, similar to how UNIX uses the $PATH variable to look for binary executables when it receives a command in the CLI. I was able to test this out on my local by making two files in the same directory, like so:
# file number 1- foobar.rb
module Foobar
module_function
def bar
p "foo"
end
end
# file number 2- foobaz.rb
$LOAD_PATH.unshift(".")
class Foobaz
def baz
require 'foobar'
p Foobar.bar
end
end
Foobaz.new.baz
Without the line $LOAD_PATH.unshift(".") in foobaz.rb, the code wouldn't execute with the simple require 'foobar' statement. I instead had to use require_relative 'foobar.rb'. But adding the current working directory to the $LOAD_PATH environment variable meant that I now had access to all the ruby files in the current dir, so it executed!
NB- it's likely that adding . to the $LOAD_PATH should go in a config file somewhere, not in the same file as the require statement.

Related

Calling classes from files

I am writing a program which includes two file. I’m the first file all I am doing is initializing the next file which includes multiple classes. I call the class at the bottom of the file, but it runs the class at the top of the file.
Btw I am running ruby
First file:
Require ‘./secondfile.rb’
newfile.Lastclass
Second file:
class Firstclass
end
class Lastclass
end
Hint #1. It's better to write without .
It depends on directory from where you run your app.
For example you have directory folder. And there you have two files:
file.rb
puts "I'm file.rb"
main.rb
require './file.rb'
If you run your app from folder - it's ok:
folder$ ruby main.rb
I'm file.rb
But if you'll run it from high level - it will be error:
folder$ cd ..
:~$ ruby folder/main.rb
kernel_require.rb:55:in `require': cannot load such file -- ./file.rb (LoadError)
But how to write in this case?
Hint #2. You can use special method
main.rb
require "./#{__dir__}/file.rb"
Now it's ok in all cases:
~$ ruby folder/main.rb
I'm file.rb
folder$ ruby main.rb
I'm file.rb
But you can write it better.
Hint #3. You can use require_relative
main.rb
require_relative 'file.rb'
And even better.
main.rb
require_relative 'file'
Ruby understand it.
~$ ruby folder/main.rb
I'm file.rb
folder$ ruby main.rb
I'm file.rb
Hope this helps you.
Classes are injected into the root namespace if they're defined. If another file defines a class, all files get it:
require_relative './secondfile.rb'
Lastclass
This is unlike JavaScript (e.g. Node.js) where you must explicitly import classes from other files. In Ruby it happens by manipulating the root namespace.
Another note is to pay close attention to which slashes you use. In your code you used a backslash, which is incorrect. You also used the wrong quotes. Often every character counts when programming.

Failed to run a very simple ruby script [duplicate]

This question already has answers here:
Ruby: how to "require" a file from the current working dir?
(5 answers)
Closed 6 years ago.
I have create a Ruby class Worker, file name is Worker.rb:
class Worker
def initialize
...
end
def doTask(task_name)
...
end
end
Then, I created another Ruby script file, named run.rb (it requires Worker):
require 'Worker'
worker = Worker.new
worker.doTask("sort")
Both two ruby files are located directly under the project folder:
ProjectFolder/
-- Worker.rb
-- run.rb
I run the run.rb under project folder by command:
ruby run.rb
But get following error:
/Users/John/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- Worker (LoadError)
from /Users/John/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from runme.rb:1:in `<main>'
Why?
I figured out after checking #Geo 's github project, I should use:
require_relative "worker"
require looks for the required file from the so called load path and not the current directory. Since the syntax for looking in the current directory was awkward Ruby 1.9 introduces require_relative, which looks in the current directory.
Change your code like this:
require_relative "Worker"
instead of
require "Worker"
The reason this does not work is because the current directory is not part of ruby's default load path.
If you run the following command, you will see what the current load path is and it will confirm that the current directory is not part of that path.
ruby -e 'puts $LOAD_PATH'
This should answer your primary question as to why the required file was not loaded.
As for a solution, require_relative will work and is probably the best solution in this case.
There are however still cases were inserting directories into the load path is helpful, if not required. For example say you have a script that can be run anywhere in the file system and you want the flexibility to require a particular version of your co-worker's foo class.
/afs/some_cell/u/john/some_ruby_lib
prod/
foo.rb
bar.rb
prev/
foo.rb
bar.rb
beta/
foo.rb
bar.rb
In a case like this either setting the RUBYSIM var (maybe in a wrapper) or setting the proper include path on the ruby command line can be a useful solution.
Again, your co-worker has not published this as a gem, he is just providing a shared directory.
There are several ways you can insert directories into the load path when it is appropriate, as demonstrated below:
You can use the -I command line flag
ruby -I some_path -e 'puts $LOAD_PATH'
You can set the RUBYLIB env var to include your current directory.
on unix/linix/osx
export RUBYLIB=some_path
on windows
set RUBYLIB=some_path

Split seeds.rb into multiple sections?

I'd like to split my seeds.rb file into multiple sections for ease of maintenance; seed all the A's in a.rb, the B's in b.rb, etc. The separate files are located in the db/ directory with seeds.rb. Each file consists of a bunch of "A.create" or "B.create" calls and I want to call those files from seeds.rb.
I've tried:
include 'a'
include 'b'
and
load 'a.rb'
load 'b.rb'
in my seeds.rb but they don't seem to be processed when I call "rake db:seed". This is probably more of a straight ruby question than a rails question but for completeness I'm using Ruby 1.9.2 and Rails 3 on a Mac.
In ./db/seeds/my_module.rb:
module MyModule
puts "In my_module.rb"
# add code here
end
In ./db/seeds.rb:
require File.expand_path('../seeds/my_module', __FILE__) # the ../ just removes `seeds.rb` filename from the path which is given by __FILE__
p "In seeds.rb"
# add code here
I would propose to create a new db/seeds/ directory where you can place your various seeds file:
db/seeds/01_stuff_that_comes_for_first.rb
db/seeds/02_stuff_that_comes_for_second.rb
...
And then edit your db/seeds.rb file with:
Dir[File.join(Rails.root, 'db', 'seeds', '*.rb')].sort.each { |seed| load seed }
So, you can load your seeds even in the order you prefer - that is often something requested.
This solution was originally proposed by nathanvda in this "duplicated" question.

Ruby require path

I have a Ruby code with different classes in a few files. In one file, I start the execution. This file requires my other files.
Is this a good way to start a ruby code?
When I run the code from a symbolic link, for example DIR2/MyRubyCode is a link to the main file DIR1/MyRubyCode.rb, then my requires will fail. I solved the problem by adding the path DIR1 to $LOAD_PATH before the require, but I think there would be much better ways to do it. Do you have any suggestions about that?
If you're using Ruby 1.9 or greater, user require_relative for your dependencies.
require_relative 'foo_class'
require_relative 'bar_module'
If you want to check if a Ruby file is being 'require'ed or executed with 'ruby MyRubyCode.rb', check the __FILE__ constant.
# If the first argument to `ruby` is this file.
if $0 == __FILE__
# Execute some stuff.
end
As far as the require/$LOAD_PATH issue, you could always use the relative path in the require statement. For example:
# MyRubyCode.rb
require "#{File.dirname(__FILE__)}/foo_class"
require "#{File.dirname(__FILE__)}/bar_module"
Which would include the foo_class.rb and bar_module.rb files in the same directory as MyRubyCode.rb.
I know this is an old question, but there is an updated answer to it, and I wanted to post it:
Starting in a more recent version of Ruby (I'm not sure when), you can require files in the same directory by using the following:
require './foo_class'
require './bar_module'
and it'll load files called foo_class.rb and bar_module.rb in the same directory.
For checking if your file is being required or ran normally, check the other answer.

Linking to external files in ruby?

Sorry if this question is very easy, but I can't find the answer anywhere. How do you refer to an external ruby file in a ruby script if, for example, the file you want is in the same folder as the one you are writing?
Thanks in advance.
You just do a require like this require "filename". Ruby will look in each of the paths in the $LOAD_PATH variable to find the file.
Have a look at $LOAD_PATH and you should get something like this:
irb(main):001:0> puts $LOAD_PATH
/usr/local/lib/ruby/site_ruby/1.8
/usr/local/lib/ruby/site_ruby/1.8/i686-darwin10.0.0
/usr/local/lib/ruby/site_ruby
/usr/local/lib/ruby/vendor_ruby/1.8
/usr/local/lib/ruby/vendor_ruby/1.8/i686-darwin10.0.0
/usr/local/lib/ruby/vendor_ruby
/usr/local/lib/ruby/1.8
/usr/local/lib/ruby/1.8/i686-darwin10.0.0
.
You can see that the last entry is the current directory.
You can also give a path specifically like require "lib/filename.rb"
require "YOUR_EXTERNAL_FILE_NAME_WITHOUT_DOT_RB_EXTENSION"
For example, if you have two files, 'file0.rb' and 'file1.rb' and want to include 'file0.rb' from 'file1.rb' (and both files are in the same folder), your 'file1.rb' should have following statement:
require 'file0'

Resources