# fieldglass Generates accessors and composable lenses from OCaml record declarations, allowing a caller to read or replace a nested field through ordinary functions while retaining the surrounding record structure. ```ocaml type swatch = { colour : string; label : string } [@@fieldglass generate] let grey = { colour = "grey"; label = "sample" } let blue = set_colour "blue" grey let labelled = update_label ~f:String.uppercase_ascii grey let colour = Fieldglass.view _colour blue ``` For each field, the rewriter emits a getter, a setter prefixed with `set_`, an updater prefixed with `update_`, and a getter/setter pair whose name begins with `_`. A setter takes the replacement value followed by the source record, while an updater applies its labelled `~f` argument to the existing field value and constructs a replacement record containing the result. Generated updates retain the unfocussed fields and perform no assignment to the source record, including when the declaration contains mutable fields. Both `[@@fieldglass generate]` and `[@@lens generate]` select this expansion, which produces ordinary OCaml functions that can be used independently of the `Fieldglass` runtime's composition operations. ## Build Run `make` to compile the runtime archive and PPX executable, or `make test` to also check lens operations, generated record accessors, configuration errors, and linkage against an explicit module interface. To compile a consumer, pass the rewriter through `-ppx` and link the runtime archive before the source file, as in the following invocation: ```sh ocamlc -ppx ./rewrite fieldglass.cma example.ml -o example ``` The command `OPAMBUILDTEST=true opam pin add fieldglass .` builds and tests the package before installing the `fieldglass` rewriter and runtime library. Use the same OCaml compiler for the rewriter and its consumers, since the PPX exchanges compiler syntax trees and links against the compiler libraries. ## Lenses `Fieldglass.lens ~view ~set` constructs a pair with representation `('s -> 'a) * ('b -> 's -> 't)`, where the getter extracts a value from the source and the setter combines a replacement with that source to produce the result. The separate type parameters permit a lens to change the type of its focussed value when the enclosing structure admits that change. `view` applies the getter, `set` applies the setter, and `over ~f` passes the getter's result through `f` before supplying it to the setter alongside the original source. With `compose outer inner`, reading follows the outer getter and then the inner getter; replacement updates the inner structure before passing it back through the outer setter, preserving the surrounding data according to the supplied setters. `Fieldglass.Infix` exposes these operations as `^.`, `^~`, and `^%`, with `^>` composing an outer lens with an inner lens and `^<` accepting the same operands in reverse order. The runtime also supplies tuple projections and the identity lens `_id`, together with `_hd` and `_tl` for focussing on a list's head or tail; either list lens raises `Invalid_argument` when asked to read or update an empty list. ## Configuration Supply labelled options after `generate` to control the generated names, argument order, and selection of operations, using identifiers or strings for prefixes and argument names. Boolean options accept a bare label as an enabled flag, or an explicit `true` or `false` value when the configuration needs to specify the setting directly. | Option | Behaviour | | --- | --- | | `~field_prefix:name` | Add a prefix to each field name. | | `~field_prefix_from_type` | Use the record type name as the prefix. | | `~get_prefix:name` | Prefix getter names. | | `~set_prefix:name` | Replace the `set` prefix. | | `~update_prefix:name` | Replace the `update` prefix. | | `~self_arg_first` | Put the record first in setters and updaters. | | `~func_named_arg:name` | Rename the updater's `f` argument. | | `~func_no_named_arg` | Make the updater's function argument positional. | | `~no_get` | Omit getters. | | `~no_set` | Omit setters. | | `~no_update` | Omit updaters. | | `~no_lens` | Omit lens pairs. | | `~just_lens` | Generate lens pairs without named accessors. | Before applying naming options, the rewriter removes the longest shared field prefix ending at an underscore boundary, so fields such as `paint_colour` and `paint_label` produce the base names `colour` and `label`. A record containing only one field keeps that field's complete name, while generated lens pairs retain replacement-first setters even when `~self_arg_first` changes the argument order of the named accessors. An annotation attached to a mutually recursive record declaration applies to the entire declaration group, whose options the rewriter processes from left to right with later settings taking precedence. When records share field labels, `~field_prefix_from_type` gives their accessors distinct names; the rewriter rejects duplicate generated bindings and repeated options within a single annotation with a compilation error. Place generation annotations on record declarations in implementations and declare the exported accessor types explicitly in module signatures, since the rewriter emits value bindings and rejects generation annotations in signatures. For private records or records containing universally quantified fields, select `~no_set ~no_update ~no_lens` to generate getters without requesting replacement operations that the rewriter does not generate for those declarations.