Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
ruby-version: ['3.2', '3.1', '3.0', '2.7', '2.6']
ruby-version: ['3.4', '3.3', '3.2', '3.1', '3.0', '2.7']
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up making a separate PR for this stuff: #49


steps:
- uses: actions/checkout@v3
Expand All @@ -25,10 +25,8 @@ jobs:
with:
ruby-version: ${{matrix.ruby-version}}
bundler-cache: true
- name: Updating RubyGems
run: gem update --system
- name: Install dependencies
run: bundle install
run: bundle install --quiet
- name: Rubocop
run: bundle exec rubocop -D
- name: Rspec
Expand Down
58 changes: 57 additions & 1 deletion lib/memfs/dir.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ def self.getwd
end
class << self; alias pwd getwd; end

def self.glob(patterns, flags = 0, &block)
def self.glob(patterns, flags = 0, base: nil, sort: true, **opts, &block)
# Handle keyword argument for flags
flags = opts[:flags] if opts.key?(:flags)

patterns = [*patterns].map(&:to_s)
list = fs.paths.select do |path|
patterns.any? do |pattern|
Expand All @@ -68,6 +71,7 @@ def self.glob(patterns, flags = 0, &block)
end
# FIXME: ugly special case for /* and /
list.delete('/') if patterns.first == '/*'

return list unless block_given?
list.each { |path| block.call(path) }
nil
Expand Down Expand Up @@ -101,6 +105,58 @@ def self.tmpdir
'/tmp'
end

def self.mktmpdir(prefix_suffix = nil, tmpdir = nil, **options)
tmpdir ||= self.tmpdir

case prefix_suffix
when nil
prefix = 'd'
suffix = ''
when String
prefix = prefix_suffix
suffix = ''
when Array
prefix = prefix_suffix[0] || 'd'
suffix = prefix_suffix[1] || ''
else
raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
end

max_try = options.fetch(:max_try, 10000)
path = nil

max_try.times do
timestamp = Time.now.strftime('%Y%m%d')
random = sprintf('%d-%d', $$, rand(0x100000000))
path = File.join(tmpdir, "#{prefix}#{timestamp}-#{random}-0#{suffix}")

begin
mkdir(path, 0o700)
break
rescue Errno::EEXIST
path = nil
next
end
end

raise "cannot generate temporary directory name" if path.nil?

if block_given?
begin
result = yield path
ensure
begin
rmdir(path) if exists?(path)
rescue
# Ignore cleanup errors
end
end
result
else
path
end
end

class << self
alias delete rmdir
alias unlink rmdir
Expand Down
70 changes: 70 additions & 0 deletions spec/memfs/dir_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,76 @@ module MemFs
end
end

describe '.mktmpdir' do
context 'when no block is given' do
it 'creates a temporary directory and returns its path' do
path = described_class.mktmpdir
expect(path).to start_with('/tmp/d')
expect(described_class.exist?(path)).to be true
end

it 'accepts a prefix' do
path = described_class.mktmpdir('myprefix')
expect(path).to start_with('/tmp/myprefix')
expect(described_class.exist?(path)).to be true
end

it 'accepts a prefix and suffix as an array' do
path = described_class.mktmpdir(['prefix_', '_suffix'])
expect(path).to start_with('/tmp/prefix_')
expect(path).to end_with('_suffix')
expect(described_class.exist?(path)).to be true
end

it 'accepts a custom tmpdir' do
described_class.mkdir('/custom_tmp')
path = described_class.mktmpdir(nil, '/custom_tmp')
expect(path).to start_with('/custom_tmp/d')
expect(described_class.exist?(path)).to be true
end
end

context 'when a block is given' do
it 'creates a temporary directory, yields it, and removes it' do
yielded_path = nil
described_class.mktmpdir do |path|
yielded_path = path
expect(path).to start_with('/tmp/d')
expect(described_class.exist?(path)).to be true
end
expect(described_class.exist?(yielded_path)).to be false
end

it 'removes the directory even if an exception occurs' do
yielded_path = nil
expect do
described_class.mktmpdir do |path|
yielded_path = path
expect(described_class.exist?(path)).to be true
raise 'test exception'
end
end.to raise_error('test exception')
expect(described_class.exist?(yielded_path)).to be false
end

it 'works with a prefix and block' do
yielded_path = nil
described_class.mktmpdir('test_') do |path|
yielded_path = path
expect(path).to start_with('/tmp/test_')
expect(described_class.exist?(path)).to be true
end
expect(described_class.exist?(yielded_path)).to be false
end
end

it 'creates unique directory names' do
path1 = described_class.mktmpdir
path2 = described_class.mktmpdir
expect(path1).not_to eq(path2)
end
end

describe '.unlink' do
subject { described_class }
it_behaves_like 'aliased method', :unlink, :rmdir
Expand Down
Loading