• Stars
    star
    99
  • Rank 341,043 (Top 7 %)
  • Language
    OCaml
  • Created about 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A React binding for (OCaml | ReasonML) + BuckleScript with compile time enforcement of the "Rules of Hooks". Live Examples: https://reaml.netlify.com

Reaml (React + ML) Build Test

A React binding for (OCaml | ReasonML) + BuckleScript with compile time enforcement of the "Rules of Hooks" (How?).

Live Examples with Code | Starter | Opinionated Starter

Overview

The "Hello, World!" of Reaml looks like this:

module R = Reaml

let main = R.h1 [ R.id "hello" ] [ R.string "Hello, world!" ]

let () = main |> R.renderTo "main"

The code above renders <h1 id="hello">Hello, World!</h1> into the first element on the page matching the selector main.

Note: If you want to use ReasonML syntax instead of OCaml, check out the last section for the equivalent ReasonML code.


Components are defined using a syntax extension [@reaml.component "DisplayNameOfComponent"] applied to lets of one argument functions:

module R = Reaml

module Counter = struct
  type props = { initial : int }

  let[@reaml.component "Counter"] make { initial } =
    R.div [] [R.int initial]
end

Components are initialized using simple function calls:

let main = Counter.make { initial = 0 }

Hooks are invoked using a [@reaml] annotation on let expressions:

let[@reaml.component "Counter"] make { initial } =
  let[@reaml] count, setCount = R.useState initial in
  R.div [] [R.int initial]

Here's a full example of a Counter with two buttons, one to increment and one to decrement the value (full source):

module Counter = struct
  type props = { initial : int }

  let[@reaml.component "Counter"] make { initial }=
    let[@reaml] count, setCount = R.useState initial in
    R.div
      []
      [ R.button [ R.onClick (fun _ -> setCount (count - 1)) ] [ R.string "-" ]
      ; R.string " "
      ; R.int count
      ; R.string " "
      ; R.button [ R.onClick (fun _ -> setCount (count + 1)) ] [ R.string "+" ]
      ]
end

Custom hooks are created using a syntax extension [@reaml.hook] applied to funs of one argument. Here's a custom hook that wraps useReducer, invoking any action dispatched twice instead of once.

let[@reaml.hook] useDoubleReducer (reducer, initialValue) =
  let[@reaml] state, dispatch = R.useReducer reducer initialValue in
  let dispatchTwice action =
    dispatch action;
    dispatch action
  in
  state, dispatchTwice

These custom hooks are called in the same manner as the built-in hooks -- using let[@reaml]:

let[@reaml.component "CustomHooks"] make () =
  let reducer state action = state + action in
  let[@reaml] state, dispatch = useDoubleReducer (reducer, 0) in
  R.button [ R.onClick (fun _ -> dispatch 2) ] [ R.int state ]

Full example here.

Quick Start

$ git clone https://github.com/utkarshkukreti/reaml-starter
$ cd reaml-starter
$ yarn install
$ yarn build

This will build /src/Main.ml into the /dist/ directory which you can run by opening /index.html in your browser.

Feel free to copy code from examples into src/Main.ml and recompile.

How are the Rules of Hooks enforced at compile time?

Reaml uses an OCaml syntax extension to enforce them.

This requires annotating components with [@reaml.component], custom hooks with [@reaml.hook], and every use of a hook with let[@reaml].

For [@reaml.hook], the syntax extension appends a dummy argument to the function, the value of which must be of type Reaml.undefined (represented as plain undefined in JS).

For both [@reaml.hook] and [@reaml.component], the syntax extension traverses the top level let expressions and rewrites let[@reaml] expressions, appending the undefined value to the function call on the right.

If you call a hook without let[@reaml], you will get a type check error due to a missing argument.

After all this is done, the syntax extension traverses the whole program and checks whether any of these annotations were not processed and throws an error if it finds any because it means the annotation was incorrectly used.

For more examples, check out the files under /examples. A live demo of all the examples is available here.

ReasonML

Here's the Hello World example in ReasonML:

module R = Reaml;

let main = R.h1([R.id("hello")], [R.string("Hello, world!")]);

main |> R.renderTo("main");

Here's an example of ReasonML code which uses all the three annotations that this library uses:

module R = Reaml;

[@reaml.hook]
let useDoubleReducer = ((reducer, initialValue)) => {
  let[@reaml] (state, dispatch) = R.useReducer(reducer, initialValue);
  let dispatchTwice = action => {
    dispatch(action);
    dispatch(action);
  };

  (state, dispatchTwice);
};

