papercraft 0.23 → 0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +116 -43
- data/lib/papercraft/renderer.rb +9 -9
- data/lib/papercraft/tags.rb +58 -9
- data/lib/papercraft/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f23902f7431dcbd6c1180e26f612ae5099d4e7f2ba468dd0e0e5e9a76e324ef4
|
4
|
+
data.tar.gz: 5bf38e4faea0ab6c6145d769b24b416e467836b29c6d8856bb96442f86b43bfe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69ed90f079f1db073bbc18b1b631c13cbcd2db5dae9e512781046fb7fa5ab0a164653137b28c201f48671d77e4d08ff1da3818381aca5d3686d61eb185f8a586
|
7
|
+
data.tar.gz: 85681c583e3e145ca27a52638e0d3370fa94462d5baaae8cccb477a1a2938ad56f3040ee4f6cceb2757b49019890bcae505bcdc008e2ff0931987f09ab9eb91a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 0.25 2023-01-12
|
2
|
+
|
3
|
+
- Implement `#def_tag` for defining custom tags inline
|
4
|
+
|
5
|
+
## 0.24 2022-03-19
|
6
|
+
|
7
|
+
- Fix usage of const components (#13)
|
8
|
+
- Fix formatting of HTML/XML attributes for non-string values
|
9
|
+
|
1
10
|
## 0.23 2022-02-15
|
2
11
|
|
3
12
|
- Remove unused `Encoding` module
|
data/README.md
CHANGED
@@ -42,6 +42,10 @@ Papercraft includes built-in support for rendering Markdown (using
|
|
42
42
|
creating template extensions in order to allow the creation of component
|
43
43
|
libraries.
|
44
44
|
|
45
|
+
Papercraft automatically escapes all text emitted in templates according to the
|
46
|
+
template type. For more information see the section on [escaping
|
47
|
+
content](#escaping-content).
|
48
|
+
|
45
49
|
```ruby
|
46
50
|
require 'papercraft'
|
47
51
|
|
@@ -59,29 +63,31 @@ hello.render('world')
|
|
59
63
|
#=> "<html><head><title>Title</title></head><body><h1>Hello, world!</h1></body></html>"
|
60
64
|
```
|
61
65
|
|
62
|
-
## Table of
|
63
|
-
|
64
|
-
- [Installing
|
65
|
-
- [Basic
|
66
|
-
- [Adding
|
67
|
-
- [Tag and
|
68
|
-
- [
|
69
|
-
- [Template
|
70
|
-
- [Template
|
71
|
-
- [
|
72
|
-
- [
|
73
|
-
- [
|
74
|
-
- [
|
75
|
-
- [
|
76
|
-
- [
|
77
|
-
- [Emitting
|
66
|
+
## Table of Content
|
67
|
+
|
68
|
+
- [Installing Papercraft](#installing-papercraft)
|
69
|
+
- [Basic Usage](#basic-usage)
|
70
|
+
- [Adding Tags](#adding-tags)
|
71
|
+
- [Tag and Attribute Formatting](#tag-and-attribute-formatting)
|
72
|
+
- [Escaping Content](#escaping-content)
|
73
|
+
- [Template Parameters](#template-parameters)
|
74
|
+
- [Template Logic](#template-logic)
|
75
|
+
- [Template Blocks](#template-blocks)
|
76
|
+
- [Plain Procs as Templates](#plain-procs-as-templates)
|
77
|
+
- [Template Composition](#template-composition)
|
78
|
+
- [Parameter and Block Application](#parameter-and-block-application)
|
79
|
+
- [Higher-Order Templates](#higher-order-templates)
|
80
|
+
- [Layout Template Composition](#layout-template-composition)
|
81
|
+
- [Emitting Raw HTML](#emitting-raw-html)
|
82
|
+
- [Emitting a String with HTML Encoding](#emitting-a-string-with-html-encoding)
|
78
83
|
- [Emitting Markdown](#emitting-markdown)
|
79
|
-
- [Working with MIME
|
80
|
-
- [Deferred
|
81
|
-
- [XML
|
82
|
-
- [JSON
|
83
|
-
- [Papercraft
|
84
|
-
- [
|
84
|
+
- [Working with MIME Types](#working-with-mime-types)
|
85
|
+
- [Deferred Evaluation](#deferred-evaluation)
|
86
|
+
- [XML Templates](#xml-templates)
|
87
|
+
- [JSON Templates](#json-templates)
|
88
|
+
- [Papercraft Extensions](#papercraft-extensions)
|
89
|
+
- [Inline Helper Methods](#inline-helper-methods)
|
90
|
+
- [Bundled Extensions](#bundled-extensions)
|
85
91
|
- [API Reference](#api-reference)
|
86
92
|
|
87
93
|
## Installing Papercraft
|
@@ -98,7 +104,7 @@ Or manually:
|
|
98
104
|
$ gem install papercraft
|
99
105
|
```
|
100
106
|
|
101
|
-
## Basic
|
107
|
+
## Basic Usage
|
102
108
|
|
103
109
|
To create an HTML template use `Papercraft.html`:
|
104
110
|
|
@@ -119,7 +125,7 @@ Rendering a template is done using `#render`:
|
|
119
125
|
html.render #=> "<div id="greeter"><p>Hello!</p></div>"
|
120
126
|
```
|
121
127
|
|
122
|
-
## Adding
|
128
|
+
## Adding Tags
|
123
129
|
|
124
130
|
Tags are added using unqualified method calls, and can be nested using blocks:
|
125
131
|
|
@@ -156,7 +162,7 @@ Papercraft.html { img src: '/my.gif' }.render #=> "<img src="/my.gif"/>
|
|
156
162
|
Papercraft.html { p "foobar", class: 'important' }.render #=> "<p class=\"important\">foobar</p>"
|
157
163
|
```
|
158
164
|
|
159
|
-
## Tag and
|
165
|
+
## Tag and Attribute Formatting
|
160
166
|
|
161
167
|
Papercraft does not make any presumption about what tags and attributes you can
|
162
168
|
use. You can mix upper and lower case letters, and you can include arbitrary
|
@@ -193,7 +199,23 @@ Papercraft.html {
|
|
193
199
|
}.render #=> '<cra_zy__:!tag>foo</cra_zy__:!tag>'
|
194
200
|
```
|
195
201
|
|
196
|
-
##
|
202
|
+
## Escaping Content
|
203
|
+
|
204
|
+
Papercraft automatically escapes all text content emitted in a template. The
|
205
|
+
specific escaping algorithm depends on the template type. For both HTML and XML
|
206
|
+
templates, Papercraft uses
|
207
|
+
[escape_utils](https://github.com/brianmario/escape_utils), specifically:
|
208
|
+
|
209
|
+
- HTML: `escape_utils.escape_html`
|
210
|
+
- XML: `escape_utils.escape_xml`
|
211
|
+
|
212
|
+
In order to emit raw HTML/XML, you can use the `#emit` method as [described
|
213
|
+
below](#emitting-raw-html).
|
214
|
+
|
215
|
+
JSON templates are rendered using the `json` gem bundled with Ruby, which takes
|
216
|
+
care of escaping text values.
|
217
|
+
|
218
|
+
## Template Parameters
|
197
219
|
|
198
220
|
In Papercraft, parameters are always passed explicitly. This means that template
|
199
221
|
parameters are specified as block parameters, and are passed to the template on
|
@@ -211,7 +233,7 @@ greeting = Papercraft.html { |name:| h1 "Hello, #{name}!" }
|
|
211
233
|
greeting.render(name: 'world') #=> "<h1>Hello, world!</h1>"
|
212
234
|
```
|
213
235
|
|
214
|
-
## Template
|
236
|
+
## Template Logic
|
215
237
|
|
216
238
|
Since Papercraft templates are just a bunch of Ruby, you can easily write your
|
217
239
|
view logic right in the template:
|
@@ -226,7 +248,7 @@ Papercraft.html { |user = nil|
|
|
226
248
|
}
|
227
249
|
```
|
228
250
|
|
229
|
-
## Template
|
251
|
+
## Template Blocks
|
230
252
|
|
231
253
|
Templates can also accept and render blocks by using `emit_yield`:
|
232
254
|
|
@@ -241,7 +263,7 @@ page = Papercraft.html {
|
|
241
263
|
page.render { h1 'hi' }
|
242
264
|
```
|
243
265
|
|
244
|
-
## Plain
|
266
|
+
## Plain Procs as Templates
|
245
267
|
|
246
268
|
With Papercraft you can write a template as a plain Ruby proc, and later render
|
247
269
|
it by passing it as a block to `Papercraft.html`:
|
@@ -258,7 +280,7 @@ greeting = ->(name) { h1 "Hello, #{name}!" }
|
|
258
280
|
Papercraft.html(&greeting).render('world')
|
259
281
|
```
|
260
282
|
|
261
|
-
## Template
|
283
|
+
## Template Composition
|
262
284
|
|
263
285
|
Papercraft makes it easy to compose multiple templates into a whole HTML
|
264
286
|
document. A Papercraft template can contain other templates, as the following
|
@@ -308,7 +330,7 @@ Papercraft.html {
|
|
308
330
|
}
|
309
331
|
```
|
310
332
|
|
311
|
-
## Parameter and
|
333
|
+
## Parameter and Block Application
|
312
334
|
|
313
335
|
Parameters and blocks can be applied to a template without it being rendered, by
|
314
336
|
using `#apply`. This mechanism is what allows template composition and the
|
@@ -333,7 +355,7 @@ wrapped_hello_world = div_wrap.apply(&hello_world)
|
|
333
355
|
wrapped_hello_world.render #=> "<div><h1>Hello, world!</h1></div>"
|
334
356
|
```
|
335
357
|
|
336
|
-
## Higher-
|
358
|
+
## Higher-Order Templates
|
337
359
|
|
338
360
|
Papercraft also lets you create higher-order templates, that is,
|
339
361
|
templates that take other templates as parameters, or as blocks. Higher-order
|
@@ -357,7 +379,7 @@ wrapped_greeter = div_wrap.apply { h1 'hi' }
|
|
357
379
|
wrapped_greeter.render #=> "<div><h1>hi</h1></div>"
|
358
380
|
```
|
359
381
|
|
360
|
-
## Layout
|
382
|
+
## Layout Template Composition
|
361
383
|
|
362
384
|
One of the principal uses of higher-order templates is the creation of nested
|
363
385
|
layouts. Suppose we have a website with a number of different layouts, and we'd
|
@@ -390,7 +412,7 @@ article_layout.render(
|
|
390
412
|
)
|
391
413
|
```
|
392
414
|
|
393
|
-
## Emitting
|
415
|
+
## Emitting Raw HTML
|
394
416
|
|
395
417
|
Raw HTML can be emitted using `#emit`:
|
396
418
|
|
@@ -399,13 +421,13 @@ wrapped = Papercraft.html { |html| div { emit html } }
|
|
399
421
|
wrapped.render("<h1>hi</h1>") #=> "<div><h1>hi</h1></div>"
|
400
422
|
```
|
401
423
|
|
402
|
-
## Emitting a
|
424
|
+
## Emitting a String with HTML Encoding
|
403
425
|
|
404
426
|
To emit a string with proper HTML encoding, without wrapping it in an HTML
|
405
427
|
element, use `#text`:
|
406
428
|
|
407
429
|
```ruby
|
408
|
-
Papercraft.html {
|
430
|
+
Papercraft.html { text 'hi&lo' }.render #=> "hi&lo"
|
409
431
|
```
|
410
432
|
|
411
433
|
## Emitting Markdown
|
@@ -454,7 +476,7 @@ The deafult options can be configured by accessing
|
|
454
476
|
Papercraft.default_kramdown_options[:auto_ids] = false
|
455
477
|
```
|
456
478
|
|
457
|
-
## Working with MIME
|
479
|
+
## Working with MIME Types
|
458
480
|
|
459
481
|
Papercraft lets you set and interrogate a template's MIME type, in order to be
|
460
482
|
able to dynamically set the `Content-Type` HTTP response header. A template's
|
@@ -470,7 +492,7 @@ def serve_template(req, template)
|
|
470
492
|
end
|
471
493
|
```
|
472
494
|
|
473
|
-
## Deferred
|
495
|
+
## Deferred Evaluation
|
474
496
|
|
475
497
|
Deferred evaluation allows deferring the rendering of parts of a template until
|
476
498
|
the last moment, thus allowing an inner template to manipulate the state of the
|
@@ -522,7 +544,7 @@ page = default_layout.apply {
|
|
522
544
|
}
|
523
545
|
```
|
524
546
|
|
525
|
-
## XML
|
547
|
+
## XML Templates
|
526
548
|
|
527
549
|
XML templates behave largely the same as HTML templates, with a few minor
|
528
550
|
differences. XML templates employ a different encoding algorithm, and lack some
|
@@ -557,7 +579,7 @@ rss = Papercraft.xml(mime_type: 'text/xml; charset=utf-8') { |resource:, **props
|
|
557
579
|
}
|
558
580
|
```
|
559
581
|
|
560
|
-
## JSON
|
582
|
+
## JSON Templates
|
561
583
|
|
562
584
|
JSON templates behave largely the same as HTML and XML templates. The only major
|
563
585
|
difference is that for adding array items you'll need to use the `#item` method:
|
@@ -588,7 +610,7 @@ Papercraft.json {
|
|
588
610
|
Papercraft uses the [JSON gem](https://rubyapi.org/3.1/o/json) under the hood in
|
589
611
|
order to generate actual JSON.
|
590
612
|
|
591
|
-
## Papercraft
|
613
|
+
## Papercraft Extensions
|
592
614
|
|
593
615
|
Papercraft extensions are modules that contain one or more methods that can be
|
594
616
|
used to render complex HTML components. Extension modules can be used by
|
@@ -660,6 +682,57 @@ Papercraft.html {
|
|
660
682
|
}
|
661
683
|
```
|
662
684
|
|
685
|
+
## Inline Helper Methods
|
686
|
+
|
687
|
+
In addition to proper extensions defined in modules, you can also define
|
688
|
+
individual extension methods inline in your Papercraft templates. You can do
|
689
|
+
this using any of the following techniques:
|
690
|
+
|
691
|
+
1. Define a method in the template body:
|
692
|
+
|
693
|
+
```ruby
|
694
|
+
Papercraft.html {
|
695
|
+
def label(text)
|
696
|
+
span text, class: 'label'
|
697
|
+
end
|
698
|
+
|
699
|
+
label 'foo'
|
700
|
+
label 'bar'
|
701
|
+
}
|
702
|
+
```
|
703
|
+
|
704
|
+
2. Use `def_tag` to define a custom tag:
|
705
|
+
|
706
|
+
```ruby
|
707
|
+
Papercraft.html {
|
708
|
+
def_tag(:label) { |text| span text, class: 'label' }
|
709
|
+
|
710
|
+
label 'foo'
|
711
|
+
label 'bar'
|
712
|
+
}
|
713
|
+
```
|
714
|
+
|
715
|
+
Note that using any of the above methods you can also create custom components
|
716
|
+
that take a block with inner HTML:
|
717
|
+
|
718
|
+
```ruby
|
719
|
+
# using def
|
720
|
+
def section(title, &inner)
|
721
|
+
div {
|
722
|
+
h1 title
|
723
|
+
emit inner
|
724
|
+
}
|
725
|
+
end
|
726
|
+
|
727
|
+
# using def_tag
|
728
|
+
def_tag(:section) do |title, &inner|
|
729
|
+
div {
|
730
|
+
h1 title
|
731
|
+
emit inner
|
732
|
+
}
|
733
|
+
end
|
734
|
+
```
|
735
|
+
|
663
736
|
## Bundled Extensions
|
664
737
|
|
665
738
|
Papercraft comes bundled with a few extensions that address common use cases.
|
@@ -669,7 +742,7 @@ be specifically required in order to be available to templates.
|
|
669
742
|
For all bundled Papercraft extensions, there's no need to call
|
670
743
|
`Papercraft.extension`, requiring the extension is sufficient.
|
671
744
|
|
672
|
-
### SOAP
|
745
|
+
### SOAP Extension
|
673
746
|
|
674
747
|
> The SOAP extension was contributed by [@aemadrid](https://github.com/aemadrid).
|
675
748
|
|
@@ -713,4 +786,4 @@ xml = Papercraft.xml {
|
|
713
786
|
## API Reference
|
714
787
|
|
715
788
|
The API reference for this library can be found
|
716
|
-
[here](https://www.rubydoc.info/gems/papercraft).
|
789
|
+
[here](https://www.rubydoc.info/gems/papercraft).
|
data/lib/papercraft/renderer.rb
CHANGED
@@ -47,17 +47,17 @@ module Papercraft
|
|
47
47
|
# components. In cases where method names in the module clash with XML
|
48
48
|
# tag names, you can use the `#tag` method to emit the relevant tag.
|
49
49
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
50
|
+
# module ComponentLibrary
|
51
|
+
# def card(title, content)
|
52
|
+
# div(class: 'card') {
|
53
|
+
# h3 title
|
54
|
+
# div(class: 'card-content') { emit_markdown content }
|
55
|
+
# }
|
56
|
+
# end
|
56
57
|
# end
|
57
|
-
# end
|
58
58
|
#
|
59
|
-
#
|
60
|
-
#
|
59
|
+
# Papercraft.extension(components: ComponentLibrary)
|
60
|
+
# Papercraft.html { components.card('Foo', '**Bar**') }
|
61
61
|
#
|
62
62
|
# @param map [Hash] hash mapping methods to extension modules
|
63
63
|
# @return [void]
|
data/lib/papercraft/tags.rb
CHANGED
@@ -161,14 +161,13 @@ module Papercraft
|
|
161
161
|
# @return [void]
|
162
162
|
def method_missing(sym, *args, **opts, &block)
|
163
163
|
tag = sym.to_s
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
|
164
|
+
if tag =~ /^[A-Z]/ && (Object.const_defined?(tag))
|
165
|
+
define_const_tag_method(tag)
|
166
|
+
# return send(tag, *args, **opts)
|
167
|
+
else
|
168
|
+
define_tag_method(tag)
|
169
|
+
end
|
170
|
+
|
172
171
|
send(sym, *args, **opts, &block)
|
173
172
|
end
|
174
173
|
|
@@ -181,8 +180,58 @@ module Papercraft
|
|
181
180
|
@buffer << escape_text(data)
|
182
181
|
end
|
183
182
|
|
183
|
+
# Defines a custom tag. This is handy for defining helper or extension
|
184
|
+
# methods inside the template body.
|
185
|
+
#
|
186
|
+
# Papercraft.html {
|
187
|
+
# def_tag(:section) { |title, &inner|
|
188
|
+
# div {
|
189
|
+
# h1 title
|
190
|
+
# emit inner
|
191
|
+
# }
|
192
|
+
# }
|
193
|
+
#
|
194
|
+
# section('Foo') {
|
195
|
+
# p 'Bar'
|
196
|
+
# }
|
197
|
+
# }
|
198
|
+
#
|
199
|
+
# @param tag [Symbol, String] tag/method name
|
200
|
+
# @param block [Proc] method body
|
201
|
+
# @return [void]
|
202
|
+
def def_tag(sym, &block)
|
203
|
+
self.class.define_method(sym, &block)
|
204
|
+
end
|
205
|
+
|
184
206
|
private
|
185
207
|
|
208
|
+
# Defines a method that emits the given tag based on a constant. The
|
209
|
+
# constant must be defined on the main (Object) binding.
|
210
|
+
#
|
211
|
+
# @param tag [Symbol, String] tag/method name
|
212
|
+
# @return [void]
|
213
|
+
def define_const_tag_method(tag)
|
214
|
+
const = Object.const_get(tag)
|
215
|
+
self.class.define_method(tag) { |*a, **b, &blk|
|
216
|
+
emit const, *a, **b, &blk
|
217
|
+
}
|
218
|
+
end
|
219
|
+
|
220
|
+
# Defines a normal tag method.
|
221
|
+
#
|
222
|
+
# @param tag [Symbol, String] tag/method name
|
223
|
+
# @return [void]
|
224
|
+
def define_tag_method(tag)
|
225
|
+
repr = tag_repr(tag)
|
226
|
+
code = S_TAG_METHOD % {
|
227
|
+
tag: tag,
|
228
|
+
TAG: tag.upcase,
|
229
|
+
tag_pre: "<#{repr}".inspect,
|
230
|
+
tag_close: "</#{repr}>".inspect
|
231
|
+
}
|
232
|
+
self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
|
233
|
+
end
|
234
|
+
|
186
235
|
# Emits an arbitrary object by converting it to string, then adding it to
|
187
236
|
# the internal buffer. This method is called internally by `Renderer#emit`.
|
188
237
|
#
|
@@ -251,7 +300,7 @@ module Papercraft
|
|
251
300
|
# emit nothing
|
252
301
|
else
|
253
302
|
@buffer << S_SPACE << att_repr(k) <<
|
254
|
-
S_EQUAL_QUOTE << v << S_QUOTE
|
303
|
+
S_EQUAL_QUOTE << escape_text(v) << S_QUOTE
|
255
304
|
end
|
256
305
|
end
|
257
306
|
}
|
data/lib/papercraft/version.rb
CHANGED
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.25'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: escape_utils
|
@@ -122,7 +122,7 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 2.0.9
|
125
|
-
description:
|
125
|
+
description:
|
126
126
|
email: sharon@noteflakes.com
|
127
127
|
executables: []
|
128
128
|
extensions: []
|
@@ -152,7 +152,7 @@ metadata:
|
|
152
152
|
documentation_uri: https://www.rubydoc.info/gems/papercraft
|
153
153
|
homepage_uri: https://github.com/digital-fabric/papercraft
|
154
154
|
changelog_uri: https://github.com/digital-fabric/papercraft/blob/master/CHANGELOG.md
|
155
|
-
post_install_message:
|
155
|
+
post_install_message:
|
156
156
|
rdoc_options:
|
157
157
|
- "--title"
|
158
158
|
- Papercraft
|
@@ -171,8 +171,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
171
|
- !ruby/object:Gem::Version
|
172
172
|
version: '0'
|
173
173
|
requirements: []
|
174
|
-
rubygems_version: 3.
|
175
|
-
signing_key:
|
174
|
+
rubygems_version: 3.4.1
|
175
|
+
signing_key:
|
176
176
|
specification_version: 4
|
177
177
|
summary: 'Papercraft: component-based HTML templating for Ruby'
|
178
178
|
test_files: []
|