# `TuningFork.Part.Source`
[🔗](https://github.com/jaman/tuning_fork/blob/v0.1.11/tuning_fork/lib/tuning_fork/part/source.ex#L1)

Reads a block of loop source into a score.

    iex> {:ok, score} = TuningFork.Part.Source.parse("part(bpm: 120) |> play(:c3, 1)")
    iex> %TuningFork.Score{} = score
    iex> TuningFork.Part.Source.parse("part(bpm: 120) |> nonsense(")
    {:error, "missing terminator: )"}

# `compile`

```elixir
@spec compile(String.t()) ::
  {:ok, (-&gt; {:ok, TuningFork.Score.t()} | {:error, String.t()})}
  | {:error, String.t()}
```

The source compiled once into a function that gives a fresh score every time it is called.

    iex> {:ok, body} = TuningFork.Part.Source.compile("part(bpm: 120) |> play(:c3, 1)")
    iex> {:ok, %TuningFork.Score{}} = body.()

Compile once and call the function as often as needed: each call evaluates the source
again, so `TuningFork.Tick` counters advance and `TuningFork.State` values are read as they
stand at that call. `TuningFork.Stage` calls it once per round.

The function returns `{:ok, score}` or `{:error, message}`; source that compiles can still
fail on a later call.

# `fault`

```elixir
@spec fault(String.t()) :: String.t() | nil
```

Why `source` will not read, in one line, or `nil` when it reads.

`parse/1` said the other way round, for a caller that only wants to report.

# `parse`

```elixir
@spec parse(String.t()) :: {:ok, TuningFork.Score.t()} | {:error, String.t()}
```

The score `source` describes, or why it will not read.

Returns `{:ok, %TuningFork.Score{}}` or `{:error, message}`, the message trimmed to one line
so it fits under the loop it belongs to. Empty source is an empty score rather than an error,
so a loop being written from scratch reports nothing until there is something to report.

# `reference`

```elixir
@spec reference() :: [String.t()]
```

What a loop may be written with, as lines of text.

The vocabulary `parse/1` evaluates against. `TuningFork.LoopsApp.reference/0` puts the
terminal's keys around it; the Livebook board shows it behind **?**.

# `template`

```elixir
@spec template() :: String.t()
```

Source a new, empty loop opens on: a four-beat drum part that plays as it stands.

    iex> {:ok, score} = TuningFork.Part.Source.parse(TuningFork.Part.Source.template())
    iex> TuningFork.Score.duration(score)
    2.0

What `mix tuning_fork.loops` gives a loop made with `Ctrl+N`, and what the Livebook board's
**+ loop** gives a new one.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