[@reaml.component "CustomHooks"]
let make = () => {
  let reducer = (state, action) => state + action;
  let[@reaml] (state, dispatch) = useDoubleReducer((reducer, 0));
  R.button([R.onClick(_ => dispatch(1))], [R.int(state)]);
};

let main = make();
main |> R.renderTo("main");

For more guidance on how to translate OCaml code into ReasonML, try pasting the OCaml code in the Try ReasonML page or read this guide.

License

MIT

More Repositories

1

select.rs

A Rust library to extract useful data from HTML documents, suitable for web scraping.
Rust
953
star
2

markup.rs

A blazing fast, type-safe template engine for Rust.
Rust
350
star
3

draco

Draco is a Rust library for building client side web applications with Web Assembly.
Rust
301
star
4

ex_top

ExTop is an interactive monitor for the Erlang VM written in Elixir.
Elixir
292
star
5

speculate.rs

An RSpec inspired minimal testing framework for Rust.
Rust
270
star
6

purescript-hedwig

Hedwig is a fast, type safe, declarative PureScript library for building web applications.
PureScript
131
star
7

diff.rs

An LCS based slice and string diffing implementation.
Rust
76
star
8

tailwind.run

62
star
9

elm-remotedev

Integration of Elm Application's `update` function with Redux DevTools Extension. An alterative to the official Elm Debugger.
JavaScript
60
star
10

edn.rs

An EDN (Extensible Data Notation) parser in Rust.
Rust
48
star
11

bs-preact

Deprecated in favor of https://github.com/utkarshkukreti/reaml, which has more features, works with the latest BuckleScript, and can be used with both React and Preact.
OCaml
39
star
12

whois.ex

Pure Elixir WHOIS client and parser.
Elixir
27
star
13

munch.rs

Blazing fast, zero-copy parser combinator library for Rust with an elegant API for both strings and bytes.
Rust
21
star
14

purescript-corefn.rs

A parser for PureScript's corefn JSON representation.
Rust
14
star
15

check.c

check.c is a mini testing framework for C that I built to do Test-Driven Development in my C projects.
C
13
star
16

purescript-hertz

PureScript
11
star
17

bootstrap-themes

Open Source, MIT Licensed, Customizable Themes for Bootstrap 4.
HTML
11
star
18

psoc

[WIP] A PureScript to JavaScript compiler focused on increasing performance and decreasing size of the generated code.
Rust
10
star
19

apl-inputrc

Easier way to input APL symbols in GNU APL (or other interactive command line programs).
Ruby
9
star
20

bs-preact-starter

Deprecated in favor of https://github.com/utkarshkukreti/reaml, which has more features, works with the latest BuckleScript, and can be used with both React and Preact.
OCaml
9
star
21

flip-flop.rs

