Checking directory for file with certain extension - ruby

I am trying to check whether a directory entered through the command line contains files with a certain file extension. For example, if I have a folder "Folder1" with another folder in it "Folder 2" and Folder2 contains several files, "test.asm", "test.vm", "test.tst". I am taking either a directory or a file through the command line like this
ruby translator.rb Folder1/Folder2
or
ruby translator.rb Folder1/Folder2/test.vm
What I'm trying to do is error checking. I already have checks for whether the input is a folder and now I need to check whether the folder actually contains a .vm file.
What I've done so far is this:
require 'pathname'
pn = Pathname.new(ARGV[0])
if ARGV.size != 1
puts "Proper usage is: ruby vmtranslator.rb file_directory\file.vm \nOR \nruby vmtranslator.rb file_directory\ where file_directory has multiple vm files test".split("\n")
elsif !pn.exist? && !pn.directory?
puts "Something is wrong with the file"
puts "Either try another file or check the file extension"
elsif pn.directory? && pn.children(false).extname.include?('.vm')
puts "this should print if Folder1 is the folder, but not if Folder2 is.."
vm_file1 = File.open("OPEN FILES WITH .vm AS EXTENSION)
elsif pn.exist? || pn.file?
puts "this is right"
vm_file = File.open(ARGV[0], "r")
asm_file = File.new(ARGV[0].sub('.vm', '.asm'), "w")
end
So what that should do is check whether there is only 1 argument first, if so, then it checks if it's a file or directory else it outputs an error, then what I'm doing is checking if it's a directory. If so, I need to check if the directory actually contains .vm files. I tried pn.each_child {|f| f.extname == '.vm'} but that only checks the first value before it returns true. Is there any easier way to check the whole array before returning true, other than just setting some boolean?
Some of the code up there isn't done, I'm just asking if there is any way to check a directory for a file of a certain extension. I can't find anything with my searches so far.

str = ARGV[0]
proc = ->(f) { puts "doing something with #{f.path}" }
if Dir.exists?(str)
Dir.glob(File.join(str, File.join('**', '*.vm'))).each do |entry|
proc[File.open(entry)]
end
elsif File.exists?(str) && File.extname(str) == '.vm'
proc[File.open(str)]
else
puts "couldn't do anything with #{str}"
end

Dir["Folder1/Folder2/*.vm"].empty?
will return false if there are any .vm files in Folder1/Folder2.

require 'pathname'
def directory_has_vm_files?(path)
Dir.glob(path.join('*.vm')).size > 0
end
unless ARGV[0]
puts %{
Proper usage is:
ruby vmtranslator.rb file_directory or file.vm
OR
ruby vmtranslator.rb file_directory
where file_directory has multiple vm files
}
else
path = Pathname.new(ARGV[0])
if path.exist?
if path.file?
if File.extname(path) == '.vm'
puts "Valid VM file"
else
puts "Not a VM file"
end
else
if directory_has_vm_files?(path)
puts "Valid Directory - contains vm files"
else
puts "#{path} does not contain any VM file"
end
end
else
puts "Invalid path"
end
end

Related

How do I open each file in a directory with Ruby?

I need to open each file inside a directory. My attempt at this looks like:
Dir.foreach('path/to/directory') do |filename|
next if filename == '.' || filename == '..'
puts "working on #{filename}"
# this is where it crashes
file = File.open(filename, 'r')
#some code
file.close
# more code
end
My code keeps crashing at File.open(filename, 'r'). I'm not sure what filename should be.
The filename should include the path to the file when the file is not in the same directory than the Ruby file itself:
path = 'path/to/directory'
Dir.foreach(path) do |filename|
next if filename == '.' || filename == '..'
puts "working on #{filename}"
file = File.open("#{path}/#{filename}", 'r')
#some code
file.close
# more code
end
I recommend using Find.find.
While we can use various methods from the Dir class, it will look and retrieve the list of files before returning, which can be costly if we're recursively searching multiple directories or have a huge number of files embedded in the directories.
Instead, Find.find will walk the directories, returning both the directories and files as each is found. A simple check lets us decide which we want to continue processing or whether we want to skip it. The documentation has this example which should be easy to understand:
The Find module supports the top-down traversal of a set of file paths.
For example, to total the size of all files under your home directory, ignoring anything in a “dot” directory (e.g. $HOME/.ssh):
require 'find'
total_size = 0
Find.find(ENV["HOME"]) do |path|
if FileTest.directory?(path)
if File.basename(path)[0] == ?.
Find.prune # Don't look any further into this directory.
else
next
end
else
total_size += FileTest.size(path)
end
end
I'd go for Dir.glob or File.find. But not Dir.foreach as it returns . and .. which you don't want.
Dir.glob('something/*').each do |filename|
next if File.directory?(filename)
do_something_with_the_file(filename)
end

Trying to change names of files using Dir and File.rename on Mac OS?

I'm following a tutorial and am trying to change the names of three files in a folder that's located under 'drive/users/myname/test'. I'm getting the error:
'chdir': No such file or directory - test'.
The starting path is already 'drive/users/myname', which is why I thought that I only had to enter 'test' for Dir.chdir.
How do I correctly input the paths on Mac OS?
Dir.chdir('test')
pic_names = Dir['test.{JPG,jpg}']
puts "What do you want to call this batch"
batch_name = gets.chomp
puts
print "Downloading #{pic_names.length} files: "
pic_number = 1
pic_names.each do |p|
print '.'
new_name = "batch_name#{pic_number}.jpg"
File.rename(name, new_name)
pic_number += 1
end
I think you have to provide the absolute path. So, your first line should be:
Dir.chdir("/drive/users/myname/test")
According to the documentation:
Dir.chdir("/var/spool/mail")
puts Dir.pwd
should output/var/spool/mail.
You can look at the documentation for more examples.
In:
File.rename(name, new_name)
name is never defined prior to its attempted use.
Perhaps p is supposed to be name, or name should be p?
With that assumption I'd write the loop something like:
pic_names.each_with_index do |name, pic_number|
print '.'
new_name = "#{ batch_name }#{ 1 + pic_number }.jpg"
File.rename(name, File.join(File.dirname(name), new_name))
end
File.join(File.dirname(name), new_name) is important. You have to refer to the same path in both the original and new filenames, otherwise the file will be moved to a new location, which would be wherever the current-working-directory points to. That's currently masked by your use of chdir at the start, but, without that, you'd wonder where your files went.

Ruby: check if a .zip file exists, and extract

2 small questions to create the effect I'm looking for.
How do I check if a file exists within a directory with the extension of .zip?
If it does exist I need to make a folder with the same name as the .zip without the .zip extension for the folder.
Then I need to extract the files into the folder.
Secondly, what do I do if there are more than one .zip files in the folder?
I'm doing something like this and trying to put it into ruby
`mkdir fileNameisRandom`
`unzip fileNameisRandom.zip -d fileNameisRandom`
On a similar post I found something like
Dir.entries("#{Dir.pwd}").select {|f| File.file? f}
which I know checks all files within a directory and makes sure they are a file.
The problem is I don't know how to make sure that it is only an extension of .zip
Also, I found the Glob function which checks the extension of a filename from: http://ruby-doc.org/core-1.9.3/Dir.html
How do I ensure the file exists in that case, and if it doesn't I can print out an error then.
From the comment I now have
if Dir['*.zip'].first == nil #check to see if any exist
puts "A .zip file was not found"
elsif Dir['*.zip'].select {|f| File.file? f} then #ensure each of them are a file
#use a foreach loop to go through each one
Dir['*.zip'].select.each do |file|
puts "#{file}"
end ## end for each loop
end
Here's a way of doing this with less branching:
# prepare the data
zips= Dir['*.zip'].select{ |f| File.file? }
# check if data is sane
if zips.empty?
puts "No zips"
exit 0 # or return
end
# process data
zips.each do |z|
end
This pattern is easier to follow for fellow programmers.
You can also do it using a ruby gem called rubyzip
Gemfile:
source 'https://rubygems.org'
gem 'rubyzip'
run bundle
unzip.rb:
require 'zip'
zips= Dir['*.zip'].select{ |f| File.file? }
if zips.empty?
puts "No zips"
exit 0 # or return
end
zips.each do |zip|
Zip::File.open(zip) do |files|
files.each do |file|
# write file somewhere
# see here https://github.com/rubyzip/rubyzip
end
end
end
I finally pieced together different information from tutorials and used #rogerdpack and his comment for help.
require 'rubygems/package'
#require 'zlib'
require 'fileutils'
#move to the unprocessed directory to unpack the files
#if a .tgz file exists
#take all .tgz files
#make a folder with the same name
#put all contained folders from .tgz file inside of similarly named folder
#Dir.chdir("awaitingApproval/")
if Dir['*.zip'].first == nil #check to see if any exist, I use .first because Dir[] returns an array
puts "A .zip file was not found"
elsif Dir['*.zip'].select {|f| File.file? f} then #ensure each of them are a file
#use a foreach loop to go through each one
Dir['*.zip'].select.each do |file|
puts "" #newlie for each file
puts "#{file}" #print out file name
#next line based on `mkdir fileNameisRandom`
`mkdir #{Dir.pwd}/awaitingValidation/#{ File.basename(file, File.extname(file)) }`
#next line based on `unzip fileNameisRandom.zip -d fileNameisRandom`
placement = "awaitingValidation/" + File.basename(file, File.extname(file))
puts "#{placement}"
`sudo unzip #{file} -d #{placement}`
puts "Unzip complete"
end ## end for each loop
end

Directory walk call method when directory is reached

Trying to write a script that will search through a directory and sub-directories for specific files. I would like to do know how a certain directory or directories come up to call a method.
this is what I have tried and failed:
def display_directory(path)
list = Dir[path+'/*']
return if list.length == 0
list.each do |f|
if File.directory? f #is it a directory?
if File.directory?('config')
puts "this is the config folder"
end
printf "%-50s %s\n", f, "is a directory:".upcase.rjust(25)
else
printf "%-50s %s\n", f, "is not a directory:".upcase.rjust(25)
end
end
end
start = File.join("**")
puts "Processing directory\n\n".upcase.center(30)
display_directory start
this is what I want to happen.
app
app/controllers
app/helpers
app/mailers
app/models
app/models/bugzilla
app/models/security
app/views
app/views/auth
app/views/calendar
app/views/layouts
app/views/step
app/views/step_mailer
app/views/suggestion
app/views/suggestion_mailer
app/views/task
app/views/user
bin
--------------------------------------
config <----------(call method foo)
config/environments
config/initializers
config/locales
--------------------------------------
db
db/bugzilla
db/migrate
db/security
lib
lib/tasks
log
public
public/images
public/javascripts
public/stylesheets
script
script/performance
script/process
--------------------------
test <---------(call method foobar)
test/fixtures
test/fixtures/mailer
test/functional
test/integration
test/performance
test/unit
--------------------------
vendor
vendor/plugins
Instead
if File.directory?('config')
Try
if f.path.include?('config')
but this will work for every directory that have config on the name. You can put a larger substring to make a better match.
Also, it is very idiomatic in ruby use do..end for multiline blocks and {..} for single line.
I figured out a way. this works pretty well. I've added a method to show all the files in mentioned directory when reached.
def special_dir(path)
puts "------------------------------------"
sp_path = Dir.glob(File.join(path,"*","**"))
sp_path.each do |cf|
puts "\t" + cf
end
end
def walk(path)
list = Dir[path+'/*'].reject{ |r| r['doc'] || r['tmp']}
list.each do |x|
path = File.join(path, x)
if File.directory?(x)
if x =~ /config/ or x =~ /test/
special_dir(x)
else
puts "#{x}"
walk(path)
end
else
#puts x
end
end
end
start = File.join("**")
walk start

How can I check if a list of folders exist in Ruby?

I am trying to find a matching list of folders on my C:/ drive and then execute some code but its not working as expected.
I can do it fine with a single folder but not sure how to get it working with a list of folders that I want to find.
My code
Dir.glob("C:/*")
directory_list = Array.new
directory_list << "FolderA"
directory_list << "FolderB"
if Dir.exists?(directory_list)
puts "Does exist"
else
puts "Does not Exist"
end
The following solution provided a proof of concept for me
dirs = ["FolderA", "FolderB"]
reg = Regexp.union dirs exists,
rest = Dir.glob("{B,C,D}:/*").partition{ |path| path =~ reg }
puts exists
With thanks to Kyle in the chat room.
On windows, the directories are prepended with the drive so you need to:
"C:/FolderB" =~ /FolderB|FolderA/
The code:
dirs = ["FolderA", "Folderb"]
reg = Regexp.union dirs
exists, rest = Dir.glob("C:/*").partition{ |path| path =~ reg }
# now you have two arrays, one of directories that exist and the rest
c_drive = Dir.glob("**/")
%w(FolderA, FolderB).each do |dir|
if c_drive.include?(dir)
puts "#{dir} exists"
else
puts "#{dir} does not exist"
end
end

Resources