# `Estructura.User`
[🔗](https://github.com/am-kantox/estructura/blob/v1.12.0/test/support/structs.ex#L90)

Nested example. The source code of the file follows.

```elixir

defmodule Calculated do
  @moduledoc false
  def person(this) do
    this.name <> ", " <> this.address.city
  end
end

use Estructura.Nested, calculated: [person: &Calculated.person/1]

shape %{
  created_at: :datetime,
  name: {:string, kind_of_codepoints: Enum.concat([?a..?c, ?l..?o])},
  address: %{city: :string, street: %{name: [:string], house: :string}},
  person: :string,
  homepage: {:list_of, Estructura.Nested.Type.URI},
  ip: Estructura.Nested.Type.IP,
  data: %{age: :float},
  birthday: Estructura.Nested.Type.Date,
  title: {Estructura.Nested.Type.Enum, ~w|junior middle señor|},
  tags: {:tags, ~w|backend frontend|}
}

init %{
  name: "Aleksei",
  address: %{city: "Barcelona"}
}

coerce do
  def data.age(age) when is_float(age), do: {:ok, age}
  def data.age(age) when is_integer(age), do: {:ok, 1.0 * age}
  def data.age(age) when is_binary(age) do
    age
    |> Float.parse()
    |> case do
      {age, ""} -> {:ok, age}
      {age, _rest} -> {:ok, age}
      :error -> {:ok, 0.0}
    end
  end
end

coerce do
  def name(value) when is_binary(value), do: {:ok, value}
  def name(value) when is_atom(value), do: {:ok, Atom.to_string(value)}
end

validate do
  def address.street.house(house), do: {:ok, house}
end
```

Now one can cast it from map as below

```elixir
User.cast %{
  address: %{city: "London", street: %{name: "Baker", house: "221 Bis"}},
  data: %{age: 32},
  name: "Watson",
  birthday: "1973-09-30",
  title: "señor",
  tags: ["backend"]}

{:ok,
   %Estructura.User{
     address: %Estructura.User.Address{
       city: "London",
       street: %Estructura.User.Address.Street{house: "221 Bis", name: "Baker"}
     },
     data: %Estructura.User.Data{age: 32.0},
     name: "Watson",
     person: "Watson, London",
     birthday: ~D[1973-09-30],
     title: "señor",
     tags: ["backend"]}
```

# `t`

```elixir
@type t() :: %Estructura.User{
  birthday: any(),
  homepage: any(),
  created_at: DateTime.t(),
  person: any(),
  tags: any(),
  title: any(),
  ip: any(),
  name: any(),
  data: Estructura.User.Data.t(),
  address: Estructura.User.Address.t()
}
```

# `__generator__`

See `Estructura.User.__generator__/2`

# `__generator__`

Returns the generator to be used in `StreamData`-powered property testing, based
  on the specification given to `use Estructura.Nested`, which contained

## shape
```elixir
%{
  data: %{age: :float},
  name: {:string, [kind_of_codepoints: ~c"abclmno"]},
  address: %{
    city: :string,
    street: %{name: [:string], house: :positive_integer}
  },
  ip: Estructura.Nested.Type.IP,
  title: {Estructura.Nested.Type.Enum, ["junior", "middle", "señor"]},
  tags: {Estructura.Nested.Type.Tags, ["backend", "frontend"]},
  person: :string,
  created_at: :datetime,
  homepage: {:list_of, Estructura.Nested.Type.URI},
  birthday: Estructura.Nested.Type.Date
}
```

## coerce
```elixir
  def coerce_age(age) when is_float(age) do
    {:ok, age}
  end
  def coerce_age(age) when is_integer(age) do
    {:ok, 1.0 * age}
  end
  def coerce_age(age) when is_binary(age) do
    age
    |> Float.parse()
    |> case do
      {age, ""} -> {:ok, age}
      {age, _rest} -> {:ok, age}
      :error -> {:ok, 0.0}
    end
  end
  def coerce_created_at(value) do
    Estructura.Coercers.Datetime.coerce(value)
  end
  def coerce_homepage(value) when is_list(value) do
    value
    |> Enum.reduce({:ok, []}, fn
      value, {:error, errors} ->
        case Estructura.Nested.Type.URI.coerce(value) do
          {:ok, _} -> {:error, errors}
          {:error, error} -> {:error, [error | errors]}
        end

      value, {:ok, result} ->
        case Estructura.Nested.Type.URI.coerce(value) do
          {:ok, coerced} -> {:ok, [coerced | result]}
          {:error, error} -> {:error, [error]}
        end
    end)
    |> then(fn {kind, list} -> {kind, Enum.reverse(list)} end)
  end
```

## validate
```elixir
  def validate_house(house) do
    {:ok, house}
  end
  def validate_age(age) when age > 0 do
    {:ok, age}
  end
  def validate_age(age) do
    {:error, "Age must be positive, given: #{age}"}
  end
```

The argument given would be used as a template to generate new values.

# `cast`

Casts the map representation as given to `Estructura.Nested.shape/1` to
  the nested `Estructura` instance.

If `split: true` is passed as an option, it will attempt to put `foo_bar` into nested `%{foo: %{bar: _}}`

# `cast!`

Same as `cast/2` but raises on errors.

# `get`

```elixir
@spec get(
  %Estructura.User{
    address: term(),
    birthday: term(),
    created_at: term(),
    data: term(),
    homepage: term(),
    ip: term(),
    name: term(),
    person: term(),
    tags: term(),
    title: term()
  },
  Estructura.Config.key(),
  any()
) :: any()
```

Gets the value for the given key from the structure

# `parse`

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

Safely parses the json, applying all the specified validations and coercions

# `parse!`

```elixir
@spec parse!(binary()) :: struct() | no_return()
```

Same as `parse/1` but either returns the result of successful parsing or raises

# `put`

```elixir
@spec put(
  %Estructura.User{
    address: term(),
    birthday: term(),
    created_at: term(),
    data: term(),
    homepage: term(),
    ip: term(),
    name: term(),
    person: term(),
    tags: term(),
    title: term()
  },
  Estructura.Config.key(),
  any()
) ::
  {:ok,
   %Estructura.User{
     address: term(),
     birthday: term(),
     created_at: term(),
     data: term(),
     homepage: term(),
     ip: term(),
     name: term(),
     person: term(),
     tags: term(),
     title: term()
   }}
  | {:error, any()}
```

Puts the value for the given key into the structure, passing coercion _and_ validation,
  returns `{:ok, updated_struct}` or `{:error, reason}` if there is no such key

# `put!`

```elixir
@spec put!(
  %Estructura.User{
    address: term(),
    birthday: term(),
    created_at: term(),
    data: term(),
    homepage: term(),
    ip: term(),
    name: term(),
    person: term(),
    tags: term(),
    title: term()
  },
  Estructura.Config.key(),
  any()
) ::
  %Estructura.User{
    address: term(),
    birthday: term(),
    created_at: term(),
    data: term(),
    homepage: term(),
    ip: term(),
    name: term(),
    person: term(),
    tags: term(),
    title: term()
  }
  | no_return()
```

Puts the value for the given key into the structure, passing coercion _and_ validation,
  returns the value or raises if there is no such key

# `recalculate_calculated`

Recalculates calculated fields for the instance of Estructura.User.

Normally one would not need to call this function explicitly because `Access`
  implementation would do that.

# `validate`

```elixir
@spec validate(t()) :: {:ok, t()} | {:error, keyword()}
```

Validates the instance of `Estructura.User` with all the defined validators.

---

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