Skip to content

Commit

Permalink
OCaml Cookbook (#1839)
Browse files Browse the repository at this point in the history
* Prototype OCaml Cookbook

* add a rule to crunch the cookbook directory

* move position of cookbook

* side-by-side code view like Go by Example

* copy to clipboard, random number gen recipe

* hierarchy: category > task > recipe

- URL we serve this under is docs/cookbook/[task slug]/[recipe slug]
- multiple recipes per task
- recipe page displays links to other recipes for the same task

* bring back the styles on the input that I accidentally replaced by 'hidden'

* move cookbook to community section, refactor active_top_nav_item to be controlled by learn_layout.eml and community_layout.eml

* move to Learn area

* Cookbook : encoding (#2097)

* Cookbook index : add encoding

* Cookbook encoding typos

* Add dune

* Update 00-camomile.md / remove tab

* Update 00-camomile.md / remove tab

* Update 00-camomile.md

* Apply suggestions from code review

Co-authored-by: Christine Rose <christinerose@users.noreply.github.com>

---------

Co-authored-by: Frederic LOYER <frederic.loyer@club-internet.fr>
Co-authored-by: Christine Rose <christinerose@users.noreply.github.com>

* Cookbook : and Sorting list and arrays (#2098)

* Cookbook: add Sorting

* Update 00-stdlib.md / remove tabs

* Update 00-stdlib.md / remove tabs

---------

Co-authored-by: Frederic LOYER <frederic.loyer@club-internet.fr>

* Cookbook textprocessing (#2104)

* Cookbook: text processing

* Cookbook: text processing (remove tabs)

* Cookbook: text processing (typo)

* Cookbook: text processing (typo)

* Cookbook: text processing (typo)

---------

Co-authored-by: Frederic LOYER <frederic.loyer@club-internet.fr>

* Cookboot : Add a Database / ezsqlite entry (#2100)

* Cookbook : Database/ezsqlite

* Remove tabs

* Declare packages

* Indent error

* typo

* Update cookbook_categories.yml : fix folder name in cookbook_categories.yml

* Update cookbook_categories.yml - cookbook index fix

* Update 00-ezsqlite.md

---------

Co-authored-by: Frederic LOYER <frederic.loyer@club-internet.fr>

* Cookbook concurrency : Lwt (#2107)

* Cookbook: add concurrency / Lwt

* Cookbook: add concurrency / Lwt - fix

* Cookbook: add concurrency / Lwt - fix

* Cookbook: add concurrency / Lwt - fix

---------

Co-authored-by: Frederic LOYER <frederic.loyer@club-internet.fr>

* Cookbook caqti ppx rapper (#2108)

* Cookbook : Caqti and ppx_rapper

* Cookbook : Caqti and ppx_rapper - fix

* Cookbook : Caqti and ppx_rapper - fix

* Cookbook : Caqti and ppx_rapper - @ notation

* add query with WITH clause

* typo WITH/WHERE

* fix

* fix

* fix

* fix

* fix

---------

Co-authored-by: Frederic LOYER <frederic.loyer@club-internet.fr>

* simplify data format of cookbook files

* change data format to .ml file with YAML header, comments get displayed side-by-side with the code

* Cookbook Ezsqlite - typo and rewriting (#2119)

Co-authored-by: Frédéric LOYER <frederic.loyer@club-internet.fr>

* Cookbook Sorting - typo (#2118)

Co-authored-by: Frédéric LOYER <frederic.loyer@club-internet.fr>

* add dark mode styles

* Cookbook : fix in Lwt (type mismatch with iter_s/iter_p functions) (#2127)

* Cookbook : fix in Lwt

* Update 00-lwt.ml

---------

Co-authored-by: Frédéric LOYER <frederic.loyer@club-internet.fr>

* Update 00-caqti-ppx-rapper.ml - fix sqlite -> sqlite3 (#2126)

* rearrange category hierarchy and render all recipes for a task, name rercipes based on task and first listed package

* rebase

* add some tasks

* list the task separately in the table and all the recipes below the task

* add aria-label to make clear to screen-readers where the recipe link is going

* Added description field to tasks

* Task pages

* Task description

* Remove str and stdlib recipes

* Cookbook description text

* Formatting

* minor style changes

* Formatting

* Update CONTRIBUTING.md

* Fix tasks.yml processing

* Formatting

* Add Yaml deserializing recipe

* Refactor JSON tasks

* Text and formatting

* Review

* Remove sorting recipe

* Cleanup

* Delete postponed recipes

* Update localtime recipe

* Do not display package versions

* Formatting

* Display used libraries per package

* Display version as tested and category path

* Fix contribution text

* Fixes

* Formatting

* Fix category path

* Formatting

* Refactoring

* Add hl_yaml recipe

* Fix comments

* Formatting

* Formatting

* Review edits

* Fix typo

* Import FS tasks from PR 1400

* Bring back random generation

* Bring back random generation, con't

* Read text and gziped file

* Formatting

* Fix typo

* Formatting

* Remove some recipes

* Rebase

* Make task description optional

* Random values

* Formatting

* line editing CONTRIBUTING.md

---------

Co-authored-by: sabine <sabine@users.noreply.github.com>
Co-authored-by: Frédéric Loyer <116354005+F-Loyer@users.noreply.github.com>
Co-authored-by: Frederic LOYER <frederic.loyer@club-internet.fr>
Co-authored-by: Christine Rose <christinerose@users.noreply.github.com>
Co-authored-by: sabine <6594573+sabine@users.noreply.github.com>
Co-authored-by: Cuihtlauac ALVARADO <cuihtmlauac@tarides.com>
  • Loading branch information
7 people authored Apr 23, 2024
1 parent 465efa3 commit 8d025ec
Show file tree
Hide file tree
Showing 38 changed files with 1,117 additions and 60 deletions.
34 changes: 32 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ We've provided a list of community-driven content below. When adding content to
- [Success Stories](#content-success-story)
- [Academic and Industrial Users](#content-user)
- [OCaml Books](#content-book)
- [OCaml Cookbook Recipes](#content-cookbook)
- [Recurring Events](#content-recurring-event)
- [Upcoming Events](#content-upcoming_event)
- [The OCaml Changelog](#content-changelog)
Expand Down Expand Up @@ -112,6 +113,35 @@ You can add a new industrial user by creating a new Markdown file in [data/acade
You can add a new OCaml book by creating a new Markdown file in [data/books/](data/books/). For instance: [ocaml-from-the-very-beginning.md](data/books/ocaml-from-the-very-beginning.md).

### <a name="content-cookbook"></a>Add a Recipe to the OCaml Cookbook

The OCaml cookbook is a place where OCaml developers share how to solve common
tasks in OCaml using packages from the OCaml ecosystem.

Here are the steps to contribute a recipe for an existing task:
* Find the task in the [data/cookbook/tasks.yml](data/cookbook/tasks.yml) file
* Go to the task folder inside [data/cookbook/](data/cookbook/) which has the
same name as the task's `slug`
* Create a `.ml` file containing the recipe and a YAML header with metadata about
the recipe.

If the recipe does not fit into any existing task, you also need to create a
task. Add a `task:` entry in [data/cookbook/tasks.yml](data/cookbook/tasks.yml)
file. Fields `title`, `description`, and `slug` are mandatory. The task must be
located under a relevant `category:` field.

Finally, it is also possible to create and organise groups of tasks by creating
new categories. Categories are recursive and may have subcategories, which are
full categories too. A task listed in
[data/cookbook/tasks.yml](data/cookbook/tasks.yml) may have no recipes yet. On the
other hand, it is not allowed to have a task folder in
[data/cookbook/](data/cookbook/) that does not correspond to a task from the
[data/cookbook/tasks.yml](data/cookbook/tasks.yml) file because it triggers a
compilation error.

Each recipe is a way to perform a task using a combination of open-source
libraries.

### <a name="content-recurring-event"></a>Add A Recurring Event

> Contribute a [Recurring Event](https://ocaml.org/community).
Expand All @@ -131,7 +161,7 @@ The [OCaml Changelog](https://ocaml.org/changelog) is a feed of the latest relea
- [The OCaml Compiler](https://github.com/ocaml/ocaml)
- [OCaml Platform Tools](https://ocaml.org/docs/platform)

Before a release of the above tools land on the `opam-repository`, the release manager of the project opens a pull request (PR) on OCaml.org with an announcement for the release.
Before a release of the above tools land on the `opam-repository`, the project's release manager opens a pull request (PR) on OCaml.org with a release announcement.

The announcement is proofread by the OCaml.org team, who will also suggest highlighting release features.

Expand All @@ -143,7 +173,7 @@ The preferred workflow for contributing to a repository is to fork the main repo

If you aren't familiar with how to work with Github or would like to learn it, here is [a great tutorial](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github).

Feel free to use any approach while creating a PR. Here are a few suggestions from the dev team:
Feel free to use any approach while creating a PR. Here are a few suggestions from the Dev team:

- If you are not sure whether your changes will be accepted or want to discuss the method before delving into it, please create an issue and ask.
- Clone the repo locally (or continue editing directly in GitHub if the change is small). Checkout
Expand Down
54 changes: 54 additions & 0 deletions data/cookbook/deserialise-from-yaml/00-yaml.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
packages:
- name: yaml
tested_version: 3.2.0
used_libraries:
- yaml
- name: ppx_deriving_yaml
tested_version: 0.2.2
used_libraries:
- ppx_deriving_yaml
---
(* The syntax `{| ... |}` is a quoted string. *)
let yaml = {|
french name: pâte sucrée
ingredients:
- name: flour
weight: 250
- name: butter
weight: 100
- name: sugar
weight: 100
- name: egg
weight: 50
- name: salt
weight: 5
steps:
- soften butter
- add sugar
- add egg and salt
- add flour
|}

(* The `[@@deriving of_yaml]` attribute makes library `ppx_deriving_yaml` generate the function
``ingredient_of_yaml : Yaml.value -> (ingredient, [> `Msg of string]) result``
If both serialising and deserialising are needed, replace `of_yaml` by `yaml`. *)
type ingredient = {
name: string;
weight: int;
} [@@deriving of_yaml]

(* The `[@@deriving of_yaml]` attribute makes library `ppx_deriving_yaml` generate the function
``recipe_of_yaml : Yaml.value -> (ingredient, [> `Msg of string]) result``. *)
type recipe = {
name: string; [@key "french name"]
ingredients: ingredient list;
steps: string list;
} [@@deriving of_yaml]

(* Parsing and conversion into record are chained. *)
let pate_sucree =
yaml
|> Yaml.of_string
|> fun yaml -> Result.bind yaml recipe_of_yaml

52 changes: 52 additions & 0 deletions data/cookbook/deserialise-from-yaml/01-hl_yaml.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
packages:
- name: hl_yaml
tested_version: 1.0.0
used_libraries:
- hl_yaml
- name: ppx_deriving_yojson
tested_version: 3.7.0
used_libraries:
- ppx_deriving_yojson
---
(* The syntax `{| ... |}` is a quoted string. *)
let yaml = {|
french name: pâte sucrée
ingredients:
- name: flour
weight: 250
- name: butter
weight: 100
- name: sugar
weight: 100
- name: egg
weight: 50
- name: salt
weight: 5
steps:
- soften butter
- add sugar
- add egg and salt
- add flour
|}

(* The `[@@deriving of_yojson]` attribute makes library `ppx_deriving_yojson` generate the function
`ingredient_of_yojson : Yojson.Safe.t -> (ingredient, string) result`.
If both serialising and deserialising are needed, replace `of_yojson` by `yojson`. *)
type ingredient = {
name: string;
weight: int;
} [@@deriving of_yojson]

(* The `[@@deriving of_yojson]` attribute makes library `ppx_deriving_yojson` generate the function
``recipe_of_yojson : Yojson.Safe.t -> (ingredient, string) result``. *)
type recipe = {
name: string; [@key "french name"]
ingredients: ingredient list;
steps: string list;
} [@@deriving of_yojson]

(* Parsing receives conversion into record as an argument. *)
let pate_sucree =
yaml
|> Hl_yaml.Unix.parse ~of_yojson:recipe_of_yojson
63 changes: 63 additions & 0 deletions data/cookbook/generate-random-values/00-mirage-crypto-rng.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
packages:
- name: mirage-crypto-rng
tested_version: 0.11.3
used_libraries:
- mirage-crypto-rng.unix
- name: cstruct
tested_version: 6.2.0
used_libraries:
- cstruct
- name: randomconv
tested_version: 0.1.3
used_libraries:
- randomconv
---

(* Initialize the `Mirage_crypto_rng` with the an entropy source. *)
let () =
Mirage_crypto_rng_unix.initialize
(module Mirage_crypto_rng.Fortuna)

(* Random bytes generation function. *)
let generator n =
n
|> Mirage_crypto_rng.generate
|> Cstruct.to_string

(* Generate `int8`, `int16`, `int32` or `int64` values. *)
let int8 () = Randomconv.int8 generator
let int16 () = Randomconv.int16 generator
let int32 () = Randomconv.int32 generator
let int64 () = Randomconv.int64 generator

(* Generate a random `int` or `float` values strictly lower than `bound`. *)
let int ?bound () =
Randomconv.int ?bound generator
let float ?bound () =
Randomconv.float ?bound generator

(* Generate `char` values *)
let char () = () |> int8 |> Char.chr
let digit () = 48 + int ~bound:10 () |> Char.chr
let majuscule () = 65 + int ~bound:26 () |> Char.chr
let minuscule () = 97 + int ~bound:26 () |> Char.chr
let letter () =
let n = int ~bound:52 () in
Char.chr @@ n + if n < 26 then 65 else 71
let alphanum () =
let n = int ~bound:62 () in
Char.chr @@ n
+ if n < 10 then 48 else if n < 36 then 55 else 61

(* Random bytes into byte arrays or big arrays. *)
let bytes n =
n
|> Mirage_crypto_rng.generate
|> Cstruct.to_bytes
let bigarray n =
n
|> Mirage_crypto_rng.generate
|> Cstruct.to_bigarray

let list n gen = List.init n (fun _ -> gen ())
23 changes: 23 additions & 0 deletions data/cookbook/get-todays-date/00-stdlib.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
packages: []
discussion: |
- **Understanding `Unix.localtime` and `Unix.time`:** The `Unix.localtime` function converts a timestamp obtained from `Unix.time` (which returns the current time since the Unix epoch) into a local time, represented by a `tm` structure. This structure includes fields like `tm_year`, `tm_mon`, and `tm_mday` for year, month, and day, respectively.
- **Month and Year Adjustments:** In OCaml's `Unix` module, the month is zero-indexed (0 for January, 11 for December), and the year is the number of years since 1900. Don't forget to adjust these values to get a human-readable date.
- **Alternative Libraries:** For more complex date-time operations, consider using external libraries like `calendar` or `timedesc`, which offer more functionalities like time zone handling and date arithmetic.
---

(* Use the `unix` library, which ships with OCaml's standard library, and
provides functions to work with dates and times. You can use the `Unix` module
to get the current date and time: *)
let today = Unix.localtime (Unix.time ());;
let day = today.Unix.tm_mday;;

(* Months are 0 to 11. *)
let month = today.Unix.tm_mon + 1;;

(* Years since 1900. *)
let year = today.Unix.tm_year + 1900;;

(* You can use the `Printf` module to print the date: *)
Printf.printf "The current date is %04d-%02d-%02d\n"
year month day;;
5 changes: 5 additions & 0 deletions data/cookbook/read-text-file/00-in_channel.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
packages: []
---
(* Read the text file. *)
let text = In_channel.(with_open_text "/etc/passwd" input_all)
Loading

0 comments on commit 8d025ec

Please sign in to comment.