dato_dast 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.projections.json +4 -0
  4. data/.rspec +3 -0
  5. data/CHANGELOG.md +6 -0
  6. data/CODE_OF_CONDUCT.md +128 -0
  7. data/Gemfile +7 -0
  8. data/Gemfile.lock +58 -0
  9. data/README.md +1082 -0
  10. data/Rakefile +8 -0
  11. data/TODO.md +0 -0
  12. data/bin/console +15 -0
  13. data/bin/setup +8 -0
  14. data/dato_dast.gemspec +29 -0
  15. data/lib/dato_dast/configuration.rb +121 -0
  16. data/lib/dato_dast/errors/block_field_missing.rb +15 -0
  17. data/lib/dato_dast/errors/block_node_missing_render_function.rb +15 -0
  18. data/lib/dato_dast/errors/invalid_block_structure_type.rb +6 -0
  19. data/lib/dato_dast/errors/invalid_blocks_configuration.rb +18 -0
  20. data/lib/dato_dast/errors/invalid_marks_configuration.rb +15 -0
  21. data/lib/dato_dast/errors/invalid_nodes.rb +15 -0
  22. data/lib/dato_dast/errors/invalid_types_configuration.rb +15 -0
  23. data/lib/dato_dast/errors/missing_render_value_function.rb +15 -0
  24. data/lib/dato_dast/errors.rb +8 -0
  25. data/lib/dato_dast/extensions/middleman.rb +35 -0
  26. data/lib/dato_dast/html_tag.rb +74 -0
  27. data/lib/dato_dast/marks.rb +12 -0
  28. data/lib/dato_dast/nodes/attributed_quote.rb +20 -0
  29. data/lib/dato_dast/nodes/base.rb +113 -0
  30. data/lib/dato_dast/nodes/block.rb +124 -0
  31. data/lib/dato_dast/nodes/blockquote.rb +6 -0
  32. data/lib/dato_dast/nodes/code.rb +35 -0
  33. data/lib/dato_dast/nodes/generic.rb +21 -0
  34. data/lib/dato_dast/nodes/heading.rb +14 -0
  35. data/lib/dato_dast/nodes/inline_item.rb +14 -0
  36. data/lib/dato_dast/nodes/item_link.rb +29 -0
  37. data/lib/dato_dast/nodes/link.rb +57 -0
  38. data/lib/dato_dast/nodes/list.rb +9 -0
  39. data/lib/dato_dast/nodes/list_item.rb +6 -0
  40. data/lib/dato_dast/nodes/paragraph.rb +6 -0
  41. data/lib/dato_dast/nodes/root.rb +6 -0
  42. data/lib/dato_dast/nodes/span.rb +21 -0
  43. data/lib/dato_dast/nodes/thematic_break.rb +9 -0
  44. data/lib/dato_dast/nodes.rb +29 -0
  45. data/lib/dato_dast/version.rb +5 -0
  46. data/lib/dato_dast.rb +39 -0
  47. metadata +119 -0
