Ruby 'require' with wildcard expression - ruby

Is there a way to load files that only match a specific string? For example, suppose I want to load files that matches account1.rb account2.rb and so on. I want to be able to do something like
require File.expand_path("../account*.rb", __FILE__)
but of course this does not work. What is the best way to do this?

You can do the same thing with a loop:
Dir.glob(File.expand_path("../account*.rb", __FILE__)).each do |file|
require file
end
The expand_path method only resolves paths. It does not expand wildcards.

I tried to use this to create a test-suite for Minitest without using Rspec. The accepted answer didn't work for me, but this did:
require "minitest/autorun"
Dir.glob("*_test.rb").each do |file|
require_relative file
end

I use this:
Dir.entries( File.dirname( __FILE__ ) ).
grep( /test.*\.rb/ ) { | file | require_relative file }
Unfortunately Ruby doesn't allow newlines before the dot, so the ideal form doesn't work:
Dir.entries( File.dirname( __FILE__ ) )
.grep( /test.*\.rb/ ) { | file | require_relative file }

Related

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

Troublesoot ruby require

Ruby require only works for me with gems not with code that I have written. I'm not sure what it is that I am doing wrong.
This works
require "test-unit"
require "require "C:\\Users\\zreichert\\workspace\\FalconQA\\PageObjects\\Users\\user.rb"
This doesn't work
require "Users/user"
require "Users\user"
require "Users/user.rb"
require "Users\user.rb"
require_relative "Users/user"
require_relative "Users\user"
require_relative "Users/user.rb"
require_relative "Users\user.rb"
The script that I am running is located in - C:/Users/zreichert/workspace/FalconQA/testCases
I have tried to change directories before require like this
Dir.chdir "C:/Users/zreichert/workspace/FalconQA/testCases"
All errors look something like this
c:/Ruby193/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in require': cannot load such file -- Users/user (LoadError)
from c:/Ruby193/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:inrequire'
from C:/Users/zreichert/workspace/FalconQA/testCases/FAL001.rb:14:in `
you can try
require "./Users/user"
You can use this:
require_relative '../PageObjects/Users/user.rb'
Slash is better than two backslashes, because it works in both Windows and Linux/MacOS.
Just to expand on Roozbeh's answer slightly, require_relative allows you to load files relative to the location of the file containing the require_relative so doing a chdir will not have any effect on this.
From what you've said in the question, the relative path from FAL001.rb to user.rb is
../PageObjects/Users/user.rb
i.e. up one level and then down into PageObjects/Users, hence
require_relative '../PageObjects/Users/user.rb'
As a mental-safety tip, anything looking like "Users\user" will fail because of how escaped characters are interpreted in double-quoted strings.
Instead, use single-quotes for your require parameter to preserve your sanity:
require 'foo'
or
require './relative/path/to/foo'
require '../relative/path/to/bar'

Is it possible to recursively require all files in a directory in Ruby?

I am working on an API that needs to load all of the .rb files in its current directory and all subdirectories. Currently, I am entering a new require statement for each file that I add but I would like to make it where I only have to place the file in one of the subdirectories and have it automatically added.
Is there a standard command to do this?
In this case its loading all the files under the lib directory:
Dir["#{File.dirname(__FILE__)}/lib/**/*.rb"].each { |f| load(f) }
require "find"
Find.find(folder) do |file|
next if File.extname(file) != ".rb"
puts "loading #{file}"
load(file)
end
This will recursively load each .rb file.
like Miguel Fonseca said, but in ruby >= 2 you can do :
Dir[File.expand_path "lib/**/*.rb"].each{|f| require_relative(f)}
I use the gem require_all all the time, and it gets the job done with the following pattern in your requires:
require 'require_all'
require_all './lib/exceptions/'
def rLoad(dir)
Dir.entries(dir).each {|f|
next if f=='.' or f=='..'
if File.directory?(f)
rInclude(f)
else
load(f) if File.fnmatch('*.rb', f)
end
}
end
This should recursively load all .rb files in the directory specified by dir. For example, rLoad Dir.pwd would work on the current working directory.
Be careful doing this, though. This does a depth-first search and if there are any conflicting definitions in your Ruby scripts, they may be resolved in some non-obvious manner (alphabetical by folder/file name I believe).
You should have a look at this gem. It is quite small so you can actually re-use the code instead of installing the whole gem.

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']?

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