Skip to content

odis-labs/ppx_obj_make

Repository files navigation

ppx_obj_make

Unreleased

This syntax extension leverages ReasonML's object literal notation to simplify initialization of labeled multi-parameter functions. In particular it is useful for large nested configuration DSLs where the regular labeled function application syntax might be cumbersome to use because of the dangling () required for optional argument erasure.

Quickstart

To install ppx_obj_make in an esy project, add the following dependency to your package.json file:

  "dependencies": {
    "ppx_obj_make": "github:rizo/ppx_obj_make#master"
  }

In your dune project add the following preprocess configuraton to your dune file:

(preprocess (pps ppx_obj_make))

Usage

Any module containing a function named make with labeled arguments can be used with this extension.

open Printf;

module Person = {
  let make = (~name, ~age, ()) =>
    printf("Hi %s! You are %d years old.\n", name, age);
};

/* Use object literal notation to call `Person.make`. */
Person { "name": "Dylan", "age": 32 };

Examples

Consider this example in ReasonML for a Kubernetes deployment (that uses the rekube library). The translation is only applied to JSON-literals.

let app = (~namespace, ~version) =>
  Deployment {
    "api_version": "extensions/v1beta1",
    "kind": "Deployment",
    "metadata": Meta { name, namespace },
    "spec": Deployment_spec {
      "replicas": 1,
      "template": Pod_template_spec {
        "metadata": Meta {
          "name": name,
          "labels": [("app", name)],
        },
        "spec": Pod_spec {
          "containers": [
            "Container" {
              "name",
              "image": "my-company/my-app:" ++ version,
              "command": ["app"],
              "args": [
                "--verbosity=debug",
                "--listen-prometheus=9090"
              ],
              "ports": [Port { "name": "metrics", "container_port": 9090 }],
              "resources": Resources {
                "limits":   [cpu("100m"), memory("500Mi")],
                "requests": [cpu("500m"), memory("1Gi")]
              }
            }
          ]
        }
      }
    }
  };

This is translated by the preprocessor into:

let app = (~namespace, ~version) =>
  Deployment.make(
    ~api_version="extensions/v1beta1",
    ~kind="Deployment",
    ~metadata=Meta.make(~name, ~namespace, ()),
    ~spec=Deployment_spec.make(
      replicas: 1,
      template: Pod_template_spec.make(
        ~metadata=Meta.make(
          ~name,
          ~labels=[("app", name)],
          ()
        ),
        ~spec=Pod_spec.make(
          ~containers: [
            Container.make(
              ~name,
              ~image="my-company/my-app:" ++ version,
              ~command=["app"],
              ~args=[
                "--verbosity=debug",
                "--listen-prometheus=9090"
              ],
              ~ports-[Port.make(~name="metrics", ~container_port=9090, ())],
              ~resources=Resources.make(
                limits:   [cpu("100m"), memory("500Mi")],
                requests: [cpu("500m"), memory("1Gi")],
                ()
              ),
              ()
            )
          ],
          ()
        ),
        ()
      ),
      ()
    ),
    ()
  );

Releases

No releases published

Packages

No packages published

Languages