papercraft 0.14 → 0.18
Sign up to get free protection for your applications and to get access to all the features.
- 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
|