diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d308e03..d69ac3d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 21 + - name: Set up JDK 11 uses: actions/setup-java@v3 with: - java-version: '21' + java-version: '11' distribution: 'temurin' cache: 'sbt' diff --git a/.scalafmt.conf b/.scalafmt.conf index 5d777ab..5824ac3 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.7.17 +version = 3.8.3 runner.dialect = scala3 fileOverride { @@ -27,16 +27,16 @@ newlines { } spaces { - beforeContextBoundColon = Always + beforeContextBoundColon = IfMultipleBounds inImportCurlyBraces = true afterSymbolicDefs = true } literals { - long=Upper - float=Lower - double=Lower - hexPrefix=Lower - hexDigits=Upper - scientific=Upper + long = Upper + float = Lower + double = Lower + hexPrefix = Lower + hexDigits = Upper + scientific = Upper } diff --git a/J/src/main/java/tinyscalautils/java/Text.java b/J/src/main/java/tinyscalautils/java/Text.java index fc57ccc..5c92813 100644 --- a/J/src/main/java/tinyscalautils/java/Text.java +++ b/J/src/main/java/tinyscalautils/java/Text.java @@ -8,167 +8,167 @@ * @see tinyscalautils.text */ public final class Text { - private Text() { - throw new AssertionError("this class cannot be instantiated"); - } + private Text() { + throw new AssertionError("this class cannot be instantiated"); + } - public final static class SILENT_MODE { - private SILENT_MODE() { - throw new AssertionError("this class cannot be instantiated"); - } + public final static class SILENT_MODE { + private SILENT_MODE() { + throw new AssertionError("this class cannot be instantiated"); + } - public static void print(Object ignoredArg) { - } + public static void print(Object ignoredArg) { + } - public static void println(Object ignoredArg) { - } + public static void println(Object ignoredArg) { + } - public static void printf(String ignoredFormat, Object... ignoredArgs) { - } + public static void printf(String ignoredFormat, Object... ignoredArgs) { } + } - public final static class STANDARD_MODE { - private STANDARD_MODE() { - throw new AssertionError("this class cannot be instantiated"); - } + public final static class STANDARD_MODE { + private STANDARD_MODE() { + throw new AssertionError("this class cannot be instantiated"); + } - public static void print(Object arg) { - tinyscalautils.text.StandardMode.print(arg, false); - } + public static void print(Object arg) { + textScala.standardMode().print(arg, false); + } - public static void println(Object arg) { - tinyscalautils.text.StandardMode.print(arg, true); - } + public static void println(Object arg) { + textScala.standardMode().print(arg, true); + } - public static void printf(String format, Object... arg) { - tinyscalautils.text.StandardMode.print(String.format(format, arg), false); - } + public static void printf(String format, Object... arg) { + textScala.standardMode().print(String.format(format, arg), false); } + } - public final static class THREAD_MODE { - private THREAD_MODE() { - throw new AssertionError("this class cannot be instantiated"); - } + public final static class THREAD_MODE { + private THREAD_MODE() { + throw new AssertionError("this class cannot be instantiated"); + } - public static void print(Object arg) { - tinyscalautils.text.ThreadMode.print(arg, false); - } + public static void print(Object arg) { + textScala.threadMode().print(arg, false); + } - public static void println(Object arg) { - tinyscalautils.text.ThreadMode.print(arg, true); - } + public static void println(Object arg) { + textScala.threadMode().print(arg, true); + } - public static void printf(String format, Object... arg) { - tinyscalautils.text.ThreadMode.print(String.format(format, arg), false); - } + public static void printf(String format, Object... arg) { + textScala.threadMode().print(String.format(format, arg), false); } + } - public final static class THREAD_TIME_DEMO_MODE { - private THREAD_TIME_DEMO_MODE() { - throw new AssertionError("this class cannot be instantiated"); - } + public final static class THREAD_TIME_DEMO_MODE { + private THREAD_TIME_DEMO_MODE() { + throw new AssertionError("this class cannot be instantiated"); + } - public static void print(Object arg) { - tinyscalautils.text.ThreadTimeDemoMode.print(arg, false); - } + public static void print(Object arg) { + textScala.threadTimeDemoMode().print(arg, false); + } - public static void println(Object arg) { - tinyscalautils.text.ThreadTimeDemoMode.print(arg, true); - } + public static void println(Object arg) { + textScala.threadTimeDemoMode().print(arg, true); + } - public static void printf(String format, Object... arg) { - tinyscalautils.text.ThreadTimeDemoMode.print(String.format(format, arg), false); - } + public static void printf(String format, Object... arg) { + textScala.threadTimeDemoMode().print(String.format(format, arg), false); } + } - public final static class THREAD_TIME_MODE { - private THREAD_TIME_MODE() { - throw new AssertionError("this class cannot be instantiated"); - } + public final static class THREAD_TIME_MODE { + private THREAD_TIME_MODE() { + throw new AssertionError("this class cannot be instantiated"); + } - public static void print(Object arg) { - tinyscalautils.text.ThreadTimeMode.print(arg, false); - } + public static void print(Object arg) { + textScala.threadTimeMode().print(arg, false); + } - public static void println(Object arg) { - tinyscalautils.text.ThreadTimeMode.print(arg, true); - } + public static void println(Object arg) { + textScala.threadTimeMode().print(arg, true); + } - public static void printf(String format, Object... arg) { - tinyscalautils.text.ThreadTimeMode.print(String.format(format, arg), false); - } + public static void printf(String format, Object... arg) { + textScala.threadTimeMode().print(String.format(format, arg), false); } + } - public final static class TIME_DEMO_MODE { - private TIME_DEMO_MODE() { - throw new AssertionError("this class cannot be instantiated"); - } + public final static class TIME_DEMO_MODE { + private TIME_DEMO_MODE() { + throw new AssertionError("this class cannot be instantiated"); + } - public static void print(Object arg) { - tinyscalautils.text.TimeDemoMode.print(arg, false); - } + public static void print(Object arg) { + textScala.timeDemoMode().print(arg, false); + } - public static void println(Object arg) { - tinyscalautils.text.TimeDemoMode.print(arg, true); - } + public static void println(Object arg) { + textScala.timeDemoMode().print(arg, true); + } - public static void printf(String format, Object... arg) { - tinyscalautils.text.TimeDemoMode.print(String.format(format, arg), false); - } + public static void printf(String format, Object... arg) { + textScala.timeDemoMode().print(String.format(format, arg), false); } + } - public final static class TIME_MODE { - private TIME_MODE() { - throw new AssertionError("this class cannot be instantiated"); - } + public final static class TIME_MODE { + private TIME_MODE() { + throw new AssertionError("this class cannot be instantiated"); + } - public static void print(Object arg) { - tinyscalautils.text.TimeMode.print(arg, false); - } + public static void print(Object arg) { + textScala.timeMode().print(arg, false); + } - public static void println(Object arg) { - tinyscalautils.text.TimeMode.print(arg, true); - } + public static void println(Object arg) { + textScala.timeMode().print(arg, true); + } - public static void printf(String format, Object... arg) { - tinyscalautils.text.TimeMode.print(String.format(format, arg), false); - } + public static void printf(String format, Object... arg) { + textScala.timeMode().print(String.format(format, arg), false); } + } - private static final TextScala textScala = new TextScala(); + private static final TextScala textScala = new TextScala(); - /** - * Note that, contrary to the Scala variant, this method sets {@code includeSystem} to true by default. - */ - public static String printout(Runnable code) { - return printout(false, true, Charset.defaultCharset(), code); - } + /** + * Note that, contrary to the Scala variant, this method sets {@code includeSystem} to true by default. + */ + public static String printout(Runnable code) { + return printout(false, true, Charset.defaultCharset(), code); + } - public static String printout(boolean includeErr, boolean includeSystem, Runnable code) { - return printout(includeErr, includeSystem, Charset.defaultCharset(), code); - } + public static String printout(boolean includeErr, boolean includeSystem, Runnable code) { + return printout(includeErr, includeSystem, Charset.defaultCharset(), code); + } - public static String printout(boolean includeErr, boolean includeSystem, Charset charset, Runnable code) { - return textScala.printout(code, includeErr, includeSystem, charset); - } + public static String printout(boolean includeErr, boolean includeSystem, Charset charset, Runnable code) { + return textScala.printout(code, includeErr, includeSystem, charset); + } - public static void info() { - textScala.info(); - } + public static void info() { + textScala.info(); + } - public static String plural(Number x, String singularForm, String pluralForm) { - return textScala.plural(x, singularForm, pluralForm); - } + public static String plural(Number x, String singularForm, String pluralForm) { + return textScala.plural(x, singularForm, pluralForm); + } - public static String plural(Number x, String singularForm) { - return textScala.plural(x, singularForm); - } - - public static String timeString(double seconds, int unitsCount) { - return textScala.timeString(seconds, unitsCount); - } + public static String plural(Number x, String singularForm) { + return textScala.plural(x, singularForm); + } - public static String timeString(double seconds) { - return timeString(seconds, 2); - } + public static String timeString(double seconds, int unitsCount) { + return textScala.timeString(seconds, unitsCount); + } + + public static String timeString(double seconds) { + return timeString(seconds, 2); + } } diff --git a/J/src/main/scala/tinyscalautils/java/TextScala.scala b/J/src/main/scala/tinyscalautils/java/TextScala.scala index c1e593d..a856dc0 100644 --- a/J/src/main/scala/tinyscalautils/java/TextScala.scala +++ b/J/src/main/scala/tinyscalautils/java/TextScala.scala @@ -18,3 +18,10 @@ private final class TextScala: def timeString(seconds: Double, unitsCount: Int): String = tinyscalautils.text.timeString(seconds, unitsCount) + + def standardMode = tinyscalautils.text.standardMode + def timeMode = tinyscalautils.text.timeMode + def timeDemoMode = tinyscalautils.text.timeDemoMode + def threadMode = tinyscalautils.text.threadMode + def threadTimeMode = tinyscalautils.text.threadTimeMode + def threadTimeDemoMode = tinyscalautils.text.threadTimeDemoMode diff --git a/S/src/main/scala/tinyscalautils/assertions/implies.scala b/S/src/main/scala/tinyscalautils/assertions/implies.scala index 3bc9117..e436a7f 100644 --- a/S/src/main/scala/tinyscalautils/assertions/implies.scala +++ b/S/src/main/scala/tinyscalautils/assertions/implies.scala @@ -6,8 +6,6 @@ extension (left: Boolean) /** Logical implication. LHS is always evaluated. RHS is only evaluated if LHS side evaluated to * true. * - * Also available as `==>` - * * @since 1.1 */ inline infix def implies(inline right: Boolean): Boolean = !left || right diff --git a/S/src/main/scala/tinyscalautils/collection/Queue.scala b/S/src/main/scala/tinyscalautils/collection/Queue.scala index ca8fd47..052c781 100644 --- a/S/src/main/scala/tinyscalautils/collection/Queue.scala +++ b/S/src/main/scala/tinyscalautils/collection/Queue.scala @@ -3,14 +3,8 @@ package tinyscalautils.collection import java.util extension [A](queue: util.Queue[A]) - /** Like `poll` but wrapping `null` in an option. - * - * @since 1.2 - */ + @deprecated("use Option instead", since = "1.3") def pollOption(): Option[A] = Option(queue.poll()) - /** Like `peek` but wrapping `null` in an option. - * - * @since 1.2 - */ + @deprecated("use Option instead", since = "1.3") def peekOption: Option[A] = Option(queue.peek()) diff --git a/S/src/main/scala/tinyscalautils/collection/sorted.scala b/S/src/main/scala/tinyscalautils/collection/sorted.scala new file mode 100644 index 0000000..13c836c --- /dev/null +++ b/S/src/main/scala/tinyscalautils/collection/sorted.scala @@ -0,0 +1,7 @@ +package tinyscalautils.collection + +import scala.collection.SeqOps + +extension [A, CC[_]](self: SeqOps[A, CC, CC[A]]) + /** Sorted according to implicit order, but in reverse. */ + def sortedInReverse[B >: A : Ordering]: CC[A] = self.sorted(using Ordering[B].reverse) diff --git a/S/src/main/scala/tinyscalautils/io/Input.scala b/S/src/main/scala/tinyscalautils/io/Input.scala new file mode 100644 index 0000000..8ef2dd6 --- /dev/null +++ b/S/src/main/scala/tinyscalautils/io/Input.scala @@ -0,0 +1,139 @@ +package tinyscalautils.io + +import java.io.{ Closeable, File, IOException, InputStream } +import java.net.URL +import java.nio.file.{ Files, Path } +import scala.collection.{ AbstractIterator, IterableFactory } +import scala.io.Codec.UTF8 +import scala.io.{ Codec, Source } +import scala.util.Using + +private lazy val nonEmpty = (str: String) => Option.unless(str.isBlank)(str) + +/** Identity parsing. By using it as a `parser` argument of `readAll`, lines are returned + * unchanged. + */ +lazy val noParsing: String => IterableOnce[String] = _ :: Nil + +/** Text inputs, suitable to the `read` and `readAll` functions. */ +@FunctionalInterface +trait Input[-I]: + /** Opens the input as a source. */ + def source(in: I): Source + +object Input: + /** Summon. */ + def apply[I: Input]: Input[I] = summon + +extension [I: Input](in: I) + /** Opens the input as a source. */ + def source: Source = Input[I].source(in) + +private given Codec = UTF8 + +given SourceIsInput: Input[Source] = identity +given InputStreamIsInput: Input[InputStream] = Source.fromInputStream(_) +given FileIsInput: Input[File] = Source.fromFile(_) +given URLIsInput: Input[URL] = Source.fromURL(_) +given FileNameIsInput: Input[String] = Source.fromFile(_) +given PathIsInput: Input[Path] = Files.newInputStream(_).source + +/** Parses a text file (sequence of lines) using a given parser to split each line. Lines that parse + * to an empty sequence (such as `None`) are ignored. Encoding is UTF8. + * + * @return + * a factory-based collection of all the parts of all the lines. + * + * @param in + * the source to parse. + * + * @param parser + * the parser to use; if omitted, each line is taken as a whole except blank lines, which are + * ignored. + * + * @param factory + * a factory for the desired collection type. + * + * @param silent + * if true, I/O errors (unreadable files, non-text files, ...) are ignored, and an empty + * collection is returned. + * + * @since 1.3 + */ +def readAll[A, C[_], I: Input]( + factory: IterableFactory[C] +)(in: I, parser: String => IterableOnce[A] = nonEmpty, silent: Boolean = false): C[A] = + try Using.resource(in.source)(_.getLines().flatMap(parser).to(factory)) + catch case e: IOException => if silent then factory.empty else throw e + +/** Simplified form of `readAll` that uses `List` as the factory. */ +def readAll[A, I: Input](in: I, parser: String => IterableOnce[A], silent: Boolean): List[A] = + readAll(List)(in, parser, silent = silent) + +/** Simplified form of `readAll` that uses `List` as the factory and `false` for the `silent` + * argument. + * + * @since 1.3 + */ +def readAll[A, I: Input](in: I, parser: String => IterableOnce[A]): List[A] = + readAll(List)(in, parser, silent = false) + +/** Simplified form of `readAll` that does not parse (blank lines are ignored) and uses `List` as + * the factory. + * + * @since 1.3 + */ +def readAll[I: Input](in: I, silent: Boolean): List[String] = readAll(List)(in, silent = silent) + +/** Simplified form of `readAll` that does not parse (blank lines are ignored), uses `List` as the + * factory, and uses `false` for the `silent` * argument. + * + * @since 1.3 + */ +def readAll[I: Input](in: I): List[String] = readAll(List)(in, silent = false) + +/** Reads a text file as a single string. Encoding is UTF8. + * + * @param in + * the source to read. + * + * @param silent + * if true, I/O errors (unreadable files, non-text files, ...) are ignored, and an empty string + * is returned. + * + * @since 1.3 + */ +def read[I: Input](in: I, silent: Boolean = false): String = + try Using.resource(in.source)(_.mkString) + catch case e: IOException => if silent then "" else throw e + +private class CloseableIterator[A](i: Iterator[A], closing: => Unit) + extends AbstractIterator[A] + with Closeable: + export i.{ hasNext, next } + + def close(): Unit = closing +end CloseableIterator + +/** Parses a text file (sequence of lines) using a given parser to split each line. Lines that parse + * to an empty sequence (such as `None`) are ignored. Encoding is UTF8. + * + * @return + * an iterator of all the parts of all the lines; closing this iterator closes the underlying + * source. + * + * @param in + * the source to parse. + * + * @param parser + * the parser to use; if omitted, each line is taken as a whole except blank lines, which are + * ignored. + * + * @since 1.3 + */ +def readingAll[A, I: Input]( + in: I, + parser: String => IterableOnce[A] = nonEmpty +): Iterator[A] & Closeable = + val source = in.source + CloseableIterator(source.getLines().flatMap(parser), source.close()) diff --git a/S/src/main/scala/tinyscalautils/io/Output.scala b/S/src/main/scala/tinyscalautils/io/Output.scala new file mode 100644 index 0000000..e710605 --- /dev/null +++ b/S/src/main/scala/tinyscalautils/io/Output.scala @@ -0,0 +1,73 @@ +package tinyscalautils.io + +import java.io.{ File, OutputStream, OutputStreamWriter } +import java.nio.charset.StandardCharsets +import java.nio.file.{ Files, Path } +import scala.util.Using + +/** Text outputs, suitable to the `write` and `writeAll` functions. */ +@FunctionalInterface +trait Output[-O]: + /** Opens the output as a stream. */ + def destination(out: O): OutputStream + +object Output: + /** Summon. */ + def apply[O: Output]: Output[O] = summon + +extension [O: Output](out: O) + /** Opens the output as a stream. */ + def destination: OutputStream = Output[O].destination(out) + +private val UTF8 = StandardCharsets.UTF_8 + +given OutputStreamIsOutput: Output[OutputStream] = identity +given PathIsOutput: Output[Path] = Files.newOutputStream(_) +given FileNameIsOutput: Output[String] = Path.of(_).destination +given FileIsOutput: Output[File] = _.toPath.destination + +/** Writes the string into a destination. Nothing is added, unless when `newLine = true`, which adds + * a final newline. Encoding is UTF8. + * + * @note + * Uses `CharSequence` instead of `Any` to avoid accidental calls to `write` that were intended + * to be `writeAll`. + * + * @param out + * the destination to write to. + * + * @param newline + * when true, adds a final newline to the output. + */ +def write[O: Output](out: O, newline: Boolean = false)(str: CharSequence): Unit = + Using.resource(OutputStreamWriter(out.destination, UTF8)): writer => + writer.write(str.toString) + if newline then writer.write('\n') + +/** Writes the string representations of a collection of values into a destination. The three + * arguments `pre`, `sep`, and `post` are as in `mkString`. Encoding is UTF8. + * + * @param out + * the destination to write to. + */ +def writeAll[A, O: Output](pre: String = "", sep: String = "", post: String = "")( + out: O +)(values: IterableOnce[A]): Unit = + Using.resource(OutputStreamWriter(out.destination, UTF8)): writer => + writer.write(pre) + val i = values.iterator + if i.nonEmpty then + writer.write(i.next().toString) + while i.hasNext do + writer.write(sep) + writer.write(i.next().toString) + writer.write(post) + +/** Writes the string representations of a collection of values into a destination. Each value is + * followed by a newline, including the last. + * + * @param out + * the destination to write to. + */ +def writeAll[A, O: Output](out: O)(values: IterableOnce[A]): Unit = + writeAll(sep = "\n")(out)(values.iterator ++ Iterator.single("")) diff --git a/S/src/main/scala/tinyscalautils/io/files.scala b/S/src/main/scala/tinyscalautils/io/files.scala index bb8a056..3e517cf 100644 --- a/S/src/main/scala/tinyscalautils/io/files.scala +++ b/S/src/main/scala/tinyscalautils/io/files.scala @@ -1,12 +1,12 @@ package tinyscalautils.io -import java.nio.charset.StandardCharsets.UTF_8 -import java.nio.file.{ Files, Path } -import scala.util.Using -import scala.jdk.StreamConverters.* import tinyscalautils.assertions.* +import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.{ Files, Path } import scala.collection.IterableFactory +import scala.jdk.StreamConverters.* +import scala.util.Using import scala.util.control.NonFatal /** The list of files and subdirectories in a directory, in no particular order. @@ -14,9 +14,11 @@ import scala.util.control.NonFatal * @param silent * if true, errors are ignored, and an empty list is returned. * + * @throws IllegalArgumentException + * if the path is not a directory. + * * @since 1.0 */ -@throws[IllegalArgumentException]("if the path is not a directory") def listPaths(dir: Path, silent: Boolean = false): List[Path] = readPaths(List)(dir, silent) /** The collection of files and subdirectories in a directory, in no particular order. @@ -27,6 +29,9 @@ def listPaths(dir: Path, silent: Boolean = false): List[Path] = readPaths(List)( * @param factory * a factory for the desired collection type. * + * @throws IllegalArgumentException + * if the path is not a directory. + * * @since 1.0 */ def readPaths[C[_]](factory: IterableFactory[C])(dir: Path, silent: Boolean = false): C[Path] = @@ -36,30 +41,12 @@ def readPaths[C[_]](factory: IterableFactory[C])(dir: Path, silent: Boolean = fa if silent then contents.getOrElse(factory.empty) else contents.get catch case NonFatal(e) => if silent then factory.empty else throw e -/** The list of lines in a text file, in UTF8 encoding. - * - * @param silent - * if true, errors (unreadable files, non-text files, ...) are ignored, and an empty list is - * returned. - * - * @since 1.0 - */ +//noinspection ScalaDeprecation +@deprecated("use readAll instead", since = "1.3") def listLines(file: Path, silent: Boolean = false): List[String] = readLines(List)(file, silent) -/** The collection of lines in a text file, in UTF8 encoding. - * - * @param silent - * if true, errors (unreadable files, non-text files, ...) are ignored, and an empty collection - * is returned. - * - * @param factory - * a factory for the desired collection type. - * - * @since 1.0 - */ -def readLines[C[_]]( - factory: IterableFactory[C] -)(file: Path, silent: Boolean = false): C[String] = +@deprecated("use readAll instead", since = "1.3") +def readLines[C[_]](factory: IterableFactory[C])(file: Path, silent: Boolean = false): C[String] = try val lines = Using(Files.lines(file, UTF_8))(stream => stream.toScala(factory)) if silent then lines.getOrElse(factory.empty) else lines.get diff --git a/S/src/main/scala/tinyscalautils/io/resources.scala b/S/src/main/scala/tinyscalautils/io/resources.scala index d98bec6..1c6e4c6 100644 --- a/S/src/main/scala/tinyscalautils/io/resources.scala +++ b/S/src/main/scala/tinyscalautils/io/resources.scala @@ -1,7 +1,9 @@ package tinyscalautils.io -import java.net.URL +import java.io.{ IOException, InputStream } +import java.net.{ URI, URL } import java.util.MissingResourceException +import java.util.zip.GZIPInputStream import scala.collection.IterableFactory import scala.io.Source import scala.util.Using @@ -20,26 +22,80 @@ extension (obj: AnyRef) * * @since 1.0 */ - @throws[MissingResourceException]("if the resource is not found") def findResource(name: String): URL = - obj.getClass.getResource(name) match - case null => throw MissingResourceException("resource not found", name, name) - case url => url - -/** Parses a test file (sequence of lines) using a given parser. Lines that parse to an empty - * sequence (such as `None`) are ignored. - * - * @param url - * the source to parse. - * - * @param parser - * the parser to use. - * - * @param factory - * a factory for the desired collection type (defaults to `List`). - * - * @since 1.1 - */ + searchResource(obj, name, trygz = false).getOrElse: + throw MissingResourceException("resource not found", name, name) + + /** Finds the given resource as a URL. This is simply a call to `getClass.getResource` that falls + * back to a default location instead of returning `null`. Note that this `findResource` variant + * does _not_ throw `MissingResourceException`. + * + * Like `getResource`, paths that start with a slash are absolute, and relative paths are + * relative to the full package name. Paths are always treated as relative to the URI when the + * fallback is used. + * + * @see + * [[java.lang.Class.getResource]] + * + * @param fallback + * a fallback URI, which must be absolute. + * + * @since 1.3 + */ + def findResource(fallback: URI)(name: String): URL = + searchResource(obj, name, trygz = false).getOrElse(url(fallback, name)) + + /** Finds the given resource as a stream. If the resource is not found, then `name.gz` is tried + * instead and, if found, opened as GZIP compressed data. (If `name` already ends with `.gz`, no + * attempt is made with a `.gz.gz` name.) + * + * Like `getResource`, paths that start with a slash are absolute, and relative paths are + * relative to the full package name. + * + * @see + * [[java.lang.Class.getResource]] + * + * Throws [[java.util.MissingResourceException]] if the resource is not found. + * @since 1.3 + */ + def findResourceAsStream(name: String): InputStream = + openURL: + searchResource(obj, name, trygz = true).getOrElse: + throw MissingResourceException("resource not found", name, name) + + /** Finds the given resource as a stream. If the resource is not found, then `name.gz` is tried + * instead. If neither is found locally, the fallback location is used to search for `name.gz` + * first and, if unsuccessful, for `name`. When a `.gz` file is found, either locally or + * remotely, it is opened as GZIP compressed data. If `name` already ends with `.gz`, no attempt + * is made with a `.gz.gz` name. + * + * Like `getClass.getResource`, paths that start with a slash are absolute, and relative paths + * are relative to the full package name. + * + * @see + * [[java.lang.Class.getResource]] + * @since 1.3 + */ + def findResourceAsStream(fallback: URI)(name: String): InputStream = + searchResource(obj, name, trygz = true) match + case Some(url) => openURL(url) + case None => + if name.endsWith(".gz") then openURL(url(fallback, name)) + else + try openURL(url(fallback, name + ".gz")) + catch case _: IOException => openURL(url(fallback, name)) + +private def searchResource(obj: AnyRef, name: String, trygz: Boolean) = + Option(obj.getClass.getResource(name)) match + case None if trygz && !name.endsWith(".gz") => Option(obj.getClass.getResource(name + ".gz")) + case other => other + +private def url(uri: URI, name: String) = uri.resolve(name.dropWhile(_ == '/')).toURL + +private def openURL(url: URL): InputStream = + if url.getPath.endsWith(".gz") then GZIPInputStream(url.openStream()) else url.openStream() + +@deprecated("use readAll instead", since = "1.3") def parseURL[A, C[_]]( url: URL, parser: String => IterableOnce[A], diff --git a/S/src/main/scala/tinyscalautils/text/Dot.scala b/S/src/main/scala/tinyscalautils/text/Dot.scala new file mode 100644 index 0000000..94e8886 --- /dev/null +++ b/S/src/main/scala/tinyscalautils/text/Dot.scala @@ -0,0 +1,16 @@ +package tinyscalautils.text + +import scala.compiletime.summonInline + +/** Returns its input and prints a single dot, according to the given printing mode. The only + * possible modes are `standardMode` (by default) and `silentMode`. + */ +inline def dot[A, M <: PrintingMode](any: A, theDot: Char = '.')(using mode: M = standardMode): A = + summonInline[M <:< standardMode.type | silentMode.type] + print(theDot) + any + +/** Returns its input and prints a single star, according to the given printing mode. The only + * possible modes are `standardMode` (by default) and `silentMode`. + */ +def star[A](any: A)(using mode: PrintingMode = standardMode): A = dot(any, '*') diff --git a/S/src/main/scala/tinyscalautils/text/PrintingMode.scala b/S/src/main/scala/tinyscalautils/text/PrintingMode.scala index ddeae18..d34c27c 100644 --- a/S/src/main/scala/tinyscalautils/text/PrintingMode.scala +++ b/S/src/main/scala/tinyscalautils/text/PrintingMode.scala @@ -45,61 +45,45 @@ private def thread = val name = theThread.getName if name.nonEmpty then name else "anonymous thread " + theThread.getId -// These objects are needed for interfacing with Java - -private object StandardMode extends PrintingMode: - def print(arg: Any, newline: Boolean) = +/** Standard printing. Equivalent to `Predef.printf/println`. */ +given standardMode: PrintingMode with + def print(arg: Any, newline: Boolean): Unit = if newline then Predef.println(arg) else Predef.print(arg) -private object SilentMode extends PrintingMode: - def print(arg: Any, newline: Boolean) = () +/** Silent. Does not print anything. No call to `Predef.printf/println` takes place. */ +given silentMode: PrintingMode with + def print(arg: Any, newline: Boolean): Unit = () -private object ThreadMode extends PrintingMode: - def print(arg: Any, newline: Boolean) = +/** Adds thread name. Strings are printed as: `: `. */ +given threadMode: PrintingMode with + def print(arg: Any, newline: Boolean): Unit = val format = if newline then "%s: %s%n" else "%s: %s" Predef.printf(format, thread, arg) -private object TimeMode extends PrintingMode: - def print(arg: Any, newline: Boolean) = +/** Adds time. Strings are printed as: `at HH:MM:SS.millis: ` */ +given timeMode: PrintingMode with + def print(arg: Any, newline: Boolean): Unit = val format = if newline then "at %1$TT.%1$TL: %2$s%n" else "at %1$TT.%1$TL: %2$s" Predef.printf(format, now(), arg) -private object TimeDemoMode extends PrintingMode: - def print(arg: Any, newline: Boolean) = +/** Adds time, but hides hours and minutes. Strings are printed as: `at XX:XX:SS.millis: ` + */ +given timeDemoMode: PrintingMode with + def print(arg: Any, newline: Boolean): Unit = val format = if newline then "at XX:XX:%1$TS.%1$TL: %2$s%n" else "at XX:XX:%1$TS.%1$TL: %2$s" Predef.printf(format, now(), arg) -private object ThreadTimeMode extends PrintingMode: - def print(arg: Any, newline: Boolean) = +/** Adds thread name and time. Strings are printed as: ` at HH:MM:SS.millis: ` */ +given threadTimeMode: PrintingMode with + def print(arg: Any, newline: Boolean): Unit = val format = if newline then "%1$s at %2$TT.%2$TL: %3$s%n" else "%1$s at %2$TT.%2$TL: %3$s" Predef.printf(format, thread, now(), arg) -private object ThreadTimeDemoMode extends PrintingMode: - def print(arg: Any, newline: Boolean) = - val format = - if newline then "%1$s at XX:XX:%2$TS.%2$TL: %3$s%n" else "%1$s at XX:XX:%2$TS.%2$TL: %3$s" - Predef.printf(format, thread, now(), arg) - -/** Standard printing. Equivalent to `Predef.printf/println`. */ -given standardMode: PrintingMode = StandardMode - -/** Silent. Does not print anything. No call to `Predef.printf/println` takes place. */ -given silentMode: PrintingMode = SilentMode - -/** Adds thread name. Strings are printed as: `: `. */ -given threadMode: PrintingMode = ThreadMode - -/** Adds time. Strings are printed as: `at HH:MM:SS.millis: ` */ -given timeMode: PrintingMode = TimeMode - -/** Adds time, but hides hours and minutes. Strings are printed as: `at XX:XX:SS.millis: ` - */ -given timeDemoMode: PrintingMode = TimeDemoMode - -/** Adds thread name and time. Strings are printed as: ` at HH:MM:SS.millis: ` */ -given threadTimeMode: PrintingMode = ThreadTimeMode - /** Adds thread name and time, but hides hours and minutes. Strings are printed as: ` at * XX:XX:SS.millis: ` */ -given threadTimeDemoMode: PrintingMode = ThreadTimeDemoMode +given threadTimeDemoMode: PrintingMode with + def print(arg: Any, newline: Boolean): Unit = + val format = + if newline then "%1$s at XX:XX:%2$TS.%2$TL: %3$s%n" else "%1$s at XX:XX:%2$TS.%2$TL: %3$s" + Predef.printf(format, thread, now(), arg) diff --git a/S/src/main/scala/tinyscalautils/text/printout.scala b/S/src/main/scala/tinyscalautils/text/printout.scala index 5b64dab..d40bfea 100644 --- a/S/src/main/scala/tinyscalautils/text/printout.scala +++ b/S/src/main/scala/tinyscalautils/text/printout.scala @@ -25,7 +25,7 @@ import java.nio.charset.Charset * }}} * * @see - * [[System.setOut]] + * [[java.lang.System.setOut]] * @see * [[Console.withOut]] * diff --git a/S/src/main/scala/tinyscalautils/threads/KeepThreadsFactory.scala b/S/src/main/scala/tinyscalautils/threads/KeepThreadsFactory.scala index 7d7fcd8..e8575d5 100644 --- a/S/src/main/scala/tinyscalautils/threads/KeepThreadsFactory.scala +++ b/S/src/main/scala/tinyscalautils/threads/KeepThreadsFactory.scala @@ -13,7 +13,7 @@ import scala.jdk.CollectionConverters.* * factory is still being used to create more threads. * * @see - * [[MarkedThreadsFactory]] + * [[MarkedThreadFactory]] * * @since 1.0 */ diff --git a/S/src/main/scala/tinyscalautils/threads/MarkedThreadFactory.scala b/S/src/main/scala/tinyscalautils/threads/MarkedThreadFactory.scala index 750ba95..fd9e2a1 100644 --- a/S/src/main/scala/tinyscalautils/threads/MarkedThreadFactory.scala +++ b/S/src/main/scala/tinyscalautils/threads/MarkedThreadFactory.scala @@ -11,7 +11,6 @@ import java.util.concurrent.atomic.AtomicInteger * @since 1.0 */ class MarkedThreadFactory extends ThreadFactory: - private val IDS = AtomicInteger() /** Creates a new thread. The thread has type `MarkedThread` and is not started. diff --git a/S/src/main/scala/tinyscalautils/threads/Timer.scala b/S/src/main/scala/tinyscalautils/threads/Timer.scala index 9cb76ce..0495b4b 100644 --- a/S/src/main/scala/tinyscalautils/threads/Timer.scala +++ b/S/src/main/scala/tinyscalautils/threads/Timer.scala @@ -11,7 +11,7 @@ import scala.util.Try * * @since 1.0 */ -trait Timer: +trait Timer extends AutoCloseable: /** Schedules a task for delayed execution. */ def schedule[A](delay: Double)(code: => A): Future[A] @@ -35,6 +35,12 @@ trait Timer: * Delayed tasks will still run, but repeated tasks are stopped. */ def shutdown(): Unit + + /** Alias for `shutdown` to implement `AutoCloseable`. + * + * @since 1.3 + */ + final def close(): Unit = shutdown() end Timer private class TimerPool(size: Int, tf: ThreadFactory, rej: RejectedExecutionHandler) diff --git a/S/src/main/scala/tinyscalautils/threads/timeout-extensions.scala b/S/src/main/scala/tinyscalautils/threads/timeout-extensions.scala index 322a9b2..12d3352 100644 --- a/S/src/main/scala/tinyscalautils/threads/timeout-extensions.scala +++ b/S/src/main/scala/tinyscalautils/threads/timeout-extensions.scala @@ -12,20 +12,33 @@ extension (exec: ExecutorService) * * @param seconds * timeout, in seconds. + * * @param force * if true, `shutdownNow` is invoked after a timeout. + * * @return * true if the executor terminates before the timeout. + * * @since 1.0 */ @throws[InterruptedException] - def shutdownAndWait(seconds: Double = Double.PositiveInfinity, force: Boolean = false): Boolean = + def shutdownAndWait(seconds: Double, force: Boolean = false): Boolean = exec.shutdown() exec.awaitTermination(seconds.toNanos, NANOSECONDS) || { if force then exec.shutdownNow() false } + /** Shuts down the executor and waits forever for termination. + * + * @return + * true. + * + * @since 1.0 + */ + @throws[InterruptedException] + def shutdownAndWait(): Boolean = shutdownAndWait(Double.PositiveInfinity) + /** Floating seconds version of `awaitTermination`. * * @param seconds @@ -88,13 +101,16 @@ extension (thread: Thread) extension [A](queue: BlockingQueue[A]) /** Like `offer` but timeout in seconds. - * - * @since 1.2 - */ - def offer(value: A, seconds: Double): Boolean = queue.offer(value, seconds.toNanos, NANOSECONDS) - - /** Like `poll` but timeout in seconds and `null` wrapped in an option. * * @since 1.2 */ + def offer(value: A, seconds: Double): Boolean = queue.offer(value, seconds.toNanos, NANOSECONDS) + + @deprecated("use Option instead", since = "1.3") def pollOption(seconds: Double): Option[A] = Option(queue.poll(seconds.toNanos, NANOSECONDS)) + + /** Like `poll` but timeout in seconds. + * + * @since 1.3 + */ + def poll(seconds: Double): A = queue.poll(seconds.toNanos, NANOSECONDS) diff --git a/S/src/test/resources/foo.txt b/S/src/test/resources/foo.txt index 4d7418a..00d52bb 100644 --- a/S/src/test/resources/foo.txt +++ b/S/src/test/resources/foo.txt @@ -1,4 +1,6 @@ line1 line2 lineX + + end diff --git a/S/src/test/resources/nums.txt b/S/src/test/resources/nums.txt new file mode 100644 index 0000000..5cd1526 --- /dev/null +++ b/S/src/test/resources/nums.txt @@ -0,0 +1,7 @@ +none +1 +2 3 4 + + +none +5 diff --git a/S/src/test/resources/ok1.txt b/S/src/test/resources/ok1.txt new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/S/src/test/resources/ok1.txt @@ -0,0 +1 @@ +ok diff --git a/S/src/test/resources/ok2.txt.gz b/S/src/test/resources/ok2.txt.gz new file mode 100644 index 0000000..4783288 Binary files /dev/null and b/S/src/test/resources/ok2.txt.gz differ diff --git a/S/src/test/scala/tinyscalautils/DotSuite.scala b/S/src/test/scala/tinyscalautils/DotSuite.scala new file mode 100644 index 0000000..d45d6aa --- /dev/null +++ b/S/src/test/scala/tinyscalautils/DotSuite.scala @@ -0,0 +1,36 @@ +package tinyscalautils + +import org.scalatest.funsuite.AnyFunSuite +import tinyscalautils.text.{ dot, printout, star } +import tinyscalautils.util.FastRandom + +// must reside outside text package to use default given arguments + +class DotSuite extends AnyFunSuite: + private val data = FastRandom.nextString(10) + + test("standard"): + import tinyscalautils.text.standardMode + val out = printout: + assert(dot(data) == data) + assert(out == ".") + + test("silent"): + import tinyscalautils.text.silentMode + val out = printout: + assert(dot(data) == data) + assert(out.isEmpty) + + test("default dot"): + val out = printout: + assert(dot(data) == data) + assert(out == ".") + + test("default star"): + val out = printout: + assert(star(data) == data) + assert(out == "*") + + test("forbidden modes"): + assertTypeError("import tinyscalautils.text.threadMode\ndot(data)") + assertTypeError("import tinyscalautils.text.threadMode\nstr(data)") diff --git a/S/src/test/scala/tinyscalautils/collection/QueuesSuite.scala b/S/src/test/scala/tinyscalautils/collection/QueuesSuite.scala deleted file mode 100644 index 57bc97c..0000000 --- a/S/src/test/scala/tinyscalautils/collection/QueuesSuite.scala +++ /dev/null @@ -1,13 +0,0 @@ -package tinyscalautils.collection - -import org.scalatest.funsuite.AnyFunSuite - -import java.util - -class QueuesSuite extends AnyFunSuite: - test("offer"): - val q = util.ArrayDeque[String]() - q.offer("X") - assert(q.peekOption.contains("X")) - assert(q.pollOption().contains("X")) - assert(q.pollOption().isEmpty) diff --git a/S/src/test/scala/tinyscalautils/collection/SortedSuite.scala b/S/src/test/scala/tinyscalautils/collection/SortedSuite.scala new file mode 100644 index 0000000..0457f22 --- /dev/null +++ b/S/src/test/scala/tinyscalautils/collection/SortedSuite.scala @@ -0,0 +1,15 @@ +package tinyscalautils.collection + +import org.scalatest.funsuite.AnyFunSuite +import tinyscalautils.util.FastRandom + +class SortedSuite extends AnyFunSuite: + test("in reverse 1"): + val l = List.fill(10)(FastRandom.nextInt()) + val s: List[Int] = l.sortedInReverse + assert(s == l.sorted.reverse) + + test("in reverse 2"): + val l = IndexedSeq.fill(10)(FastRandom.nextInt()) + val s: IndexedSeq[Int] = l.sortedInReverse + assert(s == l.sorted.reverse) diff --git a/S/src/test/scala/tinyscalautils/io/FilesSuite.scala b/S/src/test/scala/tinyscalautils/io/FilesSuite.scala index 7e79036..fd43eef 100644 --- a/S/src/test/scala/tinyscalautils/io/FilesSuite.scala +++ b/S/src/test/scala/tinyscalautils/io/FilesSuite.scala @@ -3,14 +3,13 @@ package tinyscalautils.io import org.scalatest.funsuite.AnyFunSuite import tinyscalautils.assertions.require -import java.io.UncheckedIOException import java.nio.file.{ AccessDeniedException, Files, Path } import java.util class FilesSuite extends AnyFunSuite: require(Path.of("").toAbsolutePath.getFileName.toString == "S") - val files = Set("foo.txt", "bar.txt") + val files = Set("foo.txt", "bar.txt", "nums.txt", "ok1.txt", "ok2.txt.gz") val subdirs = Set("tinyscalautils") val dir = Path.of("src", "test", "resources") @@ -27,16 +26,3 @@ class FilesSuite extends AnyFunSuite: test("listPaths, argument"): assertThrows[IllegalArgumentException](listPaths(dir.resolve("foo.txt"))) - - test("listLines"): - for f <- files do assert(listLines(dir.resolve(f)).take(2) == List("line1", "line2")) - - test("listLines, errors"): - assertThrows[UncheckedIOException](listLines(dir)) - assert(listLines(dir, silent = true).isEmpty) - val perms = Files.getPosixFilePermissions(dir) - try - Files.setPosixFilePermissions(dir, util.Collections.emptySet) - assertThrows[AccessDeniedException](listLines(dir)) - assert(listLines(dir, silent = true).isEmpty) - finally Files.setPosixFilePermissions(dir, perms) diff --git a/S/src/test/scala/tinyscalautils/io/InputSuite.scala b/S/src/test/scala/tinyscalautils/io/InputSuite.scala new file mode 100644 index 0000000..e942dc2 --- /dev/null +++ b/S/src/test/scala/tinyscalautils/io/InputSuite.scala @@ -0,0 +1,152 @@ +package tinyscalautils.io + +import org.scalatest.funsuite.AnyFunSuite +import tinyscalautils.assertions.requireState + +import java.io.IOException +import java.nio.file.{ AccessDeniedException, Files, Path } +import java.util +import scala.io.Source +import scala.util.Using + +class InputSuite extends AnyFunSuite: + requireState(Path.of("").toAbsolutePath.getFileName.toString == "S") + + val dir = Path.of("src", "test", "resources") + val path = dir.resolve("nums.txt") + val url = path.toUri.toURL + val name = path.toString + val file = path.toFile + + val nums = 1 to 5 + + def parse(line: String) = line.split(' ').flatMap(_.toIntOption).iterator + + test("demo 1"): + val numsSeq: IndexedSeq[Int] = readAll(IndexedSeq)(file, parse) + val nonBlankLines: IndexedSeq[String] = readAll(IndexedSeq)(file) + val allLines: IndexedSeq[String] = readAll(IndexedSeq)(file, noParsing) + val numsList: List[Int] = readAll(file, parse) + val nonBlankLinesList: List[String] = readAll(file) + val allLinesList: List[String] = readAll(file, noParsing) + assert(numsSeq == nums) + assert(nonBlankLines.length == 5) + assert(allLines.length == 7) + assert(numsList == nums) + assert(nonBlankLinesList.length == 5) + assert(allLinesList.length == 7) + + test("demo 2"): + Using.resource(readingAll(file, parse)): i => + assert(i.toSeq == nums) + + test("errors"): + assertThrows[IOException](readAll(dir)) + assert(readAll(dir, silent = true).isEmpty) + val perms = Files.getPosixFilePermissions(path) + try + Files.setPosixFilePermissions(path, util.Collections.emptySet) + assertThrows[AccessDeniedException](readAll(path)) + assert(readAll(path, silent = true).isEmpty) + finally Files.setPosixFilePermissions(path, perms) + + test("no parsing"): + assert(readAll(path, noParsing).length == 7) + + test("readAll InputStream, indexed seq"): + val seq: IndexedSeq[Int] = readAll(IndexedSeq)(Files.newInputStream(path), parse) + assert(seq == nums) + + test("readAll InputStream, indexed seq, default parser"): + val seq: IndexedSeq[String] = readAll(IndexedSeq)(Files.newInputStream(path)) + assert(seq.length == 5) + + test("readAll InputStream, list"): + val list: List[Int] = readAll(Files.newInputStream(path), parse) + assert(list == nums) + + test("readAll InputStream, list, default parser"): + val list: List[String] = readAll(Files.newInputStream(path)) + assert(list.length == 5) + + test("readAll Path, indexed seq"): + val seq: IndexedSeq[Int] = readAll(IndexedSeq)(path, parse) + assert(seq == nums) + + test("readAll Path, indexed seq, default parser"): + val seq: IndexedSeq[String] = readAll(IndexedSeq)(path) + assert(seq.length == 5) + + test("readAll Path, list"): + val list: List[Int] = readAll(path, parse) + assert(list == nums) + + test("readAll Path, list, default parser"): + val list: List[String] = readAll(path) + assert(list.length == 5) + + test("readAll URL, indexed seq"): + val seq: IndexedSeq[Int] = readAll(IndexedSeq)(url, parse) + assert(seq == nums) + + test("readAll URL, indexed seq, default parser"): + val seq: IndexedSeq[String] = readAll(IndexedSeq)(url) + assert(seq.length == 5) + + test("readAll URL, list"): + val list: List[Int] = readAll(url, parse) + assert(list == nums) + + test("readAll URL, list, default parser"): + val list: List[String] = readAll(url) + assert(list.length == 5) + + test("readAll name, indexed seq"): + val seq: IndexedSeq[Int] = readAll(IndexedSeq)(name, parse) + assert(seq == nums) + + test("readAll name, indexed seq, default parser"): + val seq: IndexedSeq[String] = readAll(IndexedSeq)(name) + assert(seq.length == 5) + + test("readAll name, list"): + val list: List[Int] = readAll(name, parse) + assert(list == nums) + + test("readAll name, list, default parser"): + val list: List[String] = readAll(name) + assert(list.length == 5) + + test("readAll file, indexed seq"): + val seq: IndexedSeq[Int] = readAll(IndexedSeq)(file, parse) + assert(seq == nums) + + test("readAll file, indexed seq, default parser"): + val seq: IndexedSeq[String] = readAll(IndexedSeq)(file) + assert(seq.length == 5) + + test("readAll file, list"): + val list: List[Int] = readAll(file, parse) + assert(list == nums) + + test("readAll file, list, default parser"): + val list: List[String] = readAll(file) + assert(list.length == 5) + + test("readingAll"): + val in = Files.newInputStream(path) + var closed = false + val source = Source + .fromFile(file) + .withClose: () => + in.close() + closed = true + Using.resource(readingAll(source, parse)): i => + assert(i.hasNext) + assert(i.next() == 1) + assert(i.next() == 2) + assert(i.hasNext) + assert(closed) + + test("read"): + assert(read(path) == "none\n1\n2 3 4\n\n \nnone\n5\n") diff --git a/S/src/test/scala/tinyscalautils/io/OutputSuite.scala b/S/src/test/scala/tinyscalautils/io/OutputSuite.scala new file mode 100644 index 0000000..6b097e9 --- /dev/null +++ b/S/src/test/scala/tinyscalautils/io/OutputSuite.scala @@ -0,0 +1,100 @@ +package tinyscalautils.io + +import org.scalatest.funsuite.AnyFunSuite +import tinyscalautils.util.FastRandom + +import java.nio.file.{ Files, Path } + +class OutputSuite extends AnyFunSuite: + private def makeFile(): Path = + val path = Files.createTempFile("tiny", ".txt") + path.toFile.deleteOnExit() + path + + private val str = FastRandom.nextString(10_000) + private val list = List(1, 2, 3) + + test("demo"): + val file = makeFile() + write(file)(list.toString) + assert(Files.readString(file) == "List(1, 2, 3)") + write(file, newline = true)(list.toString) + assert(Files.readString(file) == "List(1, 2, 3)\n") + writeAll(file)(list) + assert(Files.readString(file) == "1\n2\n3\n") + writeAll(sep = ",")(file)(list) + assert(Files.readString(file) == "1,2,3") + writeAll(pre = "[", sep = ",", post = "]")(file)(list) + assert(Files.readString(file) == "[1,2,3]") + writeAll()(file)(list) + assert(Files.readString(file) == "123") + + test("write 1"): + val path = makeFile() + write(path)(str) + assert(Files.readString(path) == str) + + test("write 2"): + val path = makeFile() + write(path, newline = true)(str) + assert(Files.readString(path) == str + '\n') + + test("write 3"): + val path = makeFile() + write(path.toFile)(str) + assert(Files.readString(path) == str) + + test("write 4"): + val path = makeFile() + write(path.toString)(str) + assert(Files.readString(path) == str) + + test("write 5"): + val path = makeFile() + write(Files.newOutputStream(path))(str) + assert(Files.readString(path) == str) + + test("writeAll 1"): + val path = makeFile() + writeAll(sep = ",")(path)(list) + assert(Files.readString(path) == "1,2,3") + + test("writeAll 2"): + val path = makeFile() + writeAll(pre = "[", sep = ",", post = "]")(path)(list) + assert(Files.readString(path) == "[1,2,3]") + + test("writeAll 3"): + val path = makeFile() + writeAll(path)(list) + assert(Files.readString(path) == "1\n2\n3\n") + + test("writeAll 4"): + val path = makeFile() + writeAll(sep = "\n")(path)(list) + assert(Files.readString(path) == "1\n2\n3") + + test("writeAll 5"): + val path = makeFile() + writeAll()(path)(list) + assert(Files.readString(path) == "123") + + test("writeAll 6"): + val path = makeFile() + writeAll(path)(Nil) + assert(Files.readString(path) == "") + + test("writeAll 7"): + val path = makeFile() + writeAll()(path)(Nil) + assert(Files.readString(path) == "") + + test("writeAll 8"): + val path = makeFile() + writeAll(sep = ",")(path)(Nil) + assert(Files.readString(path) == "") + + test("writeAll 9"): + val path = makeFile() + writeAll(pre = "[", sep = ",", post = "]")(path)(Nil) + assert(Files.readString(path) == "[]") diff --git a/S/src/test/scala/tinyscalautils/io/ResourcesSuite.scala b/S/src/test/scala/tinyscalautils/io/ResourcesSuite.scala index 52aa39b..79c2ffa 100644 --- a/S/src/test/scala/tinyscalautils/io/ResourcesSuite.scala +++ b/S/src/test/scala/tinyscalautils/io/ResourcesSuite.scala @@ -1,30 +1,39 @@ package tinyscalautils.io import org.scalatest.funsuite.AnyFunSuite + +import java.io.IOException +import java.net.URI import java.util.MissingResourceException class ResourcesSuite extends AnyFunSuite: - test("findResource absolute") { + test("findResource absolute"): val url = this.findResource("/foo.txt") assert(url.getPath.endsWith("foo.txt")) assertThrows[MissingResourceException](this.findResource("nonexisting")) - } - test("findResource relative") { + test("findResource relative"): val url = this.findResource("rel.txt") assert(url.getPath.endsWith("rel.txt")) assertThrows[MissingResourceException](this.findResource("nonexisting")) - } - private def parse(line: String): Option[Int] = - Option.when(line.startsWith("line"))(line.substring(4).toIntOption).flatten + test("findResourceAsStream relative"): + assert(read(this.findResourceAsStream("rel.txt")) == "line1\nline2\n") + + test("findResourceAsStream fallback relative"): + val uri = URI.create("https://example.com") + assert(read(this.findResourceAsStream(uri)("rel.txt")) == "line1\nline2\n") + + test("findResource fallback"): + val url = this.findResource(URI.create("https://httpbin.org/anything/"))("fallback.txt") + assert(url.getPath.endsWith("fallback.txt")) + assert(url.openConnection().getContentLength > 0) - test("parseURL list") { - val list: List[Int] = parseURL(this.findResource("/foo.txt"), parse) - assert(list == List(1, 2)) - } + test("findResourceAsStream"): + assert(read(this.findResourceAsStream("/ok1.txt")) == "ok\n") + assert(read(this.findResourceAsStream("/ok2.txt")) == "ok\n") - test("parseURL indexed seq") { - val seq: IndexedSeq[Int] = parseURL(this.findResource("/foo.txt"), parse, IndexedSeq) - assert(seq == Seq(1, 2)) - } + test("findResourceAsStream fallback not found"): + val uri = URI.create("https://httpbin.org/status/404") + val e = intercept[IOException](this.findResourceAsStream(uri)("fallback.txt")) + assert(e.getMessage.endsWith("fallback.txt")) diff --git a/S/src/test/scala/tinyscalautils/text/PrintingSuite.scala b/S/src/test/scala/tinyscalautils/text/PrintingSuite.scala index 482157a..4103116 100644 --- a/S/src/test/scala/tinyscalautils/text/PrintingSuite.scala +++ b/S/src/test/scala/tinyscalautils/text/PrintingSuite.scala @@ -17,66 +17,56 @@ class PrintingSuite extends AnyFunSuite: val at = "(" + threadName + """ )?at XX:XX:([0-5]\d)\.\d\d\d: (.*?)""" (at + at).r - private def doPrint(mode: PrintingMode): String = printout { - newThread("Joe") { + private def doPrint(mode: PrintingMode): String = printout: + newThread("Joe"): if FastRandom.nextBoolean() then mode.printf("X%dX", msg1) mode.println(msg2) else printf("X%dX", msg1)(using mode) println(msg2)(using mode) - }.join() - } + .join() private def parse(str: String): Boolean = - assert(str.last === '\n') + assert(str.last == '\n') val line = str.init line match case time(t1, h1, m1, s1, str1, t2, h2, m2, s2, str2) => - assert(t1 === t2) - assert(h1 === h2) - assert(m1 === m2) - assert(s1 === s2) - assert(str1 === s"X${msg1}X") - assert(str2 === msg2) + assert(t1 == t2) + assert(h1 == h2 || m1 == "59" && s1 == "59") + assert(m1 == m2 || s1 == "59") + assert(str1 == s"X${msg1}X") + assert(str2 == msg2) t1 ne null case demo(t1, s1, str1, t2, s2, str2) => - assert(t1 === t2) - assert(s1 === s2) - assert(str1 === s"X${msg1}X") - assert(str2 === msg2) + assert(t1 == t2) + assert(s1 == s2) + assert(str1 == s"X${msg1}X") + assert(str2 == msg2) t1 ne null case _ => fail(s"no match for '$line'") - test("StandardMode") { - assert(doPrint(StandardMode) === s"X${msg1}X$msg2\n") - } + test("StandardMode"): + assert(doPrint(standardMode) == s"X${msg1}X$msg2\n") - test("SilentMode") { - assert(doPrint(SilentMode).isEmpty) - } + test("SilentMode"): + assert(doPrint(silentMode).isEmpty) - test("ThreadMode") { - assert(doPrint(ThreadMode) === s"$threadName: X${msg1}X$threadName: $msg2\n") - } + test("ThreadMode"): + assert(doPrint(threadMode) == s"$threadName: X${msg1}X$threadName: $msg2\n") - test("TimeMode") { - assert(!parse(doPrint(TimeMode))) - } + test("TimeMode"): + assert(!parse(doPrint(timeMode))) - test("TimeDemoMode") { - assert(!parse(doPrint(TimeDemoMode))) - } + test("TimeDemoMode"): + assert(!parse(doPrint(timeDemoMode))) - test("ThreadTimeMode") { - assert(parse(doPrint(ThreadTimeMode))) - } + test("ThreadTimeMode"): + assert(parse(doPrint(threadTimeMode))) - test("ThreadTimeDemoMode") { - assert(parse(doPrint(ThreadTimeDemoMode))) - } - - test("simpler imports") { + test("ThreadTimeDemoMode"): + assert(parse(doPrint(threadTimeDemoMode))) + + test("simpler imports"): import tinyscalautils.text.silentMode.println - println("not displayed") - } + assert(printout(println("not displayed")).isEmpty) diff --git a/S/src/test/scala/tinyscalautils/threads/ExtensionsSuite.scala b/S/src/test/scala/tinyscalautils/threads/ExtensionsSuite.scala index e3a48d5..43dcabf 100644 --- a/S/src/test/scala/tinyscalautils/threads/ExtensionsSuite.scala +++ b/S/src/test/scala/tinyscalautils/threads/ExtensionsSuite.scala @@ -18,17 +18,16 @@ class ExtensionsSuite extends AnyFunSuite with Tolerance: assert(time2 === 1.0 +- 0.1) test("queue timeout"): - val q = ArrayBlockingQueue[String](1) - + val q = ArrayBlockingQueue[String](1) val (res1, time1) = timeIt(q.offer("X", seconds = 1.0)) assert(res1) assert(time1 === 0.0 +- 0.1) val (res2, time2) = timeIt(q.offer("X", seconds = 1.0)) assert(!res2) assert(time2 === 1.0 +- 0.1) - val (res3, time3) = timeIt(q.pollOption(seconds = 1.0)) - assert(res3.contains("X")) + val (res3, time3) = timeIt(q.poll(seconds = 1.0)) + assert(res3 == "X") assert(time3 === 0.0 +- 0.1) - val (res4, time4) = timeIt(q.pollOption(seconds = 1.0)) - assert(res4.isEmpty) + val (res4, time4) = timeIt(q.poll(seconds = 1.0)) + assert(res4 == null) assert(time4 === 1.0 +- 0.1) diff --git a/S/src/test/scala/tinyscalautils/threads/TimerSuite.scala b/S/src/test/scala/tinyscalautils/threads/TimerSuite.scala index 44b047b..fe44ba4 100644 --- a/S/src/test/scala/tinyscalautils/threads/TimerSuite.scala +++ b/S/src/test/scala/tinyscalautils/threads/TimerSuite.scala @@ -2,11 +2,12 @@ package tinyscalautils.threads import org.scalactic.Tolerance import org.scalatest.funsuite.AnyFunSuite -import tinyscalautils.timing.{sleep, timeOf, zipWithDuration} +import tinyscalautils.timing.{ sleep, timeIt, timeOf, zipWithDuration } import java.util.concurrent.CountDownLatch import java.util.concurrent.atomic.AtomicInteger import scala.concurrent.Future +import scala.util.Using class TimerSuite extends AnyFunSuite with Tolerance: test("schedule"): @@ -42,3 +43,20 @@ class TimerSuite extends AnyFunSuite with Tolerance: timer.shutdown() assert(timeOf(latch.await()) === 1.0 +- 0.1) assert(repeats.get == 4) + + test("shutdown"): + val (thread, time) = timeIt: + withUnlimitedThreadsAndWait(): + val timer = Executors.newTimer(1) + val f = timer.schedule(1.5)(Thread.currentThread) + timer.shutdown() + f + assert(time === 1.5 +- 0.1) + assert(thread.joined(1.0)) + + test("close"): + val (thread, time) = timeIt: + withUnlimitedThreadsAndWait(): + Using.resource(Executors.newTimer(1))(_.schedule(1.5)(Thread.currentThread)) + assert(time === 1.5 +- 0.1) + assert(thread.joined(1.0)) diff --git a/S/src/test/scala/tinyscalautils/timing/SlowSuite.scala b/S/src/test/scala/tinyscalautils/timing/SlowSuite.scala index 063ee93..61b97e6 100644 --- a/S/src/test/scala/tinyscalautils/timing/SlowSuite.scala +++ b/S/src/test/scala/tinyscalautils/timing/SlowSuite.scala @@ -8,7 +8,7 @@ import tinyscalautils.timing.* import scala.compiletime.asMatchable import scala.io.Source -@org.scalatest.Ignore +// @org.scalatest.Ignore // Note: This suite takes 50 minutes and 40 seconds to run. class SlowSuite extends AnyFunSuite with Tolerance: private given Equality[Double] with diff --git a/T/failed_tests.txt b/T/failed_tests.txt new file mode 100644 index 0000000..a2248d9 --- /dev/null +++ b/T/failed_tests.txt @@ -0,0 +1,2 @@ +fail +fail .* diff --git a/T/src/main/scala/tinyscalautils/test/grading/Grader.scala b/T/src/main/scala/tinyscalautils/test/grading/Grader.scala index 6760d78..652701c 100644 --- a/T/src/main/scala/tinyscalautils/test/grading/Grader.scala +++ b/T/src/main/scala/tinyscalautils/test/grading/Grader.scala @@ -1,69 +1,22 @@ package tinyscalautils.test.grading -import org.scalatest.* -import org.scalatest.events.* - -/** A test reporter that counts passing and failing tests into a grade. Ignored tests are ignored - * (i.e., not passed or failed and do not affect the grade). - * - * Tests can have an optional weight, specified between square brackets as follows: - * {{{ - * test("this is a test [2]") {...} - * }}} - * - * or - * - * {{{ - * test("a big test [10pts]") {...} - * }}} - * - * The default weight is 1. - * - * Instances of this class are not thread-safe. +/** A grade reporter. * * @see - * [[org.scalatest.Reporter]] + * [[package.Grading]] * * @since 1.0 */ -class Grader extends Reporter: - import Grader.weight - - private var sumWeight, sumPassed, w = 0.0 - private var tests = 0 +trait Grader: + /** The grade. This is a number between 0.0 and 1.0. */ + def grade: Double - /** The grade. This is the weighted ratio of tests passed over tests failed. */ - def grade: Double = sumPassed / sumWeight + /** Total weight of the graded suite. */ + def totalWeight: Double - /** Total weight. This is the sum of the weights of all the tests. */ - def totalWeight: Double = sumWeight - - /** Total number of tests that were run. + /** Total number of tests that were run, not including nested suites. * * @since 1.1 */ - def testCount: Int = tests - - /** Processes an event. - * - * `TestStarting`, `TestSucceeded` and `TestFailed` are used to keep track of the grade. Other - * events are ignored. - * @see - * [[org.scalatest.events.Event]] - */ - def apply(event: Event): Unit = - event match - case e: TestStarting => w = weight(e.testName); tests += 1 - case _: TestSucceeded => sumWeight += w; sumPassed += w - case _: TestFailed => sumWeight += w - case _ => () // do nothing -end Grader - -/** Companion object of [[package.Grader]]. */ -private object Grader: - private val weightRegex = """\[\s*(\d*\.?\d+)\s*\p{Alpha}*\]""".r.unanchored - - private def weight(name: String): Double = weightRegex.findAllMatchIn(name).toSeq match - case Seq() => 1.0 - case s => s.last.group(1).toDoubleOption.getOrElse(1.0) + def testCount: Int end Grader diff --git a/T/src/main/scala/tinyscalautils/test/grading/GraderApp.scala b/T/src/main/scala/tinyscalautils/test/grading/GraderApp.scala index 87e9467..70e0402 100644 --- a/T/src/main/scala/tinyscalautils/test/grading/GraderApp.scala +++ b/T/src/main/scala/tinyscalautils/test/grading/GraderApp.scala @@ -1,53 +1,62 @@ package tinyscalautils.test.grading -import org.scalatest.{ ConfigMap, Suite } -import tinyscalautils.io.parseURL +import org.scalatest.{ ConfigMap, Filter } +import tinyscalautils.io.readAll import tinyscalautils.text.{ info, plural, timeString } import tinyscalautils.timing.timeOf -import java.io.IOException -import java.net.URI - -/** Grading main application. +/** Grading main application. It is defined as an open class because subclasses and singleton + * objects can be run more easily in IntelliJ. Tests with names in a local `failed_tests.txt` file + * are manually failed. (Lines in this file are interpreted as anchored regular expressions.) + * + * @note + * This application relies on the default text reporter from Scalatest. Unfortunately, this + * reporter uses its own separate thread. As a result, there is an unavoidable race condition + * with output from other reporters, if any. If more text output is needed, it should come from + * the same default reporter (e.g., using `info`). * * @note * This application _does_ call `System.exit(0)`. * * @param suites - * a sequence of (weight -> suite) testing suites; tests with names in `failed_tests.txt` are - * manually failed. + * an instance of `GradingSuites` taken as a container of testing suites; */ -open class GraderApp(suites: (Int, Suite & Grading)*): +open class GraderApp(suites: GradingSuites): + /** Alternate constructor. It wraps the given suites into a new instance of `GradingSuites`. */ + def this(suites: GradingSuite*) = this(GradingSuites(suites*)) + def main(args: Array[String]): Unit = - val verbose = args.nonEmpty && args(0) == "-v" + val failedTests = readFailedTests() + val verbose = args.nonEmpty && args(0) == "-v" if verbose then info(newlines = 1) - var grade = 0.0 - var weights = 0 - var tests = 0 + val expectedTests = suites.expectedTestCount(Filter.default) + println(s"""Starting run for $expectedTests ${plural(expectedTests, "test")}:""") val time = timeOf: - for (weight, suite) <- suites do + for suite <- suites.nestedSuites do suite.execute( durations = true, color = false, shortstacks = true, - configMap = readFailedTests() + configMap = failedTests ) - val g = suite.grader.grade * weight - val n = suite.grader.testCount - weights += weight - grade += g - tests += n - if verbose then - println(f"""${suite.suiteName}: $g%.1f / $weight ($n ${plural(n, "test")})""") + println: + val name = suite.suiteName + val weight = suite.grader.totalWeight + val grade = suite.grader.grade * weight + val tests = suite.grader.testCount + f"""$name: $grade%.1f / $weight%.1f ($tests ${plural(tests, "test")})""" println(s"time: ${timeString(time)}") println: - f"grade: $grade%.0f / $weights" + - (if verbose then s""" ($tests ${plural(tests, "test")})""" else "") + val weight = suites.grader.totalWeight + val grade = suites.grader.grade * weight + val tests = suites.grader.testCount + f"""grade: $grade%.0f / $weight%.0f ($tests ${plural(tests, "test")})""" System.exit(0) // possible hanging threads; forcing termination +end GraderApp private def readFailedTests(): ConfigMap = + import tinyscalautils.io.FileNameIsInput def parse(line: String) = Some(line.trim).filterNot(str => str.isBlank || str.startsWith("#")) - try ConfigMap("failed" -> parseURL(failedTestsURL, parse, Set)) - catch case _: IOException => ConfigMap.empty + ConfigMap("failed" -> readAll(Set)(failedTestsFile, parse, silent = true)) -private val failedTestsURL = URI.create("file:failed_tests.txt").toURL +private val failedTestsFile = "failed_tests.txt" diff --git a/T/src/main/scala/tinyscalautils/test/grading/Grading.scala b/T/src/main/scala/tinyscalautils/test/grading/Grading.scala index 040e29f..06a2280 100644 --- a/T/src/main/scala/tinyscalautils/test/grading/Grading.scala +++ b/T/src/main/scala/tinyscalautils/test/grading/Grading.scala @@ -1,16 +1,73 @@ package tinyscalautils.test.grading -import org.scalatest.Suite -import tinyscalautils.test.mixins.Reporting +import org.scalatest.* +import org.scalatest.concurrent.{ Signaler, ThreadSignaler } +import org.scalatest.time.Span +import org.scalatest.time.SpanSugar.convertIntToGrainOfTime +import tinyscalautils.test.mixins.{ DualTimeLimits, NoStackOverflowError, Reporting } +import tinyscalautils.test.tagobjects.{ Async, Fail } +import tinyscalautils.threads.Executors.global +import tinyscalautils.threads.runAsync -/** A special case of `Reporting` suite in which the reporter is an instance of `Grader`. +/** Setup for a grading run. This trait sets default time limits for fast and slow tests (1 second + * and 1 minute, to be overridden for customization), uses a `Timeout` tag for specific timeouts, + * catches `StackOverflowError`, detects a `Fail` tag to fail a test manually, and relies on + * `Async` tags to run tests in separate (interruptible) threads. + * + * @see + * [[tinyscalautils.lang.StackOverflowException]] + * + * @see + * [[tinyscalautils.test.mixins.DualTimeLimits]] + * + * @see + * [[tinyscalautils.test.tagobjects.Timeout]] + * + * @see + * [[tinyscalautils.test.tagobjects.Async]] + * + * @see + * [[tinyscalautils.test.tagobjects.Fail]] * * @since 1.0 */ -trait Grading extends Reporting: - self: Suite => +trait Grading(weight: Int = 0) extends GradingSuite, Reporting, DualTimeLimits, NoStackOverflowError: + self: TestSuite => - override val reporter: Grader = Grader() + val reporter: Grader & Reporter = WeightedGrader(weight.toDouble) - /** The reporter, as a grader. */ def grader: Grader = reporter + + override val defaultTestSignaler: Signaler = ThreadSignaler + + val shortTimeLimit: Span = 1.second + val longTimeLimit: Span = 1.minute + + abstract override def withFixture(test: NoArgTest): Outcome = + val failed = test.configMap.getWithDefault[Set[String]]("failed", Set.empty) + if failed.exists(_.r.matches(test.name)) then Failed("""test name in "failed" set""") + else if test.tags.isEmpty then super.withFixture(test) // no tag (fast path) + else + val failTags = test.tags.filter(_.startsWith(Fail.name)) + if failTags.size > 1 then Canceled(s"""conflicting tags: ${failTags.mkString(", ")}""") + else if failTags.nonEmpty then // Fail tag + val failTag = failTags.head + Fail.regex.findFirstMatchIn(failTag) match + case None => Canceled(s"'$failTag' is not a valid tag") + case Some(m) => + val message = m.group(1) + if message eq null then Failed() else Failed(message) + else if test.tags.contains(Async.name) then // Async tag + val newTest = + new NoArgTest: + def apply(): Outcome = runAsync(test.apply())(using global) + + val configMap = test.configMap + val name = test.name + val scopes = test.scopes + val text = test.text + val tags = test.tags + val pos = test.pos + super.withFixture(newTest) + else super.withFixture(test) // other tags +end Grading diff --git a/T/src/main/scala/tinyscalautils/test/grading/GradingPrettifier.scala b/T/src/main/scala/tinyscalautils/test/grading/GradingPrettifier.scala new file mode 100644 index 0000000..8662f61 --- /dev/null +++ b/T/src/main/scala/tinyscalautils/test/grading/GradingPrettifier.scala @@ -0,0 +1,13 @@ +package tinyscalautils.test.grading + +import org.scalactic.{ Prettifier, SizeLimit } +import tinyscalautils.test.text.{ TruncatingPrettifier, noAnalysis } + +/** Default prettifier for grading tests. + * + * @since 1.2 + */ +def gradingPrettifier(bypass: Matchable => Boolean = _ => false): Prettifier = + val p1 = Prettifier.truncateAt(SizeLimit(32)) + val p2 = TruncatingPrettifier(256)(o => if bypass(o) then o.toString else p1(o)) + p2.noAnalysis diff --git a/T/src/main/scala/tinyscalautils/test/grading/GradingRun.scala b/T/src/main/scala/tinyscalautils/test/grading/GradingRun.scala deleted file mode 100644 index 228f616..0000000 --- a/T/src/main/scala/tinyscalautils/test/grading/GradingRun.scala +++ /dev/null @@ -1,61 +0,0 @@ -package tinyscalautils.test.grading - -import org.scalatest.concurrent.{ Signaler, ThreadSignaler } -import org.scalatest.time.Span -import org.scalatest.time.SpanSugar.convertIntToGrainOfTime -import org.scalatest.{ Canceled, Failed, Outcome, TestSuite } -import tinyscalautils.test.mixins.{ DualTimeLimits, NoStackOverflowError } -import tinyscalautils.test.tagobjects.{ Async, Fail } -import tinyscalautils.threads.Executors.global -import tinyscalautils.threads.runAsync - -/** Setup for a grading run. This trait sets time limits (1 second and 1 minute, to be overridden - * for customization), catches `StackOverflowError`, detects a `Fail` tag to fail a test manually, - * and relies on `Async` tags to run tests in separate (interruptible) threads. - * - * @see - * [[tinyscalautils.test.mixins.DualTimeLimits]] - * - * @see - * [[tinyscalautils.test.tagobjects.Async]] - * - * @see - * [[tinyscalautils.test.tagobjects.Fail]] - * - * @since 1.0 - */ -trait GradingRun extends Grading, DualTimeLimits, NoStackOverflowError: - self: TestSuite => - - override val defaultTestSignaler: Signaler = ThreadSignaler - - val shortTimeLimit: Span = 1.second - val longTimeLimit: Span = 1.minute - - abstract override def withFixture(test: NoArgTest): Outcome = - val failed = test.configMap.getWithDefault[Set[String]]("failed", Set.empty) - if failed(test.name) then Failed(s"test name in failed set") - else if test.tags.isEmpty then super.withFixture(test) // no tag (fast path) - else - val failTags = test.tags.filter(_.startsWith(Fail.name)) - if failTags.size > 1 then Canceled(s"""conflicting tags: ${failTags.mkString(", ")}""") - else if failTags.nonEmpty then // Fail tag - val failTag = failTags.head - Fail.regex.findFirstMatchIn(failTag) match - case None => Canceled(s"'$failTag' is not a valid tag") - case Some(m) => - val message = m.group(1) - if message eq null then Failed() else Failed(message) - else if test.tags.contains(Async.name) then // Async tag - val newTest = - new NoArgTest: - def apply(): Outcome = runAsync(test.apply())(using global) - - val configMap = test.configMap - val name = test.name - val scopes = test.scopes - val text = test.text - val tags = test.tags - val pos = test.pos - super.withFixture(newTest) - else super.withFixture(test) // other tags diff --git a/T/src/main/scala/tinyscalautils/test/grading/GradingSuite.scala b/T/src/main/scala/tinyscalautils/test/grading/GradingSuite.scala new file mode 100644 index 0000000..56e04a6 --- /dev/null +++ b/T/src/main/scala/tinyscalautils/test/grading/GradingSuite.scala @@ -0,0 +1,11 @@ +package tinyscalautils.test.grading + +import org.scalatest.Suite + +/** A trait for test suites that have a grader. + * + * @since 1.3 + */ +trait GradingSuite extends Suite: + /** The grader. */ + def grader: Grader diff --git a/T/src/main/scala/tinyscalautils/test/grading/GradingSuites.scala b/T/src/main/scala/tinyscalautils/test/grading/GradingSuites.scala new file mode 100644 index 0000000..5c58095 --- /dev/null +++ b/T/src/main/scala/tinyscalautils/test/grading/GradingSuites.scala @@ -0,0 +1,33 @@ +package tinyscalautils.test.grading + +/** A class to combine multiple grading suites. This is a grade-aware replacement for + * `org.scalatest.Suites`. + * + * @since 1.3 + */ +open class GradingSuites private ( + defaultTotalWeight: Double, + override val nestedSuites: IndexedSeq[GradingSuite] +) extends GradingSuite: + + /** Creates a combined suite.Its weight is the sum of the weights of the nested suites. */ + def this(weight: Double)(suites: GradingSuite*) = this(weight, suites.toIndexedSeq) + + /** Creates a combined suite. Its weight is given and must be positive. */ + def this(suites: GradingSuite*) = this(0.0, suites.toIndexedSeq) + + val grader: Grader = Graders() + + private class Graders extends Grader: + private def graders = nestedSuites.map(_.grader) + + private def gradeSum = graders.map(g => g.grade * g.totalWeight).sum + + private def sumWeight: Double = graders.map(_.totalWeight).sum + + def totalWeight: Double = if defaultTotalWeight > 0.0 then defaultTotalWeight else sumWeight + + def testCount: Int = graders.map(_.testCount).sum + + def grade: Double = gradeSum / sumWeight +end GradingSuites diff --git a/T/src/main/scala/tinyscalautils/test/grading/WeightedGrader.scala b/T/src/main/scala/tinyscalautils/test/grading/WeightedGrader.scala new file mode 100644 index 0000000..3192d91 --- /dev/null +++ b/T/src/main/scala/tinyscalautils/test/grading/WeightedGrader.scala @@ -0,0 +1,69 @@ +package tinyscalautils.test.grading + +import org.scalatest.* +import org.scalatest.events.* + +/** A test reporter that counts passing and failing tests into a grade. Ignored tests are ignored + * (i.e., not passed or failed and do not affect the grade). + * + * Tests can have an optional weight, specified between square brackets as follows: + * {{{ + * test("this is a test [2]") {...} + * }}} + * + * or + * + * {{{ + * test("a big test [10pts]") {...} + * }}} + * + * The default weight is 1. + * + * Instances of this class are not thread-safe. + * + * @see + * [[org.scalatest.Reporter]] + * + * @since 1.3 + */ +private class WeightedGrader(defaultTotalWeight: Double) extends Grader with Reporter: + import WeightedGrader.weight + + private var sumWeight, sumPassed, w = 0.0 + private var tests = 0 + + /** The grade. This is the weighted ratio of tests passed over tests failed. */ + def grade: Double = sumPassed / sumWeight + + /** Total weight. By default, this is the sum of the weights of all the tests. */ + def totalWeight: Double = if defaultTotalWeight > 0.0 then defaultTotalWeight else sumWeight + + /** Total number of tests that were run. + * + * @since 1.1 + */ + def testCount: Int = tests + + /** Processes an event. + * + * `TestStarting`, `TestSucceeded` and `TestFailed` are used to keep track of the grade. Other + * events are ignored. + * @see + * [[org.scalatest.events.Event]] + */ + def apply(event: Event): Unit = + event match + case e: TestStarting => w = weight(e.testName); tests += 1 + case _: TestSucceeded => sumWeight += w; sumPassed += w + case _: TestFailed => sumWeight += w + case _ => () // do nothing +end WeightedGrader + +/** Companion object. */ +private object WeightedGrader: + private val weightRegex = """\[\s*(\d*\.?\d+)\s*\p{Alpha}*\]""".r.unanchored + + private def weight(name: String): Double = weightRegex.findAllMatchIn(name).toSeq match + case Seq() => 1.0 + case s => s.last.group(1).toDoubleOption.getOrElse(1.0) +end WeightedGrader diff --git a/T/src/main/scala/tinyscalautils/test/tagobjects/Async.scala b/T/src/main/scala/tinyscalautils/test/tagobjects/Async.scala index 4acbbff..810dea4 100644 --- a/T/src/main/scala/tinyscalautils/test/tagobjects/Async.scala +++ b/T/src/main/scala/tinyscalautils/test/tagobjects/Async.scala @@ -19,7 +19,7 @@ import org.scalatest.Tag * [[tinyscalautils.threads.runAsync]] * * @see - * [[tinyscalautils.test.grading.GradingRun]] + * [[tinyscalautils.test.grading.Grading]] * * @since 1.1 */ diff --git a/T/src/main/scala/tinyscalautils/test/tagobjects/Fail.scala b/T/src/main/scala/tinyscalautils/test/tagobjects/Fail.scala index dcf2c27..ceca71a 100644 --- a/T/src/main/scala/tinyscalautils/test/tagobjects/Fail.scala +++ b/T/src/main/scala/tinyscalautils/test/tagobjects/Fail.scala @@ -8,7 +8,7 @@ import scala.util.matching.Regex /** A tag to fail a test. This makes it easier to manually fail tests in grading runs. * * @see - * [[tinyscalautils.test.grading.GradingRun]] + * [[tinyscalautils.test.grading.Grading]] * * @since 1.1 */ diff --git a/T/src/main/scala/tinyscalautils/test/text/TruncatingPrettifier.scala b/T/src/main/scala/tinyscalautils/test/text/TruncatingPrettifier.scala index 2828c0c..43f9acf 100644 --- a/T/src/main/scala/tinyscalautils/test/text/TruncatingPrettifier.scala +++ b/T/src/main/scala/tinyscalautils/test/text/TruncatingPrettifier.scala @@ -3,12 +3,15 @@ package tinyscalautils.test.text import org.scalactic.{ Prettifier, PrettyPair } import tinyscalautils.text.short +import scala.compiletime.asMatchable + /** A truncating prettifier. It can be used to guarantee that failed tests do not produce humongous * outputs. * * @constructor * @param prettifier * the underlying prettifier. + * * @param limit * the maximum length of individual strings; must be at least 3. */ @@ -23,8 +26,15 @@ class TruncatingPrettifier(prettifier: Prettifier, limit: Int) extends Prettifie * TruncatingPrettifier(256): o => * ... * }}} + * or + * {{{ + * TruncatingPrettifier(256): + * case ... => ... + * case ... => ... + * }}} */ - def this(limit: Int)(using DummyImplicit)(prettifier: Prettifier) = this(prettifier, limit) + def this(limit: Int)(prettifier: Matchable => String) = + this(o => prettifier(o.asMatchable), limit) private def s(str: String) = str.short(limit) diff --git a/T/src/test/scala/GraderAppTest.scala b/T/src/test/scala/GraderAppTest.scala new file mode 100644 index 0000000..ac56b62 --- /dev/null +++ b/T/src/test/scala/GraderAppTest.scala @@ -0,0 +1,24 @@ +import org.scalatest.funsuite.AnyFunSuite +import tinyscalautils.lang.unit +import tinyscalautils.test.grading.{ GraderApp, Grading, GradingSuites } + +// run inside "T" to fail tests + +private class Tests1 extends AnyFunSuite with Grading(20): + override def suiteName = "Tests1" + test("pass 1 [2pts]")(unit) + test("fail")(unit) + test("pass 2 [2pts]")(unit) + +private class Tests2 extends AnyFunSuite with Grading: + override def suiteName = "Tests2" + test("fail 1 [4pts]")(unit) + test("pass [5pts]")(unit) + test("fail 2")(unit) + +private class Combined extends GradingSuites(10)(Tests1(), Tests2()): + override def suiteName = "Combined" + +private class AllTests extends GradingSuites(Tests1(), Tests2(), Combined()) + +object GraderAppTest extends GraderApp(AllTests()) diff --git a/T/src/test/scala/GradingRunTests.scala b/T/src/test/scala/GradingTests.scala similarity index 84% rename from T/src/test/scala/GradingRunTests.scala rename to T/src/test/scala/GradingTests.scala index 270bab7..2006a96 100644 --- a/T/src/test/scala/GradingRunTests.scala +++ b/T/src/test/scala/GradingTests.scala @@ -1,24 +1,24 @@ -import org.scalactic.{Prettifier, SizeLimit, Tolerance} -import org.scalatest.{Args, ConfigMap} -import org.scalatest.events.{TestCanceled, TestFailed} +import org.scalactic.{ Prettifier, SizeLimit, Tolerance } +import org.scalatest.{ Args, ConfigMap } +import org.scalatest.events.{ TestCanceled, TestFailed } import org.scalatest.exceptions.TestFailedException import org.scalatest.funsuite.AnyFunSuite import org.scalatest.tagobjects.Slow import org.scalatest.time.SpanSugar.convertDoubleToGrainOfTime -import tinyscalautils.lang.{InterruptibleConstructor, InterruptibleEquality} -import tinyscalautils.test.grading.GradingRun -import tinyscalautils.test.tagobjects.{Async, Fail} +import tinyscalautils.lang.{ InterruptibleConstructor, InterruptibleEquality } +import tinyscalautils.test.grading.Grading +import tinyscalautils.test.tagobjects.{ Async, Fail } import tinyscalautils.threads.Executors.global import tinyscalautils.threads.runAsync -import tinyscalautils.timing.{getTime, sleep, timeOf} +import tinyscalautils.timing.{ getTime, sleep, timeOf } import tinyscalautils.lang.unit import tinyscalautils.test.text.TruncatingPrettifier -class GradingRunTests extends AnyFunSuite with Tolerance: +class GradingTests extends AnyFunSuite with Tolerance: private val nums = List.range(0, 42) test("prettifier and grade"): - class Tests(using Prettifier) extends AnyFunSuite with GradingRun: + class Tests(using Prettifier) extends AnyFunSuite with Grading: test("default prettifier"): val e = intercept[TestFailedException](assert(nums.isEmpty)) assert(e.message.exists(_.endsWith(", 31, ...) was not empty"))) @@ -37,7 +37,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: assert(suite.grader.grade == 0.4) test("truncating default prettifier and grade"): - class Tests(using Prettifier) extends AnyFunSuite with GradingRun: + class Tests(using Prettifier) extends AnyFunSuite with Grading: test("prettifier"): val e = intercept[TestFailedException](assert(nums.isEmpty)) assert(e.message.exists(_.endsWith(", 10, 1... was not empty"))) @@ -49,7 +49,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: test("truncating prettifier and grade"): given Prettifier = Prettifier.truncateAt(SizeLimit(5)) - class Tests(using Prettifier) extends AnyFunSuite with GradingRun: + class Tests(using Prettifier) extends AnyFunSuite with Grading: test("prettifier"): val e = intercept[TestFailedException](assert(nums.isEmpty)) assert(e.message.exists(_.endsWith(", 4, ... was not empty"))) @@ -59,7 +59,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: assert(suite.grader.grade == 1.0) test("timeout"): - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: test("the test")(sleep(2.0)) val suite = Tests() @@ -70,7 +70,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: test("interruptible construction"): class C extends InterruptibleConstructor - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: test("the test"): while true do if C().## == getTime() then fail() @@ -82,7 +82,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: test("interruptible equality"): class C extends InterruptibleEquality - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: test("the test"): while true do if C().## == getTime() then fail() @@ -92,7 +92,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: assert(suite.grader.grade == 0.0) test("runAsync"): - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: override val shortTimeLimit = 0.5.seconds test("test 1"): @@ -107,7 +107,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: assert(time === 0.5 +- 0.1) test("Async object"): - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: override val shortTimeLimit = 0.5.seconds override val longTimeLimit = 1.second @@ -127,7 +127,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: test("Async annotation"): @tinyscalautils.test.tags.Async - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: override val shortTimeLimit = 0.5.seconds override val longTimeLimit = 1.second @@ -146,7 +146,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: assert(time2 === 1.0 +- 0.1) test("Fail"): - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: var testHasRun = false test("stuck", Fail): testHasRun = true @@ -158,7 +158,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: test("Fail annotation"): @tinyscalautils.test.tags.Fail - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: var testHasRun = false test("stuck"): testHasRun = true @@ -169,7 +169,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: assert(!suite.testHasRun) test("Fail(message)"): - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: var testHasRun = false test("stuck", Fail("bad")): testHasRun = true @@ -183,7 +183,7 @@ class GradingRunTests extends AnyFunSuite with Tolerance: case other => fail(s"unexpected: $other ") test("Fail broken"): - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: var testHasRun = false test("stuck", Fail("good"), Fail("bad")): testHasRun = true @@ -197,12 +197,12 @@ class GradingRunTests extends AnyFunSuite with Tolerance: case other => fail(s"unexpected: $other ") test("config map"): - class Tests extends AnyFunSuite with GradingRun: + class Tests extends AnyFunSuite with Grading: test("the test")(unit) end Tests val config = ConfigMap("failed" -> Set("the test")) assert(!Tests().run(None, Args(R).copy(configMap = config)).succeeds()) R.lastEvent match - case Some(ev: TestFailed) => assert(ev.message == "test name in failed set") + case Some(ev: TestFailed) => assert(ev.message == """test name in "failed" set""") case other => fail(s"unexpected: $other ") diff --git a/build.sbt b/build.sbt index e65e432..a066928 100644 --- a/build.sbt +++ b/build.sbt @@ -1,8 +1,8 @@ val jcip = "net.jcip" % "jcip-annotations" % "1.0" -val ScalaTest = "org.scalatest" %% "scalatest" % "3.2.18" -val JUnit = "org.junit.jupiter" % "junit-jupiter" % "5.10.2" +val ScalaTest = "org.scalatest" %% "scalatest" % "3.2.19" +val JUnit = "org.junit.jupiter" % "junit-jupiter" % "5.10.3" -ThisBuild / version := "1.2.1" +ThisBuild / version := "1.3.0" ThisBuild / scalaVersion := "3.3.3" ThisBuild / versionScheme := Some("semver-spec") @@ -36,10 +36,6 @@ ThisBuild / homepage := Some(url("https://github.com/charpov/TinyScalaUti ThisBuild / apiURL := Some(url("https://charpov.github.io/TinyScalaUtils/")) ThisBuild / releaseNotesURL := Some(url("https://github.com/charpov/TinyScalaUtils/releases")) -val GithubPackagePublish = - "GitHub Package Registry" at "https://maven.pkg.github.com/charpov/TinyScalaUtils" -//ThisBuild / credentials += Credentials(Path.userHome / ".sbt" / "github-credentials") - ThisBuild / publishMavenStyle := true ThisBuild / publishTo := Some(MavenCache("local-maven", baseDirectory.value / "docs" / "maven-add")) @@ -53,19 +49,15 @@ ThisBuild / scalacOptions := Seq( "-source:future", // source version. "-language:noAutoTupling", // no auto-tupling "-Wunused:all", // unused stuff + "-java-output-version:11", // Target Java 11, which is needed anyway ) val docOptions = Compile / doc / scalacOptions := Seq( - "-project", - "TinyScalaUtils", - "-project-version", - version.value, - "-project-footer", - "Copyright Michel Charpentier, 2023", - "-siteroot", - "./site", - "-doc-root-content", - "./api.md", + "-project:TinyScalaUtils", + s"-project-version:${version.value}", + "-project-footer:Copyright Michel Charpentier, 2024", + "-siteroot:./site", + "-doc-root-content:./api.md", "-author", "-groups", "-external-mappings:.*scala.*::scaladoc3::https://scala-lang.org/api/3.x/," + @@ -99,7 +91,7 @@ lazy val J = project .settings( name := "tiny-scala-utils-java", Compile / compile / javacOptions ++= Seq("-deprecation", "-Xlint"), - Compile / doc / javacOptions += "--ignore-source-errors", + Compile / doc / javacOptions ++= Seq("--ignore-source-errors", "-Xdoclint:none"), Compile / doc / sources ~= (files => files.filterNot(_.getName.endsWith(".scala"))), libraryDependencies ++= Seq(JUnit % Test), ) diff --git a/docs/docs/examples.html b/docs/docs/examples.html index 856c644..c099f10 100644 --- a/docs/docs/examples.html +++ b/docs/docs/examples.html @@ -1,11 +1,11 @@ -Code Examples
-

Code Examples

+Code Examples
+

Code Examples

-
-

Package lang

+
+

Package lang

-
-

unit

+
+

unit

A unit value is defined instead of the usual () token for improved readability, e.g.:

f(((), ())) // hard to parse
@@ -17,8 +17,8 @@ 

unit

-
-

InterruptibleConstructor / InterruptibleEquality

+
+

InterruptibleConstructor / InterruptibleEquality

Checks the interrupted status of the current thread before instance creation and/or equality and hash code:

import tinyscalautils.lang.{ InterruptibleConstructor, InterruptibleEquality }
@@ -32,11 +32,11 @@ 

-
-

Package control

+
+

Package control

-
-

times

+
+

times

This is the same times as in Scalactic:

import tinyscalautils.control.times
@@ -47,8 +47,8 @@ 

times

-
-

limitedStack / StackOverflowException

+
+

limitedStack / StackOverflowException

StackOverflowException can replace StackOverflowError where the latter would not adequately be caught:

import tinyscalautils.lang.StackOverflowException
@@ -65,8 +65,8 @@ 

-
-

interruptibly

+
+

interruptibly

Checks the interrupted status of the current thread before running some code:

import tinyscalautils.control.interruptibly
@@ -78,11 +78,11 @@ 

interrupti

The infinite loops terminates with InterruptedException if the thread is interrupted.

-
-

Package collection

+
+

Package collection

-
-

circular

+
+

circular

Produces an infinite collection of elements by continuously repeating a finite collection:

import tinyscalautils.collection.circular
@@ -95,8 +95,8 @@ 

circular

-
-

shuffle

+
+

shuffle

A convenient way yo invoke Random.shuffle in a pipeline:

import tinyscalautils.collection.shuffle
@@ -121,8 +121,8 @@ 

shuffle

-
-

randomly

+
+

randomly

Produces an infinite collection of elements randomly selected from a finite collection:

import tinyscalautils.collection.randomly
@@ -135,8 +135,8 @@ 

randomly

-
-

pickOne/pickOneOption

+
+

pickOne/pickOneOption

Produces a randomly selected element from a finite, non-empty collection:

import tinyscalautils.collection.pickOne
@@ -150,8 +150,8 @@ 

pic

Exists also as pickOneOption to handle empty collections. These methods should not be used in a loop over the same collection; use randomly instead.

-
-

JavaList

+
+

JavaList

Like List.of but with mutable lists:

import tinyscalautils.collection.JavaList
@@ -170,26 +170,23 @@ 

JavaList

-
-

pollOption / peekOption

-

Like poll / peek but wrapping null in an option.

+
+

sortedInReverse

+

Like sorted, but in reverse:

-
import tinyscalautils.collection.{ pollOption, peekOption }
+  
import tinyscalautils.collection.sortedInReverse
 
-val q = util.ArrayDeque[String]()
-q.offer("X")
-q.peekOption   // Some("X")
-q.pollOption() // Some("X")
-q.pollOption() // None
+val seq = ...       // a sequence
+seq.sortedInReverse // same sequence as seq.sorted.reverse, but more efficient
 
-
-

Package assertions

+
+

Package assertions

-
-

require / requireState

+
+

require / requireState

Simple precondition checking:

import tinyscalautils.assertions.require
@@ -205,8 +202,8 @@ 

re

In either case, someMethod() is only evaluated if the condition is false.

When a requirement fails, require throws IllegalArgumentException while requireState throws IllegalStateException.

-
-

checkNonNull

+
+

checkNonNull

A utility to help reject null with IllegalArgumentException instead of NullPointerException:

require(str.nonEmpty, "string cannot be empty") // throws NPE if str is null, Java style
@@ -218,8 +215,8 @@ 

checkNonNul

-
-

implies

+
+

implies

Logical implication:

val s: IndexedSeq[Int] = ...
@@ -231,10 +228,10 @@ 

implies

-

The evaluation is short-circuited: RHS is evaluated only if LHS is true. Operator also available under the symbolic name ==>.

+

The evaluation is short-circuited: RHS is evaluated only if LHS is true.

-
-

in

+
+

in

An infix operator that swaps the arguments of contains:

import tinyscalautils.assertions.in
@@ -244,11 +241,11 @@ 

in

-
-

Package text

+
+

Package text

-
-

StringLetters / CharLetters

+
+

StringLetters / CharLetters

All cap letters as strings or characters:

import StringLetters.*
@@ -259,8 +256,8 @@ 

-
-

short/pad

+
+

short/pad

Shortens or pads strings:

import tinyscalautils.text.{ short, pad }
@@ -275,8 +272,8 @@ 

short/pad

Note that standard method padTo pads strings on the right.

-
-
-

timeString

+
+

timeString

Human-friendly representation of a duration expressed in seconds:

import tinyscalautils.text.timeString
@@ -365,11 +362,11 @@ 

timeString

-
-

Package timing

+
+

Package timing

-
-

sleep

+
+

sleep

Suspends the running thread for a specified number of seconds:

import tinyscalautils.timing.{ getTime, sleep }
@@ -386,8 +383,8 @@ 

sleep

This method sleep does not undershoot even if Thread.sleep does, and does not throw InterruptedException (but leaves interrupted threads interrupted).

Non-positive values incur no delay.

-
-

delay

+
+

delay

Delays returning a value:

import tinyscalautils.timing.delay
@@ -400,8 +397,8 @@ 

delay

This produces the same value as code, but takes 3 seconds (assuming the evaluation of code took less than 3 seconds). Like sleep, also exists in a start variant: delay(3.0, start)(code).

Non-positive values incur no delay.

-
-

timeOf

+
+

timeOf

The time it took to evaluate some code, in seconds:

import tinyscalautils.timing.timeOf
@@ -413,8 +410,8 @@ 

timeOf

The value produced by the code, if any, is ignored.

-
-

timeIt

+
+

timeIt

The value produced by some code, and the time it took to compute it, as a pair:

import tinyscalautils.timing.timeIt
@@ -425,8 +422,8 @@ 

timeIt

-
-

Timers

+
+

Timers

Simple timers. Can be used explicitly:

import tinyscalautils.threads.Executors
@@ -455,10 +452,10 @@ 

Timers

-

Note that timers need to be explicitly shut down for their threads to terminate.

+

Note that timers need to be explicitly shut down for their threads to terminate. Timers implement the AutoCloseable interface.

-
-

zipWithDuration

+
+

zipWithDuration

Asynchronously adds duration to a future:

import tinyscalautils.timing.zipWithDuration
@@ -470,8 +467,8 @@ 

zipWithD

The second half of the pair is the duration (in seconds) between the invocation of zipWithFuture and the completion of future.

-
-

slow

+
+

slow

A mechanism to slow down sources of values:

import tinyscalautils.timing.SlowIterator
@@ -481,21 +478,21 @@ 

slow

val sum = i.sum // 499500 val sum = i.slow(10.0).sum // 499500, but in about 10 seconds -// first 10 elements delayed by about 1 second, then fast: +// first 10 elements delayed by about 1 second each, then fast: i.slow(10.0, delayedElements = 10) -// first 100 elements delayed by about 0.1 second, then fast +// first 100 elements delayed by about 0.1 second each, then fast i.slow(10.0, delayedElements = 100) -// all elements delayed by about 0.001 second, then 9-second delay to finish +// all elements delayed by about 0.001 second each, then 9-second delay to finish i.slow(10.0, delayedElements = 10_000)

Also available on Source and LazyList.

-
-

runFor / callFor

+
+

runFor / callFor

Runs iterative code with a time bound:

import tinyscalautils.threads.Timer
@@ -540,11 +537,11 @@ 

runFor

This last variant produces a last value when it terminates (i.e., (last, None)).

-
-

Package threads

+
+

Package threads

-
-

orTimeout

+
+

orTimeout

Adds a timeout feature to future, similar to Java's:

import tinyscalautils.threads.{ orTimeout, completeOnTimeout } 
@@ -568,8 +565,8 @@ 

orTimeout

-
-

Executors

+
+

Executors

A facility to more easily create thread pools with customized thread factories and/or rejected execution handlers. All pools have type ExecutionContextExecutorService for easier use of both Java and Scala features.

import tinyscalautils.threads.Executors
@@ -621,8 +618,8 @@ 

Executors

-
-

run / Execute/ExecuteAfter

+
+

run / Execute/ExecuteAfter

Executes code on an executor:

import tinyscalautils.threads.{ run, Execute, ExecuteAfter }
@@ -639,8 +636,8 @@ 

Both functions return Unit (no future).

-
-

KeepThreadsFactory

+
+

KeepThreadsFactory

A thread factory that keeps a reference on all the threads it creates:

import tinyscalautils.threads.{ KeepThreadsFactory, Executors }
@@ -656,8 +653,8 @@ 

KeepT

The collection returned by allThreads is live: threads newly created by the factory will be added to it. The factory can be reset: threads created before the reset are discarded.

-
-

MarkedThreadsFactory

+
+

MarkedThreadsFactory

A cheaper alternative to KeepThreadsFactory: All the threads produced by the factory are distinguished by having type MarkedThread:

import tinyscalautils.threads.{ MarkedThreadsFactory, Executors }
@@ -680,8 +677,8 @@ 

Mar

-
-

awaitTermination

+
+

awaitTermination

A variant of the standard awaitTermination method in which the timeout is optional and specified in seconds:

import tinyscalautils.threads.awaitTermination
@@ -694,8 +691,8 @@ 

awaitTe

-
-

shutdownAndWait

+
+

shutdownAndWait

Combines shutdown, shutdownNow and awaitTermination in one method:

import tinyscalautils.threads.shutdownAndWait
@@ -710,13 +707,13 @@ 

shutdown then // shutdown was invoked, and pool terminated within 5 seconds else // shutdown was invoked, then after 5 seconds, shutdownNow was invoked -exec.shutdownAndWait() // invokes shutdown and waits indefinitely; force flag is ignored +exec.shutdownAndWait() // invokes shutdown and waits indefinitely; returns true

-
-

await

+
+

await

Adds a variant of await on CountDownLatch that specifies its timeout in seconds:

import tinyscalautils.threads.await
@@ -728,8 +725,8 @@ 

await

-
-

countDownAndWait

+
+

countDownAndWait

Combines countDown and await:

import tinyscalautils.threads.countDownAndWait
@@ -743,8 +740,8 @@ 

countDo

Waits forever (interruptibly) if no timeout is specified.

-
-

acquire

+
+

acquire

Adds a variant of acquire on Semaphore that specifies its timeout in seconds:

import tinyscalautils.threads.acquire
@@ -756,23 +753,23 @@ 

acquire

-
-

offer / pollOption

-

Adds variant of offer and poll on blocking queues that specifies their timeout in seconds and wrap null in an option:

+
+

offer / poll

+

Adds variant of offer and poll on blocking queues that specifies their timeout in seconds:

-
import tinyscalautils.threads.{ offer, pollOption }
+  
import tinyscalautils.threads.{ offer, poll }
 
 val q = ArrayBlockingQueue[String](1)
 q.offer("X", seconds = 1.0) // true, immediately
 q.offer("X", seconds = 1.0) // false, after 1 second
-q.pollOption(seconds = 1.0) // Some("X"), immediately
-q.pollOption(seconds = 1.0) // None, after 1 second
+q.poll(seconds = 1.0)       // "X", immediately
+q.poll(seconds = 1.0)       // null, after 1 second
 
-
-

joined

+
+

joined

Combines join and isAlive:

import tinyscalautils.threads.joined
@@ -784,8 +781,8 @@ 

joined

-
-

newThread

+
+

newThread

Kotlin-like functions for easier thread creation:

import tinyscalautils.threads.newThread 
@@ -797,15 +794,14 @@ 

newThread

All arguments have default values and are optional. Be aware that waitForChildren only works if children are created within the same thread group (which is not always the case for the default thread factory of java.util.concurrent.Executors).

-
-

Execution contexts

+
+

Execution contexts

Easy setup of execution contexts, mostly for testing:

import tinyscalautils.threads.withThreadsAndWait
 
 val result = withThreadsAndWait(4):
-   Future:
-      42
+   Future(42)
 
@@ -817,8 +813,7 @@

Execution c val exec = Executors.newUnlimitedThreadPool() val result = withThreadPoolAndWait(exec): - Future: - 42 + Future(42)
@@ -833,8 +828,8 @@

Execution c

This runs the future on the global execution context, and waits for its termination.

-
-

runAsync

+
+

runAsync

Run code synchronously in another thread:

import tinyscalautils.threads.runAsync
@@ -846,11 +841,11 @@ 

runAsync

The thread is specified as an implicit Executor or ExecutionContext.

The purpose of this function is to run non-interruptible code interruptibly.

-
-

Package io

+
+

Package io

-
-

listPaths

+
+

listPaths

The contents of a directory, as a list:

import tinyscalautils.io.listPaths
@@ -869,57 +864,91 @@ 

listPaths

DO NOT use a stream for the collection. Since the directory is closed before this function finishes, lazily evaluated collections won't work.

-
-

listLines

-

The contents of a UTF8 text file, as a list:

+
+

read/readAll

+

The contents of a UTF8 text file, as a collection of line elements:

-
import tinyscalautils.io.listLines
+  
import tinyscalautils.io.{ readAll, given }
 
-for line: String <- listLines(file) do ...
+def parse(line: String): Option[Int] = ...
+
+readAll(IndexedSeq)(file, parse)     // an IndexedSeq[Int]
+readAll(IndexedSeq)(file)            // all non-blank lines
+readAll(IndexedSeq)(file, noParsing) // all lines
 
-

If a list type is not suitable, use readLines instead:

+

If no factory is specified, it defaults to List, e.g.:

-
import tinyscalautils.io.readLines
-
-val lines: IndexedSeq[String] = readLines(IndexedSeq)(file)
+  
readAll(file, parse)     // a List[Int]
+readAll(file)            // a List[String]
+readAll(file, noParsing) // a List[String]
 
-

DO NOT use a stream for the collection. Since the file is closed before this function finishes, lazily evaluated collections won't work.

+

read does no parsing and returns the entire file contents as a single string.

+

The argument file must belong to the Input type class, which is predefined to contain InputStream, URL, Path, File and String (as a filename).

+

DO NOT use a stream for the collection. Since the source is closed before this function finishes, lazily evaluated collections won't work.

-
-

findResource

+
+

readingAll

+

This is a variant of readAll that returns values as a closeable iterator:

-
import tinyscalautils.io.findResource
+  
import tinyscalautils.io.{ readingAll, given }
 
-val url = this.findResource(name)
+def parse(line: String): Option[Int] = ...
+
+Using.resource(readingAll(file, parse)): i =>
+   // i has type Iterator[Int]
+// file input closed here
 
-

This is equivalent to getClass.getResource(name), except that it throws an exception for missing resources (instead of returning null). In particular, a leading slash in the resource name makes it an absolute path, instead of being associated with the package name by default.

+

readingAll does not support a silent mode.

+
+
+

write/writeAll

+

Write data to a UTF8 text file:

+
+
import tinyscalautils.io.{ write, writeAll, given }
+   
+   val list = List(1, 2, 3)
+
+   write(file)(list)                                      // file contains "List(1, 2, 3)"
+   write(file, newline = true)(list)                      // file contains "List(1, 2, 3)\n"
+   writeAll(file)(list)                                   // file contains "1\n2\n3\n"
+   writeAll(sep = ",")(file)(list)                        // file contains "1,2,3"
+   writeAll(pre = "[", sep = ",", post = "]")(file)(list) // file contains "[1,2,3]"
+   writeAll()(file)(list)                                 // file contains "123"
+
+
+
+

Note that the simplified writeAll variant includes a final newline after the last value.

+

The argument file must belong to the Output type class, which is predefined to contain OutputStream, Path, File and String (as a filename).

-
-

parseURL

+
+

findResource/findResourceAsStream

-
def parse(line: String): Option[Int] = ...
-val list: List[Int] = parseURL(url, parse)
+  
import tinyscalautils.io.findResource
+
+val url = this.findResource(name)
 
-

If a list type is not suitable, specify a factory:

+

This is equivalent to getClass.getResource(name), except that it throws an exception for missing resources (instead of returning null). In particular, a leading slash in the resource name makes it an absolute path, instead of being associated with the package name by default.

-
val seq: IndexedSeq[Int] = parseURL(url, parse, IndexedSeq)
+  
val url = this.findResource(fallback)(name)
 
+

This variant uses a fallback URI instead of failing with MissingResourceException.

+

The findResourceAsStream variants work in the same way but looks for a GZIP compressed variant of a resource before giving up.

-
-

Package util

+
+

Package util

-
-

FastRandom

+
+

FastRandom

Faster random number generators that don't rely on the java.util.Random thread-safe implementation. Individual instances are not thread-safe, but the singleton FastRandom can be shared among threads without contention:

import tinyscalautils.util.FastRandom
@@ -933,8 +962,8 @@ 

FastRandom

The implementation relies on ThreadLocalRandom and SplittableRandom, available in Java 11, not on the fancier generators that were added to Java 17.

-
-

nextInt

+
+

nextInt

A Kotlin-inspired alternative to pickOne to select random numbers from a range:

import tinyscalautils.util.nextInt
@@ -949,8 +978,8 @@ 

nextInt

This looks nicer than (1 to 10).pickone(using rand) and (0 until 100).pickone(using rand).

-
-

log2

+
+

log2

Base 2 integer logarithm:

import tinyscalautils.util.log2
@@ -963,8 +992,8 @@ 

log2

-
-

average

+
+

average

Calculates an average by ignoring a fixed number of low/high values:

val nums: Seq[BigDecimal] = Seq(12, 1, 7, 11, 14, 9)
@@ -977,4 +1006,17 @@ 

average

The function works on any Fractional type, including Double.

-
\ No newline at end of file +
+
+

dot/star

+

An identity function that prints a single dot (or star):

+
+
import tinyscalautils.util.dot
+
+val x = dot(y)  // x eq y and a dot was printed
+val x = star(y) // x eq y and a star was printed
+
+
+
+

Importing tinyscalautils.text.silentMode stops the dot/star from being printed. Printing modes other than silent and standard cannot be used.

+
\ No newline at end of file diff --git a/docs/docs/index.html b/docs/docs/index.html index 7bbbbd1..c806c6d 100644 --- a/docs/docs/index.html +++ b/docs/docs/index.html @@ -1,8 +1,8 @@ -TinyScalaUtils
-

Package Documentation

+TinyScalaUtils
+

Package Documentation

-
-

Installation

+
+

Installation

Using sbt:

resolvers += "TinyScalaUtils" at "https://charpov.github.io/TinyScalaUtils/maven/"
@@ -12,12 +12,12 @@ 

Installation

(Adjust for other Maven-based tools.)

-
-

Binary compatibility

+
+

Binary compatibility

Java 11 and Scala 3.3, or newer.

-
-

Structure

+
+

Structure

The library is organized in themed sub-packages:

  • lang: general stuff.
  • @@ -30,4 +30,4 @@

    Structure

  • timing: timers, delayers, elapsed time calculation.
  • util: utility functions, fast random number generators.
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 466ea54..91abd53 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,4 +1,4 @@ -TinyScalaUtils
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar new file mode 100644 index 0000000..f069793 Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar.md5 new file mode 100644 index 0000000..260845f --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar.md5 @@ -0,0 +1 @@ +42212a6f0698d1efa945b8e4cb241900 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar.sha1 new file mode 100644 index 0000000..586e42e --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-javadoc.jar.sha1 @@ -0,0 +1 @@ +291dc43ff81db3563dab925d7b95a44978484d9a \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar new file mode 100644 index 0000000..32e729e Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar.md5 new file mode 100644 index 0000000..a2ceb2f --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar.md5 @@ -0,0 +1 @@ +e6284bd3670478aa5376c4355c184afa \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar.sha1 new file mode 100644 index 0000000..dce9329 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0-sources.jar.sha1 @@ -0,0 +1 @@ +c2bc6b1c78266176c9ed4ed902d64479f6942823 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar new file mode 100644 index 0000000..5dab240 Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar.md5 new file mode 100644 index 0000000..f238190 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar.md5 @@ -0,0 +1 @@ +31cd2cfd4034fa0f5af784e0dcea88b6 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar.sha1 new file mode 100644 index 0000000..905f181 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.jar.sha1 @@ -0,0 +1 @@ +e4bbdd183261dafecf53471df3ae5d9274b6bae4 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom new file mode 100644 index 0000000..46c970b --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom @@ -0,0 +1,57 @@ + + + 4.0.0 + com.github.charpov + tiny-scala-utils-java_3 + jar + A tiny, no (real) dependencies, Scala library, mostly used for teaching. + https://github.com/charpov/TinyScalaUtils + 1.3.0 + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + tiny-scala-utils-java + + charpov + https://github.com/charpov + + + https://github.com/charpov/TinyScalaUtils + scm:git@github.com:charpov/TinyScalaUtils.git + + + + charpov + Michel Charpentier + https://github.com/charpov + Michel.Charpentier@unh.edu + + + + https://charpov.github.io/TinyScalaUtils/ + https://github.com/charpov/TinyScalaUtils/releases + semver-spec + + + + com.github.charpov + tiny-scala-utils_3 + 1.3.0 + + + org.scala-lang + scala3-library_3 + 3.3.3 + + + org.junit.jupiter + junit-jupiter + 5.10.3 + test + + + \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom.md5 new file mode 100644 index 0000000..fd31f7b --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom.md5 @@ -0,0 +1 @@ +ad19340fc8feff6ebc6c7c9e7ec2ce11 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom.sha1 new file mode 100644 index 0000000..935ff3a --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-java_3/1.3.0/tiny-scala-utils-java_3-1.3.0.pom.sha1 @@ -0,0 +1 @@ +c7ee1cd98bf46a5cd65c4279a94682427337c86d \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar new file mode 100644 index 0000000..073e7a7 Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar.md5 new file mode 100644 index 0000000..7fb1726 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar.md5 @@ -0,0 +1 @@ +e4cc1a7430d36766a7fdf3466f99ced0 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar.sha1 new file mode 100644 index 0000000..4890b5b --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-javadoc.jar.sha1 @@ -0,0 +1 @@ +66f23c21846dde8dd9ed9847a15784c6f5d9fabf \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar new file mode 100644 index 0000000..0a7e270 Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar.md5 new file mode 100644 index 0000000..7a4c488 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar.md5 @@ -0,0 +1 @@ +b84df54a7b48ad6f0261dc1c42c5908c \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar.sha1 new file mode 100644 index 0000000..665fce5 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0-sources.jar.sha1 @@ -0,0 +1 @@ +459f9e9d33f6d34a539f407ded6065ac47c86a6d \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar new file mode 100644 index 0000000..edd1e7e Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar.md5 new file mode 100644 index 0000000..b2a5686 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar.md5 @@ -0,0 +1 @@ +177dc675cdef3d05fcfd866ec07514c1 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar.sha1 new file mode 100644 index 0000000..f31dd2a --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.jar.sha1 @@ -0,0 +1 @@ +e8b584878a3fb9f75b6f4fe5a21c47393f5f5d24 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom new file mode 100644 index 0000000..08f6065 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom @@ -0,0 +1,56 @@ + + + 4.0.0 + com.github.charpov + tiny-scala-utils-test_3 + jar + A tiny, no (real) dependencies, Scala library, mostly used for teaching. + https://github.com/charpov/TinyScalaUtils + 1.3.0 + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + tiny-scala-utils-test + + charpov + https://github.com/charpov + + + https://github.com/charpov/TinyScalaUtils + scm:git@github.com:charpov/TinyScalaUtils.git + + + + charpov + Michel Charpentier + https://github.com/charpov + Michel.Charpentier@unh.edu + + + + https://charpov.github.io/TinyScalaUtils/ + https://github.com/charpov/TinyScalaUtils/releases + semver-spec + + + + com.github.charpov + tiny-scala-utils_3 + 1.3.0 + + + org.scala-lang + scala3-library_3 + 3.3.3 + + + org.scalatest + scalatest_3 + 3.2.19 + + + \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom.md5 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom.md5 new file mode 100644 index 0000000..c409afc --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom.md5 @@ -0,0 +1 @@ +8b02380a740ce7a6fc01dfa16efa4e1f \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom.sha1 new file mode 100644 index 0000000..c991968 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils-test_3/1.3.0/tiny-scala-utils-test_3-1.3.0.pom.sha1 @@ -0,0 +1 @@ +820e7c8076d89b7c2e4f364cb30c16721401bdd1 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar new file mode 100644 index 0000000..8e23a06 Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar.md5 new file mode 100644 index 0000000..8f742ba --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar.md5 @@ -0,0 +1 @@ +ba6492eb912168f99166ac669ef3bd52 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar.sha1 new file mode 100644 index 0000000..ad2e3f3 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-javadoc.jar.sha1 @@ -0,0 +1 @@ +91b46abf2b9086d4bdf1fd818e2fd9cd03ca66b5 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar new file mode 100644 index 0000000..bc4cfc5 Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar.md5 new file mode 100644 index 0000000..bf51e45 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar.md5 @@ -0,0 +1 @@ +f4e476a003fb090945c7bf50497eddcf \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar.sha1 new file mode 100644 index 0000000..3ecdb95 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0-sources.jar.sha1 @@ -0,0 +1 @@ +683cfdab2db5a49e1cbcdefa90892d3e791b8173 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar new file mode 100644 index 0000000..1684847 Binary files /dev/null and b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar differ diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar.md5 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar.md5 new file mode 100644 index 0000000..afd13b3 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar.md5 @@ -0,0 +1 @@ +bf46a4d56332792efb2a63b774055cbb \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar.sha1 new file mode 100644 index 0000000..ffb9e75 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.jar.sha1 @@ -0,0 +1 @@ +2ee42217978fbc5e64f74719040bad46f6f105b8 \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom new file mode 100644 index 0000000..a152c0c --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom @@ -0,0 +1,57 @@ + + + 4.0.0 + com.github.charpov + tiny-scala-utils_3 + jar + A tiny, no (real) dependencies, Scala library, mostly used for teaching. + https://github.com/charpov/TinyScalaUtils + 1.3.0 + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + tiny-scala-utils + + charpov + https://github.com/charpov + + + https://github.com/charpov/TinyScalaUtils + scm:git@github.com:charpov/TinyScalaUtils.git + + + + charpov + Michel Charpentier + https://github.com/charpov + Michel.Charpentier@unh.edu + + + + https://charpov.github.io/TinyScalaUtils/ + https://github.com/charpov/TinyScalaUtils/releases + semver-spec + + + + org.scala-lang + scala3-library_3 + 3.3.3 + + + net.jcip + jcip-annotations + 1.0 + + + org.scalatest + scalatest_3 + 3.2.19 + test + + + \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom.md5 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom.md5 new file mode 100644 index 0000000..130a5f7 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom.md5 @@ -0,0 +1 @@ +5babecfb0cb3c8adba1d1b19244b804b \ No newline at end of file diff --git a/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom.sha1 b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom.sha1 new file mode 100644 index 0000000..8baa2d5 --- /dev/null +++ b/docs/maven/com/github/charpov/tiny-scala-utils_3/1.3.0/tiny-scala-utils_3-1.3.0.pom.sha1 @@ -0,0 +1 @@ +772e0fcec037bdc20193f9853d1dba96f1cad27b \ No newline at end of file diff --git a/docs/scripts/searchData.js b/docs/scripts/searchData.js index 192f35f..5fa734e 100644 --- a/docs/scripts/searchData.js +++ b/docs/scripts/searchData.js @@ -19,6 +19,7 @@ pages = [{"l":"index.html#","e":false,"i":"","n":"TinyScalaUtils","t":"TinyScala {"l":"https://scala-lang.org/api/3.x/tinyscalautils/collection.html#pollOption-fffff53d","e":true,"i":"extension [A](queue: Queue[A])","n":"pollOption","t":"pollOption(): Option[A]","d":"tinyscalautils.collection","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/collection.html#randomly-fffff339","e":true,"i":"extension [A](elements: IterableOnce[A])","n":"randomly","t":"randomly(using rand: Random): Iterator[A]","d":"tinyscalautils.collection","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/collection.html#shuffle-fffffa63","e":true,"i":"extension [A](elements: IterableOnce[A])","n":"shuffle","t":"shuffle[C](using rand: Random)(using BuildFrom[elements.type, A, C]): C","d":"tinyscalautils.collection","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/collection.html#sortedInReverse-add","e":true,"i":"extension [A, CC[_]](self: SeqOps[A, CC, CC[A]])","n":"sortedInReverse","t":"sortedInReverse[B >: A](using evidence$1: Ordering[B]): CC[A]","d":"tinyscalautils.collection","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/collection/ArrayList$.html","e":true,"i":"","n":"ArrayList","t":"ArrayList","d":"tinyscalautils.collection","k":"object","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/collection/ArrayList$.html#factory-0","e":true,"i":"","n":"factory","t":"factory: factory","d":"tinyscalautils.collection.ArrayList","k":"given","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/collection/ArrayList$$factory$.html","e":true,"i":"","n":"factory","t":"factory extends JavaListFactory[ArrayList]","d":"tinyscalautils.collection.ArrayList","k":"object","x":""}, @@ -37,12 +38,46 @@ pages = [{"l":"index.html#","e":false,"i":"","n":"TinyScalaUtils","t":"TinyScala {"l":"https://scala-lang.org/api/3.x/tinyscalautils/control.html#noStackOverflow-957","e":true,"i":"","n":"noStackOverflow","t":"noStackOverflow[A](inline code: A): A","d":"tinyscalautils.control","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/control.html#times-386","e":true,"i":"extension (number: Int)","n":"times","t":"times(inline code: Any): Unit","d":"tinyscalautils.control","k":"def","x":""}, {"l":"tinyscalautils/io.html#","e":false,"i":"","n":"tinyscalautils.io","t":"tinyscalautils.io","d":"","k":"package","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#FileIsInput-0","e":true,"i":"","n":"FileIsInput","t":"FileIsInput: Input[File]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#FileIsOutput-0","e":true,"i":"","n":"FileIsOutput","t":"FileIsOutput: Output[File]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#FileNameIsInput-0","e":true,"i":"","n":"FileNameIsInput","t":"FileNameIsInput: Input[String]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#FileNameIsOutput-0","e":true,"i":"","n":"FileNameIsOutput","t":"FileNameIsOutput: Output[String]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#InputStreamIsInput-0","e":true,"i":"","n":"InputStreamIsInput","t":"InputStreamIsInput: Input[InputStream]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#OutputStreamIsOutput-0","e":true,"i":"","n":"OutputStreamIsOutput","t":"OutputStreamIsOutput: Output[OutputStream]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#PathIsInput-0","e":true,"i":"","n":"PathIsInput","t":"PathIsInput: Input[Path]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#PathIsOutput-0","e":true,"i":"","n":"PathIsOutput","t":"PathIsOutput: Output[Path]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#SourceIsInput-0","e":true,"i":"","n":"SourceIsInput","t":"SourceIsInput: Input[Source]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#URLIsInput-0","e":true,"i":"","n":"URLIsInput","t":"URLIsInput: Input[URL]","d":"tinyscalautils.io","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#destination-da7","e":true,"i":"extension [O](out: O)(using evidence$1: Output[O])","n":"destination","t":"destination: OutputStream","d":"tinyscalautils.io","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#findResource-fffff3aa","e":true,"i":"extension (obj: AnyRef)","n":"findResource","t":"findResource(name: String): URL","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#findResource-59","e":true,"i":"extension (obj: AnyRef)","n":"findResource","t":"findResource(fallback: URI)(name: String): URL","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#findResourceAsStream-f56","e":true,"i":"extension (obj: AnyRef)","n":"findResourceAsStream","t":"findResourceAsStream(name: String): InputStream","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#findResourceAsStream-fc7","e":true,"i":"extension (obj: AnyRef)","n":"findResourceAsStream","t":"findResourceAsStream(fallback: URI)(name: String): InputStream","d":"tinyscalautils.io","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#listLines-2c3","e":true,"i":"","n":"listLines","t":"listLines(file: Path, silent: Boolean): List[String]","d":"tinyscalautils.io","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#listPaths-2c3","e":true,"i":"","n":"listPaths","t":"listPaths(dir: Path, silent: Boolean): List[Path]","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#noParsing-0","e":true,"i":"","n":"noParsing","t":"noParsing: String => IterableOnce[String]","d":"tinyscalautils.io","k":"val","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#parseURL-ffffff30","e":true,"i":"","n":"parseURL","t":"parseURL[A, C[_]](url: URL, parser: String => IterableOnce[A], factory: IterableFactory[C]): C[A]","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#read-fffff00e","e":true,"i":"","n":"read","t":"read[I](in: I, silent: Boolean)(using evidence$1: Input[I]): String","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readAll-193","e":true,"i":"","n":"readAll","t":"readAll[A, C[_], I](factory: IterableFactory[C])(in: I, parser: String => IterableOnce[A], silent: Boolean)(using evidence$1: Input[I]): C[A]","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readAll-e21","e":true,"i":"","n":"readAll","t":"readAll[A, I](in: I, parser: String => IterableOnce[A], silent: Boolean)(using evidence$1: Input[I]): List[A]","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readAll-d99","e":true,"i":"","n":"readAll","t":"readAll[A, I](in: I, parser: String => IterableOnce[A])(using evidence$1: Input[I]): List[A]","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readAll-b89","e":true,"i":"","n":"readAll","t":"readAll[I](in: I, silent: Boolean)(using evidence$1: Input[I]): List[String]","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readAll-fffff731","e":true,"i":"","n":"readAll","t":"readAll[I](in: I)(using evidence$1: Input[I]): List[String]","d":"tinyscalautils.io","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readLines-fffffa81","e":true,"i":"","n":"readLines","t":"readLines[C[_]](factory: IterableFactory[C])(file: Path, silent: Boolean): C[String]","d":"tinyscalautils.io","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readPaths-fffffa81","e":true,"i":"","n":"readPaths","t":"readPaths[C[_]](factory: IterableFactory[C])(dir: Path, silent: Boolean): C[Path]","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#readingAll-23d","e":true,"i":"","n":"readingAll","t":"readingAll[A, I](in: I, parser: String => IterableOnce[A])(using evidence$1: Input[I]): Iterator[A] & Closeable","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#source-fffffc3a","e":true,"i":"extension [I](in: I)(using evidence$1: Input[I])","n":"source","t":"source: Source","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#write-fffff099","e":true,"i":"","n":"write","t":"write[O](out: O, newline: Boolean)(str: CharSequence)(using evidence$1: Output[O]): Unit","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#writeAll-fffff559","e":true,"i":"","n":"writeAll","t":"writeAll[A, O](pre: String, sep: String, post: String)(out: O)(values: IterableOnce[A])(using evidence$1: Output[O]): Unit","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io.html#writeAll-fffffa68","e":true,"i":"","n":"writeAll","t":"writeAll[A, O](out: O)(values: IterableOnce[A])(using evidence$1: Output[O]): Unit","d":"tinyscalautils.io","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Input.html","e":true,"i":"","n":"Input","t":"Input[-I]","d":"tinyscalautils.io","k":"trait","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Input.html#source-fffff168","e":true,"i":"","n":"source","t":"source(in: I): Source","d":"tinyscalautils.io.Input","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Input$.html","e":true,"i":"","n":"Input","t":"Input","d":"tinyscalautils.io","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Input$.html#apply-4d1","e":true,"i":"","n":"apply","t":"apply[I](using evidence$1: Input[I]): Input[I]","d":"tinyscalautils.io.Input","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Output.html","e":true,"i":"","n":"Output","t":"Output[-O]","d":"tinyscalautils.io","k":"trait","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Output.html#destination-610","e":true,"i":"","n":"destination","t":"destination(out: O): OutputStream","d":"tinyscalautils.io.Output","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Output$.html","e":true,"i":"","n":"Output","t":"Output","d":"tinyscalautils.io","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/io/Output$.html#apply-5fd","e":true,"i":"","n":"apply","t":"apply[O](using evidence$1: Output[O]): Output[O]","d":"tinyscalautils.io.Output","k":"def","x":""}, {"l":"tinyscalautils/lang.html#","e":false,"i":"","n":"tinyscalautils.lang","t":"tinyscalautils.lang","d":"","k":"package","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/lang.html#unit-0","e":true,"i":"","n":"unit","t":"unit: Unit","d":"tinyscalautils.lang","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/lang/InterruptibleConstructor.html","e":true,"i":"","n":"InterruptibleConstructor","t":"InterruptibleConstructor","d":"tinyscalautils.lang","k":"trait","x":""}, @@ -50,6 +85,7 @@ pages = [{"l":"index.html#","e":false,"i":"","n":"TinyScalaUtils","t":"TinyScala {"l":"https://scala-lang.org/api/3.x/tinyscalautils/lang/StackOverflowException.html","e":true,"i":"","n":"StackOverflowException","t":"StackOverflowException(error: StackOverflowError) extends RuntimeException","d":"tinyscalautils.lang","k":"class","x":""}, {"l":"tinyscalautils/text.html#","e":false,"i":"","n":"tinyscalautils.text","t":"tinyscalautils.text","d":"","k":"package","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#cleanCRLF-fffff2ca","e":true,"i":"extension (str: String)","n":"cleanCRLF","t":"cleanCRLF: String","d":"tinyscalautils.text","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#dot-5cc","e":true,"i":"","n":"dot","t":"dot[A, M <: PrintingMode](any: A, theDot: Char)(using mode: M): A","d":"tinyscalautils.text","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#info-fffff3b3","e":true,"i":"","n":"info","t":"info(newlines: Int): Unit","d":"tinyscalautils.text","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#pad-165","e":true,"i":"extension (str: String)","n":"pad","t":"pad(minLen: Int, padding: Char): String","d":"tinyscalautils.text","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#plural-fffff522","e":true,"i":"","n":"plural","t":"plural[A](x: A, singularForm: String, pluralForm: String)(using evidence$1: Numeric[A]): String","d":"tinyscalautils.text","k":"def","x":""}, @@ -61,13 +97,14 @@ pages = [{"l":"index.html#","e":false,"i":"","n":"TinyScalaUtils","t":"TinyScala {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#printout-fffff4a4","e":true,"i":"","n":"printout","t":"printout[A](code: => A): String","d":"tinyscalautils.text","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#short-fffff2ca","e":true,"i":"extension (str: String)","n":"short","t":"short: String","d":"tinyscalautils.text","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#short-cc7","e":true,"i":"extension (str: String)","n":"short","t":"short(maxLen: Int): String","d":"tinyscalautils.text","k":"def","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#silentMode-0","e":true,"i":"","n":"silentMode","t":"silentMode: PrintingMode","d":"tinyscalautils.text","k":"given","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#standardMode-0","e":true,"i":"","n":"standardMode","t":"standardMode: PrintingMode","d":"tinyscalautils.text","k":"given","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#threadMode-0","e":true,"i":"","n":"threadMode","t":"threadMode: PrintingMode","d":"tinyscalautils.text","k":"given","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#threadTimeDemoMode-0","e":true,"i":"","n":"threadTimeDemoMode","t":"threadTimeDemoMode: PrintingMode","d":"tinyscalautils.text","k":"given","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#threadTimeMode-0","e":true,"i":"","n":"threadTimeMode","t":"threadTimeMode: PrintingMode","d":"tinyscalautils.text","k":"given","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#timeDemoMode-0","e":true,"i":"","n":"timeDemoMode","t":"timeDemoMode: PrintingMode","d":"tinyscalautils.text","k":"given","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#timeMode-0","e":true,"i":"","n":"timeMode","t":"timeMode: PrintingMode","d":"tinyscalautils.text","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#silentMode-0","e":true,"i":"","n":"silentMode","t":"silentMode: silentMode","d":"tinyscalautils.text","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#standardMode-0","e":true,"i":"","n":"standardMode","t":"standardMode: standardMode","d":"tinyscalautils.text","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#star-fffff0ed","e":true,"i":"","n":"star","t":"star[A](any: A)(using mode: PrintingMode): A","d":"tinyscalautils.text","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#threadMode-0","e":true,"i":"","n":"threadMode","t":"threadMode: threadMode","d":"tinyscalautils.text","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#threadTimeDemoMode-0","e":true,"i":"","n":"threadTimeDemoMode","t":"threadTimeDemoMode: threadTimeDemoMode","d":"tinyscalautils.text","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#threadTimeMode-0","e":true,"i":"","n":"threadTimeMode","t":"threadTimeMode: threadTimeMode","d":"tinyscalautils.text","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#timeDemoMode-0","e":true,"i":"","n":"timeDemoMode","t":"timeDemoMode: timeDemoMode","d":"tinyscalautils.text","k":"given","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#timeMode-0","e":true,"i":"","n":"timeMode","t":"timeMode: timeMode","d":"tinyscalautils.text","k":"given","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text.html#timeString-fffffc13","e":true,"i":"","n":"timeString","t":"timeString(seconds: Double, unitsCount: Int): String","d":"tinyscalautils.text","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/CharLetters$.html","e":true,"i":"","n":"CharLetters","t":"CharLetters","d":"tinyscalautils.text","k":"object","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/CharLetters$.html#A-0","e":true,"i":"","n":"A","t":"A: 'A'","d":"tinyscalautils.text.CharLetters","k":"val","x":""}, @@ -127,6 +164,20 @@ pages = [{"l":"index.html#","e":false,"i":"","n":"TinyScalaUtils","t":"TinyScala {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/StringLetters$.html#X-0","e":true,"i":"","n":"X","t":"X: \"X\"","d":"tinyscalautils.text.StringLetters","k":"val","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/StringLetters$.html#Y-0","e":true,"i":"","n":"Y","t":"Y: \"Y\"","d":"tinyscalautils.text.StringLetters","k":"val","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/StringLetters$.html#Z-0","e":true,"i":"","n":"Z","t":"Z: \"Z\"","d":"tinyscalautils.text.StringLetters","k":"val","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/silentMode$.html","e":true,"i":"","n":"silentMode","t":"silentMode extends PrintingMode","d":"tinyscalautils.text","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/silentMode$.html#print-9b9","e":true,"i":"","n":"print","t":"print(arg: Any, newline: Boolean): Unit","d":"tinyscalautils.text.silentMode","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/standardMode$.html","e":true,"i":"","n":"standardMode","t":"standardMode extends PrintingMode","d":"tinyscalautils.text","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/standardMode$.html#print-9b9","e":true,"i":"","n":"print","t":"print(arg: Any, newline: Boolean): Unit","d":"tinyscalautils.text.standardMode","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/threadMode$.html","e":true,"i":"","n":"threadMode","t":"threadMode extends PrintingMode","d":"tinyscalautils.text","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/threadMode$.html#print-9b9","e":true,"i":"","n":"print","t":"print(arg: Any, newline: Boolean): Unit","d":"tinyscalautils.text.threadMode","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/threadTimeDemoMode$.html","e":true,"i":"","n":"threadTimeDemoMode","t":"threadTimeDemoMode extends PrintingMode","d":"tinyscalautils.text","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/threadTimeDemoMode$.html#print-9b9","e":true,"i":"","n":"print","t":"print(arg: Any, newline: Boolean): Unit","d":"tinyscalautils.text.threadTimeDemoMode","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/threadTimeMode$.html","e":true,"i":"","n":"threadTimeMode","t":"threadTimeMode extends PrintingMode","d":"tinyscalautils.text","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/threadTimeMode$.html#print-9b9","e":true,"i":"","n":"print","t":"print(arg: Any, newline: Boolean): Unit","d":"tinyscalautils.text.threadTimeMode","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/timeDemoMode$.html","e":true,"i":"","n":"timeDemoMode","t":"timeDemoMode extends PrintingMode","d":"tinyscalautils.text","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/timeDemoMode$.html#print-9b9","e":true,"i":"","n":"print","t":"print(arg: Any, newline: Boolean): Unit","d":"tinyscalautils.text.timeDemoMode","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/timeMode$.html","e":true,"i":"","n":"timeMode","t":"timeMode extends PrintingMode","d":"tinyscalautils.text","k":"object","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/text/timeMode$.html#print-9b9","e":true,"i":"","n":"print","t":"print(arg: Any, newline: Boolean): Unit","d":"tinyscalautils.text.timeMode","k":"def","x":""}, {"l":"tinyscalautils/threads.html#","e":false,"i":"","n":"tinyscalautils.threads","t":"tinyscalautils.threads","d":"","k":"package","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#acquire-fffffa2d","e":true,"i":"extension (sem: Semaphore)","n":"acquire","t":"acquire(permits: Int, seconds: Double): Boolean","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#availableProcessors-0","e":true,"i":"","n":"availableProcessors","t":"availableProcessors: Int","d":"tinyscalautils.threads","k":"val","x":""}, @@ -142,10 +193,12 @@ pages = [{"l":"index.html#","e":false,"i":"","n":"TinyScalaUtils","t":"TinyScala {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#newThread-29d","e":true,"i":"","n":"newThread","t":"newThread[U](code: => U): Thread","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#offer-fffff59e","e":true,"i":"extension [A](queue: BlockingQueue[A])","n":"offer","t":"offer(value: A, seconds: Double): Boolean","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#orTimeout-ec5","e":true,"i":"extension [A](future: Future[A])","n":"orTimeout","t":"orTimeout(seconds: Double, cancelCode: => Any)(using exec: ExecutionContext, timer: Timer): Future[A]","d":"tinyscalautils.threads","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#poll-fffff782","e":true,"i":"extension [A](queue: BlockingQueue[A])","n":"poll","t":"poll(seconds: Double): A","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#pollOption-fffff3ac","e":true,"i":"extension [A](queue: BlockingQueue[A])","n":"pollOption","t":"pollOption(seconds: Double): Option[A]","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#run-a9e","e":true,"i":"extension (exec: Executor | ExecutionContext)","n":"run","t":"run[U](code: => U): Unit","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#runAsync-d65","e":true,"i":"","n":"runAsync","t":"runAsync[A](code: => A)(using exec: Executor | ExecutionContext): A","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#shutdownAndWait-dc4","e":true,"i":"extension (exec: ExecutorService)","n":"shutdownAndWait","t":"shutdownAndWait(seconds: Double, force: Boolean): Boolean","d":"tinyscalautils.threads","k":"def","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#shutdownAndWait-795","e":true,"i":"extension (exec: ExecutorService)","n":"shutdownAndWait","t":"shutdownAndWait(): Boolean","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#timeoutTimer-0","e":true,"i":"","n":"timeoutTimer","t":"timeoutTimer: Timer","d":"tinyscalautils.threads","k":"given","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#withThreadPoolAndWait-b09","e":true,"i":"","n":"withThreadPoolAndWait","t":"withThreadPoolAndWait[A, Exec](exec: Exec, inline shutdown: Boolean)(code: Exec ?=> Future[A]): A","d":"tinyscalautils.threads","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads.html#withThreads-6d3","e":true,"i":"","n":"withThreads","t":"withThreads[U](maxThreads: Int, awaitTermination: Boolean)(code: ExecutionContextExecutorService ?=> U): Unit","d":"tinyscalautils.threads","k":"def","x":""}, @@ -181,7 +234,8 @@ pages = [{"l":"index.html#","e":false,"i":"","n":"TinyScalaUtils","t":"TinyScala {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/MarkedThreadFactory.html","e":true,"i":"","n":"MarkedThreadFactory","t":"MarkedThreadFactory extends ThreadFactory","d":"tinyscalautils.threads","k":"class","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/MarkedThreadFactory.html#newThread-fffff6cf","e":true,"i":"","n":"newThread","t":"newThread(r: Runnable): Thread","d":"tinyscalautils.threads.MarkedThreadFactory","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/MarkedThreadFactory$.html","e":true,"i":"","n":"MarkedThreadFactory","t":"MarkedThreadFactory extends MarkedThreadFactory","d":"tinyscalautils.threads","k":"object","x":""}, -{"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/Timer.html","e":true,"i":"","n":"Timer","t":"Timer","d":"tinyscalautils.threads","k":"trait","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/Timer.html","e":true,"i":"","n":"Timer","t":"Timer extends AutoCloseable","d":"tinyscalautils.threads","k":"trait","x":""}, +{"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/Timer.html#close-94c","e":true,"i":"","n":"close","t":"close(): Unit","d":"tinyscalautils.threads.Timer","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/Timer.html#execute-fffff8d2","e":true,"i":"","n":"execute","t":"execute[U](delay: Double)(code: => U): Unit","d":"tinyscalautils.threads.Timer","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/Timer.html#schedule-d8c","e":true,"i":"","n":"schedule","t":"schedule[A](delay: Double)(code: => A): Future[A]","d":"tinyscalautils.threads.Timer","k":"def","x":""}, {"l":"https://scala-lang.org/api/3.x/tinyscalautils/threads/Timer.html#scheduleAtFixedRate-fffffc59","e":true,"i":"","n":"scheduleAtFixedRate","t":"scheduleAtFixedRate[U](initDelay: Double, rate: Double)(code: => U): Unit","d":"tinyscalautils.threads.Timer","k":"def","x":""}, diff --git a/docs/tinyscalautils.html b/docs/tinyscalautils.html index c8fdeea..873f074 100644 --- a/docs/tinyscalautils.html +++ b/docs/tinyscalautils.html @@ -1,4 +1,4 @@ -tinyscalautils
In this article
\ No newline at end of file +
In this article
\ No newline at end of file diff --git a/docs/tinyscalautils/assertions.html b/docs/tinyscalautils/assertions.html index 4174396..42cf024 100644 --- a/docs/tinyscalautils/assertions.html +++ b/docs/tinyscalautils/assertions.html @@ -1,4 +1,4 @@ -tinyscalautils.assertions
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/collection.html b/docs/tinyscalautils/collection.html index 0729905..12c20cc 100644 --- a/docs/tinyscalautils/collection.html +++ b/docs/tinyscalautils/collection.html @@ -1,4 +1,4 @@ -tinyscalautils.collection
+tinyscalautils.collection

tinyscalautils.collection

@@ -570,13 +570,13 @@

Attributes

- extension [A](queue: Queue[A]) -
+ extension [A, CC[_]](self: SeqOps[A, CC, CC[A]]) +
- def peekOption: Option[A] + def sortedInReverse[B >: A](using evidence$1: Ordering[B]): CC[A]
@@ -586,25 +586,66 @@

Attributes

-

Like peek but wrapping null in an option.

+

Sorted according to implicit order, but in reverse.

-

Like peek but wrapping null in an option.

+

Sorted according to implicit order, but in reverse.

Attributes

- Since + Source +
+
+ sorted.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+ +

Deprecated extensions

+
+
+ extension [A](queue: Queue[A]) +
+
+ +
+
+ def peekOption: Option[A] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Deprecated
-

1.2

+ [Since version 1.3]
Source
- Queue.scala + Queue.scala
@@ -617,7 +658,7 @@

Attributes

- def pollOption(): Option[A] + def pollOption(): Option[A]
@@ -626,26 +667,21 @@

Attributes

-
-

Like poll but wrapping null in an option.

-
-
-

Like poll but wrapping null in an option.

-
+

Attributes

- Since + Deprecated
-

1.2

+ [Since version 1.3]
Source
- Queue.scala + Queue.scala
@@ -661,4 +697,4 @@

Attributes

-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/collection/ArrayList$$factory$.html b/docs/tinyscalautils/collection/ArrayList$$factory$.html index be9fc6c..07e6de2 100644 --- a/docs/tinyscalautils/collection/ArrayList$$factory$.html +++ b/docs/tinyscalautils/collection/ArrayList$$factory$.html @@ -1,4 +1,4 @@ -factory
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/collection/ArrayList$.html b/docs/tinyscalautils/collection/ArrayList$.html index 4293771..83c7a22 100644 --- a/docs/tinyscalautils/collection/ArrayList$.html +++ b/docs/tinyscalautils/collection/ArrayList$.html @@ -1,4 +1,4 @@ -ArrayList
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/collection/JavaList$.html b/docs/tinyscalautils/collection/JavaList$.html index 84fe0a0..6435eed 100644 --- a/docs/tinyscalautils/collection/JavaList$.html +++ b/docs/tinyscalautils/collection/JavaList$.html @@ -1,4 +1,4 @@ -JavaList
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/collection/JavaListFactory.html b/docs/tinyscalautils/collection/JavaListFactory.html index 1850629..6857ef5 100644 --- a/docs/tinyscalautils/collection/JavaListFactory.html +++ b/docs/tinyscalautils/collection/JavaListFactory.html @@ -1,4 +1,4 @@ -JavaListFactory
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/collection/LinkedList$$factory$.html b/docs/tinyscalautils/collection/LinkedList$$factory$.html index 2e7fe19..04233b2 100644 --- a/docs/tinyscalautils/collection/LinkedList$$factory$.html +++ b/docs/tinyscalautils/collection/LinkedList$$factory$.html @@ -1,4 +1,4 @@ -factory
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/collection/LinkedList$.html b/docs/tinyscalautils/collection/LinkedList$.html index ea1cbf8..d940298 100644 --- a/docs/tinyscalautils/collection/LinkedList$.html +++ b/docs/tinyscalautils/collection/LinkedList$.html @@ -1,4 +1,4 @@ -LinkedList
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/control.html b/docs/tinyscalautils/control.html index abc6f63..5fa6a64 100644 --- a/docs/tinyscalautils/control.html +++ b/docs/tinyscalautils/control.html @@ -1,4 +1,4 @@ -tinyscalautils.control
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/io.html b/docs/tinyscalautils/io.html index 1bebc7a..9f7670b 100644 --- a/docs/tinyscalautils/io.html +++ b/docs/tinyscalautils/io.html @@ -1,4 +1,4 @@ -tinyscalautils.io
+tinyscalautils.io

tinyscalautils.io

@@ -18,23 +18,26 @@

Members list

-
-
+
+
-

Value members

+

Type members

-
+
-

Concrete methods

+

Classlikes

-
+
@@ -44,34 +47,227 @@

Concrete methods

-

The list of lines in a text file, in UTF8 encoding.

+

Text inputs, suitable to the read and readAll functions.

-

The list of lines in a text file, in UTF8 encoding.

+

Text inputs, suitable to the read and readAll functions.

-

Value parameters

+

Attributes

- silent + Companion +
+
+ object +
+
+ Source
-

if true, errors (unreadable files, non-text files, ...) are ignored, and an empty list is returned.

+ Input.scala +
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+
+
+
+
+
+ +
+
+ object Input +
+
+
+
+ +
+
+
+
+

Attributes

- Since + Companion
-

1.0

+ trait +
+
+ Source +
+
+ Input.scala +
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ Input.type +
+
+
+
+
+
+
+
+
+
+
+ + +
+
+ trait Output[-O] +
+
+
+
+ +
+
+
+
+

Text outputs, suitable to the write and writeAll functions.

+
+
+
+

Text outputs, suitable to the write and writeAll functions.

+
+

Attributes

+
+
+ Companion +
+
+ object +
+
+ Source +
+
+ Output.scala +
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+
+
+
+
+
+
+
+ +
+
+ object Output +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Companion +
+
+ trait
Source
- files.scala + Output.scala +
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ Output.type +
+
@@ -79,6 +275,21 @@

Attributes

+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
@@ -111,6 +322,17 @@

Value parameters

Attributes

+
+ Throws +
+
+
+
+ IllegalArgumentException +

if the path is not a directory.

+
+
+
Since
@@ -121,7 +343,7 @@

Attributes

Source
- files.scala + files.scala
@@ -129,12 +351,12 @@

Attributes

-
+
- def parseURL[A, C[_]](url: URL, parser: String => IterableOnce[A], factory: IterableFactory[C]): C[A] + def read[I](in: I, silent: Boolean)(using evidence$1: Input[I]): String
@@ -144,31 +366,25 @@

Attributes

-

Parses a test file (sequence of lines) using a given parser. Lines that parse to an empty sequence (such as None) are ignored.

+

Reads a text file as a single string. Encoding is UTF8.

-

Parses a test file (sequence of lines) using a given parser. Lines that parse to an empty sequence (such as None) are ignored.

+

Reads a text file as a single string. Encoding is UTF8.

Value parameters

- factory -
-
-

a factory for the desired collection type (defaults to List).

-
-
- parser + in
-

the parser to use.

+

the source to read.

- url + silent
-

the source to parse.

+

if true, I/O errors (unreadable files, non-text files, ...) are ignored, and an empty string is returned.

Attributes

@@ -177,13 +393,13 @@

Attributes

Since
-

1.1

+

1.3

Source
- resources.scala + Input.scala
@@ -191,12 +407,12 @@

Attributes

-
+
@@ -206,11 +422,11 @@

Attributes

-

The collection of lines in a text file, in UTF8 encoding.

+

Parses a text file (sequence of lines) using a given parser to split each line. Lines that parse to an empty sequence (such as None) are ignored. Encoding is UTF8.

-

The collection of lines in a text file, in UTF8 encoding.

+

Parses a text file (sequence of lines) using a given parser to split each line. Lines that parse to an empty sequence (such as None) are ignored. Encoding is UTF8.

Value parameters

@@ -220,26 +436,44 @@

Value parameters

a factory for the desired collection type.

+
+ in +
+
+

the source to parse.

+
+
+ parser +
+
+

the parser to use; if omitted, each line is taken as a whole except blank lines, which are ignored.

+
silent
-

if true, errors (unreadable files, non-text files, ...) are ignored, and an empty collection is returned.

+

if true, I/O errors (unreadable files, non-text files, ...) are ignored, and an empty collection is returned.

Attributes

+
+ Returns +
+
+

a factory-based collection of all the parts of all the lines.

+
Since
-

1.0

+

1.3

Source
- files.scala + Input.scala
@@ -247,12 +481,12 @@

Attributes

-
+
@@ -262,40 +496,60 @@

Attributes

-

The collection of files and subdirectories in a directory, in no particular order.

+

Simplified form of readAll that uses List as the factory.

-

The collection of files and subdirectories in a directory, in no particular order.

+

Simplified form of readAll that uses List as the factory.

-

Value parameters

+

Attributes

- factory -
-
-

a factory for the desired collection type.

-
-
- silent + Source
-

if true, errors are ignored, and an empty collection is returned.

+ Input.scala
+
+
+
+
+
+
+
+ +
+
+ def readAll[A, I](in: I, parser: String => IterableOnce[A])(using evidence$1: Input[I]): List[A] +
+
+
+
+ +
+
+
+
+

Simplified form of readAll that uses List as the factory and false for the silent argument.

+
+
+
+

Simplified form of readAll that uses List as the factory and false for the silent argument.

+

Attributes

Since
-

1.0

+

1.3

Source
- files.scala + Input.scala
@@ -303,28 +557,899 @@

Attributes

-
-
-
-
-
-
-
-

Extensions

-
-
-
-
- -

Extensions

-
-
- extension (obj: AnyRef) -
-
- -
-
+
+
+ +
+
+ def readAll[I](in: I, silent: Boolean)(using evidence$1: Input[I]): List[String] +
+
+
+
+ +
+
+
+
+

Simplified form of readAll that does not parse (blank lines are ignored) and uses List as the factory.

+
+
+
+

Simplified form of readAll that does not parse (blank lines are ignored) and uses List as the factory.

+
+

Attributes

+
+
+ Since +
+
+

1.3

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ +
+
+ def readAll[I](in: I)(using evidence$1: Input[I]): List[String] +
+
+
+
+ +
+
+
+
+

Simplified form of readAll that does not parse (blank lines are ignored), uses List as the factory, and uses false for the silent * argument.

+
+
+
+

Simplified form of readAll that does not parse (blank lines are ignored), uses List as the factory, and uses false for the silent * argument.

+
+

Attributes

+
+
+ Since +
+
+

1.3

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+

The collection of files and subdirectories in a directory, in no particular order.

+
+
+
+

The collection of files and subdirectories in a directory, in no particular order.

+
+

Value parameters

+
+
+ factory +
+
+

a factory for the desired collection type.

+
+
+ silent +
+
+

if true, errors are ignored, and an empty collection is returned.

+
+
+

Attributes

+
+
+ Throws +
+
+
+
+ IllegalArgumentException +

if the path is not a directory.

+
+
+
+
+ Since +
+
+

1.0

+
+
+ Source +
+
+ files.scala +
+
+
+
+
+
+
+
+
+ +
+
+ def readingAll[A, I](in: I, parser: String => IterableOnce[A])(using evidence$1: Input[I]): Iterator[A] & Closeable +
+
+
+
+ +
+
+
+
+

Parses a text file (sequence of lines) using a given parser to split each line. Lines that parse to an empty sequence (such as None) are ignored. Encoding is UTF8.

+
+
+
+

Parses a text file (sequence of lines) using a given parser to split each line. Lines that parse to an empty sequence (such as None) are ignored. Encoding is UTF8.

+
+

Value parameters

+
+
+ in +
+
+

the source to parse.

+
+
+ parser +
+
+

the parser to use; if omitted, each line is taken as a whole except blank lines, which are ignored.

+
+
+

Attributes

+
+
+ Returns +
+
+

an iterator of all the parts of all the lines; closing this iterator closes the underlying source.

+
+
+ Since +
+
+

1.3

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ +
+
+ def write[O](out: O, newline: Boolean)(str: CharSequence)(using evidence$1: Output[O]): Unit +
+
+
+
+ +
+
+
+
+

Writes the string into a destination. Nothing is added, unless when newLine = true, which adds a final newline. Encoding is UTF8.

+
+
+
+

Writes the string into a destination. Nothing is added, unless when newLine = true, which adds a final newline. Encoding is UTF8.

+
+

Value parameters

+
+
+ newline +
+
+

when true, adds a final newline to the output.

+
+
+ out +
+
+

the destination to write to.

+
+
+

Attributes

+
+
+ Note +
+
+
+
+

Uses CharSequence instead of Any to avoid accidental calls to write that were intended to be writeAll.

+
+
+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+ +
+
+ def writeAll[A, O](pre: String, sep: String, post: String)(out: O)(values: IterableOnce[A])(using evidence$1: Output[O]): Unit +
+
+
+
+ +
+
+
+
+

Writes the string representations of a collection of values into a destination. The three arguments pre, sep, and post are as in mkString. Encoding is UTF8.

+
+
+
+

Writes the string representations of a collection of values into a destination. The three arguments pre, sep, and post are as in mkString. Encoding is UTF8.

+
+

Value parameters

+
+
+ out +
+
+

the destination to write to.

+
+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+ +
+
+ def writeAll[A, O](out: O)(values: IterableOnce[A])(using evidence$1: Output[O]): Unit +
+
+
+
+ +
+
+
+
+

Writes the string representations of a collection of values into a destination. Each value is followed by a newline, including the last.

+
+
+
+

Writes the string representations of a collection of values into a destination. Each value is followed by a newline, including the last.

+
+

Value parameters

+
+
+ out +
+
+

the destination to write to.

+
+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+
+
+
+ +

Deprecated methods

+
+
+
+ + +
+
+ +
+
+
+
+
+

Attributes

+
+
+ Deprecated +
+
+ [Since version 1.3] +
+
+ Source +
+
+ files.scala +
+
+
+
+
+
+
+
+
+ +
+
+ def parseURL[A, C[_]](url: URL, parser: String => IterableOnce[A], factory: IterableFactory[C]): C[A] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Deprecated +
+
+ [Since version 1.3] +
+
+ Source +
+
+ resources.scala +
+
+
+
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+

Attributes

+
+
+ Deprecated +
+
+ [Since version 1.3] +
+
+ Source +
+
+ files.scala +
+
+
+
+
+
+
+
+
+
+
+
+ +

Concrete fields

+
+
+
+ +
+
+ lazy val noParsing: String => IterableOnce[String] +
+
+
+
+ +
+
+
+
+

Identity parsing. By using it as a parser argument of readAll, lines are returned unchanged.

+
+
+
+

Identity parsing. By using it as a parser argument of readAll, lines are returned unchanged.

+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Givens

+
+
+
+
+ +

Givens

+
+
+
+ +
+
+ given FileIsInput: Input[File] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ +
+
+ given FileIsOutput: Output[File] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ + +
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+ +
+
+ given PathIsInput: Input[Path] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ +
+
+ given PathIsOutput: Output[Path] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+ +
+
+ given SourceIsInput: Input[Source] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ +
+
+ given URLIsInput: Input[URL] +
+
+
+
+ +
+
+
+
+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Extensions

+
+
+
+
+ +

Extensions

+
+
+ extension [I](in: I)(using evidence$1: Input[I]) +
+
+ +
+
+ def source: Source +
+
+
+
+ +
+
+
+
+

Opens the input as a source.

+
+
+
+

Opens the input as a source.

+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+ extension (obj: AnyRef) +
+
+ + @@ -364,7 +1489,210 @@

Attributes

Source
- resources.scala + resources.scala +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+

Finds the given resource as a URL. This is simply a call to getClass.getResource that falls back to a default location instead of returning null. Note that this findResource variant does not throw MissingResourceException.

+
+
+
+

Finds the given resource as a URL. This is simply a call to getClass.getResource that falls back to a default location instead of returning null. Note that this findResource variant does not throw MissingResourceException.

+

Like getResource, paths that start with a slash are absolute, and relative paths are relative to the full package name. Paths are always treated as relative to the URI when the fallback is used.

+
+

Value parameters

+
+
+ fallback +
+
+

a fallback URI, which must be absolute.

+
+
+

Attributes

+
+
+ See also +
+
+ +
+
+ Since +
+
+

1.3

+
+
+ Source +
+
+ resources.scala +
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+

Finds the given resource as a stream. If the resource is not found, then name.gz is tried instead and, if found, opened as GZIP compressed data. (If name already ends with .gz, no attempt is made with a .gz.gz name.)

+
+
+
+

Finds the given resource as a stream. If the resource is not found, then name.gz is tried instead and, if found, opened as GZIP compressed data. (If name already ends with .gz, no attempt is made with a .gz.gz name.)

+

Like getResource, paths that start with a slash are absolute, and relative paths are relative to the full package name.

+
+

Attributes

+
+
+ See also +
+
+
+
+

java.lang.Class.getResource Throws java.util.MissingResourceException if the resource is not found.

+
+
+
+
+ Since +
+
+

1.3

+
+
+ Source +
+
+ resources.scala +
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+

Finds the given resource as a stream. If the resource is not found, then name.gz is tried instead. If neither is found locally, the fallback location is used to search for name.gz first and, if unsuccessful, for name. When a .gz file is found, either locally or remotely, it is opened as GZIP compressed data. If name already ends with .gz, no attempt is made with a .gz.gz name.

+
+
+
+

Finds the given resource as a stream. If the resource is not found, then name.gz is tried instead. If neither is found locally, the fallback location is used to search for name.gz first and, if unsuccessful, for name. When a .gz file is found, either locally or remotely, it is opened as GZIP compressed data. If name already ends with .gz, no attempt is made with a .gz.gz name.

+

Like getClass.getResource, paths that start with a slash are absolute, and relative paths are relative to the full package name.

+
+

Attributes

+
+
+ See also +
+
+ +
+
+ Since +
+
+

1.3

+
+
+ Source +
+
+ resources.scala +
+
+
+
+
+
+
+ +
+ extension [O](out: O)(using evidence$1: Output[O]) +
+
+ +
+ +
+
+
+ +
+
+
+
+

Opens the output as a stream.

+
+
+
+

Opens the output as a stream.

+
+

Attributes

+
+
+ Source +
+
+ Output.scala
@@ -380,4 +1708,4 @@

Attributes

-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/io/Input$.html b/docs/tinyscalautils/io/Input$.html new file mode 100644 index 0000000..12e4484 --- /dev/null +++ b/docs/tinyscalautils/io/Input$.html @@ -0,0 +1,147 @@ +Input
+ +

Input

+
+
+ tinyscalautils.io.Input +
+
+ See theInput companion trait +
+
+
+ object Input +
+
+
+
+
+

Attributes

+
+
+ Companion +
+
+ trait +
+
+ Source +
+
+ Input.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ Input.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+
+
+ +
+
+ def apply[I](using evidence$1: Input[I]): Input[I] +
+
+
+
+ +
+
+
+
+

Summon.

+
+
+
+

Summon.

+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/io/Input.html b/docs/tinyscalautils/io/Input.html new file mode 100644 index 0000000..794d8ed --- /dev/null +++ b/docs/tinyscalautils/io/Input.html @@ -0,0 +1,139 @@ +Input
+ +

Input

+
+
+ tinyscalautils.io.Input +
+
+ See theInput companion object +
+
+ @FunctionalInterface +
+ trait Input[-I] +
+
+
+
+

Text inputs, suitable to the read and readAll functions.

+
+
+

Attributes

+
+
+ Companion +
+
+ object +
+
+ Source +
+
+ Input.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Abstract methods

+
+
+
+ +
+
+ def source(in: I): Source +
+
+
+
+ +
+
+
+
+

Opens the input as a source.

+
+
+
+

Opens the input as a source.

+
+

Attributes

+
+
+ Source +
+
+ Input.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/io/Output$.html b/docs/tinyscalautils/io/Output$.html new file mode 100644 index 0000000..a59faae --- /dev/null +++ b/docs/tinyscalautils/io/Output$.html @@ -0,0 +1,147 @@ +Output
+ +

Output

+
+
+ tinyscalautils.io.Output +
+
+ See theOutput companion trait +
+
+
+ object Output +
+
+
+
+
+

Attributes

+
+
+ Companion +
+
+ trait +
+
+ Source +
+
+ Output.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ Output.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+
+
+ +
+
+ def apply[O](using evidence$1: Output[O]): Output[O] +
+
+
+
+ +
+
+
+
+

Summon.

+
+
+
+

Summon.

+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/io/Output.html b/docs/tinyscalautils/io/Output.html new file mode 100644 index 0000000..db1fd67 --- /dev/null +++ b/docs/tinyscalautils/io/Output.html @@ -0,0 +1,139 @@ +Output
+ +

Output

+
+
+ tinyscalautils.io.Output +
+
+ See theOutput companion object +
+
+ @FunctionalInterface +
+ trait Output[-O] +
+
+
+
+

Text outputs, suitable to the write and writeAll functions.

+
+
+

Attributes

+
+
+ Companion +
+
+ object +
+
+ Source +
+
+ Output.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Abstract methods

+
+
+
+ +
+ +
+
+
+ +
+
+
+
+

Opens the output as a stream.

+
+
+
+

Opens the output as a stream.

+
+

Attributes

+
+
+ Source +
+
+ Output.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/lang.html b/docs/tinyscalautils/lang.html index 2a05226..9fd1300 100644 --- a/docs/tinyscalautils/lang.html +++ b/docs/tinyscalautils/lang.html @@ -1,4 +1,4 @@ -tinyscalautils.lang
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/lang/InterruptibleConstructor.html b/docs/tinyscalautils/lang/InterruptibleConstructor.html index f9850ef..1999b8f 100644 --- a/docs/tinyscalautils/lang/InterruptibleConstructor.html +++ b/docs/tinyscalautils/lang/InterruptibleConstructor.html @@ -1,4 +1,4 @@ -InterruptibleConstructor
-
In this article
\ No newline at end of file +
In this article
\ No newline at end of file diff --git a/docs/tinyscalautils/lang/InterruptibleEquality.html b/docs/tinyscalautils/lang/InterruptibleEquality.html index f958d03..b8380b9 100644 --- a/docs/tinyscalautils/lang/InterruptibleEquality.html +++ b/docs/tinyscalautils/lang/InterruptibleEquality.html @@ -1,4 +1,4 @@ -InterruptibleEquality
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/lang/StackOverflowException.html b/docs/tinyscalautils/lang/StackOverflowException.html index 422a168..422ef80 100644 --- a/docs/tinyscalautils/lang/StackOverflowException.html +++ b/docs/tinyscalautils/lang/StackOverflowException.html @@ -1,4 +1,4 @@ -StackOverflowException
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/text.html b/docs/tinyscalautils/text.html index 12e5e59..efff3da 100644 --- a/docs/tinyscalautils/text.html +++ b/docs/tinyscalautils/text.html @@ -1,4 +1,4 @@ -tinyscalautils.text
+
+
+ +
+
+ object silentMode extends PrintingMode +
+
+
+
+ +
+
+
+
+

Silent. Does not print anything. No call to Predef.printf/println takes place.

+
+
+
+

Silent. Does not print anything. No call to Predef.printf/println takes place.

+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ silentMode.type +
+
+
+
+
+
+
+
+
+
+
+ +
+
+ object standardMode extends PrintingMode +
+
+
+
+ +
+
+
+
+

Standard printing. Equivalent to Predef.printf/println.

+
+
+
+

Standard printing. Equivalent to Predef.printf/println.

+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ standardMode.type +
+
+
+
+
+
+
+
+
+
+
+ +
+
+ object threadMode extends PrintingMode +
+
+
+
+ +
+
+
+
+

Adds thread name. Strings are printed as: <thread>: <string>.

+
+
+
+

Adds thread name. Strings are printed as: <thread>: <string>.

+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ threadMode.type +
+
+
+
+
+
+
+
+
+
+
+ +
+
+ object threadTimeDemoMode extends PrintingMode +
+
+
+
+ +
+
+
+
+

Adds thread name and time, but hides hours and minutes. Strings are printed as: <thread> at XX:XX:SS.millis: <string>

+
+
+
+

Adds thread name and time, but hides hours and minutes. Strings are printed as: <thread> at XX:XX:SS.millis: <string>

+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+ +
+
+ object threadTimeMode extends PrintingMode +
+
+
+
+ +
+
+
+
+

Adds thread name and time. Strings are printed as: <thread> at HH:MM:SS.millis: <string>

+
+
+
+

Adds thread name and time. Strings are printed as: <thread> at HH:MM:SS.millis: <string>

+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ threadTimeMode.type +
+
+
+
+
+
+
+
+
+
+
+ +
+
+ object timeDemoMode extends PrintingMode +
+
+
+
+ +
+
+
+
+

Adds time, but hides hours and minutes. Strings are printed as: at XX:XX:SS.millis: <string>

+
+
+
+

Adds time, but hides hours and minutes. Strings are printed as: at XX:XX:SS.millis: <string>

+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ timeDemoMode.type +
+
+
+
+
+
+
+
+
+
+
+ +
+
+ object timeMode extends PrintingMode +
+
+
+
+ +
+
+
+
+

Adds time. Strings are printed as: at HH:MM:SS.millis: <string>

+
+
+
+

Adds time. Strings are printed as: at HH:MM:SS.millis: <string>

+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ timeMode.type +
+
+
+
+
+
+
+
+
@@ -249,6 +732,41 @@

Value members

Concrete methods

+
+
+ +
+
+ inline def dot[A, M <: PrintingMode](any: A, theDot: Char)(using mode: M): A +
+
+
+
+ +
+
+
+
+

Returns its input and prints a single dot, according to the given printing mode. The only possible modes are standardMode (by default) and silentMode.

+
+
+
+

Returns its input and prints a single dot, according to the given printing mode. The only possible modes are standardMode (by default) and silentMode.

+
+

Attributes

+
+
+ Source +
+
+ Dot.scala +
+
+
+
+
+
+
@@ -560,7 +1078,7 @@

Attributes

-

System.setOut

+

java.lang.System.setOut

Console.withOut

@@ -627,6 +1145,41 @@

Attributes

+
+
+ +
+
+ def star[A](any: A)(using mode: PrintingMode): A +
+
+
+
+ +
+
+
+
+

Returns its input and prints a single star, according to the given printing mode. The only possible modes are standardMode (by default) and silentMode.

+
+
+
+

Returns its input and prints a single star, according to the given printing mode. The only possible modes are standardMode (by default) and silentMode.

+
+

Attributes

+
+
+ Source +
+
+ Dot.scala +
+
+
+
+
+
+
@@ -708,7 +1261,7 @@

Givens

@@ -730,7 +1283,7 @@

Attributes

Source
- PrintingMode.scala + PrintingMode.scala
@@ -743,7 +1296,7 @@

Attributes

@@ -765,7 +1318,7 @@

Attributes

Source
- PrintingMode.scala + PrintingMode.scala
@@ -778,7 +1331,7 @@

Attributes

@@ -800,7 +1353,7 @@

Attributes

Source
- PrintingMode.scala + PrintingMode.scala
@@ -813,7 +1366,7 @@

Attributes

@@ -835,7 +1388,7 @@

Attributes

Source
- PrintingMode.scala + PrintingMode.scala
@@ -848,7 +1401,7 @@

Attributes

@@ -870,7 +1423,7 @@

Attributes

Source
- PrintingMode.scala + PrintingMode.scala
@@ -883,7 +1436,7 @@

Attributes

@@ -905,7 +1458,7 @@

Attributes

Source
- PrintingMode.scala + PrintingMode.scala
@@ -918,7 +1471,7 @@

Attributes

@@ -940,7 +1493,7 @@

Attributes

Source
- PrintingMode.scala + PrintingMode.scala
@@ -1162,4 +1715,4 @@

Attributes

-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/text/CharLetters$.html b/docs/tinyscalautils/text/CharLetters$.html index 59f29f6..8d408f3 100644 --- a/docs/tinyscalautils/text/CharLetters$.html +++ b/docs/tinyscalautils/text/CharLetters$.html @@ -1,4 +1,4 @@ -CharLetters
\ No newline at end of file + \ No newline at end of file diff --git a/docs/tinyscalautils/text/PrintingMode.html b/docs/tinyscalautils/text/PrintingMode.html index ba3edf5..f90b4ac 100644 --- a/docs/tinyscalautils/text/PrintingMode.html +++ b/docs/tinyscalautils/text/PrintingMode.html @@ -1,4 +1,4 @@ -PrintingMode
+PrintingMode

PrintingMode

@@ -65,12 +65,26 @@

Attributes

node1 [id=node1, label="class Object", class="class vertex"]; node2 [id=node2, label="class Any", class="class vertex"]; node3 [id=node3, label="trait Matchable", class="trait vertex"]; +node4 [id=node4, label="object silentMode", class="object vertex"]; +node5 [id=node5, label="object standardMode", class="object vertex"]; +node6 [id=node6, label="object threadMode", class="object vertex"]; +node7 [id=node7, label="object threadTimeDemoMode", class="object vertex"]; +node8 [id=node8, label="object threadTimeMode", class="object vertex"]; +node9 [id=node9, label="object timeDemoMode", class="object vertex"]; +node10 [id=node10, label="object timeMode", class="object vertex"]; node0 -> node1; node1 -> node2; node1 -> node3; node3 -> node2; +node4 -> node0; +node5 -> node0; +node6 -> node0; +node7 -> node0; +node8 -> node0; +node9 -> node0; +node10 -> node0; } @@ -92,6 +106,34 @@

Attributes

+
+ Known subtypes +
+
+
+
+ object silentMode +
+
+ object standardMode +
+
+ object threadMode +
+
+ object threadTimeDemoMode +
+
+ object threadTimeMode +
+
+ object timeDemoMode +
+
+ object timeMode +
Show all +
+
@@ -234,4 +276,4 @@

Attributes

-
\ No newline at end of file + \ No newline at end of file diff --git a/docs/tinyscalautils/text/StringLetters$.html b/docs/tinyscalautils/text/StringLetters$.html index cee14fe..2b17846 100644 --- a/docs/tinyscalautils/text/StringLetters$.html +++ b/docs/tinyscalautils/text/StringLetters$.html @@ -1,4 +1,4 @@ -StringLetters
\ No newline at end of file diff --git a/docs/tinyscalautils/text/silentMode$.html b/docs/tinyscalautils/text/silentMode$.html new file mode 100644 index 0000000..675bf33 --- /dev/null +++ b/docs/tinyscalautils/text/silentMode$.html @@ -0,0 +1,236 @@ +silentMode
+ +

silentMode

+
+
+ tinyscalautils.text.PrintingMode$package.silentMode +
+
+
+ object silentMode extends PrintingMode +
+
+
+
+

Silent. Does not print anything. No call to Predef.printf/println takes place.

+
+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ silentMode.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+ +
+
+
+
+
+ +

Inherited methods

+
+
+
+ +
+
+ final def printf(format: String, args: Any*): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a format.

+
+
+
+

Formatted printing with a format.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+ +
+
+ final def println(arg: Any): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a newline.

+
+
+
+

Formatted printing with a newline.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/text/standardMode$.html b/docs/tinyscalautils/text/standardMode$.html new file mode 100644 index 0000000..bf65213 --- /dev/null +++ b/docs/tinyscalautils/text/standardMode$.html @@ -0,0 +1,236 @@ +standardMode
+ +

standardMode

+
+
+ tinyscalautils.text.PrintingMode$package.standardMode +
+
+
+ object standardMode extends PrintingMode +
+
+
+
+

Standard printing. Equivalent to Predef.printf/println.

+
+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ standardMode.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+ +
+
+
+
+
+ +

Inherited methods

+
+
+
+ +
+
+ final def printf(format: String, args: Any*): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a format.

+
+
+
+

Formatted printing with a format.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+ +
+
+ final def println(arg: Any): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a newline.

+
+
+
+

Formatted printing with a newline.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/text/threadMode$.html b/docs/tinyscalautils/text/threadMode$.html new file mode 100644 index 0000000..5e72161 --- /dev/null +++ b/docs/tinyscalautils/text/threadMode$.html @@ -0,0 +1,236 @@ +threadMode
+ +

threadMode

+
+
+ tinyscalautils.text.PrintingMode$package.threadMode +
+
+
+ object threadMode extends PrintingMode +
+
+
+
+

Adds thread name. Strings are printed as: <thread>: <string>.

+
+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ threadMode.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+ +
+
+
+
+
+ +

Inherited methods

+
+
+
+ +
+
+ final def printf(format: String, args: Any*): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a format.

+
+
+
+

Formatted printing with a format.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+ +
+
+ final def println(arg: Any): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a newline.

+
+
+
+

Formatted printing with a newline.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/text/threadTimeDemoMode$.html b/docs/tinyscalautils/text/threadTimeDemoMode$.html new file mode 100644 index 0000000..9652138 --- /dev/null +++ b/docs/tinyscalautils/text/threadTimeDemoMode$.html @@ -0,0 +1,236 @@ +threadTimeDemoMode
+ +

threadTimeDemoMode

+
+
+ tinyscalautils.text.PrintingMode$package.threadTimeDemoMode +
+
+
+ object threadTimeDemoMode extends PrintingMode +
+
+
+
+

Adds thread name and time, but hides hours and minutes. Strings are printed as: <thread> at XX:XX:SS.millis: <string>

+
+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ + +
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+ +
+
+
+
+
+ +

Inherited methods

+
+
+
+ +
+
+ final def printf(format: String, args: Any*): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a format.

+
+
+
+

Formatted printing with a format.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+ +
+
+ final def println(arg: Any): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a newline.

+
+
+
+

Formatted printing with a newline.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/text/threadTimeMode$.html b/docs/tinyscalautils/text/threadTimeMode$.html new file mode 100644 index 0000000..8ebac1e --- /dev/null +++ b/docs/tinyscalautils/text/threadTimeMode$.html @@ -0,0 +1,236 @@ +threadTimeMode
+ +

threadTimeMode

+
+
+ tinyscalautils.text.PrintingMode$package.threadTimeMode +
+
+
+ object threadTimeMode extends PrintingMode +
+
+
+
+

Adds thread name and time. Strings are printed as: <thread> at HH:MM:SS.millis: <string>

+
+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ threadTimeMode.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+ +
+
+
+
+
+ +

Inherited methods

+
+
+
+ +
+
+ final def printf(format: String, args: Any*): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a format.

+
+
+
+

Formatted printing with a format.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+ +
+
+ final def println(arg: Any): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a newline.

+
+
+
+

Formatted printing with a newline.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/text/timeDemoMode$.html b/docs/tinyscalautils/text/timeDemoMode$.html new file mode 100644 index 0000000..2355395 --- /dev/null +++ b/docs/tinyscalautils/text/timeDemoMode$.html @@ -0,0 +1,236 @@ +timeDemoMode
+ +

timeDemoMode

+
+
+ tinyscalautils.text.PrintingMode$package.timeDemoMode +
+
+
+ object timeDemoMode extends PrintingMode +
+
+
+
+

Adds time, but hides hours and minutes. Strings are printed as: at XX:XX:SS.millis: <string>

+
+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ timeDemoMode.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+ +
+
+
+
+
+ +

Inherited methods

+
+
+
+ +
+
+ final def printf(format: String, args: Any*): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a format.

+
+
+
+

Formatted printing with a format.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+ +
+
+ final def println(arg: Any): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a newline.

+
+
+
+

Formatted printing with a newline.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/text/timeMode$.html b/docs/tinyscalautils/text/timeMode$.html new file mode 100644 index 0000000..ba02a23 --- /dev/null +++ b/docs/tinyscalautils/text/timeMode$.html @@ -0,0 +1,236 @@ +timeMode
+ +

timeMode

+
+
+ tinyscalautils.text.PrintingMode$package.timeMode +
+
+
+ object timeMode extends PrintingMode +
+
+
+
+

Adds time. Strings are printed as: at HH:MM:SS.millis: <string>

+
+
+

Attributes

+
+
+ Source +
+
+ PrintingMode.scala +
+
+ Graph +
+
+
+ + + +
+
+
+ Supertypes +
+
+
+
+ trait PrintingMode +
+
+ class Object +
+
+ trait Matchable +
+
+ class Any +
+
+
+
+ Self type +
+
+
+ +
+ timeMode.type +
+
+
+
+
+
+
+

Members list

+
+
+
+
+
+
+
+
+
+

Value members

+
+
+
+
+ +

Concrete methods

+
+ +
+
+
+
+
+ +

Inherited methods

+
+
+
+ +
+
+ final def printf(format: String, args: Any*): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a format.

+
+
+
+

Formatted printing with a format.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+ +
+
+ final def println(arg: Any): Unit +
+
+
+
+ +
+
+
+
+

Formatted printing with a newline.

+
+
+
+

Formatted printing with a newline.

+
+

Attributes

+
+
+ Inherited from: +
+
+ PrintingMode +
+
+ Source +
+
+ PrintingMode.scala +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/docs/tinyscalautils/threads.html b/docs/tinyscalautils/threads.html index 8d0342e..095feb2 100644 --- a/docs/tinyscalautils/threads.html +++ b/docs/tinyscalautils/threads.html @@ -1,4 +1,4 @@ -tinyscalautils.threads
+tinyscalautils.threads

tinyscalautils.threads

@@ -56,7 +56,7 @@

Attributes

Source
- Timer.scala + Timer.scala
Supertypes @@ -401,7 +401,7 @@

Attributes

-

MarkedThreadsFactory

+

MarkedThreadFactory

@@ -706,7 +706,7 @@

Attributes

Source
- MarkedThreadFactory.scala + MarkedThreadFactory.scala
Supertypes @@ -752,7 +752,7 @@

Attributes

- trait Timer + trait Timer extends AutoCloseable
@@ -787,6 +787,9 @@

Attributes

+
+ trait AutoCloseable +
class Object
@@ -1436,7 +1439,7 @@

Attributes

Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -1499,7 +1502,7 @@

Attributes

Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -1562,7 +1565,54 @@

Attributes

Source
- timeout-extensions.scala + timeout-extensions.scala +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+

Shuts down the executor and waits forever for termination.

+
+
+
+

Shuts down the executor and waits forever for termination.

+
+

Attributes

+
+
+ Returns +
+
+

true.

+
+
+ Since +
+
+

1.0

+
+
+ Source +
+
+ timeout-extensions.scala
@@ -1792,7 +1842,7 @@

Attributes

Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -1827,7 +1877,7 @@

Attributes

Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -1862,7 +1912,7 @@

Attributes

Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -1872,13 +1922,13 @@

Attributes

- extension [A](queue: BlockingQueue[A]) -
+ extension (sem: Semaphore) +
@@ -1888,11 +1938,11 @@

Attributes

-

Like offer but timeout in seconds.

+

Same as standard tryAcquire but in seconds.

-

Like offer but timeout in seconds.

+

Same as standard tryAcquire but in seconds.

Attributes

@@ -1900,13 +1950,23 @@

Attributes

Since
-

1.2

+

1.1

+
+
+ Note +
+
+
+
+

Should be named tryAcquire, but that conflicts with existing signatures.

+
+
Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -1914,12 +1974,15 @@

Attributes

-
+
+
+ extension (thread: Thread) +
@@ -1929,25 +1992,35 @@

Attributes

-

Like poll but timeout in seconds and null wrapped in an option.

+

Adds an isMarkedThread method to threads.

-

Like poll but timeout in seconds and null wrapped in an option.

+

Adds an isMarkedThread method to threads.

Attributes

+
+ See also +
+
+
+ +
+
Since
-

1.2

+

1.0

Source
- timeout-extensions.scala + MarkedThread.scala
@@ -1957,13 +2030,13 @@

Attributes

- extension (sem: Semaphore) -
+ extension (thread: Thread) +
@@ -1973,35 +2046,34 @@

Attributes

-

Same as standard tryAcquire but in seconds.

+

Waits for thread termination.

-

Same as standard tryAcquire but in seconds.

+

Waits for thread termination.

-

Attributes

+

Value parameters

- Since + seconds
-

1.1

+

timeout, in seconds.

+
+

Attributes

+
- Note + Returns
-
-
-

Should be named tryAcquire, but that conflicts with existing signatures.

-
-
+

true is thread terminates within time limit.

Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -2010,14 +2082,22 @@

Attributes

+
+ +
+
+
+ +

Deprecated extensions

+
- extension (thread: Thread) -
+ extension [A](queue: BlockingQueue[A]) +
@@ -2027,35 +2107,25 @@

Attributes

-

Adds an isMarkedThread method to threads.

+

Like offer but timeout in seconds.

-

Adds an isMarkedThread method to threads.

+

Like offer but timeout in seconds.

Attributes

-
- See also -
-
-
- -
-
Since
-

1.0

+

1.2

Source
- MarkedThread.scala + timeout-extensions.scala
@@ -2063,15 +2133,12 @@

Attributes

-
-
- extension (thread: Thread) -
+
@@ -2081,34 +2148,61 @@

Attributes

-

Waits for thread termination.

+

Like poll but timeout in seconds.

-

Waits for thread termination.

+

Like poll but timeout in seconds.

-

Value parameters

+

Attributes

- seconds + Since
-

timeout, in seconds.

+

1.3

+
+
+ Source +
+
+ timeout-extensions.scala
+
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+

Attributes

- Returns + Deprecated
-

true is thread terminates within time limit.

+ [Since version 1.3]
Source
- timeout-extensions.scala + timeout-extensions.scala
@@ -2124,4 +2218,4 @@

Attributes

-
\ No newline at end of file + \ No newline at end of file diff --git a/docs/tinyscalautils/threads/DelayedFuture$.html b/docs/tinyscalautils/threads/DelayedFuture$.html index 085c200..84316af 100644 --- a/docs/tinyscalautils/threads/DelayedFuture$.html +++ b/docs/tinyscalautils/threads/DelayedFuture$.html @@ -1,4 +1,4 @@ -DelayedFuture
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/Execute$.html b/docs/tinyscalautils/threads/Execute$.html index 66c13ab..c60a045 100644 --- a/docs/tinyscalautils/threads/Execute$.html +++ b/docs/tinyscalautils/threads/Execute$.html @@ -1,4 +1,4 @@ -Execute
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/ExecuteAfter$.html b/docs/tinyscalautils/threads/ExecuteAfter$.html index 3da97cb..79250b0 100644 --- a/docs/tinyscalautils/threads/ExecuteAfter$.html +++ b/docs/tinyscalautils/threads/ExecuteAfter$.html @@ -1,4 +1,4 @@ -ExecuteAfter
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/Executors$.html b/docs/tinyscalautils/threads/Executors$.html index 648c951..35a42ea 100644 --- a/docs/tinyscalautils/threads/Executors$.html +++ b/docs/tinyscalautils/threads/Executors$.html @@ -1,4 +1,4 @@ -Executors
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/Executors.html b/docs/tinyscalautils/threads/Executors.html index 881ad07..41fe84d 100644 --- a/docs/tinyscalautils/threads/Executors.html +++ b/docs/tinyscalautils/threads/Executors.html @@ -1,4 +1,4 @@ -Executors
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/KeepThreadsFactory$.html b/docs/tinyscalautils/threads/KeepThreadsFactory$.html index 34d0e7a..7a69910 100644 --- a/docs/tinyscalautils/threads/KeepThreadsFactory$.html +++ b/docs/tinyscalautils/threads/KeepThreadsFactory$.html @@ -1,4 +1,4 @@ -KeepThreadsFactory
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/KeepThreadsFactory.html b/docs/tinyscalautils/threads/KeepThreadsFactory.html index 4b28338..ff4c5bc 100644 --- a/docs/tinyscalautils/threads/KeepThreadsFactory.html +++ b/docs/tinyscalautils/threads/KeepThreadsFactory.html @@ -1,4 +1,4 @@ -KeepThreadsFactory
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/MarkedThread.html b/docs/tinyscalautils/threads/MarkedThread.html index 1db8c15..dd79e2d 100644 --- a/docs/tinyscalautils/threads/MarkedThread.html +++ b/docs/tinyscalautils/threads/MarkedThread.html @@ -1,4 +1,4 @@ -MarkedThread
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/MarkedThreadFactory$.html b/docs/tinyscalautils/threads/MarkedThreadFactory$.html index 8671bbc..e5198e1 100644 --- a/docs/tinyscalautils/threads/MarkedThreadFactory$.html +++ b/docs/tinyscalautils/threads/MarkedThreadFactory$.html @@ -1,4 +1,4 @@ -MarkedThreadFactory
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/MarkedThreadFactory.html b/docs/tinyscalautils/threads/MarkedThreadFactory.html index 24f0155..d42d402 100644 --- a/docs/tinyscalautils/threads/MarkedThreadFactory.html +++ b/docs/tinyscalautils/threads/MarkedThreadFactory.html @@ -1,4 +1,4 @@ -MarkedThreadFactory
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tinyscalautils/threads/Timer.html b/docs/tinyscalautils/threads/Timer.html index 9b3f170..2fefc0e 100644 --- a/docs/tinyscalautils/threads/Timer.html +++ b/docs/tinyscalautils/threads/Timer.html @@ -1,4 +1,4 @@ -Timer
+Timer

Timer

@@ -7,7 +7,7 @@

Timer

- trait Timer + trait Timer extends AutoCloseable
@@ -41,12 +41,15 @@

Attributes

node1 [id=node1, label="class Object", class="class vertex"]; node2 [id=node2, label="class Any", class="class vertex"]; node3 [id=node3, label="trait Matchable", class="trait vertex"]; +node4 [id=node4, label="trait AutoCloseable", class="trait vertex"]; node0 -> node1; node1 -> node2; node1 -> node3; node3 -> node2; +node0 -> node4; +node4 -> node1; } @@ -57,6 +60,9 @@

Attributes

+
+ trait AutoCloseable +
class Object
@@ -270,9 +276,58 @@

Attributes

+
+
+
+ +

Concrete methods

+
+
+
+ +
+
+ final def close(): Unit +
+
+
+
+ +
+
+
+
+

Alias for shutdown to implement AutoCloseable.

+
+
+
+

Alias for shutdown to implement AutoCloseable.

+
+

Attributes

+
+
+ Since +
+
+

1.3

+
+
+ Source +
+
+ Timer.scala +
+
+
+
+
+
+
+
+
-
\ No newline at end of file + \ No newline at end of file diff --git a/docs/tinyscalautils/timing.html b/docs/tinyscalautils/timing.html index b479567..5df1210 100644 --- a/docs/tinyscalautils/timing.html +++ b/docs/tinyscalautils/timing.html @@ -1,4 +1,4 @@ -tinyscalautils.timing
\ No newline at end of file diff --git a/docs/tinyscalautils/timing/SlowIterator$.html b/docs/tinyscalautils/timing/SlowIterator$.html index 0d76452..d143071 100644 --- a/docs/tinyscalautils/timing/SlowIterator$.html +++ b/docs/tinyscalautils/timing/SlowIterator$.html @@ -1,4 +1,4 @@ -SlowIterator
\ No newline at end of file diff --git a/docs/tinyscalautils/timing/SlowLazyList$.html b/docs/tinyscalautils/timing/SlowLazyList$.html index d4b62a0..b8b5044 100644 --- a/docs/tinyscalautils/timing/SlowLazyList$.html +++ b/docs/tinyscalautils/timing/SlowLazyList$.html @@ -1,4 +1,4 @@ -SlowLazyList
\ No newline at end of file diff --git a/docs/tinyscalautils/timing/SlowSource$.html b/docs/tinyscalautils/timing/SlowSource$.html index 398acbe..39bc8ba 100644 --- a/docs/tinyscalautils/timing/SlowSource$.html +++ b/docs/tinyscalautils/timing/SlowSource$.html @@ -1,4 +1,4 @@ -SlowSource
\ No newline at end of file diff --git a/docs/tinyscalautils/util.html b/docs/tinyscalautils/util.html index 2382eb9..2fe0092 100644 --- a/docs/tinyscalautils/util.html +++ b/docs/tinyscalautils/util.html @@ -1,4 +1,4 @@ -tinyscalautils.util
\ No newline at end of file diff --git a/docs/tinyscalautils/util/FastRandom$.html b/docs/tinyscalautils/util/FastRandom$.html index 0d37251..1eb0596 100644 --- a/docs/tinyscalautils/util/FastRandom$.html +++ b/docs/tinyscalautils/util/FastRandom$.html @@ -1,4 +1,4 @@ -FastRandom
\ No newline at end of file diff --git a/docs/tinyscalautils/util/FastRandom.html b/docs/tinyscalautils/util/FastRandom.html index cbfac9f..7d5441f 100644 --- a/docs/tinyscalautils/util/FastRandom.html +++ b/docs/tinyscalautils/util/FastRandom.html @@ -1,4 +1,4 @@ -FastRandom
\ No newline at end of file diff --git a/project/build.properties b/project/build.properties index 04267b1..ee4c672 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.9.9 +sbt.version=1.10.1 diff --git a/site/_docs/examples.md b/site/_docs/examples.md index c7c012d..a9cebad 100644 --- a/site/_docs/examples.md +++ b/site/_docs/examples.md @@ -162,18 +162,15 @@ import tinyscalautils.collection.LinkedList.factory val list = JavaList.of("X", "Y") // a mutable linked list ``` -### `pollOption` / `peekOption` +### `sortedInReverse` -Like `poll` / `peek` but wrapping `null` in an option. +Like `sorted`, but in reverse: ```scala -import tinyscalautils.collection.{ pollOption, peekOption } +import tinyscalautils.collection.sortedInReverse -val q = util.ArrayDeque[String]() -q.offer("X") -q.peekOption // Some("X") -q.pollOption() // Some("X") -q.pollOption() // None +val seq = ... // a sequence +seq.sortedInReverse // same sequence as seq.sorted.reverse, but more efficient ``` ## Package `assertions` @@ -220,7 +217,6 @@ import tinyscalautils.assertions.implies require(s.indices.contains(i) implies s(i) > 0) ``` The evaluation is short-circuited: RHS is evaluated only if LHS is true. -Operator also available under the symbolic name `==>`. ### `in` @@ -446,6 +442,7 @@ val future = DelayedFuture(1.5): ``` Note that timers need to be explicitly shut down for their threads to terminate. +Timers implement the `AutoCloseable` interface. ### `zipWithDuration` @@ -472,13 +469,13 @@ def i = Iterator.range(0, 1000) val sum = i.sum // 499500 val sum = i.slow(10.0).sum // 499500, but in about 10 seconds -// first 10 elements delayed by about 1 second, then fast: +// first 10 elements delayed by about 1 second each, then fast: i.slow(10.0, delayedElements = 10) -// first 100 elements delayed by about 0.1 second, then fast +// first 100 elements delayed by about 0.1 second each, then fast i.slow(10.0, delayedElements = 100) -// all elements delayed by about 0.001 second, then 9-second delay to finish +// all elements delayed by about 0.001 second each, then 9-second delay to finish i.slow(10.0, delayedElements = 10_000) ``` @@ -696,7 +693,7 @@ if exec.shutdownAndWait(5.0, force = true) then // shutdown was invoked, and pool terminated within 5 seconds else // shutdown was invoked, then after 5 seconds, shutdownNow was invoked -exec.shutdownAndWait() // invokes shutdown and waits indefinitely; force flag is ignored +exec.shutdownAndWait() // invokes shutdown and waits indefinitely; returns true ``` ### `await` @@ -738,18 +735,18 @@ val sem: Semaphore = ... sem.acquire(1, seconds = 3.0) ``` -### `offer` / `pollOption` +### `offer` / `poll` -Adds variant of `offer` and `poll` on blocking queues that specifies their timeout in seconds and wrap `null` in an option: +Adds variant of `offer` and `poll` on blocking queues that specifies their timeout in seconds: ```scala -import tinyscalautils.threads.{ offer, pollOption } +import tinyscalautils.threads.{ offer, poll } val q = ArrayBlockingQueue[String](1) q.offer("X", seconds = 1.0) // true, immediately q.offer("X", seconds = 1.0) // false, after 1 second -q.pollOption(seconds = 1.0) // Some("X"), immediately -q.pollOption(seconds = 1.0) // None, after 1 second +q.poll(seconds = 1.0) // "X", immediately +q.poll(seconds = 1.0) // null, after 1 second ``` ### `joined` @@ -786,8 +783,7 @@ Easy setup of execution contexts, mostly for testing: import tinyscalautils.threads.withThreadsAndWait val result = withThreadsAndWait(4): - Future: - 42 + Future(42) ``` This creates a 4-thread pool, runs the future on it, waits for the future to finish, shuts down the thread pool, and sets `result` to 42. @@ -806,8 +802,7 @@ import tinyscalautils.threads.withThreadPoolAndWait val exec = Executors.newUnlimitedThreadPool() val result = withThreadPoolAndWait(exec): - Future: - 42 + Future(42) ``` This runs the future on the thread pool and waits for the future to finish before setting `result` to 42. @@ -862,51 +857,89 @@ val paths: Set[Path] = readPaths(Set)(dir) *DO NOT* use a stream for the collection. Since the directory is closed before this function finishes, lazily evaluated collections won't work. -### `listLines` +### `read/readAll` -The contents of a UTF8 text file, as a list: +The contents of a UTF8 text file, as a collection of line elements: ```scala -import tinyscalautils.io.listLines +import tinyscalautils.io.{ readAll, given } -for line: String <- listLines(file) do ... +def parse(line: String): Option[Int] = ... + +readAll(IndexedSeq)(file, parse) // an IndexedSeq[Int] +readAll(IndexedSeq)(file) // all non-blank lines +readAll(IndexedSeq)(file, noParsing) // all lines ``` -If a list type is not suitable, use `readLines` instead: +If no factory is specified, it defaults to `List`, e.g.: ```scala -import tinyscalautils.io.readLines - -val lines: IndexedSeq[String] = readLines(IndexedSeq)(file) +readAll(file, parse) // a List[Int] +readAll(file) // a List[String] +readAll(file, noParsing) // a List[String] ``` +`read` does no parsing and returns the entire file contents as a single string. + +The argument `file` must belong to the `Input` type class, which is predefined to contain `InputStream`, `URL`, `Path`, `File` and `String` (as a filename). + *DO NOT* use a stream for the collection. -Since the file is closed before this function finishes, lazily evaluated collections won't work. +Since the source is closed before this function finishes, lazily evaluated collections won't work. -### `findResource` +### `readingAll` + +This is a variant of `readAll` that returns values as a closeable iterator: ```scala -import tinyscalautils.io.findResource +import tinyscalautils.io.{ readingAll, given } -val url = this.findResource(name) +def parse(line: String): Option[Int] = ... + +Using.resource(readingAll(file, parse)): i => + // i has type Iterator[Int] +// file input closed here ``` +`readingAll` does not support a silent mode. -This is equivalent to `getClass.getResource(name)`, except that it throws an exception for missing resources (instead of returning `null`). -In particular, a leading slash in the resource name makes it an absolute path, instead of being associated with the package name by default. +### `write/writeAll` -### `parseURL` +Write data to a UTF8 text file: ```scala -def parse(line: String): Option[Int] = ... -val list: List[Int] = parseURL(url, parse) + import tinyscalautils.io.{ write, writeAll, given } + + val list = List(1, 2, 3) + + write(file)(list) // file contains "List(1, 2, 3)" + write(file, newline = true)(list) // file contains "List(1, 2, 3)\n" + writeAll(file)(list) // file contains "1\n2\n3\n" + writeAll(sep = ",")(file)(list) // file contains "1,2,3" + writeAll(pre = "[", sep = ",", post = "]")(file)(list) // file contains "[1,2,3]" + writeAll()(file)(list) // file contains "123" +``` +Note that the simplified `writeAll` variant includes a final newline after the last value. + +The argument `file` must belong to the `Output` type class, which is predefined to contain `OutputStream`, `Path`, `File` and `String` (as a filename). + + +### `findResource/findResourceAsStream` + +```scala +import tinyscalautils.io.findResource + +val url = this.findResource(name) ``` -If a list type is not suitable, specify a factory: +This is equivalent to `getClass.getResource(name)`, except that it throws an exception for missing resources (instead of returning `null`). +In particular, a leading slash in the resource name makes it an absolute path, instead of being associated with the package name by default. ```scala -val seq: IndexedSeq[Int] = parseURL(url, parse, IndexedSeq) +val url = this.findResource(fallback)(name) ``` +This variant uses a fallback URI instead of failing with `MissingResourceException`. + +The `findResourceAsStream` variants work in the same way but looks for a GZIP compressed variant of a resource before giving up. ## Package `util` @@ -969,3 +1002,17 @@ average(nums, 3) // 0 ``` The function works on any `Fractional` type, including `Double`. + +### `dot/star` + +An identity function that prints a single dot (or star): + +```scala +import tinyscalautils.util.dot + +val x = dot(y) // x eq y and a dot was printed +val x = star(y) // x eq y and a star was printed +``` + +Importing `tinyscalautils.text.silentMode` stops the dot/star from being printed. +Printing modes other than `silent` and `standard` cannot be used.