package yocaml

  1. Overview
  2. Docs

Description of a build rule.

Type

('a, 'b) Build.t describes a special case of a function. Indeed, it is a function of 'a -> b Effect.t to which a dependency link (Deps.t) is attached.

type ('a, 'b) t

Action on rules

val get_dependencies : ('a, 'b) t -> Deps.t

get_dependencies rule returns the dependencies of the rule.

val get_task : ('a, 'b) t -> 'a -> 'b Effect.t

get_task rule returns the task of the rule.

val init : Deps.t -> (unit, unit) t

Create a task with fixed deps and without task.

val make : Deps.t -> ('a -> 'b Effect.t) -> ('a, 'b) t

Create a new build rules.

Building rules

Combiners to build rules (increasingly complex, to infinity and beyond).

val watch : Filepath.t -> (unit, unit) t

watch file generates an Arrow that adds a file to the dependency list without reading it. It can be useful for making file generation dependent on other files. For example :

let track_binary_update = watch Sys.argv.(0)

Which adds the generating binary to the list of dependencies.

val create_file : Filepath.t -> (unit, string) t -> unit Effect.t

create_file target build_rule executes the build_rule task if the dependencies are not up-to-date for target (or target does not exist).

val fold_dependencies : ('a, 'b) t list -> (('c -> 'd Effect.t) -> ('c, 'd) t) * ('a -> 'b Effect.t) list
val copy_file : ?new_name:string -> Filepath.t -> into:Filepath.t -> unit Effect.t

Copy files from a destination to a source, taking account of dependencies.

val read_file : Filepath.t -> (unit, string) t

Arrow version of a file reader.

val pipe_content : ?separator:string -> Filepath.t -> (string, string) t

Pipe an arrow to an other and concat the results.

val concat_files : ?separator:string -> Filepath.t -> Filepath.t -> (unit, string) t

Concat two files.

val read_file_with_metadata : (module Metadata.VALIDABLE) -> (module Metadata.READABLE with type t = 'a) -> Filepath.t -> (unit, 'a * string) t

Read a file and parse metadata in the header. If the metadata is invalid, the arrow will throw an error. The first module defines how to go from string to structured object (for example the module Yocaml_yaml which process Yaml) and the second one describes the parsed metadata (see: Metadata).

