Search code examples
rubypathdir

Ruby paths with backslash on Mac


Venturing into Ruby lands (learning Ruby). I like it, fun programming language.

Anyhow, I'm trying to build a simple program to delete suffixes from a folder, where user provides the path to the folder in the Mac terminal.

The scenario goes like this:

  1. User runs my program
  2. The program ask user to enter the folder path
  3. User drags and drop the folder into the Mac terminal
  4. Program receives path such as "/Users/zhang/Desktop/test\ folder"
  5. Program goes and renames all files in that folder with suffix such as "image_mdpi.png" to "image.png"

I'm encountering a problem though.

Right now, I'm trying to list the contents of the directory using:

Dir.entries(@directoryPath)

However, it seems Dir.entries doesn't like backslashes '\' in the path. If I use Dir.entries() for a path with backslash, I get an exception saying folder or file doesn't exist.

So my next thought would be to use :

Pathname.new(rawPath)

To let Ruby create a proper path. Unfortunately, even Pathname.new() doesn't like backslash either. My terminal is spitting out

@directoryPath is not dir

This is my source code so far:

# ------------------------------------------------------------------------------
# Renamer.rb
# ------------------------------------------------------------------------------
#
# Program to strip out Android suffixes like _xhdpi, _hpdi, _mdpi and _ldpi
# but only for Mac at the moment.
#
# --------------------------------------------------
# Usage:
# --------------------------------------------------
# 1. User enters a the path to the drawable folder to clean
# 2. program outputs list of files and folder it detects to clean
# 3. program ask user to confirm cleaning

require "Pathname"


@directoryPath = ''
@isCorrectPath = false

# --------------------------------------------------
# Method definitions
# --------------------------------------------------
def ask_for_directory_path
  puts "What is the path to the drawable folder you need cleaning?:"
  rawPath = gets.chomp.strip
  path = Pathname.new("#{rawPath}")

  puts "Stored dir path = '#{path}'"

  if path.directory?
    puts "@directoryPath is dir"
  else
    puts "@directoryPath is not dir"
  end

  @directoryPath = path.to_path
end

def confirm_input_correct
  print "\n\nIs this correct? [y/N]: "
  @isCorrectPath = gets.chomp.strip
end

def reconfirm_input_correct
  print "please enter 'y' or 'N': "
  @isCorrectPath = gets.strip
end

def output_folder_path
  puts "The folder '#{@directoryPath}' contains the following files and folders:"

  # Dir.entries doesn't like \
  # @directoryPath = @directoryPath.gsub("\\", "")

  puts "cleaned path is '#{@directoryPath}'"
  begin
    puts Dir.entries(@directoryPath)
  rescue
    puts "\n\nLooks like the path is incorrect:"
    puts @directoryPath
  end
end

def clean_directory
  puts "Cleaning directory now..."
end


puts "Hello, welcome to Renamer commander.\n\n"

ask_for_directory_path

output_folder_path

confirm_input_correct

while @isCorrectPath != 'y' && @isCorrectPath != 'N' do
  reconfirm_input_correct
end

if @isCorrectPath == 'y'
  clean_directory
else
  ask_for_directory_path
end

I went through this learning resource for Ruby two three days ago:

http://rubylearning.com/satishtalim/tutorial.html

I'm also using these resource to figure out what I'm doing wrong:

http://ruby-doc.org/core-2.3.0/Dir.html

https://robm.me.uk/ruby/2014/01/18/pathname.html

Any ideas?

Edit

Well, the current work around(?) is to clean my raw string and delete any backslashes, using new method:

def cleanBackslash(originalString)
  return originalString.gsub("\\", "")
end

Then

def ask_for_directory_path
  puts "\nWhat is the path to the drawable folder you need cleaning?:"
  rawPath = gets.chomp.strip
  rawPath = cleanBackslash(rawPath)

  ...

end

Not the prettiest I guess.

A sample run of the program:

Zhang-computer:$ ruby Renamer.rb 
Hello, welcome to Renamer commander.

What is the path to the drawable folder you need cleaning?:
/Users/zhang/Desktop/test\ folder 
Stored dir path = '/Users/zhang/Desktop/test folder'
@directoryPath is dir
The folder '/Users/zhang/Desktop/test folder' contains the following files and folders:
cleaned path is '/Users/zhang/Desktop/test folder'
.
..
.DS_Store
file1.txt
file2.txt
file3.txt


Is this correct? [y/N]: 

:]


Solution

  • Okay, first of all, using gets.chomp.strip is probably not a good idea :P

    The better and closer solution to what your normally see in a real bash program is to use the Readline library:

    i.e.

    require "Readline"
    
    ...
    
    def ask_for_directory_path
      rawPath = String.new
    
      rawPath = Readline.readline("\nWhat is the path to the drawable folder you need cleaning?\n> ", true)
      rawPath = rawPath.chomp.strip
      rawPath = cleanBackslash(rawPath)
    
      @directoryPath = Pathname.new(rawPath)
    end
    

    Using Readline lets you tab complete the folder path. I also needed to clean my backslash from the readline using my own defined:

    def cleanBackslash(originalString)
      return originalString.gsub("\\", "")
    end
    

    After that, the Dir.entries(@directorPath) is able to list all the files and folders in the path, whether the user typed it in manually or drag and drop the folder into the Mac terminal:

    Zhang-iMac:Renamer zhang$ ruby Renamer.rb 
    Hello, welcome to Renamer commander.
    
    What is the path to the drawable folder you need cleaning?
    > /Users/zhang/Ruby\ Learning/Renamer/test_folder 
    
    The folder '/Users/zhang/Ruby Learning/Renamer/test_folder' contains the following files and folders:
    .
    ..
    .DS_Store
    drawable
    drawable-hdpi
    drawable-mdpi
    drawable-xhdpi
    drawable-xxhdpi
    drawable-xxxhdpi
    
    
    Is this correct? [y/N]: y
    Cleaning directory now...
    

    The program is not finish but I think that fixes my problem of the backslash getting in the way.

    I don't know how real bash programs are made, but consider this my poor man's bash program lol.

    Final program

    Check it out:

    demo run screenshot

    I feel like a boss now! :D