How to stop 'require_relative' requiring itself? - ruby

In my Ruby without Rails application, I have a bunch of methods saved in various files, like methods.rb, other_methods.rb etc, that I want to access from my main file, main.rb.
Rather than spell out each 'require_relative' individually, my main.rb file currently reads:
main.rb
Dir["./*.rb"].each {|file| require_relative file }
puts "executing"
The only problem is this outputs:
"executing"
"executing"
My current hacky approach is:
Dir["./*.rb"].each {|file| next if file == "./main.rb"; require file }
Is there a better way?
Should I be wrapping my methods in a Module, or a Mixin instead and then using 'include'?

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.

Dynamic require_relative in test_helper not working

I've been battling for an hour with a require_relative in my test_helper.rb that I just can't seem to get to work.
Given a project structure like so
lib
|-- square_digits.rb
test
|-- test_square_digits.rb
|-- test_helper.rb
And these test files:
# test/test_square_digits.rb
require 'test_helper'
# test/test_helper.rb
require "minitest/autorun"
Dir.glob('../lib/**/*.rb').each { |f| require_relative f }
# require_relative "../lib/square_every_digit.rb"
I cannot get my tests to run correctly with the dynamic require, but directly requiring with the hardcoded path does function as intended, though the Dir.glob does seem to catch the file (while running pry in test/)
$ pry(main)> Dir.glob('../lib/**/*.rb')
$ => ["../lib/square_every_digit.rb"]
I have tried the require_relative gem, Dir[] and various solutions to no avail...
Have you tried generating the lines of code and using eval
baseDir = __dir__+"/RGSS Classes"
fileCol = Dir.children(baseDir)
fileCol.each do |library|
libPath = baseDir+"/"+library
code = "require '"+libPath+"'"
puts code
eval(code)
end
you wont be able to use require_reletive because it'll give a "LoadError: cannot infer basepath", i am unsure if it's the same reason as stated in this answer but using require worked
first need to get the current file location using __dir__ and then append whatever subfolder the files you want to require are. then you loop though the results generating the line of code for each file (i choose to generate the path in a variable first before adding it to the code)
obviously since eval is executing string as code if this is used outside of personal private use you'd might want to add some sanitization to the file names as a bad or maliciously named file will execute as code.
alternatively you can forgo using eval and have it output each line to a .rb file which you would then require which eliminates the risk of filenames being used to inject code

Require file without executing code?

Here I have two files:
file.rb
def method
puts "This won't be outputted."
end
puts "This will be outputted."
main.rb
require "./file"
When running main.rb it will load all the code inside file.rb so I will get "This will be outputted." on the screen.
Is it possible to load a file without having it to run the code?
Cause I want to load all the methods (in modules and classes too) without having to execute code outside these scopes.
Is it possible to load a file without having it to run the code?
No, everything in a ruby file is executable code, including class and method definitions (you can see this when you try to define a method inside an if-statement for example, which works just fine). So if you wouldn't execute anything in the file, nothing would be defined.
You can however tell ruby that certain code shall only execute if the file is run directly - not if it is required. For this simply put the code in question inside an if __FILE__ == $0 block. So for your example, this would work:
file.rb
def method
puts "This won't be outputted."
end
if __FILE__ == $0
puts "This will not be outputted."
end
main.rb
require "./file"
the if __FILE__ == $0 is nice, but a way more in keeping with ruby's Object Oriented approach is to put all the methods you want access to in a class (as class methods), and then call them from main.rb.
e.g.
file.rb
class MyUtils
def self.method
puts "this won't be outputted"
end
end
and then in main.rb
require "/.file.rb"
and when you want to use your utility methods:
MyUtils.method
I don't think modifying file is good idea - there are could be a lot of files like this one or these files belong to customer and a ton of another reasons.
Ruby is good at metaprogramming so why don't use this feature?
It could be like this.
Create file with fake module and put here the file.
File.open("mfile.rb","w") do |f|
f.write "module FakeModule
"
f.write File.open("file.rb").read
f.write "
end"
end
Then load this file:
require "/.mfile.rb
and accessing to the method:
FakeModule::method

Is there a shorter way to require a file in the same directory in ruby?

