papercraft 0.8.3 → 0.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 125df0455a1b4c3373b36b3f52b6d965249a7ddf470439ec48df3f7216ea3991
4
- data.tar.gz: be9cea2084785a3dc135b852b66f0d91375cafd6050834d06f26f8a6b497f95f
3
+ metadata.gz: 3452d115d85742018d1497b369ea27970f0c144e3dcb1772f4d81e33315dce51
4
+ data.tar.gz: e7217a9d9bcfd7af0dc92482650bc03392b0406cf4f3d6141c253a2918638545
5
5
  SHA512:
6
- metadata.gz: f45e9101d8bb14bfdde19958988343d6e4d87e270462a0db13630860aff5d6adc560df90aefd78317642f6987d3853cc68ad8adb7d0b74e381b43930424d7a79
7
- data.tar.gz: c7a153329948a8fa5dbe90602a293b22e060f0118cc3cdfd629f9af9644f57bea4add8ec13e40a5194178bdebc5dd43a26c0507f03e8dd78e3a3a5662968e390
6
+ metadata.gz: 8f76b9e73aa48f91af932af3308d3dd43239c3d5ca39e305cb1535417b5997483aa884f0e34ed128800b07a3135ebc1d18ea81d0df64e6170726a66c86969288
7
+ data.tar.gz: dbe744ca25996c3d263ff609ca26f42076784fdbceabd2dd1604dd1016e2d840830230f4205a673b9e5ba14eb8e480627612971b71ca6631e0a6e473d59ccb73
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.11 2022-01-04
2
+
3
+ - Add deferred evaluation
4
+
5
+ ## 0.10.1 2021-12-25
6
+
7
+ - Fix tag rendering with empty text in Ruby 3.0
8
+
9
+ ## 0.10 2021-12-25
10
+
11
+ - Add support for extensions
12
+
13
+ ## 0.9 2021-12-23
14
+
15
+ - Add support for emitting Markdown
16
+ - Add support for passing proc as argument to `#H` and `#X`
17
+ - Deprecate `Encoding` module
18
+
1
19
  ## 0.8.1 2021-12-22
2
20
 
3
21
  - Fix gemspec
data/README.md CHANGED
@@ -1,30 +1,56 @@
1
- # Papercraft - Composable HTML templating for Ruby
1
+ <h1 align="center">
2
+ Papercraft
3
+ </h1>
4
+
5
+ <h4 align="center">Composable HTML templating for Ruby</h4>
6
+
7
+ <p align="center">
8
+ <a href="http://rubygems.org/gems/papercraft">
9
+ <img src="https://badge.fury.io/rb/papercraft.svg" alt="Ruby gem">
10
+ </a>
11
+ <a href="https://github.com/digital-fabric/papercraft/actions?query=workflow%3ATests">
12
+ <img src="https://github.com/digital-fabric/papercraft/workflows/Tests/badge.svg" alt="Tests">
13
+ </a>
14
+ <a href="https://github.com/digital-fabric/papercraft/blob/master/LICENSE">
15
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
16
+ </a>
17
+ </p>
18
+
19
+ <p align="center">
20
+ <a href="https://www.rubydoc.info/gems/papercraft">API reference</a>
21
+ </p>
2
22
 
