class Novika::Resolver::RunnableContainer

Overview

A runnable container is an ordered, arbitrarily filtered collection of runnables - and a runnable itself. It holds and advances (through rewriting) a generation of runnables.

Defined in:

novika/resolver.cr

Constructors

Instance Method Summary

Instance methods inherited from class Novika::Resolver::Runnable

ancestor? : Ancestor | Nil ancestor?, ancestors : Array(Ancestor) ancestors, backtrace(io : IO, indent : Int32 = 0, annex : String | Nil = nil)
backtrace(*args, **kwargs, & : IO -> )
backtrace
, constituents : Array(Runnable) constituents, each_ancestor(& : Ancestor -> ) each_ancestor, specialize(root : RunnableRoot, container : RunnableContainer) specialize

Constructor methods inherited from class Novika::Resolver::Runnable

new(ancestor : Ancestor | Nil = nil) new

Instance methods inherited from module Novika::Resolver::Runnable::Ancestor

ancestor? : Ancestor | Nil ancestor?

Constructor Detail

def self.new(root : RunnableRoot, dir : Path, env : RunnableEnvironment, parent : RunnableContainer | Nil = nil, transparent : Bool = false, ancestor = nil) #

Initializes a new runnable container for the given directory.

parent is the parent runnable container. You don't normally need to specify it. Prefer to call #child on the parent instead.

transparent specifies whether the container is transparent, see #transparent?.


Instance Method Detail

def abspath #

Returns the absolute path of the directory of this container.


def allow?(warn = false, &filter : Runnable -> Bool) #

Introduces a filter for the constituent runnables of this container. filter should decide whether to accept (true) or reject (false) a runnable.

warn specifies whether the RunnableIgnored signal should be sent if filter rejects a runnable.


def append(runnable : Runnable) #

Inserts runnable after all other runnables in this container.


def append(runnables : Array(Runnable)) #

Inserts the entire array of runnables after all other runnables in this container.


def can_contain?(runnable : Runnable) #

Returns whether this container's filters allow it to contain the given runnable.


def child(dir = @dir, ancestor = self, *, transparent : Bool) #

Builds and returns a child of this container.

Optionally, the directory of the child can be provided. Otherwise, the directory of this container will be used.

Additionally, you can specify whether the child should be transparent (see #transparent?).


def classify?(datum : Path, ancestor : Ancestor | Nil) : Runnable | Nil #

Creates a RunnableDir, RunnableScript, or RunnableSharedObject depending on what datum points to and on its extension.

ancestor is set as the ancestor of the created runnable.

Returns nil if datum does not exist, or if there is no appropriate classification.


def classify?(datum : String, ancestor : Ancestor | Nil) : Runnable | Nil #

If datum is a capability, creates and returns an appropriate RunnableCapability object. Otherwise, tries to convert datum to an absolute, normalized path, and then passes the path to the other #classify?(datum : Path, ancestor : Ancestor?).

Returns nil if nothing succeeded, deeming datum unclassifiable.


def constituents #
Description copied from class Novika::Resolver::Runnable

Returns an array with contained runnables. If none, returns an array with self.


def each(& : Runnable -> ) #

Yields constituent runnables.


def each_path(fn : Path -> ) #

Recursively yields file and directory paths in this container.


def each_path(&fn : Path -> ) #

Recursively yields file and directory paths in this container.


def each_sorted_path(selector : GlobSelector, & : Path -> ) #

Yields all paths matching selector in lexicographic order. The paths are initially taken from the directory of this container. See Disk#glob for details.


def empty? #

Returns whether this container is empty, i.e., holds has no constituent runnables.


Returns the RunnableEnvironment assigned to this container.


def flatten! #

Recursively replaces each runnable in this container with its #constituents. Most notably, rewrites transparent containers to their constituents.


def from?(env : RunnableEnvironment) #

Returns whether env is this container's environment.


def includes?(other) #

Returns whether this container includes the given runnable.


def paths #

Returns a set of all paths (file, directory, etc. paths) in this container, including those in nested containers.


def prepend(runnable : Runnable) #

Inserts runnable before all other runnables in this container.


def recursive_nonterminal_each(fn : Runnable, RunnableContainer -> ) #

Calls fn with each nonterminal and the container it's from, recurses into nested RunnableContainers.


def recursive_nonterminal_each(&fn : Runnable, RunnableContainer -> ) #

Calls fn with each nonterminal and the container it's from, recurses into nested RunnableContainers.


def recursive_nonterminal_map!(fn : Runnable, RunnableContainer -> Runnable) #

Replaces all non-terminal (see Runnable::Terminal) runnables with the result of fn. Recurses into nested containers.


def recursive_nonterminal_map!(&fn : Runnable, RunnableContainer -> Runnable) #

Replaces all non-terminal (see Runnable::Terminal) runnables with the result of fn. Recurses into nested containers.


def recursive_select!(fn : Runnable -> Bool) #

Accepts only those runnable in this container and in all nested containers for which fn returns true.

Runnables for which fn returned false are mutably deleted.


def recursive_select!(&fn : Runnable -> Bool) #

Accepts only those runnable in this container and in all nested containers for which fn returns true.

Runnables for which fn returned false are mutably deleted.


def replace(pattern : Runnable, replacement : Runnable) #

Replaces pattern runnable with the replacement runnable in this container only (i.e., does not recurse).


def replace(pattern : Runnable, replacement : Array(Runnable)) #

Replaces pattern runnable with multiple replacement runnables in this container only (i.e. does not recurse). Their order will be the same as that in replacement.

Runnables from replacement that this container cannot contain are left out.


def request(dependency : Resolution::Dependency) #

Communicates with this container's environment permission server in order to determine whether the use dependency should be allowed to self.


def rewrite #

Rewrites this container until there is no point in doing so. That is, until R (current) and R' (rewritten) are equal: R = R'.

Quite obviously this method is susceptible to cyclic expansion when the length of the cycle is higher than, well, zero (e.g. R -> R' -> R -> ...). So please don't do that nor cause that!


def specialize(root : RunnableRoot, container : RunnableContainer) #
Description copied from class Novika::Resolver::Runnable

Further specializes this runnable. Appends the specialized runnable to (or interacts in some other way with) container. The latter is assumed to be incomplete (or partially complete, which is really the same thing).

root is the runnable root object. It is mainly used for flags and thorough rewriting.


def thorough_rewrite #

def to_resolution_set(*, deps = Set(Resolution::Dependency).new, set = ResolutionSet.new) #

Builds and returns a ResolutionSet with resolutions from this container and all nested containers.

You must call this after #flatten!. Otherwise, the resulting ResolutionSet will be underpopulated with dependencies due to transparent containers standing in the way.

deps is a set of dependencies that all resolutions in the resulting set should have, regardless of nesting. Beware that it is mutated.


def to_s(io, indent = 0, lead = indent) #

def transparent? : Bool #

Returns whether this container is transparent.

Transparent containers get "merged" with their parent during flattening, for example. At the same time opaque continers remain still and unbreakable. The #constituents of a transparent container are plainly visible & accessible; those of an opaque one are not.

Transparent containers are transparent to filter inheritance. This means that transparent containers can inherit filters of their parent containers. Opaque containers are opaque to filter inheritance. Therefore, transparent containers won't inherit filters of containers above an opaque container, and opaque containers themselves won't inherit anything from parent container(s).