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.
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
@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.
A place in the containment tree.
Functions
The nearest place enclosing both a and b, or nil when they
share no ancestor.
Arguments
aandbare each at/0.
Returns
the innermost common
t/0; ornilwhen 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"
true when outer encloses inner, at any depth. A place contains
itself.
Arguments
Returns
trueorfalse.
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
Build a place, optionally inside another.
Arguments
nameis the place's name.
Options
:withinis the enclosingt/0. The default isnil, making this place a root.
Returns
- a
t/0.
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"
The chain of places from the root down to place, inclusive.
Arguments
placeis at/0.
Returns
- a list of
t/0ordered 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"]
The outermost place enclosing place, or place itself when it is
already a root.
Arguments
placeis at/0.
Returns
- a
t/0.
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"
@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
aandbare each at/0.
Returns
0whenaandbare the same place;a positive integer — the number of levels from the deeper place up to the nearest common ancestor; or
:disjointwhen 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