papercraft 0.9 → 0.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1f7aa5872a78830c1a5662f055639ae2012b5b9d0f029640dce041f58d1ef4e
4
- data.tar.gz: 0c5acc8b14254c63db2132caab42ce003a8ae4713ae6daea7225d0390a420219
3
+ metadata.gz: be072094c35a6f89327b9c88b90264ad3db61cb43311d0e3baca865f403fdbc5
4
+ data.tar.gz: 7e565933dd83c48c05bac8c648cbe9b0007bc43f8fc5bd862af46dcd00dfb328
5
5
  SHA512:
6
- metadata.gz: 02bf1f7bc1300f4fa7871a6942c6a2eae2dd2f8202c7f3cc354171806f82e8a68262c3ca5e2232b7b6dcf6788a33b134b5811641561fa5baba3b7c342643b082
7
- data.tar.gz: 97a68a0f854f631a6a36b52a350faae4b1da1e337b27701209c6eec9dc16c62856555fdff3ab3d8f33e144e7fed8dc892b22433f38dd3f951a04010f710b63c4
6
+ metadata.gz: 9b8da36fb3c7298e8121b9c612cb81752609e1e3d1f01a94e4bf939864b29de718884989203077c5c1392926a54205c921adbcaa1bf3aa75d84694b7b4db4dcc
7
+ data.tar.gz: 778163311cb86ee425c4617ff54b10e8853d9b92404ef29abac848a4252818386b2e23058c355678c286a5bae3db9d4a7bfb182acb0a4aacf00a042431cc196a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.12 2022-01-06
2
+
3
+ - Improve documentation
4
+ - Add `Renderer#tag` method
5
+ - Add `HTML#style`, `HTML#script` methods
6
+
7
+ ## 0.11 2022-01-04
8
+
9
+ - Add deferred evaluation
10
+
11
+ ## 0.10.1 2021-12-25
12
+
13
+ - Fix tag rendering with empty text in Ruby 3.0
14
+
15
+ ## 0.10 2021-12-25
16
+
17
+ - Add support for extensions
18
+
1
19
  ## 0.9 2021-12-23
2
20
 
3
21
  - Add support for emitting Markdown