Is there a shorter way to require a file located in the same directory (as the script being executed)?
require File.expand_path(File.dirname(__FILE__) + '/some_other_script')
I read that require "my_script" and require "./my_script" will actually load the script twice (ruby will not recognize that it is actually the same script), and this is the reason why File.expand_path is recommended: if it is used every time the script is required, then it will only be loaded once.
It seems weird to me that a concise language like Ruby does not seem to have a shorter solution. For example, python simply has this:
import .some_other_module_in_the_same_directory
I guess I could monkey-patch require... but that's just evil! ;-)
Since ruby 1.9 you can use require_relative.
Check the latest doc for require_relative or another version of the Core API.
Just require filename.
Yes, it will import it twice if you specify it as filename and ./filename, so don't do that. You're not specifying the .rb, so don't specify the path. I usually put the bulk of my application logic into a file in lib, and then have a script in bin that looks something like this:
#!/usr/bin/env ruby
$: << File.join(File.dirname(__FILE__), "/../lib")
require 'app.rb'
App.new.run(ARGV)
Another advantage is that I find it easier to do unit testing if the loading the application logic doesn't automatically start executing it.
The above will work even when you're running the script from some other directory.
However, inside the same directory the shorter forms you refer to work as expected and at least for ruby 1.9 won't result in a double-require.
testa.rb
puts "start test A"
require 'testb'
require './testb'
puts "finish test A"
testb.rb
puts "start test B"
puts "finish test B"
running 'ruby testa.rb' will result in:
start test A
start test B
finish test B
finish test A
However, the longer form will work even from another directory (eg. ruby somedir/script.rb)
Put this in a standard library directory (somewhere that's already in your default loadpath $:):
# push-loadpath.rb
if caller.first
$: << File.expand_path(File.dirname(caller.first))
end
Then, this should work
% ls /path/to/
bin.rb lib1.rb lib2.rb #...
% cat /path/to/bin.rb
load 'push-loadpath.rb'
require 'lib1'
require 'lib2'
#...
caller gives you access to the current callstack, and tells you what file and where, so push-loadpath.rb uses that to add the file that load'd it to the loadpath.
Note that you should load the file, rather than require it, so the body can be invoked multiple times (once for each time you want to alter the loadpath).
Alternately, you could wrap the body in a method,
# push-loadpath.rb
def push_loadpath
$: << File.expand_path(File.dirname(caller.first))
end
This would allow you to require it, and use it this way:
% ls /path/to/
bin.rb lib1.rb lib2.rb #...
% cat /path/to/bin.rb
require 'push-loadpath'
push_loadpath
require 'lib1'
require 'lib2'
#...

Best way to require all files from a directory in ruby?

What's the best way to require all files from a directory in ruby ?
How about:
Dir["/path/to/directory/*.rb"].each {|file| require file }
If it's a directory relative to the file that does the requiring (e.g. you want to load all files in the lib directory):
Dir[File.dirname(__FILE__) + '/lib/*.rb'].each {|file| require file }
Edit: Based on comments below, an updated version:
Dir[File.join(__dir__, 'lib', '*.rb')].each { |file| require file }
Try the require_all gem:
http://github.com/jarmo/require_all
https://rubygems.org/gems/require_all
It lets you simply:
require_all 'path/to/directory'
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file|
require File.basename(file, File.extname(file))
end
If you don't strip the extension then you may end up requiring the same file twice (ruby won't realize that "foo" and "foo.rb" are the same file). Requiring the same file twice can lead to spurious warnings (e.g. "warning: already initialized constant").
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))
or alternatively, if you want to scope the files to load to specific folders:
Dir.glob(File.join('path', '{folder1,folder2}', '**', '*.rb'), &method(:require))
explanation:
Dir.glob takes a block as argument.
method(:require) will return the require method.
&method(:require) will convert the method to a bloc.
The best way is to add the directory to the load path and then require the basename of each file. This is because you want to avoid accidentally requiring the same file twice -- often not the intended behavior. Whether a file will be loaded or not is dependent on whether require has seen the path passed to it before. For example, this simple irb session shows that you can mistakenly require and load the same file twice.
$ irb
irb(main):001:0> require 'test'
=> true
irb(main):002:0> require './test'
=> true
irb(main):003:0> require './test.rb'
=> false
irb(main):004:0> require 'test'
=> false
Note that the first two lines return true meaning the same file was loaded both times. When paths are used, even if the paths point to the same location, require doesn't know that the file was already required.
Here instead, we add a directory to the load path and then require the basename of each *.rb file within.
dir = "/path/to/directory"
$LOAD_PATH.unshift(dir)
Dir[File.join(dir, "*.rb")].each {|file| require File.basename(file) }
If you don't care about the file being required more than once, or your intention is just to load the contents of the file, perhaps load should be used instead of require. Use load in this case, because it better expresses what you're trying to accomplish. For example:
Dir["/path/to/directory/*.rb"].each {|file| load file }
Instead of concatenating paths like in some answers, I use File.expand_path:
Dir[File.expand_path('importers/*.rb', File.dirname(__FILE__))].each do |file|
require file
end
Update:
Instead of using File.dirname you could do the following:
Dir[File.expand_path('../importers/*.rb', __FILE__)].each do |file|
require file
end
Where .. strips the filename of __FILE__.
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
require file
end
This will work recursively on your local machine and a remote (Like Heroku) which does not use relative paths.
In Rails, you can do:
Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Update: Corrected with suggestion of #Jiggneshh Gohel to remove slashes.
I'm a few years late to the party, but I kind of like this one-line solution I used to get rails to include everything in app/workers/concerns:
Dir[ Rails.root.join *%w(app workers concerns *) ].each{ |f| require f }
And what about: require_relative *Dir['relative path']?

Resources