Agenda.Place (Agenda v0.1.0)

Copy Markdown View Source

A place — a named location that contains resources and other places.

Places form a tree of arbitrary depth. A campus contains buildings, a building contains floors, a floor contains rooms; the library never interprets what a level means, only how the levels nest.

The tree exists so that travel between two resources can be derived rather than configured. A flat location: :sydney attribute can answer "is this room in Sydney?", but not "can someone get from here to there in the ten-minute break?" — and only the second question decides whether a programme is workable. separation/2 is the primitive that answers it.

Summary

Types

How far apart two places are: 0 when they are the same place, n when the deeper of the two is n levels below their nearest common ancestor, and :disjoint when they share no ancestor at all.

t()

A place in the containment tree.

Functions

The nearest place enclosing both a and b, or nil when they share no ancestor.

true when outer encloses inner, at any depth. A place contains itself.

Build a place, optionally inside another.

The chain of places from the root down to place, inclusive.

The outermost place enclosing place, or place itself when it is already a root.

How far apart two places are, measured in levels of the containment tree.

Types

separation()

@type separation() :: non_neg_integer() | :disjoint

How far apart two places are: 0 when they are the same place, n when the deeper of the two is n levels below their nearest common ancestor, and :disjoint when they share no ancestor at all.

t()

@type t() :: %Agenda.Place{name: String.t(), within: t() | nil}

A place in the containment tree.

Functions

common_ancestor(a, b)

@spec common_ancestor(t(), t()) :: t() | nil

The nearest place enclosing both a and b, or nil when they share no ancestor.

Arguments

  • a and b are each a t/0.

Returns

  • the innermost common t/0; or

  • nil when the two are in unrelated trees.

Examples

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> level_2 = Agenda.Place.new("Level 2", within: sydney)
iex> level_3 = Agenda.Place.new("Level 3", within: sydney)
iex> Agenda.Place.common_ancestor(level_2, level_3).name
"Sydney Convention Centre"

contains?(outer, inner)

@spec contains?(t(), t()) :: boolean()

true when outer encloses inner, at any depth. A place contains itself.

Arguments

  • outer is the enclosing t/0.

  • inner is the enclosed t/0.

Returns

  • true or false.

Examples

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> level_2 = Agenda.Place.new("Level 2", within: sydney)
iex> Agenda.Place.contains?(sydney, level_2)
true

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> level_2 = Agenda.Place.new("Level 2", within: sydney)
iex> Agenda.Place.contains?(level_2, sydney)
false

new(name, options \\ [])

@spec new(
  String.t(),
  keyword()
) :: t()

Build a place, optionally inside another.

Arguments

  • name is the place's name.

Options

  • :within is the enclosing t/0. The default is nil, making this place a root.

Returns

Examples

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> level_2 = Agenda.Place.new("Level 2", within: sydney)
iex> level_2.within.name
"Sydney Convention Centre"

path(place)

@spec path(t()) :: [t()]

The chain of places from the root down to place, inclusive.

Arguments

  • place is a t/0.

Returns

  • a list of t/0 ordered outermost first.

Examples

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> level_2 = Agenda.Place.new("Level 2", within: sydney)
iex> Enum.map(Agenda.Place.path(level_2), & &1.name)
["Sydney Convention Centre", "Level 2"]

root(place)

@spec root(t()) :: t()

The outermost place enclosing place, or place itself when it is already a root.

Arguments

  • place is a t/0.

Returns

Examples

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> level_2 = Agenda.Place.new("Level 2", within: sydney)
iex> Agenda.Place.root(level_2).name
"Sydney Convention Centre"

separation(a, b)

@spec separation(t(), t()) :: separation()

How far apart two places are, measured in levels of the containment tree.

This is the primitive travel time is derived from: the further up the tree you must climb to get from one place to the other, the longer the journey.

Arguments

  • a and b are each a t/0.

Returns

  • 0 when a and b are the same place;

  • a positive integer — the number of levels from the deeper place up to the nearest common ancestor; or

  • :disjoint when the two share no ancestor.

Examples

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> level_2 = Agenda.Place.new("Level 2", within: sydney)
iex> level_3 = Agenda.Place.new("Level 3", within: sydney)
iex> {Agenda.Place.separation(level_2, level_2),
...>  Agenda.Place.separation(level_2, level_3)}
{0, 1}

iex> sydney = Agenda.Place.new("Sydney Convention Centre")
iex> darling = Agenda.Place.new("Darling Harbour Theatre")
iex> Agenda.Place.separation(sydney, darling)
:disjoint