# `Tempo.RRule.Selection`
[🔗](https://github.com/kipcole9/tempo/blob/v0.5.0/lib/tempo/rrule/selection.ex#L1)

Resolve RRULE `BY*` selection tokens during recurrence expansion.

Called from `Tempo.to_interval/2`'s recurrence loop. Given a
candidate occurrence and a `repeat_rule` whose `:time` carries
a `[{:selection, [...]}]` keyword list (the shared AST produced
by `Tempo.RRule.parse/2` and `Tempo.RRule.Expander.to_ast/3`),
decide whether the candidate is kept, dropped, or expanded into
multiple occurrences.

## Implemented rules

Per RFC 5545 §3.3.10's EXPAND/LIMIT table:

| Part         | Role and when                                     |
| ------------ | ------------------------------------------------- |
| `BYMONTH`    | LIMIT — always.                                   |
| `BYMONTHDAY` | LIMIT — any FREQ except WEEKLY (forbidden).       |
| `BYYEARDAY`  | LIMIT — any FREQ coarser than DAILY.              |
| `BYWEEKNO`   | LIMIT — `YEARLY` only.                            |
| `BYDAY` (no ordinal) | LIMIT for DAILY/HOURLY/MINUTELY/SECONDLY; |
|              | EXPAND within the enclosing week/month/year for   |
|              | WEEKLY, MONTHLY, YEARLY.                          |
| `BYDAY` (with ordinal) | EXPAND — pairs `(ordinal, weekday)` like  |
|              | `1MO` and `-1FR` pick the Nth / Nth-from-last     |
|              | matching weekday within the enclosing period      |
|              | (month for MONTHLY, year for YEARLY). Backed by   |
|              | `Calendrical.Kday.nth_kday/3`.                    |
| `BYHOUR`     | EXPAND when FREQ is coarser than hour; LIMIT      |
|              | when FREQ is hour-or-finer.                       |
| `BYMINUTE`   | Same pattern at the minute unit.                  |
| `BYSECOND`   | Same pattern at the second unit.                  |
| `BYSETPOS`   | LIMIT — applied last, across the post-filter      |
|              | per-period candidate set. Negative values count   |
|              | from the end (`-1` = last).                       |

Tokens this module doesn't interpret pass through unchanged
so partial support is correct for the partial inputs.

# `apply`

```elixir
@spec apply(Tempo.Interval.t(), Tempo.t() | nil, atom()) :: [Tempo.Interval.t()]
```

Apply a `repeat_rule` to one candidate occurrence and return the
resulting list of occurrences.

### Arguments

* `candidate` is a `t:Tempo.Interval.t/0` — the current
  occurrence under consideration.

* `repeat_rule` is either `nil` (no rule — passthrough) or a
  `%Tempo{}` whose `:time` holds `[selection: [...]]`.

* `freq` is the enclosing `FREQ` atom (`:second`, `:minute`,
  `:hour`, `:day`, `:week`, `:month`, `:year`). Drives the
  EXPAND-vs-LIMIT dispatch for rules whose role depends on
  the enclosing frequency.

### Returns

* A list of `t:Tempo.Interval.t/0` occurrences — `[]` on LIMIT
  rejection, `[candidate]` on passthrough or LIMIT accept,
  `[c1, c2, …]` on EXPAND.

### Examples

    iex> candidate = %Tempo.Interval{from: ~o"2022-06-15", to: ~o"2022-06-16"}
    iex> rule = %Tempo{time: [selection: [month: 6]], calendar: Calendrical.Gregorian}
    iex> Tempo.RRule.Selection.apply(candidate, rule, :month)
    [candidate]

    iex> candidate = %Tempo.Interval{from: ~o"2022-07-15", to: ~o"2022-07-16"}
    iex> rule = %Tempo{time: [selection: [month: 6]], calendar: Calendrical.Gregorian}
    iex> Tempo.RRule.Selection.apply(candidate, rule, :month)
    []

---

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