val apply_as_template : (module Metadata.INJECTABLE with type t = 'a) -> (module Metadata.RENDERABLE) -> ?strict:bool -> Filepath.t -> ('a * string, 'a * string) t

Applies a file as a template. (and replacing the metadata). Once the content has been transformed, the arrow returns a pair containing the metadata and the file content injected into the template. The first module describes how to make a metadata compliant with a template language (e.g. Mustache) and the second describes how to apply the template with variables.

val without_body : 'a -> 'a * string

When a template should be applied without body.

val collection : 'a list Effect.t -> ('a -> (unit, 'b) t) -> ('b list -> 'c -> 'e) -> ('c, 'e) t Effect.t

Sometimes it is necessary to calculate a page according to other pages, for example to make an index of articles. With collection you can separate this procedure into 3 steps.

  • First, it executes an effect that acts on a list
  • Then it goes through the list of collected data and applies an arbitrary arrow to it.
  • Finally, it applies an aggregate function to the collected list.

For example, let's build our index by projecting the list of articles into the Articles metadata:

let index =
  let open Build in
  let* articles =
    collection
      (read_child_files "articles/" (with_extension "md"))
      (fun source ->
        track_binary_update
        >>> Yocaml_yaml.read_file_with_metadata
              (module Metadata.Article)
              source
        >>^ fun (x, _) -> x, article_destination source)
      (fun x (meta, content) ->
        x
        |> Metadata.Articles.make
             ?title:(Metadata.Page.title meta)
             ?description:(Metadata.Page.description meta)
        |> Metadata.Articles.sort_articles_by_date
        |> fun x -> x, content)
  in
  create_file
    (into destination "index.html")
    (track_binary_update
    >>> Yocaml_yaml.read_file_with_metadata
          (module Metadata.Page)
          "index.md"
    >>> Yocaml_markdown.content_to_html ()
    >>> articles
    >>> Yocaml_mustache.apply_as_template
          (module Metadata.Articles)
          "templates/list.html"
    >>> Yocaml_mustache.apply_as_template
          (module Metadata.Articles)
          "templates/layout.html"
    >>^ Stdlib.snd)
;;

Included Arrow combinators

A build rule respects the interface of an Arrow Choice (which implies Category and Arrow, by construction), for ergonomic reasons, the combinators of the three classes are included in the module toplevel.

include Preface.Specs.ARROW_CHOICE with type ('a, 'b) t := ('a, 'b) t

Type

Functions

val left : ('a, 'b) t -> (('a, 'c) Preface_core.Shims.Either.t, ('b, 'c) Preface_core.Shims.Either.t) t

Feed marked inputs through the argument arrow, passing the rest through unchanged to the output.

val choose : ('a, 'b) t -> ('c, 'd) t -> (('a, 'c) Preface_core.Shims.Either.t, ('b, 'd) Preface_core.Shims.Either.t) t

Split the input between the two argument arrows, re-tagging and merging their outputs.

include Preface_specs.Category.WITH_ID with type ('a, 'b) t := ('a, 'b) t
val id : ('a, 'a) t

The identity morphism.

include Preface_specs.Semigroupoid.WITH_COMPOSE with type ('a, 'b) t := ('a, 'b) t
val compose : ('b, 'c) t -> ('a, 'b) t -> ('a, 'c) t

Morphism composition (from right to left).

val fst : ('a, 'b) t -> ('a * 'd, 'b * 'd) t

Send the first component of the input through the argument Arrow, and copy the rest unchanged to the output.

val arrow : ('a -> 'b) -> ('a, 'b) t

Lift a function to an Arrow.

val split : ('a, 'b) t -> ('c, 'd) t -> ('a * 'c, 'b * 'd) t

Split the input between the two given Arrows and combine their output.

val compose_right_to_left : ('b, 'c) t -> ('a, 'b) t -> ('a, 'c) t

An alias of CORE.compose.

val compose_left_to_right : ('a, 'b) t -> ('b, 'c) t -> ('a, 'c) t

An alias of CORE.compose with flipped argument.

val return : unit -> ('a, 'a) t

Represent the identity Arrow.

val snd : ('a, 'b) t -> ('d * 'a, 'd * 'b) t

Send the second component of the input through the given Arrow, and copy the rest unchanged to the output.

val fan_out : ('a, 'b) t -> ('a, 'c) t -> ('a, 'b * 'c) t

Send the input to both argument arrows and combine their output.

val pre_compose_left_to_right : ('a -> 'b) -> ('b, 'c) t -> ('a, 'c) t

Pre composition with a function (the function should be pure).

val post_compose_left_to_right : ('a, 'b) t -> ('b -> 'c) -> ('a, 'c) t

Post composition with a function (the function should be pure).

val pre_compose_right_to_left : ('b, 'c) t -> ('a -> 'b) -> ('a, 'c) t
val post_compose_right_to_left : ('b -> 'c) -> ('a, 'b) t -> ('a, 'c) t
val right : ('a, 'b) t -> (('c, 'a) Preface_core.Shims.Either.t, ('c, 'b) Preface_core.Shims.Either.t) t

The mirror image of left.

val fan_in : ('a, 'c) t -> ('b, 'c) t -> (('a, 'b) Preface_core.Shims.Either.t, 'c) t

Split the input between the two argument arrows and merge their outputs.

Infix operators

module Infix : Preface_specs.Arrow_choice.INFIX with type ('a, 'b) t = ('a, 'b) t
val (%) : ('b, 'c) t -> ('a, 'b) t -> ('a, 'c) t

An alias of CORE.compose (to be iso with Preface_core).

val (<%) : ('b, 'c) t -> ('a, 'b) t -> ('a, 'c) t

An alias of CORE.compose (to be iso with Preface_core).

val (%>) : ('a, 'b) t -> ('b, 'c) t -> ('a, 'c) t

An alias of OPERATION.compose_left_to_right (to be iso with Preface_core).

val (<<<) : ('b, 'c) t -> ('a, 'b) t -> ('a, 'c) t

An alias of CORE.compose (to be iso with Haskell's approach). Even <<< looks like <% (it is an alias for the same function), they differ in their priorities. OCaml documentation of operators priorities

val (>>>) : ('a, 'b) t -> ('b, 'c) t -> ('a, 'c) t

An alias of CORE.compose_left_to_right (to be iso with Haskell's approach). Even >>> looks like %> (it is an alias for the same function), they differ in their priorities. OCaml documentation of operators priorities

val (***) : ('a, 'b) t -> ('c, 'd) t -> ('a * 'c, 'b * 'd) t
val (&&&) : ('a, 'b) t -> ('a, 'c) t -> ('a, 'b * 'c) t
val (^>>) : ('a -> 'b) -> ('b, 'c) t -> ('a, 'c) t
val (>>^) : ('a, 'b) t -> ('b -> 'c) -> ('a, 'c) t
val (<<^) : ('b, 'c) t -> ('a -> 'b) -> ('a, 'c) t
val (^<<) : ('b -> 'c) -> ('a, 'b) t -> ('a, 'c) t
val (+++) : ('a, 'b) t -> ('c, 'd) t -> (('a, 'c) Preface_core.Shims.Either.t, ('b, 'd) Preface_core.Shims.Either.t) t

Infix version of CORE.choose.

val (|||) : ('a, 'c) t -> ('b, 'c) t -> (('a, 'b) Preface_core.Shims.Either.t, 'c) t

Infix version of CORE.fan_in.