SkillAgentSearch skills...

Sourcecode

Scala library providing "source" metadata to your program, similar to Python's __name__, C++'s __LINE__ or Ruby's __FILE__.

Install / Use

/learn @com-lihaoyi/Sourcecode
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

SourceCode Join the chat at https://gitter.im/lihaoyi/Ammonite Maven Central

sourcecode is a small Scala library that provides common "source code" context to your program at runtime, similar to Python's __name__, C++'s __LINE__ or Ruby's __FILE__. For example, you can ask for the file-name and line number of the current file, either through the () syntax or via an implicit:

val file = sourcecode.File()
assert(file.endsWith("/sourcecode/shared/src/test/scala/sourcecode/Tests.scala"))

val line = implicitly[sourcecode.Line]
assert(line == 16)

This might not be something you want to use for "business logic", but is very helpful for things like debugging, logging or providing automatic diagnostics for DSLs. This information is also available via an implicit, letting you write functions that automatically pull it in.

Using SourceCode on code dealing with lots of anonymous functions or anonymous classes can easily turn what you see in your debug printouts from this:

Before

To this:

After

By capturing source information you can use to give your objects and function meaningful names that tell you where they were defined, automatically without needing you to manually assign a string-ID to every anonymous function or anonymous class you define all over your code base.

If you like using Sourcecode, you might also enjoy this book by the author which teaches you Scala in a similarly simple and straightforward way:

Table of Contents

Overview

The kinds of compilation-time data that sourcecode provides are:

  • sourcecode.File: full path of the current file where the call occurs
  • sourcecode.FileName: name of the current file where the call occurs; less verbose than sourcecode.File but often enough for debugging purposes
  • sourcecode.Line: current line number
  • sourcecode.Name: the name of the nearest enclosing definition: val, class, whatever.
  • sourcecode.FullName: the name of the nearest enclosing definition: val, class, whatever, prefixed by the names of all enclosing classs, traits, objects or packages. Note that this does not include other enclosing defs, vals, vars or lazy vals`
  • sourcecode.Enclosing: the name of the nearest enclosing definition: val, class, whatever, prefixed by the names of all enclosing classs, traits, objects or packages, defs, vals, vars or lazy vals`
  • sourcecode.Text[T]: when you want to take a value of type T, but also want to get the "source text" of that particular value. Note that if you have multiple statements in a {} block, sourcecode.Text will only capture the source code for the last expression that gets returned. This implicit is slightly experimental; be sure to report any bugs you find!
  • sourcecode.Args: the arguments that were provided to the nearest enclosing method
  • sourcecode.Name.Machine, sourcecode.FullName.Machine and sourcecode.Enclosing.Machine which are similar to sourcecode.Name, sourcecode.FullName and sourcecode.Enclosing except they do not filter out synthetic method names; e.g. if you want to see the <init> names or <local foo> names as part of the path, use these instead.

All these are available both via () and as implicits, e.g. sourcecode.File can be summoned via sourcecode.File() or implicitly[sourcecode.File].value. This also means you can define functions that pull in this information automatically:

def foo(arg: String)(implicit file: sourcecode.File) = {
  ... do something with arg ...
  ... do something with file.value ...
}

foo("hello") // the implicit sourcecode.File is filled in automatically

sourcecode does not rely on runtime reflection or stack inspection, and is done at compile-time using macros. This means that it is both orders of magnitude faster than e.g. getting file-name and line-numbers using stack inspection, and also works on Scala.js where reflection and stack inspection can't be used.

Download

Mill

sourcecode is published to Maven Central.

def ivyDeps = Agg(
  ivy"com.lihaoyi::sourcecode:0.4.2", // Scala-JVM
  ivy"com.lihaoyi::sourcecode::0.4.2" // Scala.js / Scala Native
)

sbt

"com.lihaoyi" %% "sourcecode" % "0.4.2" // Scala-JVM
"com.lihaoyi" %%% "sourcecode" % "0.4.2" // Scala.js / Scala Native

Examples

Here are a few examples of sourcecode's core functions being used in a variety of contexts. Hopefully they will give you an idea of how the various implicits behave:

package sourcecode

