papercraft 0.14 → 0.18
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 +22 -1
- data/README.md +180 -53
- data/lib/papercraft/component.rb +30 -13
- data/lib/papercraft/html.rb +1 -39
- data/lib/papercraft/json.rb +73 -0
- data/lib/papercraft/renderer.rb +16 -8
- data/lib/papercraft/version.rb +1 -1
- data/lib/papercraft.rb +94 -44
- metadata +19 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a887e5946cfe19b6874046cb4ef173a1de4deb11509ea4c7dca5c6434e0d710d
|
4
|
+
data.tar.gz: 3bdd374b54c72dac9f8137f5878cd43f0415c84eadebfef50fc90eb30029bf3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d4a911c94bb39ab8da06e3f61a965a7db13725b143a2cf38feae44cbb1ac0ae0a8d79b899008a14c87d890ba5ebff61fb3616b5a2014bd84049da8af95a9029
|
7
|
+
data.tar.gz: fe798bfc67006d21e6bc62cfa32d50141720f44d0089d9da58b7b7406b8d1386e8f77d10f4a34863dad05968e0342acd9d94be68afeca98955189853b367a8e0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
## 0.18 2022-02-04
|
2
|
+
|
3
|
+
- Cleanup and update examples
|
4
|
+
- Fix behaviour of #emit with block
|
5
|
+
- Improve README
|
6
|
+
|
7
|
+
## 0.17 2022-01-23
|
8
|
+
|
9
|
+
- Refactor markdown code, add `Papercraft.markdown` method (#8)
|
10
|
+
|
11
|
+
## 0.16 2022-01-23
|
12
|
+
|
13
|
+
- Implement JSON templating (#7)
|
14
|
+
- Add support for MIME types (#6)
|
15
|
+
- Change entrypoint from `Kernel#H`, `Kernel#X` to `Papercraft.html`, `.xml` (#5)
|
16
|
+
|
17
|
+
## 0.15 2022-01-20
|
18
|
+
|
19
|
+
- Fix tag method line reference
|
20
|
+
- Don't clobber ArgumentError exception
|
21
|
+
|
1
22
|
## 0.14 2022-01-19
|
2
23
|
|
3
24
|
- Add support for #emit_yield in applied component (#4)
|
@@ -37,7 +58,7 @@
|
|
37
58
|
## 0.8 2021-12-22
|
38
59
|
|
39
60
|
- Cleanup and refactor code
|
40
|
-
- Add
|
61
|
+
- Add Papercraft.xml global method for XML templates
|
41
62
|
- Make `Component` a descendant of `Proc`
|
42
63
|
- Introduce new component API
|
43
64
|
- Rename Rubyoshka to Papercraft
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
<h1 align="center">
|
2
|
+
<img src="papercraft.png">
|
3
|
+
<br>
|
2
4
|
Papercraft
|
3
5
|
</h1>
|
4
6
|
|
5
|
-
<h4 align="center">Composable
|
7
|
+
<h4 align="center">Composable templating for Ruby</h4>
|
6
8
|
|
7
9
|
<p align="center">
|
8
10
|
<a href="http://rubygems.org/gems/papercraft">
|
@@ -22,33 +24,63 @@
|
|
22
24
|
|
23
25
|
## What is Papercraft?
|
24
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
|
+
|
25
45
|
```ruby
|
26
46
|
require 'papercraft'
|
27
47
|
|
28
|
-
page =
|
48
|
+
page = Papercraft.html { |*args|
|
29
49
|
html {
|
30
|
-
head { }
|
50
|
+
head { title 'Title' }
|
31
51
|
body { emit_yield *args }
|
32
52
|
}
|
33
53
|
}
|
54
|
+
page.render { p 'foo' }
|
55
|
+
#=> "<html><head><title>Title</title></head><body><p>foo</p></body></html>"
|
34
56
|
|
35
|
-
hello =
|
57
|
+
hello = page.apply { |name| h1 "Hello, #{name}!" }
|
36
58
|
hello.render('world')
|
37
|
-
#=> "<html><head
|
59
|
+
#=> "<html><head><title>Title</title></head><body><h1>Hello, world!</h1></body></html>"
|
38
60
|
```
|
39
61
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
-
|
44
|
-
-
|
45
|
-
-
|
46
|
-
-
|
47
|
-
-
|
48
|
-
-
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
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 components](#higher-order-components)
|
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)
|
52
84
|
|
53
85
|
## Installing Papercraft
|
54
86
|
|
@@ -64,30 +96,33 @@ Or manually:
|
|
64
96
|
$ gem install papercraft
|
65
97
|
```
|
66
98
|
|
67
|
-
##
|
99
|
+
## Basic usage
|
68
100
|
|
69
|
-
To create
|
101
|
+
To create an HTML template use `Papercraft.html`:
|
70
102
|
|
71
103
|
```ruby
|
72
104
|
require 'papercraft'
|
73
105
|
|
74
|
-
html =
|
106
|
+
html = Papercraft.html {
|
75
107
|
div(id: 'greeter') { p 'Hello!' }
|
76
108
|
}
|
77
109
|
```
|
78
110
|
|
111
|
+
(You can also use `Papercraft.xml` and `Papercraft.json` to create XML and JSON
|
112
|
+
templates, respectively.)
|
113
|
+
|
79
114
|
Rendering a template is done using `#render`:
|
80
115
|
|
81
116
|
```ruby
|
82
117
|
html.render #=> "<div id="greeter"><p>Hello!</p></div>"
|
83
118
|
```
|
84
119
|
|
85
|
-
##
|
120
|
+
## Adding tags
|
86
121
|
|
87
122
|
Tags are added using unqualified method calls, and can be nested using blocks:
|
88
123
|
|
89
124
|
```ruby
|
90
|
-
|
125
|
+
Papercraft.html {
|
91
126
|
html {
|
92
127
|
head {
|
93
128
|
title 'page title'
|
@@ -104,19 +139,19 @@ H {
|
|
104
139
|
Tag methods accept a string argument, a block, or no argument at all:
|
105
140
|
|
106
141
|
```ruby
|
107
|
-
|
142
|
+
Papercraft.html { p 'hello' }.render #=> "<p>hello</p>"
|
108
143
|
|
109
|
-
|
144
|
+
Papercraft.html { p { span '1'; span '2' } }.render #=> "<p><span>1</span><span>2</span></p>"
|
110
145
|
|
111
|
-
|
146
|
+
Papercraft.html { hr() }.render #=> "<hr/>"
|
112
147
|
```
|
113
148
|
|
114
149
|
Tag methods also accept tag attributes, given as a hash:
|
115
150
|
|
116
151
|
```ruby
|
117
|
-
|
152
|
+
Papercraft.html { img src: '/my.gif' }.render #=> "<img src="/my.gif"/>
|
118
153
|
|
119
|
-
|
154
|
+
Papercraft.html { p "foobar", class: 'important' }.render #=> "<p class=\"important\">foobar</p>"
|
120
155
|
```
|
121
156
|
|
122
157
|
## Template parameters
|
@@ -126,24 +161,24 @@ parameters are specified as block parameters, and are passed to the template on
|
|
126
161
|
rendering:
|
127
162
|
|
128
163
|
```ruby
|
129
|
-
greeting =
|
164
|
+
greeting = Papercraft.html { |name| h1 "Hello, #{name}!" }
|
130
165
|
greeting.render('world') #=> "<h1>Hello, world!</h1>"
|
131
166
|
```
|
132
167
|
|
133
168
|
Templates can also accept named parameters:
|
134
169
|
|
135
170
|
```ruby
|
136
|
-
greeting =
|
171
|
+
greeting = Papercraft.html { |name:| h1 "Hello, #{name}!" }
|
137
172
|
greeting.render(name: 'world') #=> "<h1>Hello, world!</h1>"
|
138
173
|
```
|
139
174
|
|
140
|
-
##
|
175
|
+
## Template logic
|
141
176
|
|
142
177
|
Since Papercraft templates are just a bunch of Ruby, you can easily write your
|
143
178
|
view logic right in the template:
|
144
179
|
|
145
180
|
```ruby
|
146
|
-
|
181
|
+
Papercraft.html { |user = nil|
|
147
182
|
if user
|
148
183
|
span "Hello, #{user.name}!"
|
149
184
|
else
|
@@ -157,7 +192,7 @@ H { |user = nil|
|
|
157
192
|
Templates can also accept and render blocks by using `emit_yield`:
|
158
193
|
|
159
194
|
```ruby
|
160
|
-
page =
|
195
|
+
page = Papercraft.html {
|
161
196
|
html {
|
162
197
|
body { emit_yield }
|
163
198
|
}
|
@@ -167,24 +202,24 @@ page = H {
|
|
167
202
|
page.render { h1 'hi' }
|
168
203
|
```
|
169
204
|
|
170
|
-
## Plain procs as
|
205
|
+
## Plain procs as templates
|
171
206
|
|
172
207
|
With Papercraft you can write a template as a plain Ruby proc, and later render
|
173
|
-
it by passing it as a block to `
|
208
|
+
it by passing it as a block to `Papercraft.html`:
|
174
209
|
|
175
210
|
```ruby
|
176
211
|
greeting = proc { |name| h1 "Hello, #{name}!" }
|
177
|
-
|
212
|
+
Papercraft.html(&greeting).render('world')
|
178
213
|
```
|
179
214
|
|
180
215
|
Components can also be expressed using lambda notation:
|
181
216
|
|
182
217
|
```ruby
|
183
218
|
greeting = ->(name) { h1 "Hello, #{name}!" }
|
184
|
-
|
219
|
+
Papercraft.html(&greeting).render('world')
|
185
220
|
```
|
186
221
|
|
187
|
-
##
|
222
|
+
## Template composition
|
188
223
|
|
189
224
|
Papercraft makes it easy to compose multiple components into a whole HTML
|
190
225
|
document. A Papercraft component can contain other components, as the following
|
@@ -208,7 +243,7 @@ ItemList = ->(items) {
|
|
208
243
|
}
|
209
244
|
}
|
210
245
|
|
211
|
-
page =
|
246
|
+
page = Papercraft.html { |title, items|
|
212
247
|
html5 {
|
213
248
|
head { Title(title) }
|
214
249
|
body { ItemList(items) }
|
@@ -227,7 +262,7 @@ non-constant components by invoking the `#emit` method:
|
|
227
262
|
```ruby
|
228
263
|
greeting = -> { span "Hello, world" }
|
229
264
|
|
230
|
-
|
265
|
+
Papercraft.html {
|
231
266
|
div {
|
232
267
|
emit greeting
|
233
268
|
}
|
@@ -245,12 +280,12 @@ or block to the original component:
|
|
245
280
|
|
246
281
|
```ruby
|
247
282
|
# parameter application
|
248
|
-
hello =
|
283
|
+
hello = Papercraft.html { |name| h1 "Hello, #{name}!" }
|
249
284
|
hello_world = hello.apply('world')
|
250
285
|
hello_world.render #=> "<h1>Hello, world!</h1>"
|
251
286
|
|
252
287
|
# block application
|
253
|
-
div_wrap =
|
288
|
+
div_wrap = Papercraft.html { div { emit_yield } }
|
254
289
|
wrapped_h1 = div_wrap.apply { h1 'hi' }
|
255
290
|
wrapped_h1.render #=> "<div><h1>hi</h1></div>"
|
256
291
|
|
@@ -269,8 +304,8 @@ markup, enhancing components or injecting component parameters.
|
|
269
304
|
Here is a HOC that takes a component as parameter:
|
270
305
|
|
271
306
|
```ruby
|
272
|
-
div_wrap =
|
273
|
-
greeter =
|
307
|
+
div_wrap = Papercraft.html { |inner| div { emit inner } }
|
308
|
+
greeter = Papercraft.html { h1 'hi' }
|
274
309
|
wrapped_greeter = div_wrap.apply(greeter)
|
275
310
|
wrapped_greeter.render #=> "<div><h1>hi</h1></div>"
|
276
311
|
```
|
@@ -278,7 +313,7 @@ wrapped_greeter.render #=> "<div><h1>hi</h1></div>"
|
|
278
313
|
The inner component can also be passed as a block, as shown above:
|
279
314
|
|
280
315
|
```ruby
|
281
|
-
div_wrap =
|
316
|
+
div_wrap = Papercraft.html { div { emit_yield } }
|
282
317
|
wrapped_greeter = div_wrap.apply { h1 'hi' }
|
283
318
|
wrapped_greeter.render #=> "<div><h1>hi</h1></div>"
|
284
319
|
```
|
@@ -292,7 +327,7 @@ this by creating a `default` page template that takes a block, then use `#apply`
|
|
292
327
|
to create the other templates:
|
293
328
|
|
294
329
|
```ruby
|
295
|
-
default_layout =
|
330
|
+
default_layout = Papercraft.html { |**params|
|
296
331
|
html5 {
|
297
332
|
head {
|
298
333
|
title: params[:title]
|
@@ -321,7 +356,7 @@ article_layout.render(
|
|
321
356
|
Raw HTML can be emitted using `#emit`:
|
322
357
|
|
323
358
|
```ruby
|
324
|
-
wrapped =
|
359
|
+
wrapped = Papercraft.html { |html| div { emit html } }
|
325
360
|
wrapped.render("<h1>hi</h1>") #=> "<div><h1>hi</h1></div>"
|
326
361
|
```
|
327
362
|
|
@@ -331,7 +366,7 @@ To emit a string with proper HTML encoding, without wrapping it in an HTML
|
|
331
366
|
element, use `#text`:
|
332
367
|
|
333
368
|
```ruby
|
334
|
-
|
369
|
+
Papercraft.html { str 'hi&lo' }.render #=> "hi&lo"
|
335
370
|
```
|
336
371
|
|
337
372
|
## Emitting Markdown
|
@@ -341,7 +376,7 @@ Markdown is rendered using the
|
|
341
376
|
`#emit_markdown`:
|
342
377
|
|
343
378
|
```ruby
|
344
|
-
template =
|
379
|
+
template = Papercraft.html { |md| div { emit_markdown md } }
|
345
380
|
template.render("Here's some *Markdown*") #=> "<div><p>Here's some <em>Markdown</em><p>\n</div>"
|
346
381
|
```
|
347
382
|
|
@@ -350,10 +385,18 @@ options](https://kramdown.gettalong.org/options.html#available-options) can be
|
|
350
385
|
specified by adding them to the `#emit_markdown` call:
|
351
386
|
|
352
387
|
```ruby
|
353
|
-
template =
|
388
|
+
template = Papercraft.html { |md| div { emit_markdown md, auto_ids: false } }
|
354
389
|
template.render("# title") #=> "<div><h1>title</h1></div>"
|
355
390
|
```
|
356
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
|
+
|
357
400
|
The default Kramdown options are:
|
358
401
|
|
359
402
|
```ruby
|
@@ -366,10 +409,26 @@ The default Kramdown options are:
|
|
366
409
|
```
|
367
410
|
|
368
411
|
The deafult options can be configured by accessing
|
369
|
-
`Papercraft
|
412
|
+
`Papercraft.default_kramdown_options`, e.g.:
|
370
413
|
|
371
414
|
```ruby
|
372
|
-
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
|
373
432
|
```
|
374
433
|
|
375
434
|
## Deferred evaluation
|
@@ -393,7 +452,7 @@ class that can collect JS and CSS dependencies from the different components
|
|
393
452
|
integrated into the page, and adds them to the page's `<head>` element:
|
394
453
|
|
395
454
|
```ruby
|
396
|
-
default_layout =
|
455
|
+
default_layout = Papercraft.html { |**args|
|
397
456
|
@dependencies = DependencyMananger.new
|
398
457
|
head {
|
399
458
|
defer { emit @dependencies.head_markup }
|
@@ -479,7 +538,7 @@ The call to `Papercraft::extension` lets us access the different methods of
|
|
479
538
|
we'll be able to express the above markup as follows:
|
480
539
|
|
481
540
|
```ruby
|
482
|
-
|
541
|
+
Papercraft.html {
|
483
542
|
bootstrap.card(style: 'width: 18rem') {
|
484
543
|
bootstrap.card_title 'Card title'
|
485
544
|
bootstrap.card_subtitle 'Card subtitle'
|
@@ -490,6 +549,74 @@ H {
|
|
490
549
|
}
|
491
550
|
```
|
492
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
|
+
|
493
620
|
## API Reference
|
494
621
|
|
495
622
|
The API reference for this library can be found
|
data/lib/papercraft/component.rb
CHANGED
@@ -11,21 +11,26 @@ module Papercraft
|
|
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
|
-
# Components are usually created using the
|
15
|
-
#
|
14
|
+
# Components 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
|
# Components can also be created using the normal constructor:
|
21
21
|
#
|
22
|
-
# greeter = Papercraft::Component.new { |name| h1 "Hello, #{name}!" }
|
22
|
+
# greeter = Papercraft::Component.new(mode: :html) { |name| h1 "Hello, #{name}!" }
|
23
23
|
# greeter.render('world') #=> "<h1>Hello, world!</h1>"
|
24
24
|
#
|
25
|
+
# The different methods for creating components 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
|
+
#
|
25
30
|
# In the component 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'
|
@@ -41,7 +46,7 @@ module Papercraft
|
|
41
46
|
# `greeter` template shown above takes a single `name` parameter. Here's how a
|
42
47
|
# anchor component could be implemented with named parameters:
|
43
48
|
#
|
44
|
-
# anchor =
|
49
|
+
# anchor = Papercraft.html { |uri: , text: | a(text, href: uri) }
|
45
50
|
#
|
46
51
|
# The above component could later be rendered by passing the needed arguments:
|
47
52
|
#
|
@@ -51,7 +56,7 @@ module Papercraft
|
|
51
56
|
#
|
52
57
|
# A component can be included in another component 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'
|
@@ -60,7 +65,7 @@ module Papercraft
|
|
60
65
|
# Another way of composing components is to pass the components 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([
|
@@ -84,14 +89,22 @@ module Papercraft
|
|
84
89
|
# Determines the rendering mode: `:html` or `:xml`.
|
85
90
|
attr_accessor :mode
|
86
91
|
|
92
|
+
STOCK_MIME_TYPE = {
|
93
|
+
html: 'text/html',
|
94
|
+
xml: 'application/xml',
|
95
|
+
json: 'application/json'
|
96
|
+
}.freeze
|
97
|
+
|
87
98
|
# Initializes a component 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
100
|
# the component defaults to HTML.
|
90
101
|
#
|
91
102
|
# @param mode [:html, :xml] rendering mode
|
103
|
+
# @param mime_type [String, nil] the component'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
|
|
@@ -109,15 +122,13 @@ module Papercraft
|
|
109
122
|
push_emit_yield_block(block) if block
|
110
123
|
instance_exec(*a, **b, &template)
|
111
124
|
end.to_s
|
112
|
-
rescue ArgumentError => e
|
113
|
-
raise Papercraft::Error, e.message
|
114
125
|
end
|
115
126
|
|
116
127
|
# Creates a new component, applying the given parameters and or block to the
|
117
128
|
# current one. Application is one of the principal methods of composing
|
118
129
|
# components, particularly when passing inner components as blocks:
|
119
130
|
#
|
120
|
-
# article_wrapper =
|
131
|
+
# article_wrapper = Papercraft.html {
|
121
132
|
# article {
|
122
133
|
# emit_yield
|
123
134
|
# }
|
@@ -133,7 +144,7 @@ module Papercraft
|
|
133
144
|
# @return [Papercraft::Component] applied component
|
134
145
|
def apply(*a, **b, &block)
|
135
146
|
template = self
|
136
|
-
Component.new(&proc do |*x, **y|
|
147
|
+
Component.new(mode: @mode, mime_type: @mime_type, &proc do |*x, **y|
|
137
148
|
push_emit_yield_block(block) if block
|
138
149
|
instance_exec(*a, *x, **b, **y, &template)
|
139
150
|
end)
|
@@ -149,10 +160,16 @@ module Papercraft
|
|
149
160
|
HTMLRenderer
|
150
161
|
when :xml
|
151
162
|
XMLRenderer
|
163
|
+
when :json
|
164
|
+
JSONRenderer
|
152
165
|
else
|
153
166
|
raise "Invalid mode #{@mode.inspect}"
|
154
167
|
end
|
155
168
|
end
|
169
|
+
|
170
|
+
def mime_type
|
171
|
+
@mime_type
|
172
|
+
end
|
156
173
|
|
157
174
|
# def compile
|
158
175
|
# Papercraft::Compiler.new.compile(self)
|
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,6 +1,9 @@
|
|
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
|
@@ -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]
|
@@ -112,7 +115,7 @@ module Papercraft
|
|
112
115
|
|
113
116
|
# The tag method template below is optimized for performance. Do not touch!
|
114
117
|
|
115
|
-
S_TAG_METHOD_LINE = __LINE__ +
|
118
|
+
S_TAG_METHOD_LINE = __LINE__ + 2
|
116
119
|
S_TAG_METHOD = <<~EOF
|
117
120
|
S_TAG_%<TAG>s_PRE = %<tag_pre>s
|
118
121
|
S_TAG_%<TAG>s_CLOSE = %<tag_close>s
|
@@ -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
222
|
# @param o [Proc, Papercraft::Component, 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
|
#
|
@@ -256,7 +260,7 @@ module Papercraft
|
|
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
|
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
7
|
require_relative 'papercraft/component'
|
6
8
|
require_relative 'papercraft/renderer'
|
7
9
|
require_relative 'papercraft/encoding'
|
8
10
|
# require_relative 'papercraft/compiler'
|
9
11
|
|
12
|
+
|
10
13
|
# Papercraft is a component-based HTML 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 component. `Papercraft.html` can take either a proc
|
35
|
+
# argument or a block. In both cases, the proc is converted to a
|
36
|
+
# `Papercraft::Component`.
|
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::Component] Papercraft component
|
43
|
+
def html(o = nil, mime_type: nil, &template)
|
44
|
+
return o if o.is_a?(Papercraft::Component)
|
45
|
+
template ||= o
|
46
|
+
Papercraft::Component.new(mode: :html, mime_type: mime_type, &template)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates a new papercraft component 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::Component`.
|
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::Component] Papercraft component
|
58
|
+
def xml(o = nil, mime_type: nil, &template)
|
59
|
+
return o if o.is_a?(Papercraft::Component)
|
60
|
+
template ||= o
|
61
|
+
Papercraft::Component.new(mode: :xml, mime_type: mime_type, &template)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Creates a new papercraft component 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::Component`.
|
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::Component] Papercraft component
|
73
|
+
def json(o = nil, mime_type: nil, &template)
|
74
|
+
return o if o.is_a?(Papercraft::Component)
|
75
|
+
template ||= o
|
76
|
+
Papercraft::Component.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
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: papercraft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.18'
|
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-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: escape_utils
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.2.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.2.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -30,28 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.3.
|
33
|
+
version: 2.3.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.3.
|
40
|
+
version: 2.3.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rouge
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 3.
|
47
|
+
version: 3.27.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 3.
|
54
|
+
version: 3.27.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: kramdown-parser-gfm
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,56 +70,56 @@ dependencies:
|
|
70
70
|
name: minitest
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 5.
|
75
|
+
version: '5.15'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 5.
|
82
|
+
version: '5.15'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: benchmark-ips
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: 2.7.2
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 2.7.2
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: erubis
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: 2.7.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 2.7.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: tilt
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: 2.0.9
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 2.0.9
|
125
125
|
description:
|
@@ -137,6 +137,7 @@ files:
|
|
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
|
141
142
|
- lib/papercraft/version.rb
|
142
143
|
homepage: http://github.com/digital-fabric/papercraft
|