DEV Community

Nic
Nic

Posted on • Originally published at coderscat.com on

Ruby change current working directory safely

CAPTURE-2020_04_02_ruby-change-working-directory.org_20200402_232121.png

There are two ways to change the current working directory in Ruby, but you need to notice the thread-safe issue.

Dir.chdir

Dir.chdir is the most traight way:

Dir.chdir('/tmp')

Enter fullscreen mode Exit fullscreen mode

If you need to go back to the previous directory:

orig_dir = Dir.pwd
Dir.chdir('/tmp')
.....

Dir.chdir(org_dir)

Enter fullscreen mode Exit fullscreen mode

Dir.chdir with block

A more idiomatic way is using a block to finish the task and go back to the previous directory:

Dir.chdir('/tmp') do
    .....
end

Enter fullscreen mode Exit fullscreen mode

The original working directory is restored when the block exits. The return value of chdir is the value of the block.

But, this is not thread-safe.

Dir.chdir will call the POSIX function to change the working dir of the current process, so it can never be made safe across threads.

MRI adds a warning message for this scenario, let’s run this code snippet:

require 'fileutils'

FileUtils.mkdir_p("/tmp/foo")

def blah(d)
  Dir.chdir(d) do
    sleep 2
  end
end

threads = []
threads << Thread.new { blah('/tmp/foo') }
threads << Thread.new { blah('/tmp/foo') }
threads.each { |t| t.join }

Enter fullscreen mode Exit fullscreen mode

The will be a warning message printed out:

./chdir\_demo.rb:3: warning: conflicting chdir during another chdir block
Enter fullscreen mode Exit fullscreen mode

How to be thread-safe

If you want to make this block to be safe-thread, you need to add Mutex for it:

require 'thread'

M = Mutex.new

def blah(d)
  M.synchronize do
    Dir.chdir(d) do
      puts Dir.pwd
      sleep 2
    end
  end
end

threads = []
threads << Thread.new { blah('/tmp/foo') }
threads << Thread.new { blah('/tmp/foo') }
threads.each { |t| t.join }

Enter fullscreen mode Exit fullscreen mode

The post Ruby change current working directory appeared first on Coder's Cat.

Discussion (0)