Records

The input file in this example Library.fs looks like this:

namespace Example
open Myriad.Plugins

[<Generator.Fields "fields">]
type Test1 = { one: int; two: string; three: float; four: float32 }
type Test2 = { one: Test1; two: string }

An attribute is used by the fields plugin so that the code generator knows which parts of the input AST should be consumed by the plugin. If you had several records and you only wanted the fields plugin to operate on Test1 then the attribute would be used like in the example about to only apply Generator.Fields to the Test1 record. Note, if you wanted a plugin that just processes the whole input then there is no need to provide such an attribute. Myriad aims to be a library rather than a full framework that ties you to the mechanism used to input and generate code, its up to you how you generate the code, Myriad just aims to help to make this as painless and flexible as possible.

To control what namespace is used as well as supplying any other information to plugins a myriad.toml configuration file is used. This is specified in the generator attribute, in the example above you can see the configuration section is fields [<Generator.Fields "fields">]. The corresponding myriad.toml file looks as follows:

[fields]
namespace = "TestFields"

The fields plugin uses only a single configuration key namespace to control the resulting namespace the record helpers are generated

The fields plugin in this example will generate the following code at prebuild and compile the code into your assembly:

//------------------------------------------------------------------------------
//        This code was generated by myriad.
//        Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------
namespace rec TestFields

module Test1 =
    open Example

    let one (x : Test1) = x.one
    let two (x : Test1) = x.two
    let three (x : Test1) = x.three
    let four (x : Test1) = x.four

    let create (one : Test1) (two : string) (three : float) (four : float32) : Test1 =
        { one = one
          two = two
          three = three
          four = four }

    let map (mapone : int -> int) (maptwo : string -> string) (mapthree : float -> float) (mapfour : float32 -> float32) (record': Test1) =
      { record' with
          one = mapone record'.one
          two = maptwo record'.two
          three = mapthree record'.three
          four = mapfour record'.four }

The fields plugin generates a map for each field in the input record, a create function taking each field, and a map function that takes one function per field in the input record.

The map functions for each field are useful in situations where you just want to use a single field from a record in a lambda like a list of records:

let records = [{one = "a"; two = "aa"; three = 42.0; four = 172.0f}
               {one = "b"; two = "bb"; three = 42.0; four = 172.0f}]
 records |> List.sortBy Test1.one