This library implements the [flip-flop operator from Perl and Ruby](https://en.wikipedia.org/wiki/Flip-flop_(programming)) as a Rust macro.
Rust
7
star
22

draco-starter

A starter for https://github.com/utkarshkukreti/draco.
Rust
6
star
23

vite-typescript-library-starter

`mkdir foo && cd foo`; `git clone https://github.com/utkarshkukreti/vite-typescript-library-starter . && rm -rf .git && git init && git add . && git commit -m init && yarn`
TypeScript
6
star
24

wn.rs

Rust
4
star
25

reaml-starter

A starter for [Reaml](https://github.com/utkarshkukreti/reaml) demonstrating a `useReducer` based Counter.
OCaml
4
star
26

catena-r1

A functional, concatenative programming language, inspired by Joy, and implemented in Haskell [Revision 1]
Haskell
4
star
27

zigzag.ex

Zigzag is a fast and flexible parallel processing library for Elixir.
Elixir
3
star
28

parco

A hyper-optimized 1kb library to build fully type-safe parsers in TypeScript.
TypeScript
3
star
29

timingapp.zsh

A simple script to enable directory level tracking for zsh in TimingApp.
Shell
3
star
30

should.c

should.c is a mini testing framework for C, which also happens to be pretty.
C
3
star
31

siphash.rs

Simple and fast implementation of the SipHash hashing algorithm in Rust
Rust
2
star
32

hybrid-core

PHP
2
star
33

rubymotion-breakout

A simple implementation of the Breakout game in RubyMotion.
Ruby
2
star
34

rubymotion-hackernews

Ruby
2
star
35

typescript-preact-tailwind-parcel-starter

TypeScript
2
star
36

phaad

A beautiful way to write PHP code.
Ruby
2
star
37

twitter-angellist-bridge

Major WIP
Ruby
2
star
38

project-euler

Repository of questions of Project Euler that I've solved, in various languages.
Common Lisp
2
star
39

snabbdom-transition

Vue.js inspired transitions component for Snabbdom.
JavaScript
2
star
40

ace_editor-rails

Ace Editor for the Rails pipeline
Ruby
2
star
41

reaml-opinionated-starter

An Opinionated Starter for Reaml which includes Preact, TypeScript, TailwindCSS, Relude, PurgeCSS. Live Demo: https://reaml-opinionated-starter.netlify.com
OCaml
2
star
42

gitstats

Ruby
1
star
43

elm-animate-on-change-poc

https://utkarshkukreti.github.io/elm-animate-on-change-poc/
JavaScript
1
star
44

fropy

Process memory and cpu time benchmarker
Ruby
1
star
45

iff.rs

Rust
1
star
46

gm.ex

Idiomatic GraphicsMagick wrapper for Elixir.
Elixir
1
star
47

bucklescript-minimal-starter

OCaml
1
star
48

rubymotion-chipmunktest

Ruby
1
star
49

nathans-university-pl101

My solutions to Nathan's University's PL101 course, done in both JS and Haskell.
Haskell
1
star
50

ruby-vps

under development
Ruby
1
star
51

rubymotion-snake

Ruby
1
star
52

snipmate-snippets

1
star
53

challenger

Ruby
1
star
54

geoip_server

Ruby
1
star
55

escodegen.rs

Rust
1
star
56

rubymotion-cocos2dbox2dtest

Ruby
1
star
57

select.ex

An Elixir library to extract useful data from HTML documents, suitable for web scraping.
Elixir
1
star
58

elm-inflect

elm-inflect lets you convert a String to its plural, singular, camelCase, and PascalCase forms.
Elm
1
star
59

hapistrano

Ruby
1
star
60

vite-library-starter

TypeScript
1
star
61

qq

A simple utility to store and access key/value pairs from the shell, useful for storing common urls, etc.
Ruby
1
star
62

calvin

Terse, APL/J/K inspired programming language. Major WIP.
Ruby
1
star
63

vite-preact-typescript-tailwind-starter

https://vite-preact-typescript-tailwind-starter.vercel.app
JavaScript
1
star
64

copath_parser

A parser for data from the CoPATH database. Currently on "prostrate" type output can be parsed.
Ruby
1
star
65

purescript-weber

PureScript
1
star
66

putf

Quickly upload files to a remote server, and copy its url to your clipboard.
Ruby
1
star
67

geoip_client

Ruby
1
star
68

sailor

Ruby
1
star
69

euler

Project Euler Solutions in Ruby
Ruby
1
star
70

subtle-lang

Subtle is a Terse, Array based Programming Language, heavily inspired by the K Programming Language, and partly by APL and J.
Ruby
1
star
71

google-codejam-solutions

My Google CodeJam solutions in various languages
1
star
72

typecodec

Under 1kB, fast, type-safe runtime validation of unknown data for TypeScript.
TypeScript
1
star
73

wp

Unofficial git clone of WordPress repository
PHP
1
star
74

ubuntu-scripts

1
star
75

repository_hosting_backup

Backs up all repositories in your RepositoryHosting.com account into a folder.
Ruby
1
star
76

dust-deploy

small server deployment tool for complex environments
Ruby
1
star
77

long_url

Ruby
1
star
78

possible_habtm_bug

Run rake db:migrate && rake db:seed. Code is in db/seeds.rb
Ruby
1
star
79

typescript-react-tailwind-sass-parcel-starter

HTML
1
star
80

gideros-community-libraries

A collection of libraries for Gideros, maintaned by the community.
Shell
1
star
81

ruport_compatible_with_stresser

(Use branch compat) A complete hack to make ruport work with https://github.com/moviepilot/stresser on Ruby 1.9.2
Ruby
1
star
82

elm-css-modules

`elm-css-modules` compiles CSS modules written in CSS, Sass, or SCSS to plain CSS files and generates Elm definitions for every rule.
JavaScript
1
star
83

better_range.rs

An alternative to the std::iter::range* iterators supporting floats and chars, and a fluent interface to construct ranges.
Rust
1
star
84

advent-of-code-2020

Ruby
1
star
85

project-euler-old

Repository of all the questions of ProjectEuler that I've solved, in various languages.
Ruby
1
star