Topa_14
Topa_14

Reputation: 199

Rename specific files depending on a diferent file in same directory

I'm practising some programming and I'm now faced with the following issue. I have a folder with multiple subfolders inside. Each subfolder contains two files: an .xlsx and a .doc file. I want to rename the .xlsx depending on the name of the .doc file. For example, in directory documents\main_folder\folder_1 there are two files: test_file.xlsx and final_file.doc. After running my code, result should be final_file.xlsx and final_file.doc. This must happen with all subfolders.

My code so far:

    require 'FileUtils'

    filename = nil
    files = Dir.glob('**/*.doc')
    files.each do |rename|
    filename = File.basename(rename, File.extname(rename))
    puts "working with file: #{filename}"
    end

    subs = Dir.glob('**/*.xlsx')
    subs.each do |renaming|
    File.rename(renaming, filename)
    end

Two issues with this code: firstly, the .xlsx is moved where the .rb file is located. Secondly, renaming is partially achieved, only that the extension is not kept, but completely removed. Any help?

Upvotes: 2

Views: 49

Answers (1)

max pleaner
max pleaner

Reputation: 26778

Dir.glob('**/*.doc').each do |doc_file|
  # extract folder path e.g. "./foo" from "./foo/bar.doc"
  dir = File.dirname(doc_file) 

  # extract filename without extension e.g. "bar" from "./foo/bar.doc"
  basename = File.basename(doc_file, File.extname(doc_file)) 

  # find the xlsx file in the same folder
  xlsx_file = Dir.glob("#{dir}/*.xlsx")[0]

  # perform the replacement
  File.rename(xlsx_file, "#{dir}/#{basename}.xlsx")
end

edit

the validation step you requested:

# first, get all the directories
dirs = Dir.glob("**/*").select { |path| File.directory?(path) }

# then validate each of them
dirs.each do |dir|
  [".doc", ".xlxs"].each do |ext|
    # raise an error unless the extension has exactly 1 file
    unless Dir.glob("#{dir}/*#{ext}").count == 1
      raise "#{dir} doesn't have exactly 1 #{ext} file"
    end
  end
end

You can also bunch up the errors into one combined message if you prefer ... just push the error message into an errors array instead of raising them as soon as they come up

Upvotes: 2

Related Questions