papercraft 0.15 → 0.19
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +200 -75
- data/lib/papercraft/html.rb +1 -39
- data/lib/papercraft/json.rb +73 -0
- data/lib/papercraft/renderer.rb +19 -11
- data/lib/papercraft/{component.rb → template.rb} +51 -32
- data/lib/papercraft/version.rb +1 -1
- data/lib/papercraft.rb +96 -46
- data/papercraft.png +0 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0f4910bd26625ca0349b1c471338fb4d13e8055e88367b5cad16f91cdee7531
|
4
|
+
data.tar.gz: 38e43978278ba069e3767abd94d83c676f42692f5eb55f1be4b4067fae2f935e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b096452cebe7b6bb34a428f4920a5940e5b745c86b54188a984a77df6175145cf6645753e6ae58b3df89813919920a17a96610e010724bc50077c6f9accc7293
|
7
|
+
data.tar.gz: 8d1cd5b2d6b70ee9ef0a748a064bbd6d1630cfa926663aded95a01c26ce289a159e2548068bf8210c5e8d37ba26c9671eb4a00fe4790a47bec6dd822b4de5d5d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## 0.19 2022-02-05
|
2
|
+
|
3
|
+
- Rename `Papercraft::Component` to `Papercraft::Template`
|
4
|
+
|
5
|
+
## 0.18 2022-02-04
|
6
|
+
|
7
|
+
- Cleanup and update examples
|
8
|
+
- Fix behaviour of #emit with block
|
9
|
+
- Improve README
|
10
|
+
|
11
|
+
## 0.17 2022-01-23
|
12
|
+
|
13
|
+
- Refactor markdown code, add `Papercraft.markdown` method (#8)
|
14
|
+
|
15
|
+
## 0.16 2022-01-23
|
16
|
+
|
17
|
+
- Implement JSON templating (#7)
|
18
|
+
- Add support for MIME types (#6)
|
19
|
+
- Change entrypoint from `Kernel#H`, `Kernel#X` to `Papercraft.html`, `.xml` (#5)
|
20
|
+
|
1
21
|
## 0.15 2022-01-20
|
2
22
|
|
3
23
|
- Fix tag method line reference
|
@@ -42,7 +62,7 @@
|
|
42
62
|
## 0.8 2021-12-22
|
43
63
|
|
44
64
|
- Cleanup and refactor code
|
45
|
-
- Add
|
65
|
+
- Add Papercraft.xml global method for XML templates
|
46
66
|
- Make `Component` a descendant of `Proc`
|
47
67
|
- Introduce new component API
|
48
68
|
- Rename Rubyoshka to Papercraft
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
Papercraft
|
5
5
|
</h1>
|
6
6
|
|
7
|
-
<h4 align="center">Composable
|
7
|
+
<h4 align="center">Composable templating for Ruby</h4>
|
8
8
|
|
9
9
|
<p align="center">
|
10
10
|
<a href="http://rubygems.org/gems/papercraft">
|
@@ -24,33 +24,63 @@
|
|
24
24
|
|
25
25
|
## What is Papercraft?
|
26
26
|
|
27
|
+
Papercraft is a templating engine for dynamically producing HTML, XML or JSON.
|
28
|
+
Papercraft templates are expressed in plain Ruby, leading to easier debugging,
|
29
|
+
better protection against HTML/XML injection attacks, and better code reuse.
|
30
|
+
|
31
|
+
Papercraft templates can be composed in a variety of ways, facilitating the
|
32
|
+
usage of layout templates, and enabling a component-oriented approach to
|
33
|
+
building complex web interfaces.
|
34
|
+
|
35
|
+
In Papercraft, dynamic data is passed explicitly to the template as block
|
36
|
+
arguments, making the data flow easy to follow and understand. Papercraft also
|
37
|
+
lets developers create derivative templates using full or partial parameter
|
38
|
+
application.
|
39
|
+
|
40
|
+
Papercraft includes built-in support for rendering Markdown (using
|
41
|
+
[Kramdown](https://github.com/gettalong/kramdown/)), as well as support for
|
42
|
+
creating template extensions in order to allow the creation of component
|
43
|
+
libraries.
|
44
|
+
|
27
45
|
```ruby
|
28
46
|
require 'papercraft'
|
29
47
|
|
30
|
-
page =
|
48
|
+
page = Papercraft.html { |*args|
|
31
49
|
html {
|
32
|
-
head { }
|
50
|
+
head { title 'Title' }
|
33
51
|
body { emit_yield *args }
|
34
52
|
}
|
35
53
|
}
|
54
|
+
page.render { p 'foo' }
|
55
|
+
#=> "<html><head><title>Title</title></head><body><p>foo</p></body></html>"
|
36
56
|
|
37
|
-
hello =
|
57
|
+
hello = page.apply { |name| h1 "Hello, #{name}!" }
|
38
58
|
hello.render('world')
|
39
|
-
#=> "<html><head
|
59
|
+
#=> "<html><head><title>Title</title></head><body><h1>Hello, world!</h1></body></html>"
|
40
60
|
```
|
41
61
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
-
|
46
|
-
-
|
47
|
-
-
|
48
|
-
-
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
52
|
-
-
|
53
|
-
-
|
62
|
+
## Table of content
|
63
|
+
|
64
|
+
- [Installing papercraft](#installing-papercraft)
|
65
|
+
- [Basic usage](#basic-usage)
|
66
|
+
- [Adding tags](#adding-tags)
|
67
|
+
- [Template parameters](#template-parameters)
|
68
|
+
- [Template logic](#template-logic)
|
69
|
+
- [Template blocks](#template-blocks)
|
70
|
+
- [Plain procs as templates](#plain-procs-as-templates)
|
71
|
+
- [Template composition](#template-composition)
|
72
|
+
- [Parameter and block application](#parameter-and-block-application)
|
73
|
+
- [Higher-order templates](#higher-order-templates)
|
74
|
+
- [Layout template composition](#layout-template-composition)
|
75
|
+
- [Emitting raw HTML](#emitting-raw-html)
|
76
|
+
- [Emitting a string with HTML Encoding](#emitting-a-string-with-html-encoding)
|
77
|
+
- [Emitting Markdown](#emitting-markdown)
|
78
|
+
- [Working with MIME types](#working-with-mime-types)
|
79
|
+
- [Deferred evaluation](#deferred-evaluation)
|
80
|
+
- [Papercraft extensions](#papercraft-extensions)
|
81
|
+
- [XML templates](#xml-templates)
|
82
|
+
- [JSON templates](#json-templates)
|
83
|
+
- [API Reference](#api-reference)
|
54
84
|
|
55
85
|
## Installing Papercraft
|
56
86
|
|
@@ -66,30 +96,33 @@ Or manually:
|
|
66
96
|
$ gem install papercraft
|
67
97
|
```
|
68
98
|
|
69
|
-
##
|
99
|
+
## Basic usage
|
70
100
|
|
71
|
-
To create
|
101
|
+
To create an HTML template use `Papercraft.html`:
|
72
102
|
|
73
103
|
```ruby
|
74
104
|
require 'papercraft'
|
75
105
|
|
76
|
-
html =
|
106
|
+
html = Papercraft.html {
|
77
107
|
div(id: 'greeter') { p 'Hello!' }
|
78
108
|
}
|
79
109
|
```
|
80
110
|
|
111
|
+
(You can also use `Papercraft.xml` and `Papercraft.json` to create XML and JSON
|
112
|
+
templates, respectively.)
|
113
|
+
|
81
114
|
Rendering a template is done using `#render`:
|
82
115
|
|
83
116
|
```ruby
|
84
117
|
html.render #=> "<div id="greeter"><p>Hello!</p></div>"
|
85
118
|
```
|
86
119
|
|
87
|
-
##
|
120
|
+
## Adding tags
|
88
121
|
|
89
122
|
Tags are added using unqualified method calls, and can be nested using blocks:
|
90
123
|
|
91
124
|
```ruby
|
92
|
-
|
125
|
+
Papercraft.html {
|
93
126
|
html {
|
94
127
|
head {
|
95
128
|
title 'page title'
|
@@ -106,19 +139,19 @@ H {
|
|
106
139
|
Tag methods accept a string argument, a block, or no argument at all:
|
107
140
|
|
108
141
|
```ruby
|
109
|
-
|
142
|
+
Papercraft.html { p 'hello' }.render #=> "<p>hello</p>"
|
110
143
|
|
111
|
-
|
144
|
+
Papercraft.html { p { span '1'; span '2' } }.render #=> "<p><span>1</span><span>2</span></p>"
|
112
145
|
|
113
|
-
|
146
|
+
Papercraft.html { hr() }.render #=> "<hr/>"
|
114
147
|
```
|
115
148
|
|
116
149
|
Tag methods also accept tag attributes, given as a hash:
|
117
150
|
|
118
151
|
```ruby
|
119
|
-
|
152
|
+
Papercraft.html { img src: '/my.gif' }.render #=> "<img src="/my.gif"/>
|
120
153
|
|
121
|
-
|
154
|
+
Papercraft.html { p "foobar", class: 'important' }.render #=> "<p class=\"important\">foobar</p>"
|
122
155
|
```
|
123
156
|
|
124
157
|
## Template parameters
|
@@ -128,24 +161,24 @@ parameters are specified as block parameters, and are passed to the template on
|
|
128
161
|
rendering:
|
129
162
|
|
130
163
|
```ruby
|
131
|
-
greeting =
|
164
|
+
greeting = Papercraft.html { |name| h1 "Hello, #{name}!" }
|
132
165
|
greeting.render('world') #=> "<h1>Hello, world!</h1>"
|
133
166
|
```
|
134
167
|
|
135
168
|
Templates can also accept named parameters:
|
136
169
|
|
137
170
|
```ruby
|
138
|
-
greeting =
|
171
|
+
greeting = Papercraft.html { |name:| h1 "Hello, #{name}!" }
|
139
172
|
greeting.render(name: 'world') #=> "<h1>Hello, world!</h1>"
|
140
173
|
```
|
141
174
|
|
142
|
-
##
|
175
|
+
## Template logic
|
143
176
|
|
144
177
|
Since Papercraft templates are just a bunch of Ruby, you can easily write your
|
145
178
|
view logic right in the template:
|
146
179
|
|
147
180
|
```ruby
|
148
|
-
|
181
|
+
Papercraft.html { |user = nil|
|
149
182
|
if user
|
150
183
|
span "Hello, #{user.name}!"
|
151
184
|
else
|
@@ -159,7 +192,7 @@ H { |user = nil|
|
|
159
192
|
Templates can also accept and render blocks by using `emit_yield`:
|
160
193
|
|
161
194
|
```ruby
|
162
|
-
page =
|
195
|
+
page = Papercraft.html {
|
163
196
|
html {
|
164
197
|
body { emit_yield }
|
165
198
|
}
|
@@ -169,27 +202,27 @@ page = H {
|
|
169
202
|
page.render { h1 'hi' }
|
170
203
|
```
|
171
204
|
|
172
|
-
## Plain procs as
|
205
|
+
## Plain procs as templates
|
173
206
|
|
174
207
|
With Papercraft you can write a template as a plain Ruby proc, and later render
|
175
|
-
it by passing it as a block to `
|
208
|
+
it by passing it as a block to `Papercraft.html`:
|
176
209
|
|
177
210
|
```ruby
|
178
211
|
greeting = proc { |name| h1 "Hello, #{name}!" }
|
179
|
-
|
212
|
+
Papercraft.html(&greeting).render('world')
|
180
213
|
```
|
181
214
|
|
182
215
|
Components can also be expressed using lambda notation:
|
183
216
|
|
184
217
|
```ruby
|
185
218
|
greeting = ->(name) { h1 "Hello, #{name}!" }
|
186
|
-
|
219
|
+
Papercraft.html(&greeting).render('world')
|
187
220
|
```
|
188
221
|
|
189
|
-
##
|
222
|
+
## Template composition
|
190
223
|
|
191
|
-
Papercraft makes it easy to compose multiple
|
192
|
-
document. A Papercraft
|
224
|
+
Papercraft makes it easy to compose multiple templates into a whole HTML
|
225
|
+
document. A Papercraft template can contain other templates, as the following
|
193
226
|
example shows.
|
194
227
|
|
195
228
|
```ruby
|
@@ -210,26 +243,26 @@ ItemList = ->(items) {
|
|
210
243
|
}
|
211
244
|
}
|
212
245
|
|
213
|
-
page =
|
246
|
+
page = Papercraft.html { |title, items|
|
214
247
|
html5 {
|
215
248
|
head { Title(title) }
|
216
249
|
body { ItemList(items) }
|
217
250
|
}
|
218
251
|
}
|
219
252
|
|
220
|
-
page.render('Hello from
|
253
|
+
page.render('Hello from composed templates', [
|
221
254
|
{ id: 1, text: 'foo', checked: false },
|
222
255
|
{ id: 2, text: 'bar', checked: true }
|
223
256
|
])
|
224
257
|
```
|
225
258
|
|
226
|
-
In addition to using
|
227
|
-
non-constant
|
259
|
+
In addition to using templates defined as constants, you can also use
|
260
|
+
non-constant templates by invoking the `#emit` method:
|
228
261
|
|
229
262
|
```ruby
|
230
263
|
greeting = -> { span "Hello, world" }
|
231
264
|
|
232
|
-
|
265
|
+
Papercraft.html {
|
233
266
|
div {
|
234
267
|
emit greeting
|
235
268
|
}
|
@@ -239,62 +272,62 @@ H {
|
|
239
272
|
## Parameter and block application
|
240
273
|
|
241
274
|
Parameters and blocks can be applied to a template without it being rendered, by
|
242
|
-
using `#apply`. This mechanism is what allows
|
243
|
-
creation of higher-order
|
275
|
+
using `#apply`. This mechanism is what allows template composition and the
|
276
|
+
creation of higher-order templates.
|
244
277
|
|
245
|
-
The `#apply` method returns a new
|
246
|
-
or block to the original
|
278
|
+
The `#apply` method returns a new template which applies the given parameters and
|
279
|
+
or block to the original template:
|
247
280
|
|
248
281
|
```ruby
|
249
282
|
# parameter application
|
250
|
-
hello =
|
283
|
+
hello = Papercraft.html { |name| h1 "Hello, #{name}!" }
|
251
284
|
hello_world = hello.apply('world')
|
252
285
|
hello_world.render #=> "<h1>Hello, world!</h1>"
|
253
286
|
|
254
287
|
# block application
|
255
|
-
div_wrap =
|
288
|
+
div_wrap = Papercraft.html { div { emit_yield } }
|
256
289
|
wrapped_h1 = div_wrap.apply { h1 'hi' }
|
257
290
|
wrapped_h1.render #=> "<div><h1>hi</h1></div>"
|
258
291
|
|
259
|
-
# wrap a
|
292
|
+
# wrap a template
|
260
293
|
wrapped_hello_world = div_wrap.apply(&hello_world)
|
261
294
|
wrapped_hello_world.render #=> "<div><h1>Hello, world!</h1></div>"
|
262
295
|
```
|
263
296
|
|
264
|
-
## Higher-order
|
297
|
+
## Higher-order templates
|
265
298
|
|
266
|
-
Papercraft also lets you create higher-order
|
267
|
-
|
268
|
-
|
269
|
-
markup, enhancing
|
299
|
+
Papercraft also lets you create higher-order templates, that is,
|
300
|
+
templates that take other templates as parameters, or as blocks. Higher-order
|
301
|
+
templates are handy for creating layouts, wrapping templates in arbitrary
|
302
|
+
markup, enhancing templates or injecting template parameters.
|
270
303
|
|
271
|
-
Here is a
|
304
|
+
Here is a higher-order template that takes a template as parameter:
|
272
305
|
|
273
306
|
```ruby
|
274
|
-
div_wrap =
|
275
|
-
greeter =
|
307
|
+
div_wrap = Papercraft.html { |inner| div { emit inner } }
|
308
|
+
greeter = Papercraft.html { h1 'hi' }
|
276
309
|
wrapped_greeter = div_wrap.apply(greeter)
|
277
310
|
wrapped_greeter.render #=> "<div><h1>hi</h1></div>"
|
278
311
|
```
|
279
312
|
|
280
|
-
The inner
|
313
|
+
The inner template can also be passed as a block, as shown above:
|
281
314
|
|
282
315
|
```ruby
|
283
|
-
div_wrap =
|
316
|
+
div_wrap = Papercraft.html { div { emit_yield } }
|
284
317
|
wrapped_greeter = div_wrap.apply { h1 'hi' }
|
285
318
|
wrapped_greeter.render #=> "<div><h1>hi</h1></div>"
|
286
319
|
```
|
287
320
|
|
288
321
|
## Layout template composition
|
289
322
|
|
290
|
-
One of the principal uses of higher-order
|
323
|
+
One of the principal uses of higher-order templates is the creation of nested
|
291
324
|
layouts. Suppose we have a website with a number of different layouts, and we'd
|
292
325
|
like to avoid having to repeat the same code in the different layouts. We can do
|
293
326
|
this by creating a `default` page template that takes a block, then use `#apply`
|
294
327
|
to create the other templates:
|
295
328
|
|
296
329
|
```ruby
|
297
|
-
default_layout =
|
330
|
+
default_layout = Papercraft.html { |**params|
|
298
331
|
html5 {
|
299
332
|
head {
|
300
333
|
title: params[:title]
|
@@ -323,7 +356,7 @@ article_layout.render(
|
|
323
356
|
Raw HTML can be emitted using `#emit`:
|
324
357
|
|
325
358
|
```ruby
|
326
|
-
wrapped =
|
359
|
+
wrapped = Papercraft.html { |html| div { emit html } }
|
327
360
|
wrapped.render("<h1>hi</h1>") #=> "<div><h1>hi</h1></div>"
|
328
361
|
```
|
329
362
|
|
@@ -333,7 +366,7 @@ To emit a string with proper HTML encoding, without wrapping it in an HTML
|
|
333
366
|
element, use `#text`:
|
334
367
|
|
335
368
|
```ruby
|
336
|
-
|
369
|
+
Papercraft.html { str 'hi&lo' }.render #=> "hi&lo"
|
337
370
|
```
|
338
371
|
|
339
372
|
## Emitting Markdown
|
@@ -343,7 +376,7 @@ Markdown is rendered using the
|
|
343
376
|
`#emit_markdown`:
|
344
377
|
|
345
378
|
```ruby
|
346
|
-
template =
|
379
|
+
template = Papercraft.html { |md| div { emit_markdown md } }
|
347
380
|
template.render("Here's some *Markdown*") #=> "<div><p>Here's some <em>Markdown</em><p>\n</div>"
|
348
381
|
```
|
349
382
|
|
@@ -352,10 +385,18 @@ options](https://kramdown.gettalong.org/options.html#available-options) can be
|
|
352
385
|
specified by adding them to the `#emit_markdown` call:
|
353
386
|
|
354
387
|
```ruby
|
355
|
-
template =
|
388
|
+
template = Papercraft.html { |md| div { emit_markdown md, auto_ids: false } }
|
356
389
|
template.render("# title") #=> "<div><h1>title</h1></div>"
|
357
390
|
```
|
358
391
|
|
392
|
+
The `#emit_markdown` method is available only to HTML templates. If you need to
|
393
|
+
render markdown in XML or JSON templates (usually for implementing RSS or JSON
|
394
|
+
feeds), you can use `Papercraft.markdown` directly:
|
395
|
+
|
396
|
+
```ruby
|
397
|
+
Papercraft.markdown('# title') #=> "<h1>title</h1>"
|
398
|
+
```
|
399
|
+
|
359
400
|
The default Kramdown options are:
|
360
401
|
|
361
402
|
```ruby
|
@@ -368,17 +409,33 @@ The default Kramdown options are:
|
|
368
409
|
```
|
369
410
|
|
370
411
|
The deafult options can be configured by accessing
|
371
|
-
`Papercraft
|
412
|
+
`Papercraft.default_kramdown_options`, e.g.:
|
372
413
|
|
373
414
|
```ruby
|
374
|
-
Papercraft
|
415
|
+
Papercraft.default_kramdown_options[:auto_ids] = false
|
416
|
+
```
|
417
|
+
|
418
|
+
## Working with MIME types
|
419
|
+
|
420
|
+
Papercraft lets you set and interrogate a template's MIME type, in order to be
|
421
|
+
able to dynamically set the `Content-Type` HTTP response header. A template's
|
422
|
+
MIME type can be set when creating the template, e.g. `Papercraft.xml(mime_type:
|
423
|
+
'application/rss+xml')`. You can interrogate the template's MIME type using
|
424
|
+
`#mime_type`:
|
425
|
+
|
426
|
+
```ruby
|
427
|
+
# using Qeweney (https://github.com/digital-fabric/qeweney)
|
428
|
+
def serve_template(req, template)
|
429
|
+
body = template.render
|
430
|
+
respond(body, 'Content-Type' => template.mime_type)
|
431
|
+
end
|
375
432
|
```
|
376
433
|
|
377
434
|
## Deferred evaluation
|
378
435
|
|
379
436
|
Deferred evaluation allows deferring the rendering of parts of a template until
|
380
|
-
the last moment, thus allowing an inner
|
381
|
-
outer
|
437
|
+
the last moment, thus allowing an inner template to manipulate the state of the
|
438
|
+
outer template. To in order to defer a part of a template, use `#defer`, and
|
382
439
|
include any markup in the provided block. This technique, in in conjunction with
|
383
440
|
holding state in instance variables, is an alternative to passing parameters,
|
384
441
|
which can be limiting in some situations.
|
@@ -387,15 +444,15 @@ A few use cases for deferred evaulation come to mind:
|
|
387
444
|
|
388
445
|
- Setting the page title.
|
389
446
|
- Adding a flash message to a page.
|
390
|
-
- Using
|
447
|
+
- Using templates that dynamically add static dependencies (JS and CSS) to the
|
391
448
|
page.
|
392
449
|
|
393
450
|
The last use case is particularly interesting. Imagine a `DependencyMananger`
|
394
|
-
class that can collect JS and CSS dependencies from the different
|
451
|
+
class that can collect JS and CSS dependencies from the different templates
|
395
452
|
integrated into the page, and adds them to the page's `<head>` element:
|
396
453
|
|
397
454
|
```ruby
|
398
|
-
default_layout =
|
455
|
+
default_layout = Papercraft.html { |**args|
|
399
456
|
@dependencies = DependencyMananger.new
|
400
457
|
head {
|
401
458
|
defer { emit @dependencies.head_markup }
|
@@ -481,7 +538,7 @@ The call to `Papercraft::extension` lets us access the different methods of
|
|
481
538
|
we'll be able to express the above markup as follows:
|
482
539
|
|
483
540
|
```ruby
|
484
|
-
|
541
|
+
Papercraft.html {
|
485
542
|
bootstrap.card(style: 'width: 18rem') {
|
486
543
|
bootstrap.card_title 'Card title'
|
487
544
|
bootstrap.card_subtitle 'Card subtitle'
|
@@ -492,6 +549,74 @@ H {
|
|
492
549
|
}
|
493
550
|
```
|
494
551
|
|
552
|
+
|
553
|
+
|
554
|
+
## XML templates
|
555
|
+
|
556
|
+
XML templates behave largely the same as HTML templates, with a few minor
|
557
|
+
differences. XML templates employ a different encoding algorithm, and lack some
|
558
|
+
specific HTML functionality, such as emitting Markdown.
|
559
|
+
|
560
|
+
Here's an example showing how to create an RSS feed:
|
561
|
+
|
562
|
+
```ruby
|
563
|
+
rss = Papercraft.xml(mime_type: 'text/xml; charset=utf-8') { |resource:, **props|
|
564
|
+
rss(version: '2.0', 'xmlns:atom' => 'http://www.w3.org/2005/Atom') {
|
565
|
+
channel {
|
566
|
+
title 'Noteflakes'
|
567
|
+
link 'https://noteflakes.com/'
|
568
|
+
description 'A website by Sharon Rosner'
|
569
|
+
language 'en-us'
|
570
|
+
pubDate Time.now.httpdate
|
571
|
+
emit '<atom:link href="https://noteflakes.com/feeds/rss" rel="self" type="application/rss+xml" />'
|
572
|
+
|
573
|
+
article_entries = resource.page_list('/articles').reverse
|
574
|
+
|
575
|
+
article_entries.each { |e|
|
576
|
+
item {
|
577
|
+
title e[:title]
|
578
|
+
link "https://noteflakes.com#{e[:url]}"
|
579
|
+
guid "https://noteflakes.com#{e[:url]}"
|
580
|
+
pubDate e[:date].to_time.httpdate
|
581
|
+
description e[:html_content]
|
582
|
+
}
|
583
|
+
}
|
584
|
+
}
|
585
|
+
}
|
586
|
+
}
|
587
|
+
```
|
588
|
+
|
589
|
+
## JSON templates
|
590
|
+
|
591
|
+
JSON templates behave largely the same as HTML and XML templates. The only major
|
592
|
+
difference is that for adding array items you'll need to use the `#item` method:
|
593
|
+
|
594
|
+
```ruby
|
595
|
+
Papercraft.json {
|
596
|
+
item 1
|
597
|
+
item 2
|
598
|
+
item 3
|
599
|
+
}.render #=> "[1,2,3]"
|
600
|
+
```
|
601
|
+
|
602
|
+
Otherwise, you can create arbitrarily complex JSON structures by mixing hashes
|
603
|
+
and arrays:
|
604
|
+
|
605
|
+
```Ruby
|
606
|
+
Papercraft.json {
|
607
|
+
foo {
|
608
|
+
bar {
|
609
|
+
item nil
|
610
|
+
item true
|
611
|
+
item 123.456
|
612
|
+
}
|
613
|
+
}
|
614
|
+
}.render #=> "{\"foo\":{\"bar\":[null,true,123.456]}}"
|
615
|
+
```
|
616
|
+
|
617
|
+
Papercraft uses the [JSON gem](https://rubyapi.org/3.1/o/json) under the hood in
|
618
|
+
order to generate actual JSON.
|
619
|
+
|
495
620
|
## API Reference
|
496
621
|
|
497
622
|
The API reference for this library can be found
|
data/lib/papercraft/html.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'kramdown'
|
4
|
-
require 'rouge'
|
5
|
-
require 'kramdown-parser-gfm'
|
6
|
-
|
7
3
|
module Papercraft
|
8
4
|
# HTML Markup extensions
|
9
5
|
module HTML
|
@@ -83,41 +79,7 @@ module Papercraft
|
|
83
79
|
# @param **opts [Hash] Kramdown options
|
84
80
|
# @return [void]
|
85
81
|
def emit_markdown(markdown, **opts)
|
86
|
-
emit
|
87
|
-
end
|
88
|
-
|
89
|
-
class << self
|
90
|
-
# Returns the default Kramdown options used for converting Markdown to
|
91
|
-
# HTML.
|
92
|
-
#
|
93
|
-
# @return [Hash] Default Kramdown options
|
94
|
-
def kramdown_options
|
95
|
-
@kramdown_options ||= {
|
96
|
-
entity_output: :numeric,
|
97
|
-
syntax_highlighter: :rouge,
|
98
|
-
input: 'GFM',
|
99
|
-
hard_wrap: false
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
# Sets the default Kramdown options used for converting Markdown to
|
104
|
-
# HTML.
|
105
|
-
#
|
106
|
-
# @param opts [Hash] New deafult Kramdown options
|
107
|
-
# @return [Hash] New default Kramdown options
|
108
|
-
def kramdown_options=(opts)
|
109
|
-
@kramdown_options = opts
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
private
|
114
|
-
|
115
|
-
# Returns the default Kramdown options, merged with the given overrides.
|
116
|
-
#
|
117
|
-
# @param opts [Hash] Kramdown option overrides
|
118
|
-
# @return [Hash] Merged Kramdown options
|
119
|
-
def kramdown_options(opts)
|
120
|
-
HTML.kramdown_options.merge(**opts)
|
82
|
+
emit Papercraft.markdown(markdown, **opts)
|
121
83
|
end
|
122
84
|
end
|
123
85
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Papercraft
|
6
|
+
# JSON renderer extensions
|
7
|
+
module JSON
|
8
|
+
def object_stack
|
9
|
+
@object_stack ||= [nil]
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_object(&block)
|
13
|
+
object_stack << nil
|
14
|
+
instance_eval(&block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def verify_array_target
|
18
|
+
case object_stack[-1]
|
19
|
+
when nil
|
20
|
+
object_stack[-1] = []
|
21
|
+
when Hash
|
22
|
+
raise "Mixing array and hash values"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def verify_hash_target
|
27
|
+
case object_stack[-1]
|
28
|
+
when nil
|
29
|
+
object_stack[-1] = {}
|
30
|
+
when Array
|
31
|
+
raise "Mixing array and hash values"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def push_array_item(value)
|
36
|
+
object_stack[-1] << value
|
37
|
+
end
|
38
|
+
|
39
|
+
def push_kv_item(key, value)
|
40
|
+
object_stack[-1][key] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
def enter_object(&block)
|
44
|
+
object_stack << nil
|
45
|
+
instance_eval(&block)
|
46
|
+
object_stack.pop
|
47
|
+
end
|
48
|
+
|
49
|
+
def item(value = nil, &block)
|
50
|
+
verify_array_target
|
51
|
+
if block
|
52
|
+
value = enter_object(&block)
|
53
|
+
end
|
54
|
+
push_array_item(value)
|
55
|
+
end
|
56
|
+
|
57
|
+
def kv(key, value, &block)
|
58
|
+
verify_hash_target
|
59
|
+
if block
|
60
|
+
value = enter_object(&block)
|
61
|
+
end
|
62
|
+
push_kv_item(key, value)
|
63
|
+
end
|
64
|
+
|
65
|
+
def method_missing(sym, value = nil, &block)
|
66
|
+
kv(sym, value, &block)
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
object_stack[0].to_json
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/papercraft/renderer.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'escape_utils'
|
4
|
+
|
3
5
|
require_relative './html'
|
6
|
+
require_relative './json'
|
4
7
|
require_relative './extension_proxy'
|
5
8
|
|
6
9
|
module Papercraft
|
7
10
|
|
8
|
-
# A Renderer renders a Papercraft
|
11
|
+
# A Renderer renders a Papercraft template into a string
|
9
12
|
class Renderer
|
10
13
|
|
11
14
|
class << self
|
@@ -40,7 +43,7 @@ module Papercraft
|
|
40
43
|
#
|
41
44
|
# Installs the given extensions, passed in the form of a Ruby hash mapping
|
42
45
|
# methods to extension modules. The methods will be available to all
|
43
|
-
# Papercraft
|
46
|
+
# Papercraft templates. Extension methods are executed in the context of
|
44
47
|
# the the renderer instance, so they can look just like normal proc
|
45
48
|
# components. In cases where method names in the module clash with HTML
|
46
49
|
# tag names, you can use the `#tag` method to emit the relevant tag.
|
@@ -55,7 +58,7 @@ module Papercraft
|
|
55
58
|
# end
|
56
59
|
#
|
57
60
|
# Papercraft.extension(components: ComponentLibrary)
|
58
|
-
#
|
61
|
+
# Papercraft.html { components.card('Foo', '**Bar**') }
|
59
62
|
#
|
60
63
|
# @param map [Hash] hash mapping methods to extension modules
|
61
64
|
# @return [void]
|
@@ -210,20 +213,21 @@ module Papercraft
|
|
210
213
|
# `#to_s` which is then added to the rendering buffer, without any escaping.
|
211
214
|
#
|
212
215
|
# greeter = proc { |name| h1 "Hello, #{name}!" }
|
213
|
-
#
|
216
|
+
# Papercraft.html { emit(greeter, 'world') }.render #=> "<h1>Hello, world!</h1>"
|
214
217
|
#
|
215
|
-
#
|
218
|
+
# Papercraft.html { emit 'hi&<bye>' }.render #=> "hi&<bye>"
|
216
219
|
#
|
217
|
-
#
|
220
|
+
# Papercraft.html { emit nil }.render #=> ""
|
218
221
|
#
|
219
|
-
# @param o [Proc, Papercraft::
|
222
|
+
# @param o [Proc, Papercraft::Template, String] emitted object
|
220
223
|
# @param *a [Array<any>] arguments to pass to a proc
|
221
224
|
# @param **b [Hash] named arguments to pass to a proc
|
222
225
|
# @return [void]
|
223
|
-
def emit(o, *a, **b)
|
226
|
+
def emit(o, *a, **b, &block)
|
224
227
|
case o
|
225
228
|
when ::Proc
|
226
229
|
Renderer.verify_proc_parameters(o, a, b)
|
230
|
+
push_emit_yield_block(block) if block
|
227
231
|
instance_exec(*a, **b, &o)
|
228
232
|
when nil
|
229
233
|
else
|
@@ -234,7 +238,7 @@ module Papercraft
|
|
234
238
|
|
235
239
|
# Emits a block supplied using `Component#apply` or `Component#render`.
|
236
240
|
#
|
237
|
-
# div_wrap =
|
241
|
+
# div_wrap = Papercraft.html { |*args| div { emit_yield(*args) } }
|
238
242
|
# greeter = div_wrap.apply { |name| h1 "Hello, #{name}!" }
|
239
243
|
# greeter.render('world') #=> "<div><h1>Hello, world!</h1></div>"
|
240
244
|
#
|
@@ -249,14 +253,14 @@ module Papercraft
|
|
249
253
|
end
|
250
254
|
|
251
255
|
# Defers the given block to be evaluated later. Deferred evaluation allows
|
252
|
-
# Papercraft
|
256
|
+
# Papercraft templates to inject state into sibling components, regardless
|
253
257
|
# of the component's order in the container component. For example, a nested
|
254
258
|
# component may set an instance variable used by another component. This is
|
255
259
|
# an elegant solution to the problem of setting the HTML page's title, or
|
256
260
|
# adding elements to the `<head>` section. Here's how a title can be
|
257
261
|
# controlled from a nested component:
|
258
262
|
#
|
259
|
-
# layout =
|
263
|
+
# layout = Papercraft.html {
|
260
264
|
# html {
|
261
265
|
# head {
|
262
266
|
# defer { title @title }
|
@@ -380,4 +384,8 @@ module Papercraft
|
|
380
384
|
EscapeUtils.escape_xml(text.to_s)
|
381
385
|
end
|
382
386
|
end
|
387
|
+
|
388
|
+
class JSONRenderer < Renderer
|
389
|
+
include JSON
|
390
|
+
end
|
383
391
|
end
|
@@ -4,28 +4,33 @@ require_relative './html'
|
|
4
4
|
|
5
5
|
module Papercraft
|
6
6
|
|
7
|
-
#
|
8
|
-
# include other
|
7
|
+
# Template represents a distinct, reusable HTML template. A template can
|
8
|
+
# include other templates, and also be nested inside other templates.
|
9
9
|
#
|
10
|
-
# Since in Papercraft HTML is expressed using blocks (or procs,) the
|
10
|
+
# Since in Papercraft HTML is expressed using blocks (or procs,) the Template
|
11
11
|
# class is simply a special kind of Proc, which has some enhanced
|
12
12
|
# capabilities, allowing it to be easily composed in a variety of ways.
|
13
13
|
#
|
14
|
-
#
|
15
|
-
#
|
14
|
+
# Templates are usually created using the class methods `html`, `xml` or
|
15
|
+
# `json`, for HTML, XML or JSON templates, respectively:
|
16
16
|
#
|
17
|
-
# greeter =
|
17
|
+
# greeter = Papercraft.html { |name| h1 "Hello, #{name}!" }
|
18
18
|
# greeter.render('world') #=> "<h1>Hello, world!</h1>"
|
19
19
|
#
|
20
|
-
#
|
20
|
+
# Templates can also be created using the normal constructor:
|
21
21
|
#
|
22
|
-
# greeter = Papercraft::
|
22
|
+
# greeter = Papercraft::Template.new(mode: :html) { |name| h1 "Hello, #{name}!" }
|
23
23
|
# greeter.render('world') #=> "<h1>Hello, world!</h1>"
|
24
24
|
#
|
25
|
-
#
|
25
|
+
# The different methods for creating templates can also take a custom MIME
|
26
|
+
# type, by passing a `mime_type` named argument:
|
27
|
+
#
|
28
|
+
# json = Papercraft.json(mime_type: 'application/feed+json') { ... }
|
29
|
+
#
|
30
|
+
# In the template block, HTML elements are created by simply calling
|
26
31
|
# unqualified methods:
|
27
32
|
#
|
28
|
-
# page_layout =
|
33
|
+
# page_layout = Papercraft.html {
|
29
34
|
# html5 {
|
30
35
|
# head {
|
31
36
|
# title 'foo'
|
@@ -36,31 +41,31 @@ module Papercraft
|
|
36
41
|
# }
|
37
42
|
# }
|
38
43
|
#
|
39
|
-
# Papercraft
|
44
|
+
# Papercraft templates can take explicit parameters in order to render
|
40
45
|
# dynamic content. This can be in the form of regular or named parameters. The
|
41
46
|
# `greeter` template shown above takes a single `name` parameter. Here's how a
|
42
|
-
# anchor
|
47
|
+
# anchor template could be implemented with named parameters:
|
43
48
|
#
|
44
|
-
# anchor =
|
49
|
+
# anchor = Papercraft.html { |uri: , text: | a(text, href: uri) }
|
45
50
|
#
|
46
|
-
# The above
|
51
|
+
# The above template could later be rendered by passing the needed arguments:
|
47
52
|
#
|
48
53
|
# anchor.render(uri: 'https://example.com', text: 'Example')
|
49
54
|
#
|
50
|
-
# ##
|
55
|
+
# ## Template Composition
|
51
56
|
#
|
52
|
-
# A
|
57
|
+
# A template can be included in another template using the `emit` method:
|
53
58
|
#
|
54
|
-
# links =
|
59
|
+
# links = Papercraft.html {
|
55
60
|
# emit anchor, uri: '/posts', text: 'Posts'
|
56
61
|
# emit anchor, uri: '/archive', text: 'Archive'
|
57
62
|
# emit anchor, uri: '/about', text: 'About'
|
58
63
|
# }
|
59
64
|
#
|
60
|
-
# Another way of composing
|
65
|
+
# Another way of composing templates is to pass the templates themselves as
|
61
66
|
# parameters:
|
62
67
|
#
|
63
|
-
# links =
|
68
|
+
# links = Papercraft.html { |anchors|
|
64
69
|
# anchors.each { |a| emit a }
|
65
70
|
# }
|
66
71
|
# links.render([
|
@@ -69,8 +74,8 @@ module Papercraft
|
|
69
74
|
# anchor.apply(uri: '/about', text: 'About')
|
70
75
|
# ])
|
71
76
|
#
|
72
|
-
# The `#apply` method creates a new
|
73
|
-
# such that the
|
77
|
+
# The `#apply` method creates a new template, applying the given parameters
|
78
|
+
# such that the template can be rendered without parameters:
|
74
79
|
#
|
75
80
|
# links_with_anchors = links.apply([
|
76
81
|
# anchor.apply(uri: '/posts', text: 'Posts'),
|
@@ -79,19 +84,27 @@ module Papercraft
|
|
79
84
|
# ])
|
80
85
|
# links_with_anchors.render
|
81
86
|
#
|
82
|
-
class
|
87
|
+
class Template < Proc
|
83
88
|
|
84
89
|
# Determines the rendering mode: `:html` or `:xml`.
|
85
90
|
attr_accessor :mode
|
86
91
|
|
87
|
-
|
92
|
+
STOCK_MIME_TYPE = {
|
93
|
+
html: 'text/html',
|
94
|
+
xml: 'application/xml',
|
95
|
+
json: 'application/json'
|
96
|
+
}.freeze
|
97
|
+
|
98
|
+
# Initializes a template with the given block. The rendering mode (HTML or
|
88
99
|
# XML) can be passed in the `mode:` parameter. If `mode:` is not specified,
|
89
|
-
# the
|
100
|
+
# the template defaults to HTML.
|
90
101
|
#
|
91
102
|
# @param mode [:html, :xml] rendering mode
|
103
|
+
# @param mime_type [String, nil] the template's mime type (nil for default)
|
92
104
|
# @param block [Proc] nested HTML block
|
93
|
-
def initialize(mode: :html, &block)
|
105
|
+
def initialize(mode: :html, mime_type: nil, &block)
|
94
106
|
@mode = mode
|
107
|
+
@mime_type = mime_type || STOCK_MIME_TYPE[mode]
|
95
108
|
super(&block)
|
96
109
|
end
|
97
110
|
|
@@ -111,11 +124,11 @@ module Papercraft
|
|
111
124
|
end.to_s
|
112
125
|
end
|
113
126
|
|
114
|
-
# Creates a new
|
127
|
+
# Creates a new template, applying the given parameters and or block to the
|
115
128
|
# current one. Application is one of the principal methods of composing
|
116
|
-
#
|
129
|
+
# templates, particularly when passing inner templates as blocks:
|
117
130
|
#
|
118
|
-
# article_wrapper =
|
131
|
+
# article_wrapper = Papercraft.html {
|
119
132
|
# article {
|
120
133
|
# emit_yield
|
121
134
|
# }
|
@@ -128,29 +141,35 @@ module Papercraft
|
|
128
141
|
# @param *a [<any>] normal parameters
|
129
142
|
# @param **b [Hash] named parameters
|
130
143
|
# @param &block [Proc] inner block
|
131
|
-
# @return [Papercraft::
|
144
|
+
# @return [Papercraft::Template] applied template
|
132
145
|
def apply(*a, **b, &block)
|
133
146
|
template = self
|
134
|
-
|
147
|
+
Template.new(mode: @mode, mime_type: @mime_type, &proc do |*x, **y|
|
135
148
|
push_emit_yield_block(block) if block
|
136
149
|
instance_exec(*a, *x, **b, **y, &template)
|
137
150
|
end)
|
138
151
|
end
|
139
152
|
|
140
153
|
# Returns the Renderer class used for rendering the templates, according to
|
141
|
-
# the
|
154
|
+
# the template's mode.
|
142
155
|
#
|
143
|
-
# @return [Papercraft::Renderer] Renderer used for rendering the
|
156
|
+
# @return [Papercraft::Renderer] Renderer used for rendering the template
|
144
157
|
def renderer_class
|
145
158
|
case @mode
|
146
159
|
when :html
|
147
160
|
HTMLRenderer
|
148
161
|
when :xml
|
149
162
|
XMLRenderer
|
163
|
+
when :json
|
164
|
+
JSONRenderer
|
150
165
|
else
|
151
166
|
raise "Invalid mode #{@mode.inspect}"
|
152
167
|
end
|
153
168
|
end
|
169
|
+
|
170
|
+
def mime_type
|
171
|
+
@mime_type
|
172
|
+
end
|
154
173
|
|
155
174
|
# def compile
|
156
175
|
# Papercraft::Compiler.new.compile(self)
|
data/lib/papercraft/version.rb
CHANGED
data/lib/papercraft.rb
CHANGED
@@ -1,60 +1,110 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'kramdown'
|
4
|
+
require 'rouge'
|
5
|
+
require 'kramdown-parser-gfm'
|
4
6
|
|
5
|
-
require_relative 'papercraft/
|
7
|
+
require_relative 'papercraft/template'
|
6
8
|
require_relative 'papercraft/renderer'
|
7
9
|
require_relative 'papercraft/encoding'
|
8
10
|
# require_relative 'papercraft/compiler'
|
9
11
|
|
10
|
-
|
12
|
+
|
13
|
+
# Papercraft is a composable templating library
|
11
14
|
module Papercraft
|
12
15
|
# Exception class used to signal templating-related errors
|
13
16
|
class Error < RuntimeError; end
|
14
|
-
|
15
|
-
# Installs one or more extensions. Extensions enhance templating capabilities
|
16
|
-
# by adding namespaced methods to emplates. An extension is implemented as a
|
17
|
-
# Ruby module containing one or more methods. Each method in the extension
|
18
|
-
# module can be used to render a specific HTML element or a set of elements.
|
19
|
-
#
|
20
|
-
# This is a convenience method. For more information on using Papercraft
|
21
|
-
# extensions, see `Papercraft::Renderer::extension`
|
22
|
-
#
|
23
|
-
# @param map [Hash] hash mapping methods to extension modules
|
24
|
-
# @return [void]
|
25
|
-
def self.extension(map)
|
26
|
-
Renderer.extension(map)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# Kernel extensions
|
31
|
-
module ::Kernel
|
32
17
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
18
|
+
class << self
|
19
|
+
|
20
|
+
# Installs one or more extensions. Extensions enhance templating capabilities
|
21
|
+
# by adding namespaced methods to emplates. An extension is implemented as a
|
22
|
+
# Ruby module containing one or more methods. Each method in the extension
|
23
|
+
# module can be used to render a specific HTML element or a set of elements.
|
24
|
+
#
|
25
|
+
# This is a convenience method. For more information on using Papercraft
|
26
|
+
# extensions, see `Papercraft::Renderer::extension`
|
27
|
+
#
|
28
|
+
# @param map [Hash] hash mapping methods to extension modules
|
29
|
+
# @return [void]
|
30
|
+
def extension(map)
|
31
|
+
Renderer.extension(map)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Creates a new papercraft template. `Papercraft.html` can take either a proc
|
35
|
+
# argument or a block. In both cases, the proc is converted to a
|
36
|
+
# `Papercraft::Template`.
|
37
|
+
#
|
38
|
+
# Papercraft.html(proc { h1 'hi' }).render #=> "<h1>hi</h1>"
|
39
|
+
# Papercraft.html { h1 'hi' }.render #=> "<h1>hi</h1>"
|
40
|
+
#
|
41
|
+
# @param template [Proc] template block
|
42
|
+
# @return [Papercraft::Template] Papercraft template
|
43
|
+
def html(o = nil, mime_type: nil, &template)
|
44
|
+
return o if o.is_a?(Papercraft::Template)
|
45
|
+
template ||= o
|
46
|
+
Papercraft::Template.new(mode: :html, mime_type: mime_type, &template)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates a new Papercraft template in XML mode. `Papercraft.xml` can take
|
50
|
+
# either a proc argument or a block. In both cases, the proc is converted to a
|
51
|
+
# `Papercraft::Template`.
|
52
|
+
#
|
53
|
+
# Papercraft.xml(proc { item 'foo' }).render #=> "<item>foo</item>"
|
54
|
+
# Papercraft.xml { item 'foo' }.render #=> "<item>foo</item>"
|
55
|
+
#
|
56
|
+
# @param template [Proc] template block
|
57
|
+
# @return [Papercraft::Template] Papercraft template
|
58
|
+
def xml(o = nil, mime_type: nil, &template)
|
59
|
+
return o if o.is_a?(Papercraft::Template)
|
60
|
+
template ||= o
|
61
|
+
Papercraft::Template.new(mode: :xml, mime_type: mime_type, &template)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Creates a new Papercraft template in JSON mode. `Papercraft.json` can take
|
65
|
+
# either a proc argument or a block. In both cases, the proc is converted to a
|
66
|
+
# `Papercraft::Template`.
|
67
|
+
#
|
68
|
+
# Papercraft.json(proc { item 42 }).render #=> "[42]"
|
69
|
+
# Papercraft.json { foo 'bar' }.render #=> "{\"foo\": \"bar\"}"
|
70
|
+
#
|
71
|
+
# @param template [Proc] template block
|
72
|
+
# @return [Papercraft::Template] Papercraft template
|
73
|
+
def json(o = nil, mime_type: nil, &template)
|
74
|
+
return o if o.is_a?(Papercraft::Template)
|
75
|
+
template ||= o
|
76
|
+
Papercraft::Template.new(mode: :json, mime_type: mime_type, &template)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Renders Markdown into HTML. The `opts` argument will be merged with the
|
80
|
+
# default Kramdown options in order to change the rendering behaviour.
|
81
|
+
#
|
82
|
+
# @param markdown [String] Markdown
|
83
|
+
# @param **opts [Hash] Kramdown option overrides
|
84
|
+
# @return [String] HTML
|
85
|
+
def markdown(markdown, **opts)
|
86
|
+
opts = default_kramdown_options.merge(opts)
|
87
|
+
Kramdown::Document.new(markdown, **opts).to_html
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the default Kramdown options used for rendering Markdown.
|
91
|
+
#
|
92
|
+
# @return [Hash] Kramdown options
|
93
|
+
def default_kramdown_options
|
94
|
+
@default_kramdown_options ||= {
|
95
|
+
entity_output: :numeric,
|
96
|
+
syntax_highlighter: :rouge,
|
97
|
+
input: 'GFM',
|
98
|
+
hard_wrap: false
|
99
|
+
}
|
100
|
+
end
|
46
101
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# @return [Papercraft::Component] Papercraft component
|
55
|
-
def X(o = nil, &template)
|
56
|
-
return o if o.is_a?(Papercraft::Component)
|
57
|
-
template ||= o
|
58
|
-
Papercraft::Component.new(mode: :xml, &template)
|
102
|
+
# Sets the default Kramdown options used for rendering Markdown.
|
103
|
+
#
|
104
|
+
# @param opts [Hash] Kramdown options
|
105
|
+
# @return [void]
|
106
|
+
def default_kramdown_options=(opts)
|
107
|
+
@default_kramdown_options = opts
|
108
|
+
end
|
59
109
|
end
|
60
110
|
end
|
data/papercraft.png
ADDED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: papercraft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.19'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: escape_utils
|
@@ -128,17 +128,20 @@ executables: []
|
|
128
128
|
extensions: []
|
129
129
|
extra_rdoc_files:
|
130
130
|
- README.md
|
131
|
+
- papercraft.png
|
131
132
|
files:
|
132
133
|
- CHANGELOG.md
|
133
134
|
- README.md
|
134
135
|
- lib/papercraft.rb
|
135
136
|
- lib/papercraft/compiler.rb
|
136
|
-
- lib/papercraft/component.rb
|
137
137
|
- lib/papercraft/encoding.rb
|
138
138
|
- lib/papercraft/extension_proxy.rb
|
139
139
|
- lib/papercraft/html.rb
|
140
|
+
- lib/papercraft/json.rb
|
140
141
|
- lib/papercraft/renderer.rb
|
142
|
+
- lib/papercraft/template.rb
|
141
143
|
- lib/papercraft/version.rb
|
144
|
+
- papercraft.png
|
142
145
|
homepage: http://github.com/digital-fabric/papercraft
|
143
146
|
licenses:
|
144
147
|
- MIT
|