data/README.md ADDED
@@ -0,0 +1,1082 @@
1
+ # DatoDast
2
+
3
+ `DatoDast` is a gem that provides a `structured_text(...)` rendering method and configuration options for rendering a [DatoCMS Dast](https://www.datocms.com/docs/structured-text/dast) document.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'dato_dast'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install dato_dast
20
+
21
+ ## Usage
22
+
23
+ The simplest use is the `DatoDast.structured_text` method, which can be used in view renderer.
24
+
25
+ ```erb
26
+ # page => DatoCMS Object
27
+ # page.content => structured text field
28
+ <%= DatoDast.structured_text(page.content) %>
29
+ ```
30
+
31
+ This will used the configuration object as defined below which can be put it in an initializer or a unique configuration can be provided to the structured_text method.
32
+
33
+ ## Extensions
34
+
35
+ Currently the only extension supported is Middleman. You can include it by installing the gem and adding this to your `config.rb`:
36
+
37
+ ```ruby
38
+ activate :dato_dast
39
+ ```
40
+
41
+ Or you can provide configuration
42
+
43
+ ```ruby
44
+ activate :dato_dast do |config|
45
+ # See "Configuration Options" Below
46
+ end
47
+ ```
48
+
49
+ ## Configuration Options
50
+
51
+ You can configure DatoDast in something like an initializer:
52
+
53
+ ```ruby
54
+ # initializers/dato_dast.rb
55
+
56
+ DatoDast.configure do |config|
57
+ # configuration here
58
+ end
59
+ ```
60
+
61
+ Or you can create a configuration object and pass it to the structured text method.
62
+
63
+ ```ruby
64
+ config = DastDast::Configuration.new
65
+ # Set your configuration
66
+ DatoDast.structured_text(item, config)
67
+ ```
68
+
69
+ The configuration options are:
70
+
71
+ ### `config.highlight`, default: `true`
72
+
73
+ Toggle whether to attempt to higlight code blocks. If the `middleman-syntax` gem is present, it is used by default to highlight a [`code`](https://www.datocms.com/docs/structured-text/dast#code) node in the structured text.
74
+
75
+ ### `config.smart_links`, default: `true`
76
+
77
+ Smart links, in conjunction with the `host` option, will attempt to always open internal links in the same window with a relative url and external links in a new window.
78
+
79
+ ### `config.host`, default: `nil`
80
+
81
+ Host for your site, used in conjunction with 'smart_links' option.
82
+
83
+ ### `config.item_links`, default: `{},`
84
+
85
+ <details>
86
+
87
+ If you are using [`itemLinks`](https://www.datocms.com/docs/structured-text/dast#itemLink), you can use this configuration hash to define which field to call on the item to determine the url. For example, if you have a `page` model and a `slug` field that contains the url, you would use:
88
+
89
+ ```ruby
90
+ DatoDast.configure do |config|
91
+ config.item_links = {
92
+ "page" => "slug",
93
+ }
94
+ end
95
+ ```
96
+
97
+ See [`itemLink`](#itemlink) for more details.
98
+
99
+ </details>
100
+
101
+ ### `config.marks`
102
+
103
+ <details>
104
+
105
+ There are [six marks](`strong`, `code`, `emphasis`, `underline`, `strikethrough` and `highlight`) defined in the DatoCMS Dast spec.
106
+
107
+ The `config.marks` option allows you to customize the mark that is used, as well as add [`wrappers`](#wrappers) for a given tag.
108
+
109
+ The default configuration is:
110
+
111
+ ```ruby
112
+ {
113
+ "code" => { "tag" => "code" },
114
+ "emphasis" => { "tag" => "em" },
115
+ "highlight" => { "tag" => "mark" },
116
+ "strikethrough" => { "tag" => "strike" },
117
+ "strong" => { "tag" => "strong" },
118
+ "underline" => { "tag" => "u" },
119
+ }
120
+ ```
121
+
122
+ If you had a [`span`](https://www.datocms.com/docs/structured-text/dast#span) object that looked like this:
123
+
124
+ ```json
125
+ {
126
+ "type": "span",
127
+ "marks": ["highlight", "emphasis"],
128
+ "value": "Some random text here, move on!"
129
+ }
130
+ ```
131
+
132
+ It would normally render as:
133
+
134
+ ```html
135
+ <highlight>
136
+ <emphasis>Some random text here, move on!</emphasis>
137
+ </highlight>
138
+ ```
139
+
140
+ If we used the following configuration:
141
+
142
+ ```ruby
143
+ DatoDast.configure do |config|
144
+ config.marks = {
145
+ "emphasis" => { "tag" => "i", "wrappers" => [{ "tag" => "div", "css_class" => "blue" }],
146
+ }
147
+ end
148
+ ```
149
+
150
+ This would use the `<i>` tag instead of `<emphasis>` and wrap that `<i>` tag with a `<div class="blue">` tag.
151
+
152
+ ```html
153
+ <highlight>
154
+ <div class="blue">
155
+ <i>Some random text here, move on!</i>
156
+ </div>
157
+ </highlight>
158
+ ```
159
+
160
+ </details>
161
+
162
+ ### `config.types`
163
+
164
+ <details>
165
+
166
+ This is the configuration use for all of the default types. Each type configuration consists of the type key and a [`Node`](#nodes) value. Most of them have an html `tag` defined as well, and can take a [wrapper](#wrappers).
167
+
168
+ The default configuration is:
169
+
170
+ ```ruby
171
+ TYPE_CONFIG = {
172
+ "block" => { "node" => Nodes::Block },
173
+ "blockquote" => { "tag" => "blockquote", "node" => Nodes::AttributedQuote },
174
+ "code" => { "tag" => "code", "node" => Nodes::Code, "wrappers" => ["pre"] },
175
+ "generic" => { "node" => Nodes::Generic },
176
+ "heading" => { "tag" => "h#", "node" => Nodes::Heading },
177
+ "itemLink" => { "tag" => "a", "node" => Nodes::ItemLink, "url_key" => :slug },
178
+ "link" => { "tag" => "a", "node" => Nodes::Link },
179
+ "list" => {
180
+ "bulleted" => { "tag" => "ul", "node" => Nodes::List },
181
+ "numbered" => { "tag" => "ol", "node" => Nodes::List },
182
+ },
183
+ "listItem" => { "tag" => "li", "node" => Nodes::ListItem },
184
+ "paragraph" => { "tag" => "p", "node" => Nodes::Paragraph },
185
+ "root" => { "tag" => "div", "node" => Nodes::Root },
186
+ "span" => { "node" => Nodes::Span },
187
+ "thematicBreak" => { "tag" => "hr", "node" => Nodes::ThematicBreak },
188
+ }
189
+ ```
190
+
191
+ Each type configuration takes the following keys:
192
+ - `tag`: The default html tag to use. `nil` can be used to not use a key. Additionally you can provide a lambda that takes the Node object.
193
+ - `node`: This represents the Node object used for rendering. See [Nodes](#nodes) for more details.
194
+ - `css_class`: This is a string that is used in the `class=""` attribute of the tag. Additionally you can provide a lambda that takes the Node object.
195
+ - [ ] `meta`: This is an array of hashes matching the dast meta structure. E.g. Found in the [`link`](https://www.datocms.com/docs/structured-text/dast#link) node. Additionally you can provide a lamdbda that takes the Node object.
196
+ - The structure is `{ "id" => "data-value", "value" => "1"}` renders as `<div data-value="1">`
197
+ - `wrappers`: This represents additional wrappers use to surrounded the given node type. See [Wrappers](#wrappers) for more details.
198
+
199
+ Some types have specific additional values.
200
+
201
+ See the individual [type configuration](#types) for each type.
202
+
203
+ </details>
204
+
205
+ ## Types
206
+
207
+ Each node type may have its own configuration values and render in a unique way. Additionally, each type can override the [node](#nodes) with custom rendering functions. Below is a description of each type and its default rendering.
208
+
209
+ ### `block`
210
+
211
+ <details>
212
+
213
+ Represents the [DatoCMS `block`](https://www.datocms.com/docs/structured-text/dast#block) node.
214
+
215
+ Blocks should be configured on a per-block basis. See the [Block](#blocks) section on how to configure specific blocks.
216
+
217
+ </details>
218
+
219
+ ### `blockquote`
220
+
221
+ <details>
222
+
223
+ Represents the [DatoCMS `blockquote`](https://www.datocms.com/docs/structured-text/dast#blockquote) node.
224
+
225
+ With the following dast node:
226
+
227
+ ```json
228
+ {
229
+ "type": "blockquote",
230
+ "attribution": "Oscar Wilde",
231
+ "children": [
232
+ {
233
+ "type": "paragraph",
234
+ "children": [
235
+ {
236
+ "type": "span",
237
+ "value": "Be yourself; everyone else is taken."
238
+ }
239
+ ]
240
+ }
241
+ ]
242
+ }
243
+ ```
244
+
245
+ This would be rendered using the `AttributedQuote` node, which would render as:
246
+
247
+ ```html
248
+ <figure>
249
+ <blockquote>
250
+ <p>
251
+ Be yourself; everyone else is taken.
252
+ </p>
253
+ </blockquote>
254
+ <figcaption>
255
+ Oscar Wilde
256
+ </figcaption>
257
+ </figure>
258
+ ```
259
+
260
+ This follows the [recommendation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote) for blockquotes tags to only include the quote itself, and separate out the attribution.
261
+
262
+ If you want to use the basic `Blockquote` node, it would render as:
263
+ ```html
264
+ <blockquote>
265
+ <p>
266
+ Be yourself; everyone else is taken.
267
+ </p>
268
+ </blockquote>
269
+ ```
270
+
271
+ </details>
272
+
273
+ ### `code`
274
+
275
+ <details>
276
+
277
+ Represents the [DatoCMS `code`](https://www.datocms.com/docs/structured-text/dast#code) node.
278
+
279
+ With the following dast node:
280
+
281
+ ```json
282
+ {
283
+ "type": "code",
284
+ "language": "javascript",
285
+ "highlight": [1],
286
+ "code": "function greetings() {\n console.log('Hi!');\n}"
287
+ }
288
+ ```
289
+
290
+ If the `config.highlight` option is set to true, AND the `middleman-syntax` gem is present, it will use that highlighter and its default configuration to render the code.
291
+
292
+ If `config.highlight` is false OR the `middleman-syntax` gem is not preset, this would use the `Code` node which wraps a `<code>` line with a `<pre>` wrapper and would render as:
293
+
294
+ ```html
295
+ <pre>
296
+ <code>
297
+ function greetings() {<br/> console.log('Hi!');<br/>}
298
+ </code>
299
+ </pre>
300
+ ```
301
+
302
+ </details>
303
+
304
+ ### `generic`
305
+
306
+ <details>
307
+
308
+ This node is not a part of the [DatoCMS Dast](https://www.datocms.com/docs/structured-text/dast) spec. Instead, it used a helper behind the scenes.
309
+
310
+ </details>
311
+
312
+ ### `heading`
313
+
314
+ <details>
315
+
316
+ Represents the [DatoCMS `heading`](https://www.datocms.com/docs/structured-text/dast#heading) node.
317
+
318
+ With the following dast node:
319
+
320
+ ```json
321
+ {
322
+ "type": "heading",
323
+ "level": 2,
324
+ "children": [
325
+ {
326
+ "type": "span",
327
+ "value": "An h2 heading!"
328
+ }
329
+ ]
330
+ }
331
+ ```
332
+
333
+ This would be rendered using the `Heading` node, which would render as:
334
+
335
+ ```html
336
+ <h2>
337
+ An h2 heading!
338
+ </h2>
339
+ ```
340
+
341
+ One note about the `Heading` node, is that it accepts a tag with a `#` symbol which it will use `gsub` on to replace with the `"level"` value.
342
+
343
+ </details>
344
+
345
+ ### `itemLink`
346
+
347
+ <details>
348
+
349
+ Represents the [DatoCMS `itemLink`](https://www.datocms.com/docs/structured-text/dast#itemLink) node.
350
+
351
+ The `itemLink` node requires a configuration to specify what field value should be called on the itemLink object to generate the url. It defaults to `slug` as the is the default name DatoCMS gives that field, but can be configured to anything.
352
+
353
+ With the following dast node:
354
+
355
+ ```json
356
+ {
357
+ "type": "itemLink",
358
+ "item": "38945648",
359
+ "meta": [
360
+ { "id": "rel", "value": "nofollow" },
361
+ { "id": "target", "value": "_blank" }
362
+ ],
363
+ "children": [
364
+ {
365
+ "type": "span",
366
+ "value": "Matteo Giaccone"
367
+ }
368
+ ]
369
+ }
370
+ ```
371
+
372
+ And an `links` array of:
373
+
374
+ ```javascript
375
+ [{ id: "38945648", slug: "my-cool-page", item_type: "page" }]
376
+ ```
377
+
378
+ This would be rendered using the `itemLink` node, which would render as:
379
+
380
+ ```html
381
+ <a href="/my-cool-page" rel="nofollow" target="_blank">
382
+ Matteo Giaccone
383
+ </a>
384
+ ```
385
+
386
+ </details>
387
+
388
+ ### `link`
389
+
390
+ <details>
391
+
392
+ Represents the [dato `link`](https://www.datocms.com/docs/structured-text/dast#link) node.
393
+
394
+ With the following dast node:
395
+
396
+ ```json
397
+ {
398
+ "type": "link",
399
+ "url": "https://www.datocms.com/"
400
+ "meta": [
401
+ { "id": "rel", "value": "nofollow" },
402
+ { "id": "target", "value": "_blank" }
403
+ ],
404
+ "children": [
405
+ {
406
+ "type": "span",
407
+ "value": "The best CMS in town"
408
+ }
409
+ ]
410
+ }
411
+ ```
412
+
413
+ This would be rendered using the `link` node, which would render as:
414
+
415
+ ```html
416
+ <a href="https://www.datocms.com/link" rel="nofollow" target="_blank">
417
+ The best CMS in town
418
+ </a>
419
+ ```
420
+
421
+ </details>
422
+
423
+ #### Emails
424
+
425
+ Given the DatoCMS Structured text link does not have an option to input an email
426
+ address, this library will also compare the path against the
427
+ URI::MailTo::EMAIL_REGEXP and if it is a match, will prepend the `mailto:`
428
+ prefix.
429
+
430
+ ### `list`
431
+
432
+ <details>
433
+
434
+ Represents the [DatoCMS `list`](https://www.datocms.com/docs/structured-text/dast#list) node.
435
+
436
+ The `list` node is special in that it has two subkeys of `bulleted` or `ordered` and each of those has its own node configuration.
437
+
438
+ With the following dast node:
439
+
440
+ ```json
441
+ {
442
+ "type": "list",
443
+ "style": "bulleted",
444
+ "children": [
445
+ {
446
+ "type": "listItem",
447
+ "children": [
448
+ {
449
+ "type": "paragraph",
450
+ "children": [
451
+ {
452
+ "type": "span",
453
+ "value": "This is a list item!"
454
+ }
455
+ ]
456
+ }
457
+ ]
458
+ }
459
+ ]
460
+ }
461
+ ```
462
+
463
+ This would be rendered using the `List` node, which would render as:
464
+
465
+ ```html
466
+ <ul>
467
+ <li>
468
+ <p>
469
+ This is a list item!
470
+ </p>
471
+ </li>
472
+ </ul>
473
+ ```
474
+
475
+ </details>
476
+
477
+ ### `listItem`
478
+
479
+ <details>
480
+
481
+ Represents the [DatoCMS `listItem`](https://www.datocms.com/docs/structured-text/dast#listItem) node.
482
+
483
+ With the following dast node:
484
+
485
+ ```json
486
+ {
487
+ "type": "listItem",
488
+ "children": [
489
+ {
490
+ "type": "paragraph",
491
+ "children": [
492
+ {
493
+ "type": "span",
494
+ "value": "This is a list item!"
495
+ }
496
+ ]
497
+ }
498
+ ]
499
+ }
500
+ ```
501
+
502
+ This would be rendered using the `ListItem` node, which would render as:
503
+
504
+ ```html
505
+ <li>
506
+ <p>
507
+ This is a list item!
508
+ </p>
509
+ </li>
510
+ ```
511
+
512
+ </details>
513
+
514
+ ### `paragraph`
515
+
516
+ <details>
517
+
518
+ Represents the [DatoCMS `paragraph`](https://www.datocms.com/docs/structured-text/dast#paragraph) node.
519
+
520
+ With the following dast node:
521
+
522
+ ```json
523
+ {
524
+ "type": "paragraph",
525
+ "children": [
526
+ {
527
+ "type": "span",
528
+ "value": "A simple paragraph!"
529
+ }
530
+ ]
531
+ }
532
+ ```
533
+
534
+ This would be rendered using the `Paragraph` node, which would render as:
535
+
536
+ ```html
537
+ <p>
538
+ A simple paragraph!
539
+ </p>
540
+ ```
541
+
542
+ </details>
543
+
544
+ ### `root`
545
+
546
+ <details>
547
+
548
+ Represents the [DatoCMS `root`](https://www.datocms.com/docs/structured-text/dast#root) node.
549
+
550
+ With the following dast node:
551
+
552
+ ```json
553
+ {
554
+ "type": "root",
555
+ "children": [
556
+ {
557
+ "type": "heading",
558
+ "level": 1,
559
+ "children": [
560
+ {
561
+ "type": "span",
562
+ "value": "Title"
563
+ }
564
+ ]
565
+ },
566
+ {
567
+ "type": "paragraph",
568
+ "children": [
569
+ {
570
+ "type": "span",
571
+ "value": "A simple paragraph!"
572
+ }
573
+ ]
574
+ }
575
+ ]
576
+ }
577
+ ```
578
+
579
+ This would be rendered using the `Root` node, which would render as:
580
+
581
+ ```html
582
+ <div>
583
+ <h1>
584
+ Title
585
+ </h1>
586
+ <p>
587
+ A simple paragraph!
588
+ </p>
589
+ </div>
590
+ ```
591
+
592
+ </details>
593
+
594
+ ### `span`
595
+
596
+ <details>
597
+
598
+ Represents the [DatoCMS `span`](https://www.datocms.com/docs/structured-text/dast#span) node.
599
+
600
+ With the following dast node:
601
+
602
+ ```json
603
+ {
604
+ "type": "span",
605
+ "marks": ["highlight", "emphasis"],
606
+ "value": "Some random text here, move on!"
607
+ }
608
+ ```
609
+
610
+ This would be rendered using the `attributedquote` node, which would render as:
611
+
612
+ ```html
613
+ <mark>
614
+ <em>
615
+ Some random text here, move on!
616
+ </em>
617
+ </mark>
618
+ ```
619
+
620
+ </details>
621
+
622
+ ### `thematicBreak`
623
+
624
+ <details>
625
+
626
+ Represents the [DatoCMS `blockquote`](https://www.datocms.com/docs/structured-text/dast#block) node.
627
+
628
+ With the following dast node:
629
+
630
+ ```json
631
+ {
632
+ "type": "thematicBreak"
633
+ }
634
+ ```
635
+
636
+ This would be rendered using the `ThematicBreak` node, which would render as:
637
+
638
+ ```html
639
+ <hr/>
640
+ ```
641
+
642
+ </details>
643
+
644
+ ## Wrappers
645
+
646
+ Marks, Types, and Blocks all supports configuring a `wrappers` field.
647
+
648
+ The wrappers are rendered from the outside in, so the first wrapper will wrap the following wrappers.
649
+
650
+ A wrapper is made up of 3 parts: `tag`, `css_class`, and `meta`.
651
+
652
+ - `tag`: **Required**. The default html tag to use, or a proc that receive a node or block.
653
+ - `css_class`: **Optional**. This is a string that is used in the `class=""` attribute of the tag, or a proc that receive a node or block.
654
+ - `meta`: **Optional**. This is an array of hashes matching the dast meta
655
+ structure. E.g. Found in the [`link`](https://www.datocms.com/docs/structured-text/dast#link) node, or a proc that receive a node or block.
656
+ - The structure is `{ "id" => "data-value", "value" => "1"}` renders as `<div data-value="1">`
657
+
658
+ ## Nodes
659
+
660
+ All parts of the [DatoCMS
661
+ Dast](https://www.datocms.com/docs/structured-text/dast) spec are rendered using
662
+ a `Node` object. The default nodes are of the namespace `DatoDast::Nodes`.
663
+
664
+ A node must implement one of two methods:
665
+
666
+ - `render_value`
667
+ - `render`
668
+
669
+ ### `render_value`
670
+
671
+ <details>
672
+
673
+ The render value method is used most commonly for the `Span` and `Code` nodes. It will still use the tags and wrappers defined in the configuration.
674
+
675
+ For example, the `Code` node, defines this as:
676
+
677
+ ```ruby
678
+ def render_value
679
+ @node["code"].gsub(/\n/, "<br/>")
680
+ end
681
+ ```
682
+
683
+ So the rendered code replaces newlines with html line breaks, but it is still wrapped with a `<pre>` and `<code>` tag.
684
+
685
+ Additionally, for objects that have `children` according to the Dast specification, the `render_value` method just iterates over the children rendering each one.
686
+
687
+ </details>
688
+
689
+ ### `render`
690
+
691
+ <details>
692
+
693
+ The default render method will render wrappers, the configured tag, and the `render_value` method. If you override the render method, you are taking responsibility for the complete rendering of a dast node and any of its children.
694
+
695
+ For example, the `ThematicBreak` node's render function is defined as:
696
+
697
+ ```ruby
698
+ def render
699
+ "<#{tag}/>\n"
700
+ end
701
+ ```
702
+
703
+ As a result, the thematic break node can't be wrapped nor does it apply a specific tag.
704
+
705
+ Additionally, the `block` type has a specific render method for the complex rendering that blocks entail.
706
+
707
+ </details>
708
+
709
+ ## Blocks
710
+
711
+ Blocks are the most powerful parts of structured text. We can take objects and render them in a specific way.
712
+
713
+ Blocks can take the same values as nodes. One difference with blocks is that the block object is provided to the proc instead of the node when a Proc is provided.
714
+
715
+ - `tag`
716
+ - `css_class`
717
+ - `meta`
718
+
719
+ The block configuration takes `item_type` value and you must provide one of three methods for rendering:
720
+
721
+ - `node`
722
+ - `render_value`
723
+ - `structure`
724
+
725
+ ### `node`
726
+
727
+ If you supply the `node` key, you must provide a class that takes the block hash as the only argument for `initialize` and has a `render` function.
728
+
729
+ <details>
730
+
731
+ For example:
732
+
733
+ ```ruby
734
+ # Let's say we have an (abbreviated) Photo block that has a dato cms image under ":image" and a ":caption" string
735
+ # {
736
+ # :id=>"1",
737
+ # :item_type=>"photo",
738
+ # :image => {
739
+ # :id=>"2",
740
+ # ...
741
+ # :alt=>nil,
742
+ # :url=>"https://www.datocms-assets.com/100/logo.png",
743
+ # }
744
+ # :caption=>"My Logo",
745
+ # }
746
+
747
+ class Photo
748
+ def initialize(photo)
749
+ @photo = photo
750
+ end
751
+
752
+ def alt
753
+ @photo[:alt]
754
+ end
755
+
756
+ def url
757
+ @photo[:url]
758
+ end
759
+
760
+ def caption
761
+ @photo[:caption]
762
+ end
763
+
764
+ def render
765
+ <<~HTML
766
+ <img alt='#{alt}' src='#{url}' />
767
+ <h3>#{caption}</h3>
768
+ HTML
769
+ end
770
+ end
771
+
772
+ DatoDast.configure do |config|
773
+ config.blocks = {
774
+ "photo" => { "node" => Photo },
775
+ }
776
+ end
777
+ ```
778
+
779
+ This node would render the following html:
780
+
781
+ ```html
782
+ <img alt="My Logo" src="https://www.datocms-assets.com/100/logo.png" />
783
+ ```
784
+
785
+ </details>
786
+
787
+ ### `render_value`
788
+
789
+ `render_value` is a simpler form where you can supply a lamba that takes the hash object and it will render the lambda by calling it with the block hash.
790
+
791
+ <details>
792
+
793
+ ```ruby
794
+ # Using the following block hash
795
+ # {
796
+ # :id=>"1",
797
+ # :item_type=>"photo",
798
+ # :image => {
799
+ # :id=>"2",
800
+ # ...
801
+ # :url=>"https://www.datocms-assets.com/100/logo.png",
802
+ # }
803
+ # }
804
+
805
+ DatoDast.configure do |config|
806
+ config.blocks = {
807
+ "photo" => {
808
+ "render_value" => ->(block) { "<img src='#{block[:url]}' />" },
809
+ }
810
+ }
811
+ end
812
+ ```
813
+
814
+ This would render the following html:
815
+
816
+ ```html
817
+ <img src="https://www.datocms-assets.com/100/logo.png" />
818
+ ```
819
+
820
+ </details>
821
+
822
+ ### `structure`
823
+
824
+ The most powerful part of `DatoDast` is the `structure` tools for rendering blocks.
825
+
826
+ The `structure` configuration can be used on nested blocks or relationships to construct multiple tags.
827
+
828
+ The `structure` format is an array of hashes each with a "type" field. The "type" can be one of four values:
829
+
830
+ - `"field"`
831
+ - `"value"`
832
+ - `"block"`
833
+ - `"blocks"`
834
+
835
+ ### `field`
836
+
837
+ <details>
838
+
839
+ When the type is `"field"`, then you also must provide a `"field"` value representing the field that you want to render. This would be used for fields that clearly implement the `to_s` method (strings, symbols, etc.).
840
+
841
+ ```ruby
842
+ # With the object
843
+ # {
844
+ # :id=>"1",
845
+ # :item_type=>"photo",
846
+ # :image => {
847
+ # :id=>"100",
848
+ # ...
849
+ # :alt=>nil,
850
+ # :url=>"https://www.datocms-assets.com/100/logo.png",
851
+ # }
852
+ # :caption=>"My Logo",
853
+ # }
854
+ DatoDast.configure do |config|
855
+ config.blocks = {
856
+ "photo" => {
857
+ "wrappers" => [{ "tag" => "div", "css_class" => "caption" }],
858
+ "structure" => [
859
+ {
860
+ "type" => "field",
861
+ "field" => "caption",
862
+ "tag" => "h1",
863
+ },
864
+ ],
865
+ },
866
+ }
867
+ end
868
+ ```
869
+
870
+ Would render the following html:
871
+
872
+ ```html
873
+ <div class="css_caption">
874
+ <h1>My Logo</h1>
875
+ </div>
876
+ ```
877
+
878
+ </details>
879
+
880
+ ### `value`
881
+
882
+ <details>
883
+
884
+ When the type is `"value"`, then you also must provide a `"render_value"` function that takes the block hash as an argument and returns a string.
885
+
886
+ ```ruby
887
+ # With the object
888
+ # {
889
+ # :id=>"1",
890
+ # :item_type=>"photo",
891
+ # :image => {
892
+ # :id=>"100",
893
+ # ...
894
+ # :alt=>nil,
895
+ # :url=>"https://www.datocms-assets.com/100/logo.png",
896
+ # }
897
+ # :caption=>"My Logo",
898
+ # }
899
+ DatoDast.configure do |config|
900
+ config.blocks = {
901
+ "photo" => {
902
+ "wrappers" => [{ "tag" => "div", "css_class" => "caption" }],
903
+ "structure" => [
904
+ {
905
+ "type" => "value",
906
+ "tag" => "span",
907
+ "css_class" => "blue",
908
+ "render_value" => ->(block) { block[:caption] },
909
+ },
910
+ ],
911
+ },
912
+ }
913
+ end
914
+ ```
915
+
916
+ Would render the following html:
917
+
918
+ ```html
919
+ <div class="css_caption">
920
+ <span class="blue">My Logo</span>
921
+ </div>
922
+ ```
923
+ </details>
924
+
925
+ ### `block`
926
+
927
+ <details>
928
+
929
+ When the type is `"block"`, then you also must provide a `"field"` value that specifies the field which contains another block. That block will the be rendered using the some block configuration.
930
+
931
+ ```ruby
932
+ # Let's imagine a card object with photo block relationship and caption
933
+ # {
934
+ # :id=>"2",
935
+ # :item_type => "card",
936
+ # :photo => {
937
+ # :id=>"1",
938
+ # :item_type=>"photo",
939
+ # :image => {
940
+ # :id=>"100",
941
+ # ...
942
+ # :alt=>nil,
943
+ # :url=>"https://www.datocms-assets.com/100/logo.png",
944
+ # }
945
+ # }
946
+ # :caption=>"My Logo",
947
+ # }
948
+ DatoDast.configure do |config|
949
+ config.blocks = {
950
+ "card" => {
951
+ "wrappers" => {
952
+ "tag" => "div",
953
+ "css_class" => "card",
954
+ "meta" => [{
955
+ "id" => "data-card",
956
+ "value" => "1",
957
+ }],
958
+ },
959
+ "structure" => []
960
+ {
961
+ "type" => "block",
962
+ "field" => "photo",
963
+ },
964
+ {
965
+ "type" => "field",
966
+ "field" => "caption",
967
+ "tag" => "h2",
968
+ },
969
+ ],
970
+ },
971
+ "photo" => {
972
+ "tag" => "div",
973
+ "css_class" => "img",
974
+ "render_value" => ->(block) { "<img src='#{block[:url]}' />" }
975
+ }
976
+ }
977
+ end
978
+ ```
979
+
980
+ Would render the following html:
981
+
982
+ ```html
983
+ <div class="card" data-card="1">
984
+ <div class="img">
985
+ <img src="https://www.datocms-assets.com/100/logo.png" />
986
+ </div>
987
+ <h2>My Logo</h2>
988
+ </div>
989
+ ```
990
+
991
+ </details>
992
+
993
+ ### `blocks`
994
+
995
+ <details>
996
+
997
+ When the type is `"blocks"`, then you also must provide a `"field"` value that specifies the field which contains an array of blocks. That block will the be rendered using the some block configuration.
998
+
999
+ ```ruby
1000
+ # Let's imagine a card object with photo block relationship and caption
1001
+ # {
1002
+ # :id=>"2",
1003
+ # :item_type => "card",
1004
+ # :gallery => [
1005
+ # {
1006
+ # :id=>"1",
1007
+ # :item_type=>"photo",
1008
+ # :image => {
1009
+ # :id=>"100",
1010
+ # ...
1011
+ # :alt=>nil,
1012
+ # :url=>"https://www.datocms-assets.com/100/logo.png",
1013
+ # },
1014
+ # },
1015
+ # {
1016
+ # :id=>"3",
1017
+ # :item_type=>"photo",
1018
+ # :image => {
1019
+ # :id=>"300",
1020
+ # ...
1021
+ # :alt=>nil,
1022
+ # :url=>"https://www.datocms-assets.com/300/logo.png",
1023
+ # },
1024
+ # },
1025
+ # ],
1026
+ # :caption=>"My Logo",
1027
+ # }
1028
+ DatoDast.configure do |config|
1029
+ config.blocks = {
1030
+ "card" => {
1031
+ "wrappers" => {
1032
+ "tag" => "div",
1033
+ "css_class" => "card",
1034
+ "meta" => [{
1035
+ "id" => "data-card",
1036
+ "value" => "1",
1037
+ }],
1038
+ },
1039
+ "structure" => []
1040
+ {
1041
+ "type" => "block",
1042
+ "field" => "gallery",
1043
+ "tag" => "div",
1044
+ "css_class" => "gallery",
1045
+ },
1046
+ {
1047
+ "type" => "field",
1048
+ "field" => "caption",
1049
+ "tag" => "h2",
1050
+ },
1051
+ ],
1052
+ },
1053
+ "photo" => {
1054
+ "tag" => "div",
1055
+ "css_class" => "img",
1056
+ "render_value" => ->(block) { "<img src='#{block[:url]}' />" }
1057
+ }
1058
+ }
1059
+ end
1060
+ ```
1061
+
1062
+ Would render the following html:
1063
+
1064
+ ```html
1065
+ <div class="card" data-card="1">
1066
+ <div class="gallery">
1067
+ <div class="img">
1068
+ <img src="https://www.datocms-assets.com/100/logo.png" />
1069
+ </div>
1070
+ <div class="img">
1071
+ <img src="https://www.datocms-assets.com/100/logo.png" />
1072
+ </div>
1073
+ </div>
1074
+ <h2>My Logo</h2>
1075
+ </div>
1076
+ ```
1077
+
1078
+ </details>
1079
+
1080
+ ## Contributing
1081
+
1082
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[dewyze]/dato_dast.