data/README.md CHANGED
@@ -1,8 +1,24 @@
1
- # Papercraft - Composable HTML templating for Ruby
2
-
3
- [INSTALL](#installing-papercraft) |
4
- [TUTORIAL](#getting-started) |
5
- [DOCS](https://www.rubydoc.info/gems/papercraft)
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>
6
22
 
7
23
  ## What is Papercraft?
8
24
 
@@ -32,9 +48,7 @@ features:
32
48
  - Explicit parameter passing to nested components
33
49
  - Higher order components
34
50
  - Built-in support for rendering [Markdown](#emitting-markdown)
35
-
36
- With Papercraft you can structure your templates as nested HTML components, in a
37
- somewhat similar fashion to React.
51
+ - Support for namespaced extensions
38
52
 
39
53
  ## Installing Papercraft
40
54
 
@@ -52,43 +66,25 @@ $ gem install papercraft
52
66
 
53
67
  ## Getting started
54
68
 
55
- To use Papercraft in your code just require it:
69
+ To create a template use the global method `Kernel#H`:
56
70
 
57
71
  ```ruby
58
72
  require 'papercraft'
59
- ```
60
-
61
- To create a template use `Papercraft::Component.new` or the global method
62
- `Kernel#H`:
63
73
 
64
- ```ruby
65
- # can also use Papercraft.new
66
74
  html = H {
67
- div { p 'hello' }
75
+ div(id: 'greeter') { p 'Hello!' }
68
76
  }
69
77
  ```
70
78
 
71
- ## Rendering a template
72
-
73
- To render a Papercraft template use the `#render` method:
74
-
75
- ```ruby
76
- H { span 'best span' }.render #=> "<span>best span</span>"
77
- ```
78
-
79
- The render method accepts an arbitrary context variable:
79
+ Rendering a template is done using `#render`:
80
80
 
81
81
  ```ruby
82
- html = H {
83
- h1 context[:title]
84
- }
85
-
86
- html.render(title: 'My title') #=> "<h1>My title</h1>"
82
+ html.render #=> "<div id="greeter"><p>Hello!</p></div>"
87
83
  ```
88
84
 
89
85
  ## All about tags
90
86
 
91
- Tags are added using unqualified method calls, and are nested using blocks:
87
+ Tags are added using unqualified method calls, and can be nested using blocks:
92
88
 
93
89
  ```ruby
94
90
  H {
@@ -370,13 +366,131 @@ The default Kramdown options are:
370
366
  ```
371
367
 
372
368
  The deafult options can be configured by accessing
373
- `Papercraft::HTML.kramdown_options`:
369
+ `Papercraft::HTML.kramdown_options`, e.g.:
374
370
 
375
371
  ```ruby
376
372
  Papercraft::HTML.kramdown_options[:auto_ids] = false
377
373
  ```
378
374
 
379
- ## Documentation
375
+ ## Deferred evaluation
376
+
377
+ Deferred evaluation allows deferring the rendering of parts of a template until
378
+ the last moment, thus allowing an inner component to manipulate the state of the
379
+ outer component. To in order to defer a part of a template, use `#defer`, and
380
+ include any markup in the provided block. This technique, in in conjunction with
381
+ holding state in instance variables, is an alternative to passing parameters,
382
+ which can be limiting in some situations.
383
+
384
+ A few use cases for deferred evaulation come to mind:
385
+
386
+ - Setting the page title.
387
+ - Adding a flash message to a page.
388
+ - Using components that dynamically add static dependencies (JS and CSS) to the
389
+ page.
390
+
391
+ The last use case is particularly interesting. Imagine a `DependencyMananger`
392
+ class that can collect JS and CSS dependencies from the different components
393
+ integrated into the page, and adds them to the page's `<head>` element:
394
+
395
+ ```ruby
396
+ default_layout = H { |**args|
397
+ @dependencies = DependencyMananger.new
398
+ head {
399
+ defer { emit @dependencies.head_markup }
400
+ }
401
+ body { emit_yield **args }
402
+ }
403
+
404
+ button = proc { |text, onclick|
405
+ @dependencies.js '/static/js/button.js'
406
+ @dependencies.css '/static/css/button.css'
407
+
408
+ button text, onclick: onclick
409
+ }
410
+
411
+ heading = proc { |text|
412
+ @dependencies.js '/static/js/heading.js'
413
+ @dependencies.css '/static/css/heading.css'
414
+
415
+ h1 text
416
+ }
417
+
418
+ page = default_layout.apply {
419
+ emit heading, "What's your favorite cheese?"
420
+
421
+ emit button, 'Beaufort', 'eat_beaufort()'
422
+ emit button, 'Mont d''or', 'eat_montdor()'
423
+ emit button, 'Époisses', 'eat_epoisses()'
424
+ }
425
+ ```
426
+
427
+ ## Papercraft extensions
428
+
429
+ Papercraft extensions are modules that contain one or more methods that can be
430
+ used to render complex HTML components. Extension modules can be used by
431
+ installing them as a namespaced extension using `Papercraft::extension`.
432
+ Extensions are particularly useful when you work with CSS frameworks such as
433
+ [Bootstrap](https://getbootstrap.com/), [Tailwind](https://tailwindui.com/) or
434
+ [Primer](https://primer.style/).
435
+
436
+ For example, to create a Bootstrap card component, the following HTML markup is
437
+ needed (example taken from the [Bootstrap
438
+ docs](https://getbootstrap.com/docs/5.1/components/card/#titles-text-and-links)):
439
+
440
+ ```html
441
+ <div class="card" style="width: 18rem;">
442
+ <div class="card-body">
443
+ <h5 class="card-title">Card title</h5>
444
+ <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
445
+ <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>
446
+ <a href="#" class="card-link">Card link</a>
447
+ <a href="#" class="card-link">Another link</a>
448
+ </div>
449
+ </div>
450
+ ```
451
+
452
+ With Papercraft, we could create a `Bootstrap` extension with a `#card` method
453
+ and other associated methods:
454
+
455
+ ```ruby
456
+ module BootstrapComponents
457
+ ...
458
+
459
+ def card(**props)
460
+ div(class: 'card', **props) {
461
+ div(class: 'card-body') {
462
+ emit_yield
463
+ }
464
+ }
465
+ end
466
+
467
+ def card_title(title)
468
+ h5 title, class: 'card-title'
469
+ end
470
+
471
+ ...
472
+ end
473
+
474
+ Papercraft.extension(bootstrap: BootstrapComponents)
475
+ ```
476
+
477
+ The call to `Papercraft::extension` lets us access the different methods of
478
+ `BootstrapComponents` by calling `#bootstrap` inside a template. With this,
479
+ we'll be able to express the above markup as follows:
480
+
481
+ ```ruby
482
+ H {
483
+ bootstrap.card(style: 'width: 18rem') {
484
+ bootstrap.card_title 'Card title'
485
+ bootstrap.card_subtitle 'Card subtitle'
486
+ bootstrap.card_text 'Some quick example text to build on the card title and make up the bulk of the card''s content.'
487
+ bootstrap.card_link '#', 'Card link'
488
+ bootstrap.card_link '#', 'Another link'
489
+ }
490
+ }
491
+ ```
492
+
493
+ ## API Reference
380
494
 
381
- The complete documentation for this library can be found
495
+ The API reference for this library can be found
382
496
  [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
@@ -44,15 +44,53 @@ module Papercraft
44
44
  link(**attributes)
45
45
  end
46
46
 
47
- def emit_markdown(markdown, **opts)
48
- emit Kramdown::Document.new(markdown, **kramdown_options(opts)).to_html
47
+ # Emits an inline CSS style element.
48
+ #
49
+ # @param css [String] CSS code
50
+ # @param **props [Hash] optional element attributes
51
+ # @return [void]
52
+ def style(css, **props, &block)
53
+ @buffer << '<style'
54
+ emit_props(props) unless props.empty?
55
+
56
+ @buffer << '>' << css << '</style>'
49
57
  end
58
+
59
+ # Emits an inline JS script element.
60
+ #
61
+ # @param js [String, nil] Javascript code
62
+ # @param **props [Hash] optional element attributes
63
+ # @return [void]
64
+ def script(js = nil, **props, &block)
65
+ @buffer << '<script'
66
+ emit_props(props) unless props.empty?
50
67
 
51
- def kramdown_options(opts)
52
- HTML.kramdown_options.merge(**opts)
68
+ if js
69
+ @buffer << '>' << js << '</script>'
70
+ else
71
+ @buffer << '></script>'
72
+ end
73
+ end
74
+
75
+ # Converts and emits the given markdown. Papercraft uses
76
+ # [Kramdown](https://github.com/gettalong/kramdown/) to do the Markdown to
77
+ # HTML conversion. Optional Kramdown settings can be provided in order to
78
+ # control the conversion. Those are merged with the default Kramdown
79
+ # settings, which can be controlled using
80
+ # `Papercraft::HTML.kramdown_options`.
81
+ #
82
+ # @param markdown [String] Markdown content
83
+ # @param **opts [Hash] Kramdown options
84
+ # @return [void]
85
+ def emit_markdown(markdown, **opts)
86
+ emit Kramdown::Document.new(markdown, **kramdown_options(opts)).to_html
53
87
  end
54
88
 
55
89
  class << self
90
+ # Returns the default Kramdown options used for converting Markdown to
91
+ # HTML.
92
+ #
93
+ # @return [Hash] Default Kramdown options
56
94
  def kramdown_options
57
95
  @kramdown_options ||= {
58
96
  entity_output: :numeric,
@@ -62,9 +100,24 @@ module Papercraft
62
100
  }
63
101
  end
64
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
65
108
  def kramdown_options=(opts)
66
109
  @kramdown_options = opts
67
110
  end
68
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)
121
+ end
69
122
  end
70
123
  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,60 @@ 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
+ # call_seq:
38
+ # Papercraft::Renderer.extension(name => mod, ...)
39
+ # Papercraft.extension(name => mod, ...)
40
+ #
41
+ # Installs the given extensions, passed in the form of a Ruby hash mapping
42
+ # methods to extension modules. The methods will be available to all
43
+ # Papercraft components. Extension methods are executed in the context of
44
+ # the the renderer instance, so they can look just like normal proc
45
+ # components. In cases where method names in the module clash with HTML
46
+ # tag names, you can use the `#tag` method to emit the relevant tag.
47
+ #
48
+ # module ComponentLibrary
49
+ # def card(title, content)
50
+ # div(class: 'card') {
51
+ # h3 title
52
+ # div(class: 'card-content') { emit_markdown content }
53
+ # }
54
+ # end
55
+ # end
56
+ #
57
+ # Papercraft.extension(components: ComponentLibrary)
58
+ # H { components.card('Foo', '**Bar**') }
59
+ #
60
+ # @param map [Hash] hash mapping methods to extension modules
61
+ # @return [void]
62
+ def extension(map)
63
+ map.each do |sym, mod|
64
+ define_extension_method(sym, mod)
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ # Defines a method returning an extension proxy for the given module
71
+ # @param sym [Symbol] method name
72
+ # @param mod [Module] extension module
73
+ # @return [void]
74
+ def define_extension_method(sym, mod)
75
+ define_method(sym) do
76
+ (@extension_proxies ||= {})[mod] ||= ExtensionProxy.new(self, mod)
77
+ end
78
+ end
35
79
  end
36
80
 
81
+ INITIAL_BUFFER_CAPACITY = 8192
82
+
37
83
  # Initializes the renderer and evaulates the given template in the
38
84
  # renderer's scope.
39
85
  #
40
86
  # @param &template [Proc] template block
41
87
  def initialize(&template)
42
- @buffer = +''
88
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
43
89
  instance_eval(&template)
44
90
  end
45
91
 
@@ -47,15 +93,36 @@ module Papercraft
47
93
  #
48
94
  # @return [String]
49
95
  def to_s
96
+ if @parts
97
+ last = @buffer
98
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
99
+ parts = @parts
100
+ @parts = nil
101
+ parts.each do |p|
102
+ if Proc === p
103
+ render_deferred_proc(&p)
104
+ else
105
+ @buffer << p
106
+ end
107
+ end
108
+ @buffer << last unless last.empty?
109
+ end
50
110
  @buffer
51
111
  end
52
112
 
113
+ # The tag method template below is optimized for performance. Do not touch!
114
+
53
115
  S_TAG_METHOD_LINE = __LINE__ + 1
54
116
  S_TAG_METHOD = <<~EOF
55
- S_TAG_%<TAG>s_PRE = '<%<tag>s'.tr('_', '-')
56
- S_TAG_%<TAG>s_CLOSE = '</%<tag>s>'.tr('_', '-')
117
+ S_TAG_%<TAG>s_PRE = %<tag_pre>s
118
+ S_TAG_%<TAG>s_CLOSE = %<tag_close>s
57
119
 
58
120
  def %<tag>s(text = nil, **props, &block)
121
+ if text.is_a?(Hash) && props.empty?
122
+ props = text
123
+ text = nil
124
+ end
125
+
59
126
  @buffer << S_TAG_%<TAG>s_PRE
60
127
  emit_props(props) unless props.empty?
61
128
 
@@ -75,6 +142,48 @@ module Papercraft
75
142
  end
76
143
  EOF
77
144
 
145
+ # Emits an HTML tag with the given content, properties and optional block.
146
+ # This method is an alternative to emitting HTML tags using dynamically
147
+ # created methods. This is particularly useful when using extensions that
148
+ # have method names that clash with HTML tags, such as `button` or `a`, or
149
+ # when you need to override the behaviour of a particular HTML tag.
150
+ #
151
+ # The following two method calls have the same effect:
152
+ #
153
+ # button 'text', id: 'button1'
154
+ # tag :button, 'text', id: 'button1'
155
+ #
156
+ # @param sym [Symbol, String] HTML tag
157
+ # @param text [String, nil] tag content
158
+ # @param **props [Hash] tag attributes
159
+ # @param &block [Proc] optional inner HTML
160
+ # @return [void]
161
+ def tag(sym, text = nil, **props, &block)
162
+ if text.is_a?(Hash) && props.empty?
163
+ props = text
164
+ text = nil
165
+ end
166
+
167
+ tag = sym.to_s.tr('_', '-')
168
+
169
+ @buffer << S_LT << tag
170
+ emit_props(props) unless props.empty?
171
+
172
+ if block
173
+ @buffer << S_GT
174
+ instance_eval(&block)
175
+ @buffer << S_LT_SLASH << tag << S_GT
176
+ elsif Proc === text
177
+ @buffer << S_GT
178
+ emit(text)
179
+ @buffer << S_LT_SLASH << tag << S_GT
180
+ elsif text
181
+ @buffer << S_GT << escape_text(text.to_s) << S_LT_SLASH << tag << S_GT
182
+ else
183
+ @buffer << S_SLASH_GT
184
+ end
185
+ end
186
+
78
187
  # Catches undefined tag method call and handles it by defining the method.
79
188
  #
80
189
  # @param sym [Symbol] HTML tag or component identifier
@@ -83,11 +192,13 @@ module Papercraft
83
192
  # @param &block [Proc] block passed to method
84
193
  # @return [void]
85
194
  def method_missing(sym, *args, **opts, &block)
86
- value = @local && @local[sym]
87
- return value if value
88
-
89
195
  tag = sym.to_s
90
- code = S_TAG_METHOD % { tag: tag, TAG: tag.upcase }
196
+ code = S_TAG_METHOD % {
197
+ tag: tag,
198
+ TAG: tag.upcase,
199
+ tag_pre: "<#{tag.tr('_', '-')}".inspect,
200
+ tag_close: "</#{tag.tr('_', '-')}>".inspect
201
+ }
91
202
  self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
92
203
  send(sym, *args, **opts, &block)
93
204
  end
@@ -135,6 +246,42 @@ module Papercraft
135
246
 
136
247
  instance_exec(*a, **b, &@inner_block)
137
248
  end
249
+
250
+ # Defers the given block to be evaluated later. Deferred evaluation allows
251
+ # Papercraft components to inject state into sibling components, regardless
252
+ # of the component's order in the container component. For example, a nested
253
+ # component may set an instance variable used by another component. This is
254
+ # an elegant solution to the problem of setting the HTML page's title, or
255
+ # adding elements to the `<head>` section. Here's how a title can be
256
+ # controlled from a nested component:
257
+ #
258
+ # layout = H {
259
+ # html {
260
+ # head {
261
+ # defer { title @title }
262
+ # }
263
+ # body {
264
+ # emit_yield
265
+ # }
266
+ # }
267
+ # }
268
+ #
269
+ # html.render {
270
+ # @title = 'My super page'
271
+ # h1 'content'
272
+ # }
273
+ #
274
+ # @param &block [Proc] Deferred block to be emitted
275
+ # @return [void]
276
+ def defer(&block)
277
+ if !@parts
278
+ @parts = [@buffer, block]
279
+ else
280
+ @parts << @buffer unless @buffer.empty?
281
+ @parts << block
282
+ end
283
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
284
+ end
138
285
 
139
286
  S_LT = '<'
140
287
  S_GT = '>'
@@ -192,6 +339,23 @@ module Papercraft
192
339
  end
193
340
  }
194
341
  end
342
+
343
+ # Renders a deferred proc by evaluating it, then adding the rendered result
344
+ # to the buffer.
345
+ #
346
+ # @param &block [Proc] deferred proc
347
+ # @return [void]
348
+ def render_deferred_proc(&block)
349
+ old_buffer = @buffer
350
+
351
+ @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
352
+ @parts = nil
353
+
354
+ instance_eval(&block)
355
+
356
+ old_buffer << to_s
357
+ @buffer = old_buffer
358
+ end
195
359
  end
196
360
 
197
361
  # Implements an HTML renderer
@@ -200,6 +364,7 @@ module Papercraft
200
364
 
201
365
  private
202
366
 
367
+ # Escapes the given text using HTML entities.
203
368
  def escape_text(text)
204
369
  EscapeUtils.escape_html(text.to_s)
205
370
  end
@@ -209,6 +374,7 @@ module Papercraft
209
374
  class XMLRenderer < Renderer
210
375
  private
211
376
 
377
+ # Escapes the given text using XML entities.
212
378
  def escape_text(text)
213
379
  EscapeUtils.escape_xml(text.to_s)
214
380
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Papercraft
4
- VERSION = '0.9'
4
+ VERSION = '0.12'
5
5
  end
data/lib/papercraft.rb CHANGED
@@ -11,6 +11,20 @@ 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
+ #
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
14
28
  end
15
29
 
16
30
  # 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.9'
4
+ version: '0.12'
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-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: escape_utils
@@ -122,7 +122,7 @@ dependencies:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
124
  version: 2.0.9
125
- description:
125
+ description:
126
126
  email: sharon@noteflakes.com
127
127
  executables: []
128
128
  extensions: []
@@ -135,6 +135,7 @@ files:
135
135
  - lib/papercraft/compiler.rb
136
136
  - lib/papercraft/component.rb
137
137
  - lib/papercraft/encoding.rb
138
+ - lib/papercraft/extension_proxy.rb
138
139
  - lib/papercraft/html.rb
139
140
  - lib/papercraft/renderer.rb
140
141
  - lib/papercraft/version.rb
@@ -146,7 +147,7 @@ metadata:
146
147
  documentation_uri: https://www.rubydoc.info/gems/papercraft
147
148
  homepage_uri: https://github.com/digital-fabric/papercraft
148
149
  changelog_uri: https://github.com/digital-fabric/papercraft/blob/master/CHANGELOG.md
149
- post_install_message:
150
+ post_install_message:
150
151
  rdoc_options:
151
152
  - "--title"
152
153
  - Papercraft
@@ -165,8 +166,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
166
  - !ruby/object:Gem::Version
166
167
  version: '0'
167
168
  requirements: []
168
- rubygems_version: 3.1.6
169
- signing_key:
169
+ rubygems_version: 3.3.3
170
+ signing_key:
170
171
  specification_version: 4
171
172
  summary: 'Papercraft: component-based HTML templating for Ruby'
172
173
  test_files: []