Skip to content

Commit 2010bed

Browse files
committed
Adds #entries feature to the public API
mend
1 parent 689a4c6 commit 2010bed

9 files changed

Lines changed: 130 additions & 1 deletion

File tree

docsite/source/file-system-utilities.html.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,7 @@ files.directory?(path)
6969

7070
# check if path is an executable (files and directories)
7171
files.executable?(path)
72+
73+
# read entries from a directory
74+
files.entries(path)
7275
```

docsite/source/index.html.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ file.directory?(path)
9999

100100
# check if path is an executable (files and directories)
101101
file.executable?(path)
102+
103+
# read entries from a directory
104+
files.entries(path)
102105
```
103106

104107
### Adapters

lib/dry/files.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,18 @@ def remove_block(path, target)
836836
remove_block(path, target) if match?(content, target)
837837
end
838838

839+
# Reads entries from a directory
840+
#
841+
# @param path [String,Pathname] the path to file
842+
#
843+
# @raise [Dry::Files::IOError] in case of I/O error
844+
#
845+
# @since 1.0.1
846+
# @api public
847+
def entries(path)
848+
adapter.entries(path)
849+
end
850+
839851
private
840852

841853
# @since 0.3.0

lib/dry/files/file_system.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ class FileSystem
1717
# @api private
1818
attr_reader :file_utils
1919

20+
# @since 1.0.1
21+
# @api private
22+
attr_reader :dir
23+
2024
# Creates a new instance
2125
#
2226
# @param file [Class]
@@ -25,9 +29,10 @@ class FileSystem
2529
# @return [Dry::Files::FileSystem]
2630
#
2731
# @since 0.1.0
28-
def initialize(file: File, file_utils: FileUtils)
32+
def initialize(file: File, file_utils: FileUtils, dir: Dir)
2933
@file = file
3034
@file_utils = file_utils
35+
@dir = dir
3136
end
3237

3338
# Opens (or creates) a new file for both read/write operations.
@@ -343,6 +348,22 @@ def executable?(path)
343348
file.executable?(path)
344349
end
345350

351+
# Get entries from a directory
352+
#
353+
# @see https://ruby-doc.org/3.2.2/Dir.html#method-c-entries
354+
#
355+
# @param [String,Pathname] the path to list entries for
356+
#
357+
# @raise [Dry::Files::IOError] in case of I/O error
358+
#
359+
# @since 1.0.1
360+
# @api private
361+
def entries(path)
362+
with_error_handling do
363+
dir.entries(path)
364+
end
365+
end
366+
346367
private
347368

348369
# Catch `SystemCallError` and re-raise a `Dry::Files::IOError`.

lib/dry/files/memory_file_system.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,24 @@ def executable?(path)
386386
node.executable?
387387
end
388388

389+
# Reads entries from a directory
390+
#
391+
# @param path [String,Pathname] the path to file
392+
# @return [Array<String>] the entries
393+
#
394+
# @raise [Dry::Files::IOError] in case of I/O error
395+
#
396+
# @since 1.0.1
397+
# @api private
398+
def entries(path)
399+
path = Path[path]
400+
node = find(path)
401+
raise IOError, Errno::ENOENT.new(path.to_s) if node.nil?
402+
raise IOError, Errno::ENOTDIR.new(path.to_s) unless node.directory?
403+
404+
[".", ".."] + node.children.keys
405+
end
406+
389407
private
390408

391409
# @since 0.1.0

lib/dry/files/memory_file_system/node.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ def self.root
9797
# @api private
9898
attr_reader :segment, :mode
9999

100+
# @since 1.0.1
101+
# @api private
102+
attr_reader :children
103+
100104
# Instantiate a new node.
101105
# It's a directory node by default.
102106
#

spec/integration/dry/files_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,4 +1880,18 @@ class Result
18801880
expect(subject.executable?(path)).to be(true)
18811881
end
18821882
end
1883+
1884+
describe "#entries" do
1885+
it "returns a list of entries for a directory" do
1886+
subject.touch(root.join("file-1.txt"))
1887+
subject.touch(root.join("file-2.txt"))
1888+
1889+
expect(subject.entries(root)).to eq [
1890+
".",
1891+
"..",
1892+
"file-2.txt",
1893+
"file-1.txt"
1894+
]
1895+
end
1896+
end
18831897
end

spec/unit/dry/files/file_system_spec.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,4 +600,23 @@
600600
expect(subject.executable?(path)).to be(true)
601601
end
602602
end
603+
604+
describe "#entries" do
605+
it "returns entries for directory" do
606+
subject.touch(root.join("file-1.txt"))
607+
subject.touch(root.join("file-2.txt"))
608+
609+
expect(subject.entries(root)).to eq [".", "..", "file-2.txt", "file-1.txt"]
610+
end
611+
612+
it "raises error if directory doesn't exist" do
613+
path = root.join("non-existent")
614+
615+
expect { subject.entries(path) }.to raise_error do |exception|
616+
expect(exception).to be_kind_of(Dry::Files::IOError)
617+
expect(exception.cause).to be_kind_of(Errno::ENOENT)
618+
expect(exception.message).to include(path.to_s)
619+
end
620+
end
621+
end
603622
end

spec/unit/dry/files/memory_file_system_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,4 +626,39 @@ def call(*)
626626
expect(subject.executable?(path)).to be(true)
627627
end
628628
end
629+
630+
describe "#entries" do
631+
it "raises an error when the path does not exist" do
632+
path = subject.join("file-1.txt")
633+
634+
expect { subject.entries(path) }.to raise_error do |exception|
635+
expect(exception).to be_kind_of(Dry::Files::IOError)
636+
expect(exception.cause).to be_kind_of(Errno::ENOENT)
637+
expect(exception.message).to include(path.to_s)
638+
end
639+
end
640+
641+
it "raises an error when the path is a file" do
642+
path = subject.join("file-1.txt")
643+
subject.touch(path)
644+
645+
expect { subject.entries(path) }.to raise_error do |exception|
646+
expect(exception).to be_kind_of(Dry::Files::IOError)
647+
expect(exception.cause).to be_kind_of(Errno::ENOTDIR)
648+
expect(exception.message).to include(path.to_s)
649+
end
650+
end
651+
652+
it "returns entries when the path is a directory" do
653+
subject.touch(subject.join("file-1.txt"))
654+
subject.touch(subject.join("file-2.txt"))
655+
656+
expect(subject.entries(subject.join)).to eq [
657+
".",
658+
"..",
659+
"file-1.txt",
660+
"file-2.txt"
661+
]
662+
end
663+
end
629664
end

0 commit comments

Comments
 (0)