FileUtils.mkdir_p support for wildcards in ruby? - ruby

I have for example directory structure like this:
./DIRECTORY/PROJECT_A/cars/
./DIRECTORY/PROJECT_B/planes/
./DIRECTORY/PROJECT_C/bikes/
I would like to recourse through them using wildcards and create other directory's, like this:
Dir['/DIRECTORY/PROJECT_*/*/'].each do FileUtils.mkdir_p 'TheNewDirectory'.
It seems "FileUtils" doesn't support wildcards.
I'm doing the same for creation of files on this way:
Dir['/DIRECTORY/PROJECT_*/*/'].each do |dir|
File.new File.join(dir, 'myFile.txt'), 'w+'
end
So I would like to do the same but for creation of directories. Any idea?

FileUtils is a module. It doesn't make sense to claim that a module "does not use wildcards".
Moreover, you are using only the function mkdir_p from FileUtils, and do not use any wildcard in its argument, so what you say, doesn't apply to your case either.
What happened is, that your are iterating through all the directories entries created by your Dir[...] expression, but then don't use the actual directory! A first step to write this better would be
Dir['/DIRECTORY/PROJECT_*/*/'].each { |d| FileUtils.mkdir_p("#{d}/TheNewDirectory") }
This works however only if it is guaranteed that d never takes the value of a plain file, and of course you can run this code only once (because the second time, you would obviously create directories of the form /DIRECTORY/PROJECT_FOO/BAR/TheNewDirectory/TheNewDirectory. I would therefore check, for the safe side, that it indeed makes sense to create the directory, before doing it.

To create directory, you need to specify full path of new directory using the current folder name:
Dir['/DIRECTORY/PROJECT_*/*/'].each do |f|
FileUtils.mkdir_p "#{f}/TheNewDirectory" if File.directory?(f)
end

Related

Requiring files from a required file

I have a file required.rb required by other files main.rb and tester.rb, each of which is invoked separately and run separately.
Within required.rb, I want to require all files in a subdirectory of the required file. The whole thing looks something like this:
main.rb
lib/
required.rb
req_files/
req1.rb
req2.rb
req3.rb
tester/
tester.rb
The code to import the required files looks like:
Dir[Dir.pwd + "/req_files/*.rb"].each do |file|
require file
end
In suggested strategies I have seen, be it utilizing Dir.pwd or __FILE__, the context applied to required.rb's location is the context of whichever original file required it in the first place, which means that I can't support requiring from both of those files separately with the current setup.
Is there a way to denote a path relative to the actual required.rb?
EDIT :
It's not though, because changing require to require_relative doesn't change the fact that Dir[Dir.pwd + "/req_files/*.rb"] and more specifically Dir.pwd resolves with respect to the original file (main or tester), so it cannot be expressed as is in required and work for both entry points
Also note that required.rb is required via require_relative already from both main.rb and tester.rb.
Is there a way to denote a path relative to the actual required.rb
Yes, kinda. There's another method for this.
http://ruby-doc.org/core-2.4.2/Kernel.html#method-i-require_relative
require_relative(string) → true or false
Ruby tries to load the library named string relative to the requiring file’s path. If the file’s path cannot be determined a LoadError is raised. If a file is loaded true is returned and false otherwise.
I was incorrect regarding __FILE__; Using File.dirname(__FILE__) instead of Dir.pwd works for giving the directory of the actual file versus the directory of the invoking file.

Check if there is any file or directory matching pattern using ruby

I want to check if pattern with wildcards, e.g. /var/data/**/*.xml is matching to any file or directory on the disk.
Obviously I could use Dir.glob but it is very slow when there are millions of files because it is too eager - it returns all files matching the pattern while I only need to know if there is any.
Is there any way I could check that?
Ruby-only
You could use Find, find and find :D.
I couldn't find any other File/Dir method that returns an Enumerator.
require 'find'
Find.find("/var/data/").find{|f| f=~/\.xml$/i }
#=> first xml file found inside "/var/data". nil otherwise
# or
Find.find("/var/data/").find{|f| File.extname(f).downcase == ".xml" }
If you really just want a boolean :
require 'find'
Find.find("/var/data/").any?{|f| f=~/\.xml$/i }
Note that if "/var/data/" exists but there is no .xml file inside it, this method will be at least as slow as Dir.glob.
As far as I can tell :
Dir.glob("/var/data/**/*.xml"){|f| break f}
creates a complete array first before returning its first element.
Bash-only
For a bash-only solution, you could use :
compgen
Shell find

How to change a file's path within ruby

I'm trying to move files from one folder to another via Ruby, but I'm stuck trying to get Pathname.new to work. For reference the files are being held in array as an inbetween from their normal dir. I know I could move it via CLI but I'd like the program to do it for me. This is what I have so far. I know it's wrong; I just don't get how to fix it.
temp_array.each {|song| song.path(Pathname.new("/Users/tsiege/Desktop/#{playlist_name}"))}
Have a look at FileUtils.mv:
require 'fileutils'
temp_array.each do |song|
FileUtils.mv song.path, "/Users/tsiege/Desktop/#{playlist_name}"
end
Be sure that the directory #{playlist_name} exists before you do, though:
FileUtils.mkdir_p "/Users/tsiege/Desktop/#{playlist_name}"
To move files you can use FileUtils.mv:
require 'fileutils'
FileUtils.mv 'from.ext', 'to.ext'
http://ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html#method-c-mv
And if you want a list of files in a directory you can use:
Dir['/path/to/dir/*']
http://ruby-doc.org/core-1.9.3/Dir.html
Lastly, you may also want to check if you have a file or directory:
File.file? file
File.directory? dir
http://ruby-doc.org/core-1.9.3/File.html#method-c-file-3F

How do I find the location of the gem?

I'm developing a library that provides access to gem metadata, including it's location on the file system. The idea was to let gem authors set it to a relative path from any script:
# $root/example.gemspec
Example::Gem.root '.' # => $root/
# $root/lib/example/gem.rb
Example::Gem.root '../..' # => $root/
Then, the path of the current script would be used to compute the absolute path. My implementation is currently as follows:
def root(relative_to = nil, file = __FILE__)
unless relative_to.nil?
#root = File.expand_path relative_to, File.dirname(file)
end
#root
end
I thought __FILE__ would return the path to the caller's script, but that assumption is wrong.
It worked within the library itself, but broke down when I tried to integrate it with one of my other gems; the generated path was always relative to the support library itself.
How can I implement this without having to pass the current __FILE__ on every call? Otherwise, there isn't much value to be gained; writing root('../..', __FILE__) is almost the same as writing an actual method to do the same thing.
If it's possible to figure out the path without having to specify anything, that would be even better, but I couldn't think of anything. How does Rails do it?
By the way, I'm aware of Gem::Specification#gem_dir, but it always returns paths relative to the installation directory, even if the gem is not actually there, which makes it useless in a development environment.
You can always make use of the backtrace facility provided:
caller.first
It produces an amalgam of file and line but is usually separated by :. I'd be careful to allow for filenames or paths that may contain colon for whatever reason by ignoring the line information but preserving the rest. In other words, do not split but sub:
caller.first.sub(/:\d+:in .*$/, '')

How to create directories recursively in ruby?

I want to store a file as /a/b/c/d.txt, but I do not know if any of these directories exist and need to recursively create them if necessary.
How can one do this in ruby?
Use mkdir_p:
FileUtils.mkdir_p '/a/b/c'
The _p is a unix holdover for parent/path you can also use the alias mkpath if that makes more sense for you.
FileUtils.mkpath '/a/b/c'
In Ruby 1.9 FileUtils was removed from the core, so you'll have to require 'fileutils'.
Use mkdir_p to create directory recursively
path = "/tmp/a/b/c"
FileUtils.mkdir_p(path) unless File.exists?(path)
If you are running on unixy machines, don't forget you can always run a shell command under ruby by placing it in backticks.
`mkdir -p /a/b/c`
Pathname to the rescue!
Pathname('/a/b/c/d.txt').dirname.mkpath
require 'ftools'
File.makedirs
You could also use your own logic
def self.create_dir_if_not_exists(path)
recursive = path.split('/')
directory = ''
recursive.each do |sub_directory|
directory += sub_directory + '/'
Dir.mkdir(directory) unless (File.directory? directory)
end
end
So if path is 'tmp/a/b/c'
if 'tmp' doesn't exist 'tmp' gets created, then 'tmp/a/' and so on and so forth.

Resources