org.scalactic.Snapshots.scala Maven / Gradle / Ivy
/* * Copyright 2001-2014 Artima, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.scalactic import scala.quoted._ /** * Case class that stores the name and value of a variable or expression. * *
Snapshots. * * Here's an example: * ** See the main documentation for trait
* * @param name the name of the expression * @param value the value of the expression */ final case class Snapshot(name: String, value: Any) { /** * OverridenSnapshots
for more information and examples. *toString
to print in {name} = {value} format. * * @return string in {name} = {value} format */ override def toString: String = Resources.variableWasValue(name, Prettifier.default(value)) } /** *Trait that provides a
snap
method that takes one or more arguments and results in a *SnapshotSeq
, whosetoString
lists the names * and values of each argument. * ** The intended use case of this trait is to help you write debug and log * messages that give a "snapshot" of program state. Here's an example: *
* ** scala> import Snapshots._ * import Snapshots._ * * scala> snap(a, b, c, d, e, f) * res3: org.scalactic.SnapshotSeq = a was 1, b was 2, c was 3, d was 4, e was null, f was null ** *
SnapshotSeq
offers alines
method that places each variable name/value pair on its own line:* *
* scala> snap(a, b, c, d, e, f).lines * res4: String = * a was 1 * b was 2 * c was 3 * d was 4 * e was null * f was null ** ** Or, because a
* *SnapshotSeq
is aIndexedSeq[Snapshot]
, you can process it just like any otherSeq
, for example: ** scala> snap(a, b, c, d, e, f).mkString("Wow! ", ", and ", ". That's so awesome!") * res6: String = Wow! a was 1, and b was 2, and c was 3, and d was 4, and e was null, and f was null. That's so awesome! **/ trait Snapshots { /** * Snap the given expressions. * * @param expressions expressions to be snapped * @return anIndexedSeq
ofSnapshot
for the given expressions. */ inline def snap(expressions: Any*): SnapshotSeq = ${ SnapshotsMacro.snap('expressions) } } /** * AnIndexedSeq[Snapshot]
providingtoString
andlines
methods that * can be useful for debug and log messages about program state. * ** See the main documentation for trait
*/ final class SnapshotSeq(underlying: collection.immutable.IndexedSeq[Snapshot]) extends collection.immutable.IndexedSeq[Snapshot] { /** * Selects an element by its index in the sequence. * *Snapshots
for more information and examples. ** This method invokes
* * @param idx the index to select * @return the element of this sequence at indexapply
on the underlying immutableIndexedSeq[String]
, passing inidx
, and returns the result. *idx
, where 0 indicates the first element */ def apply(idx: Int): Snapshot = underlying.apply(idx) /** * The length of this sequence. * ** This method invokes
* * @return the number of elements in this sequence */ def length: Int = underlying.length /** * Appends a string element to this sequence, if it doesn't already exist in the sequence. * *length
on the underlying immutableIndexedSeq[String]
and returns the result. ** If the string element already exists in this sequence, this method returns itself. If not, * this method returns a new
* * @param the string element to append to this sequence * @return aMultiSelOptionSeq
with the passed value appended to the * end of the originalMultiSelOptionSeq
. *MultiSelOptionSeq
that contains the passed string value */ def +(value: Snapshot): SnapshotSeq = { if (!underlying.contains(value)) new SnapshotSeq(underlying :+ value) else this } /** * Removes a string element to this sequence, if it already exists in the sequence. * ** If the string element does not already exist in this sequence, this method returns itself. If the element * is contained in this sequence, this method returns a new
* * @param the string element to append to this sequence * @return aMultiSelOptionSeq
with the passed value * removed from the the originalMultiSelOptionSeq
, leaving any other elements in the same order. *MultiSelOptionSeq
that contains the passed string value */ def -(value: Snapshot): SnapshotSeq = { if (underlying.contains(value)) new SnapshotSeq(underlying.filter(_ != value)) else this } /** * The default way to present the result of thesnap
method of trait* scala> snap(a, b, c, d, e, f) * res3: org.scalactic.SnapshotSeq = a was 1, b was 2, c was 3, d was 4, e was null, f was null **/ override def toString: String = mkString(", ") /** * An alternate way to present the result of thesnap
method of trait Snapshots that * puts each variable or expression on its own line. * * Here's an example: * ** scala> snap(a, b, c, d, e, f).lines * res4: String = * a was 1 * b was 2 * c was 3 * d was 4 * e was null * f was null **/ def lines: String = mkString("\n") } object SnapshotSeq { def apply(snapshots: Snapshot*): SnapshotSeq = new SnapshotSeq(Vector(snapshots: _*)) } /** * Companion object that facilitates the importing ofSnapshots
members as * an alternative to mixing it in. One use case is to importSnapshots
members so you can use * them in the Scala interpreter: * ** $scala -classpath scalatest.jar * Welcome to Scala version 2.10.3.final (Java HotSpot(TM) Client VM, Java xxxxxx). * Type in expressions to have them evaluated. * Type :help for more information. * * scala> import org.scalactic.Snapshots._ * import org.scalatest.Snapshots._ * * scala> val a = 8 * a: Int = 8 * * scala> snap(a) * res0: scala.collection.immutable.Vector[org.scalactic.Snapshot] = Vector(a = 8) **/ object Snapshots extends Snapshots object SnapshotsMacro { def snap(expressions: Expr[Seq[Any]])(using Quotes): Expr[SnapshotSeq] = { import quotes.reflect._ def liftSeq(args: Seq[Expr[Snapshot]]): Expr[Seq[Snapshot]] = args match { case x :: xs => '{ ($x) +: ${ liftSeq(xs) } } case Nil => '{ Seq(): Seq[Snapshot] } } val snapshots: List[Expr[Snapshot]] = expressions.asTerm.underlyingArgument match { case Typed(Repeated(args, _), _) => // only sequence literal args.map { arg => val str = Expr(arg.asExpr.show) '{ Snapshot($str, ${ arg.asExpr }) } } case arg => report.throwError("snap can only be used with sequence literal, not `seq : _*`") } val argumentsS: Expr[Seq[Snapshot]] = liftSeq(snapshots) '{ SnapshotSeq($argumentsS : _*) } } }