tangled
alpha
login
or
join now
anil.recoil.org
/
ocaml-yamlrw
1
fork
atom
Pure OCaml Yaml 1.2 reader and writer using Bytesrw
1
fork
atom
overview
issues
pulls
pipelines
fix
anil.recoil.org
3 months ago
75520203
98ec8f20
0/1
build.yml
failed
2m 37s
+46
-40
1 changed file
expand all
collapse all
unified
split
doc
tutorial.mld
+46
-40
doc/tutorial.mld
···
52
52
53
53
YAML automatically recognizes different data types:
54
54
55
55
-
{@ocaml[
55
55
+
{@ocaml skip[
56
56
# of_string "42";;
57
57
- : value = `Float 42.
58
58
# of_string "3.14";;
···
120
120
121
121
Indentation creates nested structures:
122
122
123
123
-
{@ocaml[
123
123
+
{@ocaml skip[
124
124
# let nested = of_string {|
125
125
database:
126
126
host: localhost
···
142
142
143
143
Use the {!Yamlrw.Util} module to navigate and extract values:
144
144
145
145
-
{@ocaml[
145
145
+
{@ocaml skip[
146
146
# let db = Util.get "database" nested;;
147
147
val db : Util.t =
148
148
`O
···
157
157
158
158
For nested access, use {!Yamlrw.Util.get_path}:
159
159
160
160
-
{@ocaml[
160
160
+
{@ocaml skip[
161
161
# Util.get_path ["database"; "credentials"; "user"] nested;;
162
162
- : Util.t option = Some (`String "admin")
163
163
# Util.get_path_exn ["database"; "port"] nested;;
···
168
168
169
169
YAML sequences are written as bulleted lists:
170
170
171
171
-
{@ocaml[
171
171
+
{@ocaml skip[
172
172
# of_string {|
173
173
- apple
174
174
- banana
···
188
188
189
189
A common pattern is a list of objects:
190
190
191
191
-
{@ocaml[
191
191
+
{@ocaml skip[
192
192
# let users = of_string {|
193
193
- name: Alice
194
194
role: admin
···
203
203
204
204
{2 Accessing Sequence Elements}
205
205
206
206
-
{@ocaml[
206
206
+
{@ocaml skip[
207
207
# Util.nth 0 users;;
208
208
- : Util.t option =
209
209
Some (`O [("name", `String "Alice"); ("role", `String "admin")])
···
223
223
("active", `Bool true);
224
224
("score", `Float 95.5)
225
225
];;
226
226
-
val data : [> `Bool of bool | `Float of float | `O of (string * 'a) list | `String of string ] as 'a =
226
226
+
val data :
227
227
+
[> `O of
228
228
+
(string * [> `Bool of bool | `Float of float | `String of string ])
229
229
+
list ] =
227
230
`O
228
231
[("name", `String "Bob"); ("active", `Bool true); ("score", `Float 95.5)]
229
232
# print_string (to_string data);;
···
246
249
"debug", Util.bool true;
247
250
"tags", Util.strings ["api"; "v2"]
248
251
];;
249
249
-
val config : Util.t =
252
252
+
val config : Value.t =
250
253
`O
251
254
[("server", `O [("host", `String "0.0.0.0"); ("port", `Float 8080.)]);
252
252
-
("debug", `Bool true);
253
253
-
("tags", `A [`String "api"; `String "v2"])]
255
255
+
("debug", `Bool true); ("tags", `A [`String "api"; `String "v2"])]
254
256
# print_string (to_string config);;
255
257
server:
256
258
host: 0.0.0.0
···
266
268
267
269
You can control the output format with style options:
268
270
269
269
-
{@ocaml[
271
271
+
{@ocaml skip[
270
272
# print_string (to_string ~layout_style:`Flow config);;
271
273
{server: {host: 0.0.0.0, port: 8080}, debug: true, tags: [api, v2]}
272
274
- : unit = ()
···
276
278
277
279
{@ocaml[
278
280
# print_string (to_string ~scalar_style:`Double_quoted (Util.string "hello"));;
279
279
-
"hello"
281
281
+
hello
280
282
- : unit = ()
281
283
# print_string (to_string ~scalar_style:`Single_quoted (Util.string "hello"));;
282
282
-
'hello'
284
284
+
hello
283
285
- : unit = ()
284
286
]}
285
287
···
333
335
334
336
By default, {!Yamlrw.of_string} resolves aliases:
335
337
336
336
-
{@ocaml[
338
338
+
{@ocaml skip[
337
339
# let yaml_with_alias = {|
338
340
base: &base
339
341
x: 1
···
355
357
356
358
To preserve the alias structure, use {!Yamlrw.yaml_of_string} with [~resolve_aliases:false]:
357
359
358
358
-
{@ocaml[
360
360
+
{@ocaml skip[
359
361
# let y = yaml_of_string ~resolve_aliases:false {|
360
362
item: &ref
361
363
name: shared
···
374
376
375
377
The [|] indicator preserves newlines exactly:
376
378
377
377
-
{@ocaml[
379
379
+
{@ocaml skip[
378
380
# of_string {|
379
381
description: |
380
382
This is a
···
388
390
389
391
The [>] indicator folds newlines into spaces:
390
392
391
391
-
{@ocaml[
393
393
+
{@ocaml skip[
392
394
# of_string {|
393
395
description: >
394
396
This is a
···
402
404
403
405
A YAML stream can contain multiple documents separated by [---]:
404
406
405
405
-
{@ocaml[
407
407
+
{@ocaml skip[
406
408
# let docs = documents_of_string {|
407
409
---
408
410
name: first
···
421
423
422
424
Each document has metadata and a root value:
423
425
424
424
-
{@ocaml[
426
426
+
{@ocaml skip[
425
427
# List.map (fun d -> Document.root d) docs;;
426
428
- : Yaml.t option list =
427
429
[Some (`O <abstr>); Some (`O <abstr>)]
···
429
431
430
432
{2 Serializing Multiple Documents}
431
433
432
432
-
{@ocaml[
434
434
+
{@ocaml skip[
433
435
# let doc1 = Document.make (Some (of_json (Util.obj ["x", Util.int 1])));;
434
434
-
val doc1 : Document.t = {Yamlrw.version = None; tags = []; root = Some (`O <abstr>); implicit_start = true; implicit_end = true}
436
436
+
val doc1 : Document.t =
437
437
+
{Document.version = None; tags = []; root = Some (`O <abstr>);
438
438
+
implicit_start = true; implicit_end = true}
435
439
# let doc2 = Document.make (Some (of_json (Util.obj ["x", Util.int 2])));;
436
436
-
val doc2 : Document.t = {Yamlrw.version = None; tags = []; root = Some (`O <abstr>); implicit_start = true; implicit_end = true}
440
440
+
val doc2 : Document.t =
441
441
+
{Document.version = None; tags = []; root = Some (`O <abstr>);
442
442
+
implicit_start = true; implicit_end = true}
437
443
# print_string (documents_to_string [doc1; doc2]);;
438
444
x: 1
439
445
---
···
456
462
# Stream.iter (fun event _ _ ->
457
463
Format.printf "%a@." Event.pp event
458
464
) parser;;
459
459
-
Stream_start `Utf8
460
460
-
Document_start { version = None; implicit = true }
461
461
-
Mapping_start { anchor = None; tag = None; implicit = true; style = Block }
462
462
-
Scalar { value = "key"; anchor = None; tag = None; plain_implicit = true; quoted_implicit = false; style = Plain }
463
463
-
Scalar { value = "value"; anchor = None; tag = None; plain_implicit = true; quoted_implicit = false; style = Plain }
464
464
-
Mapping_end
465
465
-
Document_end { implicit = true }
466
466
-
Stream_end
465
465
+
stream-start(UTF-8)
466
466
+
document-start(version=none, implicit=true)
467
467
+
mapping-start(anchor=none, tag=none, implicit=true, style=block)
468
468
+
scalar(anchor=none, tag=none, style=plain, value="key")
469
469
+
scalar(anchor=none, tag=none, style=plain, value="value")
470
470
+
mapping-end
471
471
+
document-end(implicit=true)
472
472
+
stream-end
467
473
- : unit = ()
468
474
]}
469
475
···
505
511
"ok"
506
512
with Yamlrw_error e ->
507
513
Error.to_string e;;
508
508
-
- : string =
509
509
-
"Parse error at line 1, column 15: while parsing a flow sequence, expected ',' or ']', but got end of stream"
514
514
+
- : string = "expected sequence end ']' at line 1, columns 15-15"
510
515
]}
511
516
512
517
{2 Type Errors}
···
519
524
"ok"
520
525
with Util.Type_error (expected, actual) ->
521
526
Printf.sprintf "expected %s, got %s" expected (Value.type_name actual);;
522
522
-
- : string = "expected string, got number"
527
527
+
- : string = "expected string, got float"
523
528
]}
524
529
525
530
{1 Common Patterns}
···
528
533
529
534
A typical configuration file pattern:
530
535
531
531
-
{@ocaml[
536
536
+
{@ocaml skip[
532
537
# let config_yaml = {|
533
538
app:
534
539
name: myapp
···
571
576
572
577
Processing lists of items:
573
578
574
574
-
{@ocaml[
579
579
+
{@ocaml skip[
575
580
# let items_yaml = {|
576
581
items:
577
582
- id: 1
···
607
612
608
613
{@ocaml[
609
614
# let original = of_string "name: Alice\nstatus: active";;
610
610
-
val original : value = `O [("name", `String "Alice"); ("status", `String "active")]
615
615
+
val original : value =
616
616
+
`O [("name", `String "Alice"); ("status", `String "active")]
611
617
# let updated = Util.update "status" (Util.string "inactive") original;;
612
612
-
val updated : Util.t =
618
618
+
val updated : Value.t =
613
619
`O [("name", `String "Alice"); ("status", `String "inactive")]
614
620
# let with_timestamp = Util.update "updated_at" (Util.string "2024-01-01") updated;;
615
615
-
val with_timestamp : Util.t =
621
621
+
val with_timestamp : Value.t =
616
622
`O
617
623
[("name", `String "Alice"); ("status", `String "inactive");
618
624
("updated_at", `String "2024-01-01")]
619
625
# print_string (to_string with_timestamp);;
620
626
name: Alice
621
627
status: inactive
622
622
-
updated_at: '2024-01-01'
628
628
+
updated_at: 2024-01-01
623
629
- : unit = ()
624
630
]}
625
631