# `ComposerNew.Ref`
[🔗](https://github.com/elixir-composer/composer/blob/v0.3.0/lib/composer_new/ref.ex#L1)

Parses a `mix composer.new` recipe reference: `COOKBOOK:GROUP/RECIPE`,
with an optional `@SOURCE` naming where the cookbook comes from.

    iex> ComposerNew.Ref.parse("cb_lab:lv/base@github:elixir-composer/cb_lab@v0.3.0")
    {:ok,
     %{
       cookbook: "cb_lab",
       path: "lv/base",
       source: [github: "elixir-composer/cb_lab", ref: "v0.3.0"],
       spec: "github:elixir-composer/cb_lab@v0.3.0"
     }}

This is a copy of the name and `@source` rules of `Composer.Ref` (the
archive can't depend on composer), and a fixture shared by both
projects' tests keeps the two in step:

  * the reference is split on its first `@`; only the name before it is
    normalized from `-` to `_`
  * names are lowercase `[a-z0-9_]` segments
  * a source is a version (`3.5.0` is `== 3.5.0`, a partial `3.5` is
    `~> 3.0`, Igniter's rule, and a requirement such as `~> 3.5` is kept),
    `github:OWNER/REPO[@GITREF]`, `git:URL` or `path:PATH`

On top of those, a reference here must name a cookbook (no shortnames),
can't be `hex:`, and `core:`, which ships with composer, takes no
source.

Parsing never creates atoms.

# `source`

```elixir
@type source() :: keyword(String.t())
```

# `t`

```elixir
@type t() :: %{
  cookbook: String.t(),
  path: String.t(),
  source: source(),
  spec: String.t() | nil
}
```

# `expand`

```elixir
@spec expand(Path.t(), %{cwd: Path.t(), home: Path.t()}) :: Path.t()
```

Expands `path` against `env.cwd`, with a leading `~` as `env.home`.

# `expand_package`

```elixir
@spec expand_package(String.t(), %{cwd: Path.t(), home: Path.t()}) :: String.t()
```

Like `install_spec/3`, for a whole `package[@spec]` string as
`--install` and `--extra-dep` take it.

# `install_spec`

```elixir
@spec install_spec(String.t(), String.t() | nil, %{cwd: Path.t(), home: Path.t()}) ::
  String.t()
```

The `mix igniter.install` argument for `package` from `spec` (the text
after `@`, or `nil`), with a `path:` source made absolute against
`env.cwd` and `env.home`, since the install runs inside the new app.

# `parse`

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

Parses a reference. `spec` is the text after the `@` as written, or
`nil`; `source` is its parsed form (`[]` for none, meaning the latest
Hex release).

# `parse_source`

```elixir
@spec parse_source(String.t()) :: {:ok, source()} | {:error, String.t()}
```

Parses a bare source, with no package name, as `--composer` takes it:
`path:../composer`, `github:owner/repo`, `~> 0.3`, ...

---

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