From 0e8deb35295ca4f18f16644b687f50461da12cdf Mon Sep 17 00:00:00 2001 From: "Todd V. Jonker" Date: Sat, 21 Feb 2026 14:13:46 -0800 Subject: [PATCH] Refactor: Tidy `SourceName`. * Bring factory methods together. * Streamline `getPath()`. * Add some docs and assertions to clarify invariants. --- .../fusion/FileSystemSpecialist.java | 14 +- .../ionfusion/runtime/base/SourceName.java | 136 ++++++++++-------- 2 files changed, 88 insertions(+), 62 deletions(-) diff --git a/runtime/src/main/java/dev/ionfusion/fusion/FileSystemSpecialist.java b/runtime/src/main/java/dev/ionfusion/fusion/FileSystemSpecialist.java index c93aa9d5..3682214c 100644 --- a/runtime/src/main/java/dev/ionfusion/fusion/FileSystemSpecialist.java +++ b/runtime/src/main/java/dev/ionfusion/fusion/FileSystemSpecialist.java @@ -30,21 +30,23 @@ public FileSystemSpecialist(DynamicParameter currentSecurityGuard, /** - * Resolve a relative path against the {@code current_directory} parameter. - * If file is absolute it is returned as-is. + * Resolve a relative path against the {@code current_directory} parameter. If + * {@code file} is absolute it is returned as-is. * * @param who identifies the invoking procedure for error messaging. + * + * @return an absolute path. */ File resolvePath(Evaluator eval, String who, File file) throws FusionException { SecurityGuard guard = myCurrentSecurityGuard.currentValue(eval); - if (! guard.isFileSystemEnabled()) + if (!guard.isFileSystemEnabled()) { throw new FusionErrorException(who + ": Access denied to " + file); } - if (file.isAbsolute()) return file; + if (file.isAbsolute()) { return file; } String cdPath = myCurrentDirectory.asString(eval); File cdFile = new File(cdPath); @@ -54,9 +56,11 @@ File resolvePath(Evaluator eval, String who, File file) /** * Resolve a relative path against the {@code current_directory} param. - * If the path is absolute it is returned as-is. + * If the path is absolute, it is returned as-is. * * @param who identifies the invoking procedure for error messaging. + * + * @return an absolute path. */ File resolvePath(Evaluator eval, String who, String path) throws FusionException diff --git a/runtime/src/main/java/dev/ionfusion/runtime/base/SourceName.java b/runtime/src/main/java/dev/ionfusion/runtime/base/SourceName.java index 2364a537..2146914d 100644 --- a/runtime/src/main/java/dev/ionfusion/runtime/base/SourceName.java +++ b/runtime/src/main/java/dev/ionfusion/runtime/base/SourceName.java @@ -3,6 +3,8 @@ package dev.ionfusion.runtime.base; +import static java.util.Objects.requireNonNull; + import java.io.File; import java.net.URL; import java.nio.file.Path; @@ -22,53 +24,6 @@ public class SourceName private final String myDisplay; - /** - * Creates a {@link SourceName} representing a file at the given path. - * - * @param path must not be null or empty. - * - * @return a new {@link SourceName} instance - * - * @see #forFile(File) - */ - public static SourceName forFile(String path) - { - if (path.isEmpty()) { - throw new IllegalArgumentException("path must not be empty"); - } - return new FileSourceName(new File(path)); - } - - /** - * Creates a {@link SourceName} representing a file. - * The {@link File}'s absolute path will be displayed. - * - * @param path must not be null or empty. - * - * @see #forFile(String) - * - * @return a new {@link SourceName} instance - */ - public static SourceName forFile(File path) - { - return new FileSourceName(path); - } - - /** - * Creates a {@link SourceName} that will simply display the given text. - * - * @param display must not be null. - * - * @return a new {@link SourceName} instance - */ - public static SourceName forDisplay(String display) - { - if (display.isEmpty()) { - throw new IllegalArgumentException("display must not be empty"); - } - return new SourceName(display); - } - private SourceName(String display) { @@ -88,21 +43,25 @@ public String display() /** - * Returns the associated source file, if one is known. + * Returns the absolute path of the source file if one is known. * This is the case for instances created by {@link #forFile(File)} or * {@link #forFile(String)}. * - * @return the source file, or null. + * @return null if this source is not an actual file. */ public File getFile() { return null; } + /** + * Returns the absolute path of the source file if one is known. + * + * @return null if this source is not an actual file. + */ public Path getPath() { - File f = getFile(); - return f == null ? null : f.toPath(); + return null; } /** @@ -195,6 +154,9 @@ private static class FileSourceName @Override public File getFile() { return myFile; } + + @Override + public Path getPath() { return myFile.toPath(); } } @@ -210,6 +172,7 @@ private static class ModuleSourceName ModuleSourceName(ModuleIdentity id, File file) { super(id + " (at file:" + file + ")"); + assert file.isAbsolute(); myId = id; myFile = file; } @@ -218,14 +181,11 @@ private static class ModuleSourceName public File getFile() { return myFile; } @Override - public ModuleIdentity getModuleIdentity() { return myId; } - } + public Path getPath() { return myFile.toPath(); } - public static SourceName forModule(ModuleIdentity id, File sourceFile) - { - assert sourceFile != null; - return new ModuleSourceName(id, sourceFile); + @Override + public ModuleIdentity getModuleIdentity() { return myId; } } @@ -244,6 +204,8 @@ private static class UrlSourceName private UrlSourceName(ModuleIdentity id, URL url) { super(id + " (at " + url.toExternalForm() + ")"); + assert !url.getProtocol().equalsIgnoreCase("file") + : "Use FileSourceName for local files"; myId = id; myUrl = url; } @@ -256,8 +218,68 @@ private UrlSourceName(ModuleIdentity id, URL url) } + //========================================================================= + // Factory methods + + /** + * Creates a {@link SourceName} that will simply display the given text. + * + * @param display must not be null. + * + * @return a new {@link SourceName} instance + */ + public static SourceName forDisplay(String display) + { + if (display.isEmpty()) { + throw new IllegalArgumentException("display must not be empty"); + } + return new SourceName(display); + } + + + /** + * Creates a {@link SourceName} representing a file at the given path. + * + * @param path must not be null or empty, and is converted to an absolute path. + * + * @return a new {@link SourceName} instance + * + * @see #forFile(File) + */ + public static SourceName forFile(String path) + { + if (path.isEmpty()) { + throw new IllegalArgumentException("path must not be empty"); + } + return new FileSourceName(new File(path).getAbsoluteFile()); + } + + /** + * Creates a {@link SourceName} representing a file. The {@link File}'s absolute + * path will be displayed. + * + * @param path is converted to an absolute path. + * + * @return a new {@link SourceName} instance + * + * @see #forFile(String) + */ + public static SourceName forFile(File path) + { + return new FileSourceName(path.getAbsoluteFile()); + } + + + public static SourceName forModule(ModuleIdentity id, File sourceFile) + { + requireNonNull(id, "id must not be null"); + return new ModuleSourceName(id, sourceFile); + } + + public static SourceName forUrl(ModuleIdentity id, URL url) { + requireNonNull(id, "id must not be null"); return new UrlSourceName(id, url); } }