3
- [INSTALL](#installing-papercraft) |
4
- [TUTORIAL](#getting-started) |
5
- [EXAMPLES](examples) |
6
- [REFERENCE](#api-reference)
23
+ # Papercraft - Composable HTML templating for Ruby
7
24
 
8
25
  ## What is Papercraft?
9
26
 
27
+ ```ruby
28
+ require 'papercraft'
29
+
30
+ page = H { |*args|
31
+ html {
32
+ head { }
33
+ body { emit_yield *args }
34
+ }
35
+ }
36
+
37
+ hello = H.apply { |name| h1 "Hello, #{name}!" }
38
+ hello.render('world')
39
+ #=> "<html><head/><body><h1>Hello, world!</h1></body></html>"
40
+ ```
41
+
10
42
  Papercraft is an HTML templating engine for Ruby that offers the following
11
43
  features:
12
44
 
13
- - HTML templating using plain Ruby syntax
45
+ - HTML and XML templating using plain Ruby syntax
14
46
  - Minimal boilerplate
15
47
  - Mix logic and tags freely
16
- - Use global and local contexts to pass values to reusable components
17
- - Automatic HTML escaping
48
+ - Automatic HTML and XML escaping
18
49
  - Composable components
50
+ - Explicit parameter passing to nested components
19
51
  - Higher order components
20
- - Built-in support for rendering Markdown
21
-
22
- > **Note** Papercraft is a new library and as such may be missing features and
23
- > contain bugs. Also, its API may change unexpectedly. Your issue reports and
24
- > code contributions are most welcome!
25
-
26
- With Papercraft you can structure your templates as nested HTML components, in a
27
- somewhat similar fashion to React.
52
+ - Built-in support for rendering [Markdown](#emitting-markdown)
53
+ - Support for namespaced extensions
28
54
 
29
55
  ## Installing Papercraft
30
56
 
@@ -42,42 +68,25 @@ $ gem install papercraft
42
68
 
43
69
  ## Getting started
44
70
 
45
- To use Papercraft in your code just require it:
71
+ To create a template use the global method `Kernel#H`:
46
72
 
47
73
  ```ruby
48
74
  require 'papercraft'
49
- ```
50
-
51
- To create a template use `Papercraft.new` or the global method `Kernel#H`:
52
75
 
53
- ```ruby
54
- # can also use Papercraft.new
55
76
  html = H {
56
- div { p 'hello' }
77
+ div(id: 'greeter') { p 'Hello!' }
57
78
  }
58
79
  ```
59
80
 
60
- ## Rendering a template
61
-
62
- To render a Papercraft template use the `#render` method:
81
+ Rendering a template is done using `#render`:
63
82
 
64
83
  ```ruby
65
- H { span 'best span' }.render #=> "<span>best span</span>"
66
- ```
67
-
68
- The render method accepts an arbitrary context variable:
69
-
70
- ```ruby
71
- html = H {
72
- h1 context[:title]
73
- }
74
-
75
- html.render(title: 'My title') #=> "<h1>My title</h1>"
84
+ html.render #=> "<div id="greeter"><p>Hello!</p></div>"
76
85
  ```
77
86
 
78
87
  ## All about tags
79
88
 
80
- Tags are added using unqualified method calls, and are nested using blocks:
89
+ Tags are added using unqualified method calls, and can be nested using blocks:
81
90
 
82
91
  ```ruby
83
92
  H {
@@ -114,8 +123,9 @@ H { p "foobar", class: 'important' }.render #=> "<p class=\"important\">foobar</
114
123
 
115
124
  ## Template parameters
116
125
 
117
- Template parameters are specified as block parameters, and are passed to the
118
- template on rendering:
126
+ In Papercraft, parameters are always passed explicitly. This means that template
127
+ parameters are specified as block parameters, and are passed to the template on
128
+ rendering:
119
129
 
120
130
  ```ruby
121
131
  greeting = H { |name| h1 "Hello, #{name}!" }
@@ -328,110 +338,161 @@ H { str 'hi&lo' }.render #=> "hi&amp;lo"
328
338
 
329
339
  ## Emitting Markdown
330
340
 
331
- To emit Markdown, use `#emit_markdown`:
341
+ Markdown is rendered using the
342
+ [Kramdown](https://kramdown.gettalong.org/index.html) gem. To emit Markdown, use
343
+ `#emit_markdown`:
332
344
 
333
345
  ```ruby
334
346
  template = H { |md| div { emit_markdown md } }
335
- template.render("Here's some *Markdown*") #=> "<div>Here's some <em>Markdown</em></div>"
347
+ template.render("Here's some *Markdown*") #=> "<div><p>Here's some <em>Markdown</em><p>\n</div>"
336
348
  ```
337
349
 
338
- ## Some interesting use cases
339
-
340
- Papercraft opens up all kinds of new possibilities when it comes to putting
341
- together pieces of HTML. Feel free to explore the API!
350
+ [Kramdown
351
+ options](https://kramdown.gettalong.org/options.html#available-options) can be
352
+ specified by adding them to the `#emit_markdown` call:
342
353
 
343
- ### A higher-order list component
354
+ ```ruby
355
+ template = H { |md| div { emit_markdown md, auto_ids: false } }
356
+ template.render("# title") #=> "<div><h1>title</h1></div>"
357
+ ```
344
358
 
345
- Here's another demonstration of a higher-order component, a list component that
346
- takes an item component as an argument. The `List` component can be reused for
347
- rendering any kind of unordered list, and with any kind of item component:
359
+ The default Kramdown options are:
348
360
 
349
361
  ```ruby
350
- List = ->(items, item_component) {
351
- H {
352
- ul {
353
- items.each { |item|
354
- with(item: item) {
355
- li { emit item_component }
356
- }
357
- }
358
- }
359
- }
362
+ {
363
+ entity_output: :numeric,
364
+ syntax_highlighter: :rouge,
365
+ input: 'GFM',
366
+ hard_wrap: false
360
367
  }
361
-
362
- TodoItem = H {
363
- span item.text, class: item.completed ? 'completed' : 'pending'
364
- }
365
-
366
- def todo_list(items)
367
- H {
368
- div { List(items, TodoItem) }
369
- }
370
- end
371
368
  ```
372
369
 
373
- ## API Reference
374
-
375
- #### `Papercraft#initialize(**context, &block)` a.k.a. `Kernel#H`
370
+ The deafult options can be configured by accessing
371
+ `Papercraft::HTML.kramdown_options`:
376
372
 
377
- - `context`: local context hash
378
- - `block`: template block
373
+ ```ruby
374
+ Papercraft::HTML.kramdown_options[:auto_ids] = false
375
+ ```
379
376
 
380
- Initializes a new Papercraft instance. This method takes a block of template
381
- code, and an optional [local context](#local-context) in the form of a hash.
382
- The `Kernel#H` method serves as a shortcut for creating Papercraft instances.
377
+ ## Deferred evaluation
383
378
 
384
- #### `Papercraft#render(**context)`
379
+ Deferred evaluation allows deferring the rendering of parts of a template until
380
+ the last moment, thus allowing an inner component to manipulate the state of the
381
+ outer component. To in order to defer a part of a template, use `#defer`, and
382
+ include any markup in the provided block. This technique, in in conjunction with
383
+ holding state in instance variables, is an alternative to passing parameters,
384
+ which can be limiting in some situations.
385
385
 
386
- - `context`: global context hash
386
+ A few use cases for deferred evaulation come to mind:
387
387
 
388
- Renders the template with an optional [global context](#global-context)
389
- hash.
388
+ - Setting the page title.
389
+ - Adding a flash message to a page.
390
+ - Using components that dynamically add static dependencies (JS and CSS) to the
391
+ page.
390
392
 
391
- #### Methods accessible inside template blocks
393
+ The last use case is particularly interesting. Imagine a `DependencyMananger`
394
+ class that can collect JS and CSS dependencies from the different components
395
+ integrated into the page, and adds them to the page's `<head>` element:
392
396
 
393
- #### `#<tag/component>(*args, **props, &block)`
397
+ ```ruby
398
+ default_layout = H { |**args|
399
+ @dependencies = DependencyMananger.new
400
+ head {
401
+ defer { emit @dependencies.head_markup }
402
+ }
403
+ body { emit_yield **args }
404
+ }
394
405
 
395
- - `args`: tag arguments. For an HTML tag Papercraft expects a single `String`
396
- argument containing the inner text of the tag.
397
- - `props`: hash of tag attributes
398
- - `block`: inner HTML block
406
+ button = proc { |text, onclick|
407
+ @dependencies.js '/static/js/button.js'
408
+ @dependencies.css '/static/css/button.css'
399
409
 
400
- Adds a tag or component to the current template. If the method name starts with
401
- an upper-case letter, it is considered a [component](#templates-as-components).
410
+ button text, onclick: onclick
411
+ }
402
412
 
403
- If a text argument is given for a tag, it will be escaped.
413
+ heading = proc { |text|
414
+ @dependencies.js '/static/js/heading.js'
415
+ @dependencies.css '/static/css/heading.css'
404
416
 
405
- #### `#cache(*vary, &block)`
417
+ h1 text
418
+ }
406
419
 
407
- - `vary`: variables used in cached block. The given values will be used to
408
- create a separate cache entry.
409
- - `block`: inner HTML block
420
+ page = default_layout.apply {
421
+ emit heading, "What's your favorite cheese?"
410
422
 
411
- Caches the markup in the given block, storing it in the Papercraft cache store.
412
- If a cache entry for the given block is found, it will be used instead of
413
- invoking the block. If one or more variables given, those will be used to create
414
- a separate cache entry.
423
+ emit button, 'Beaufort', 'eat_beaufort()'
424
+ emit button, 'Mont d''or', 'eat_montdor()'
425
+ emit button, 'Époisses', 'eat_epoisses()'
426
+ }
427
+ ```
415
428
 
416
- #### `#context`
429
+ ## Papercraft extensions
430
+
431
+ Papercraft extensions are modules that contain one or more methods that can be
432
+ used to render complex HTML components. Extension modules can be used by
433
+ installing them as a namespaced extension using `Papercraft.extension`.
434
+ Extensions are particularly useful when you work with CSS frameworks such as
435
+ [Bootstrap](https://getbootstrap.com/), [Tailwind](https://tailwindui.com/) or
436
+ [Primer](https://primer.style/).
437
+
438
+ For example, to create a Bootstrap card component, the following HTML markup is
439
+ needed (example taken from the [Bootstrap
440
+ docs](https://getbootstrap.com/docs/5.1/components/card/#titles-text-and-links)):
441
+
442
+ ```html
443
+ <div class="card" style="width: 18rem;">
444
+ <div class="card-body">
445
+ <h5 class="card-title">Card title</h5>
446
+ <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
447
+ <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
448
+ <a href="#" class="card-link">Card link</a>
449
+ <a href="#" class="card-link">Another link</a>
450
+ </div>
451
+ </div>
452
+ ```
417
453
 
418
- Accesses the [global context](#global-context).
454
+ With Papercraft, we could create a `Bootstrap` extension with a `#card` method
455
+ and other associated methods:
419
456
 
420
- #### `#emit(object)` a.k.a. `#e(object)`
457
+ ```ruby
458
+ module BootstrapComponents
459
+ ...
421
460
 
422
- - `object`: `Proc`, `Papercraft` instance or `String`
461
+ def card(**props)
462
+ div(class: 'card', **props) {
463
+ div(class: 'card-body') {
464
+ emit_yield
465
+ }
466
+ }
467
+ end
423
468
 
424
- Adds the given object to the current template. If a `String` is given, it is
425
- rendered verbatim, i.e. without escaping.
469
+ def card_title(title)
470
+ h5 title, class: 'card-title'
471
+ end
426
472
 
427
- #### `html5(&block)`
473
+ ...
474
+ end
428
475
 
429
- - `block`: inner HTML block
476
+ Papercraft.extension(bootstrap: BootstrapComponents)
477
+ ```
430
478
 
431
- Adds an HTML5 `doctype` tag, followed by an `html` tag with the given block.
479
+ The call to `Papercraft.extension` lets us access the different methods of
480
+ `BootstrapComponents` by calling `#bootstrap` inside a template. With this,
481
+ we'll be able to express the above markup as follows:
432
482
 
433
- #### `#text(data)`
483
+ ```ruby
484
+ H {
485
+ bootstrap.card(style: 'width: 18rem') {
486
+ bootstrap.card_title 'Card title'
487
+ bootstrap.card_subtitle 'Card subtitle'
488
+ bootstrap.card_text 'Some quick example text to build on the card title and make up the bulk of the card''s content.'
489
+ bootstrap.card_link '#', 'Card link'
490
+ bootstrap.card_link '#', 'Another link'
491
+ }
492
+ }
493
+ ```
434
494
 
435
- - `data` - text to add
495
+ ## API Reference
436
496
 
437
- Adds text without wrapping it in a tag. The text will be escaped.
497
+ The API reference for this library can be found
498
+ [here](https://www.rubydoc.info/gems/papercraft).
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Papercraft
4
+
5
+ # An ExtensionProxy proxies method calls to a renderer. Extension proxies are
6
+ # used to provide an namespaced interface to Papercraft extensions. When an
7
+ # extension is installed using `Papercraft.extension`, a corresponding method
8
+ # is defined on the `Papercraft::Renderer` class that creates an extension
9
+ # proxy that gives access to the different extension methods.
10
+ class ExtensionProxy
11
+
12
+ # Initializes a new ExtensionProxy.
13
+ # @param renderer [Papercraft::Renderer] renderer to proxy to
14
+ # @param mod [Module] extension module
15
+ # @return [void]
16
+ def initialize(renderer, mod)
17
+ @renderer = renderer
18
+ extend(mod)
19
+ end
20
+
21
+ # Proxies missing methods to the renderer
22
+ # @param sym [Symbol] method name
23
+ # @param *args [Array] arguments
24
+ # @param &block [Proc] block
25
+ # @return void
26
+ def method_missing(sym, *args, &block)
27
+ @renderer.send(sym, *args, &block)
28
+ end
29
+ end
30
+ end
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './html'
3
+ require 'kramdown'
4
+ require 'rouge'
5
+ require 'kramdown-parser-gfm'
4
6
 
5
- module Papercraft
6
-
7
+ module Papercraft
7
8
  # HTML Markup extensions
8
9
  module HTML
9
10
  # Emits the p tag (overrides Object#p)
@@ -42,5 +43,28 @@ module Papercraft
42
43
  end
43
44
  link(**attributes)
44
45
  end
46
+
47
+ def emit_markdown(markdown, **opts)
48
+ emit Kramdown::Document.new(markdown, **kramdown_options(opts)).to_html
49
+ end
50
+
51
+ def kramdown_options(opts)
52
+ HTML.kramdown_options.merge(**opts)
53
+ end
54
+
55
+ class << self
56
+ def kramdown_options
57
+ @kramdown_options ||= {
58
+ entity_output: :numeric,
59
+ syntax_highlighter: :rouge,
60
+ input: 'GFM',
61
+ hard_wrap: false
62
+ }
63
+ end
64
+
65
+ def kramdown_options=(opts)
66
+ @kramdown_options = opts
67
+ end
68
+ end
45
69
  end
46
70
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative './html'
4
+ require_relative './extension_proxy'
4
5
 
5
6
  module Papercraft
6
7
 
@@ -31,15 +32,39 @@ module Papercraft
31
32
  if param_count > args.size
32
33
  raise Papercraft::Error, "Missing template parameters"
33
34
  end
34
- end
35
+ end
36
+
37
+ # Installs the given extensions, mapping a method name to the extension
38
+ # module.
39
+ # @param map [Hash] hash mapping methods to extension modules
40
+ # @return [void]
41
+ def extension(map)
42
+ map.each do |sym, mod|
43
+ define_extension_method(sym, mod)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # Defines a method returning an extension proxy for the given module
50
+ # @param sym [Symbol] method name
51
+ # @param mod [Module] extension module
52
+ # @return [void]
53
+ def define_extension_method(sym, mod)
54
+ define_method(sym) do
55
+ (@extension_proxies ||= {})[mod] ||= ExtensionProxy.new(self, mod)
56
+ end
57
+ end
35
58
  end
36
59
 
60
+ INITIAL_BUFFER_CAPACITY = 8192
61
+
37
62
  # Initializes the renderer and evaulates the given template in the
38
63
  # renderer's scope.
39
64
  #
40
65
  # @param &template [Proc] template block
41
66
  def initialize(&template)
42
- @buffer = +''
67
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
43
68
  instance_eval(&template)
44
69
  end
45
70
 
@@ -47,6 +72,20 @@ module Papercraft
47
72
  #
48
73
  # @return [String]
49
74
  def to_s
75
+ if @parts
76
+ last = @buffer
77
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
78
+ parts = @parts
79
+ @parts = nil
80
+ parts.each do |p|
81
+ if Proc === p
82
+ render_deferred_proc(&p)
83
+ else
84
+ @buffer << p
85
+ end
86
+ end
87
+ @buffer << last unless last.empty?
88
+ end
50
89
  @buffer
51
90
  end
52
91
 
@@ -56,6 +95,11 @@ module Papercraft
56
95
  S_TAG_%<TAG>s_CLOSE = '</%<tag>s>'.tr('_', '-')
57
96
 
58
97
  def %<tag>s(text = nil, **props, &block)
98
+ if text.is_a?(Hash) && props.empty?
99
+ props = text
100
+ text = nil
101
+ end
102
+
59
103
  @buffer << S_TAG_%<TAG>s_PRE
60
104
  emit_props(props) unless props.empty?
61
105
 
@@ -83,9 +127,6 @@ module Papercraft
83
127
  # @param &block [Proc] block passed to method
84
128
  # @return [void]
85
129
  def method_missing(sym, *args, **opts, &block)
86
- value = @local && @local[sym]
87
- return value if value
88
-
89
130
  tag = sym.to_s
90
131
  code = S_TAG_METHOD % { tag: tag, TAG: tag.upcase }
91
132
  self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
@@ -135,6 +176,42 @@ module Papercraft
135
176
 
136
177
  instance_exec(*a, **b, &@inner_block)
137
178
  end
179
+
180
+ # Defers the given block to be evaluated later. Deferred evaluation allows
181
+ # Papercraft components to inject state into sibling components, regardless
182
+ # of the component's order in the container component. For example, a nested
183
+ # component may set an instance variable used by another component. This is
184
+ # an elegant solution to the problem of setting the HTML page's title, or
185
+ # adding elements to the `<head>` section. Here's how a title can be
186
+ # controlled from a nested component:
187
+ #
188
+ # layout = H {
189
+ # html {
190
+ # head {
191
+ # defer { title @title }
192
+ # }
193
+ # body {
194
+ # emit_yield
195
+ # }
196
+ # }
197
+ # }
198
+ #
199
+ # html.render {
200
+ # @title = 'My super page'
201
+ # h1 'content'
202
+ # }
203
+ #
204
+ # @param &block [Proc] Deferred block to be emitted
205
+ # @return [void]
206
+ def defer(&block)
207
+ if !@parts
208
+ @parts = [@buffer, block]
209
+ else
210
+ @parts << @buffer unless @buffer.empty?
211
+ @parts << block
212
+ end
213
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
214
+ end
138
215
 
139
216
  S_LT = '<'
140
217
  S_GT = '>'
@@ -192,6 +269,23 @@ module Papercraft
192
269
  end
193
270
  }
194
271
  end
272
+
273
+ # Renders a deferred proc by evaluating it, then adding the rendered result
274
+ # to the buffer.
275
+ #
276
+ # @param &block [Proc] deferred proc
277
+ # @return [void]
278
+ def render_deferred_proc(&block)
279
+ old_buffer = @buffer
280
+
281
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
282
+ @parts = nil
283
+
284
+ instance_eval(&block)
285
+
286
+ old_buffer << to_s
287
+ @buffer = old_buffer
288
+ end
195
289
  end
196
290
 
197
291
  # Implements an HTML renderer
@@ -200,6 +294,7 @@ module Papercraft
200
294
 
201
295
  private
202
296
 
297
+ # Escapes the given text using HTML entities.
203
298
  def escape_text(text)
204
299
  EscapeUtils.escape_html(text.to_s)
205
300
  end
@@ -209,6 +304,7 @@ module Papercraft
209
304
  class XMLRenderer < Renderer
210
305
  private
211
306
 
307
+ # Escapes the given text using XML entities.
212
308
  def escape_text(text)
213
309
  EscapeUtils.escape_xml(text.to_s)
214
310
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Papercraft
4
- VERSION = '0.8.3'
4
+ VERSION = '0.11'
5
5
  end
data/lib/papercraft.rb CHANGED
@@ -11,6 +11,14 @@ require_relative 'papercraft/encoding'
11
11
  module Papercraft
12
12
  # Exception class used to signal templating-related errors
13
13
  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
+ def self.extension(map)
20
+ Renderer.extension(map)
21
+ end
14
22
  end
15
23
 
16
24
  # Kernel extensions
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.8.3
4
+ version: '0.11'
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: 2021-12-23 00:00:00.000000000 Z
11
+ date: 2022-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: escape_utils
@@ -24,6 +24,48 @@ dependencies:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.2.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: kramdown
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.3.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rouge
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.26.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.26.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: kramdown-parser-gfm
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.1.0
27
69
  - !ruby/object:Gem::Dependency
28
70
  name: minitest
29
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,7 +122,7 @@ dependencies:
80
122
  - - '='
81
123
  - !ruby/object:Gem::Version
82
124
  version: 2.0.9
83
- description:
125
+ description:
84
126
  email: sharon@noteflakes.com
85
127
  executables: []
86
128
  extensions: []
@@ -93,6 +135,7 @@ files:
93
135
  - lib/papercraft/compiler.rb
94
136
  - lib/papercraft/component.rb
95
137
  - lib/papercraft/encoding.rb
138
+ - lib/papercraft/extension_proxy.rb
96
139
  - lib/papercraft/html.rb
97
140
  - lib/papercraft/renderer.rb
98
141
  - lib/papercraft/version.rb
@@ -104,7 +147,7 @@ metadata:
104
147
  documentation_uri: https://www.rubydoc.info/gems/papercraft
105
148
  homepage_uri: https://github.com/digital-fabric/papercraft
106
149
  changelog_uri: https://github.com/digital-fabric/papercraft/blob/master/CHANGELOG.md
107
- post_install_message:
150
+ post_install_message:
108
151
  rdoc_options:
109
152
  - "--title"
110
153
  - Papercraft
@@ -123,8 +166,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
166
  - !ruby/object:Gem::Version
124
167
  version: '0'
125
168
  requirements: []
126
- rubygems_version: 3.1.6
127
- signing_key:
169
+ rubygems_version: 3.3.3
170
+ signing_key:
128
171
  specification_version: 4
129
172
  summary: 'Papercraft: component-based HTML templating for Ruby'
130
173
  test_files: []