object Implicits {
  def implicitRun() = {
    val name = implicitly[sourcecode.Name]
    assert(name.value == "name")

    val fullName = implicitly[sourcecode.FullName]
    assert(fullName.value == "sourcecode.Implicits.fullName")

    val enclosing = implicitly[sourcecode.Enclosing]
    assert(enclosing.value == "sourcecode.Implicits.implicitRun enclosing")

    val pkg = implicitly[sourcecode.Pkg]
    assert(pkg.value == "sourcecode")

    val file = implicitly[sourcecode.File]
    assert(file.value.endsWith("/sourcecode/Implicits.scala"))

    val fileName = implicitly[sourcecode.FileName]
    assert(fileName.value == "Implicits.scala")

    val line = implicitly[sourcecode.Line]
    assert(line.value == 23)

    lazy val myLazy = {
      trait Bar{
        val name = implicitly[sourcecode.Name]
        assert(name.value == "name")

        val fullName = implicitly[sourcecode.FullName]
        assert(fullName.value == "sourcecode.Implicits.Bar.fullName")

        val file = implicitly[sourcecode.File]
        assert(file.value.endsWith("/sourcecode/Implicits.scala"))

        val fileName = implicitly[sourcecode.FileName]
        assert(fileName.value == "Implicits.scala")

        val line = implicitly[sourcecode.Line]
        assert(line.value == 40)

        val enclosing = implicitly[sourcecode.Enclosing]
        assert(
          (enclosing.value == "sourcecode.Implicits.implicitRun myLazy$lzy Bar#enclosing") ||
          (enclosing.value == "sourcecode.Implicits.implicitRun myLazy Bar#enclosing") // encoding changed in Scala 2.12
        )
      }
      val b = new Bar{}
    }
    myLazy
  }
}

Note that in "normal" usage you would not directly call implicitly to summon up sourcecode values; rather, you would add implicit parameters of these types to your functions. That would make these values automatically available to your functions without needing to manually keep passing them in. Apart from summoning them via implicits, you can also use the apply method on each type to pull them in using the () syntax:

package sourcecode

object Implicits {
  def implicitRun() = {
    val name = implicitly[sourcecode.Name]
    assert(name.value == "name")

    val fullName = implicitly[sourcecode.FullName]
    assert(fullName.value == "sourcecode.Implicits.fullName")

    val enclosing = implicitly[sourcecode.Enclosing]
    assert(enclosing.value == "sourcecode.Implicits.implicitRun enclosing")

    val pkg = implicitly[sourcecode.Pkg]
    assert(pkg.value == "sourcecode")

    val file = implicitly[sourcecode.File]
    assert(file.value.endsWith("/sourcecode/Implicits.scala"))

    val fileName = implicitly[sourcecode.FileName]
    assert(fileName.value == "Implicits.scala")

    val line = implicitly[sourcecode.Line]
    assert(line.value == 23)

    lazy val myLazy = {
      trait Bar{
        val name = implicitly[sourcecode.Name]
        assert(name.value == "name")

        val fullName = implicitly[sourcecode.FullName]
        assert(fullName.value == "sourcecode.Implicits.Bar.fullName")

        val file = implicitly[sourcecode.File]
        assert(file.value.endsWith("/sourcecode/Implicits.scala"))

        val fileName = implicitly[sourcecode.FileName]
        assert(fileName.value == "Implicits.scala")

        val line = implicitly[sourcecode.Line]
        assert(line.value == 40)

        val enclosing = implicitly[sourcecode.Enclosing]
        assert(
          (enclosing.value == "sourcecode.Implicits.implicitRun myLazy$lzy Bar#enclosing") ||
          (enclosing.value == "sourcecode.Implicits.implicitRun myLazy Bar#enclosing") // encoding changed in Scala 2.12
        )
      }
      val b = new Bar{}
    }
    myLazy
  }
}

By default, the various implicits all ignore any synthetic <init>, <local Foo> or $anonfun methods that might be present:

package sourcecode

object NoSynthetic {
  def run() = {
    class EnumValue(implicit name: sourcecode.Name){
      override def toString = name.value
    }
    object Foo extends EnumValue

    assert(Foo.toString == "Foo")

    object Bar{
      assert(sourcecode.Name() == "Bar")
      assert(sourcecode.FullName() == "sourcecode.NoSynthetic.Bar")
      assert(sourcecode.Enclosing() == "sourcecode.NoSynthetic.run Bar")
    }
    Bar
  }
}

If you want these synthetic methods to be shown, use the .Machine versions of each of these instead:

package sourcecode

object Synthetic {
  def run() = {
    class EnumValue(implicit name: sourcecode.Name.Mach
View on GitHub
GitHub Stars540
CategoryDevelopment
Updated16d ago
Forks77

Languages

Scala

Security Score

80/100

Audited on Mar 21, 2026

No findings