gears.filesystem: Improve get_random_file_from_dir.

Previously, only a filename was returned. Getting the path was
inconvinient when used within a declarative construct.

It was also misbehaving then the directory didn't exist. Finally,
the extention list now accept extension names starting with a dot.
This commit is contained in:
Emmanuel Lepage Vallee 2021-09-07 16:32:59 -07:00
parent eddabebac4
commit cefd4f843e
2 changed files with 46 additions and 17 deletions

View File

@ -172,28 +172,39 @@ end
-- @tparam string path The directory to search. -- @tparam string path The directory to search.
-- @tparam[opt] table exts Specific extensions to limit the search to. eg:`{ "jpg", "png" }` -- @tparam[opt] table exts Specific extensions to limit the search to. eg:`{ "jpg", "png" }`
-- If ommited, all files are considered. -- If ommited, all files are considered.
-- @tparam[opt=false] boolean absolute_path Return the absolute path instead of the filename.
-- @treturn string|nil A randomly selected filename from the specified path (with -- @treturn string|nil A randomly selected filename from the specified path (with
-- a specified extension if required) or nil if no suitable file is found. -- a specified extension if required) or nil if no suitable file is found. If `absolute_path`
-- is set, then a path is returned instead of a file name.
-- @staticfct gears.filesystem.get_random_file_from_dir -- @staticfct gears.filesystem.get_random_file_from_dir
function filesystem.get_random_file_from_dir(path, exts) function filesystem.get_random_file_from_dir(path, exts, absolute_path)
local files, valid_exts = {}, {} local files, valid_exts = {}, {}
-- Transforms { "jpg", ... } into { [jpg] = #, ... } -- Transforms { "jpg", ... } into { [jpg] = #, ... }
if exts then for i, j in ipairs(exts) do valid_exts[j:lower()] = i end end if exts then for i, j in ipairs(exts) do valid_exts[j:lower():gsub("^[.]", "")] = i end end
-- Build a table of files from the path with the required extensions -- Build a table of files from the path with the required extensions
local file_list = Gio.File.new_for_path(path):enumerate_children("standard::*", 0) local file_list = Gio.File.new_for_path(path):enumerate_children("standard::*", 0)
-- This will happen when the directory doesn't exist.
if not file_list then return nil end
for file in function() return file_list:next_file() end do for file in function() return file_list:next_file() end do
if file:get_file_type() == "REGULAR" then if file:get_file_type() == "REGULAR" then
local file_name = file:get_display_name() local file_name = file:get_display_name()
if not exts or valid_exts[file_name:lower():match(".+%.(.*)$") or ""] then if not exts or valid_exts[file_name:lower():match(".+%.(.*)$") or ""] then
table.insert(files, file_name) table.insert(files, file_name)
end end
end end
end end
if #files == 0 then return nil end
-- Return a randomly selected filename from the file table -- Return a randomly selected filename from the file table
return #files > 0 and files[math.random(#files)] or nil local file = files[math.random(#files)]
return absolute_path and (path:gsub("[/]*$", "") .. "/" .. file) or file
end end
return filesystem return filesystem

View File

@ -115,22 +115,40 @@ describe("gears.filesystem", function()
assert.is_true(test_b == "a.png" assert.is_true(test_b == "a.png"
or test_b == "b.jpg") or test_b == "b.jpg")
-- Any file found (selected extensions)
local test_c = gfs.get_random_file_from_dir(root .. "filesystem_tests", {".png", ".jpg"})
assert.is_true(test_c == "a.png"
or test_c == "b.jpg")
-- Test absolute paths.
local test_d = gfs.get_random_file_from_dir(root .. "filesystem_tests", {".png", ".jpg"}, true)
assert.is_true(test_d == root .. "filesystem_tests/a.png"
or test_d == root .. "filesystem_tests/b.jpg")
-- Make sure the paths are generated correctly.
assert.is_nil(test_d:match("//"))
-- "." in filename test cases with extensions -- "." in filename test cases with extensions
local test_c = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {"ext"}) local test_e = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {"ext"})
assert.is_true(test_c == "filename.ext" assert.is_true(test_e == "filename.ext"
or test_c == ".filename.ext" or test_e == ".filename.ext"
or test_c == "file.name.ext" or test_e == "file.name.ext"
or test_c == ".file.name.ext") or test_e == ".file.name.ext")
-- "." in filename test cases with no extensions -- "." in filename test cases with no extensions
local test_d = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {""}) local test_f = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {""})
assert.is_true(test_d == "filename" assert.is_true(test_f == "filename"
or test_d == "filename." or test_f == "filename."
or test_d == "filename.ext." or test_f == "filename.ext."
or test_d == ".filename" or test_f == ".filename"
or test_d == ".filename." or test_f == ".filename."
or test_d == "file.name.ext." or test_f == "file.name.ext."
or test_d == ".file.name.ext.") or test_f == ".file.name.ext.")
-- Test invalid directories.
local test_g = gfs.get_random_file_from_dir(root .. "filesystem_tests/fake_dir")
assert.is_nil(test_g)
end end
end) end)
end) end)