papercraft 0.21 → 0.24

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: a23bf614d84747a18eecf84545604c9c2f58710dc3fa0e0c651a863a53c919b0
4
- data.tar.gz: 6b1ca8f4a90801beff11807dd357ce801b7526b5d114d5cca5f41f41aec69958
3
+ metadata.gz: f90c4ea6ac9d3090ae45d79f7f4a58668ccf7f8ae5d4dfa2a727b44a82699eb9
4
+ data.tar.gz: 10ff5bc3df10c10b0a968921517d2e0c18a61973dd97b88e95eef38670b9e451
5
5
  SHA512:
6
- metadata.gz: dcd7eada8280cb0fcd68528eaea0d2500ff99ac149c8495dd5a3955a93c3f181301a4decc9eeb4d7efdd8cfe2c4f6047c9f838e5084b413c1118a76d6abc4252
7
- data.tar.gz: 840ce0fc2a83de9b5a83bb10a5f4ed98986f7201737d6e31a4e89877aeb6bb22b2f2449c6efa08302473c073e26c830cfbe9e267456b450a56222b57a429fd15
6
+ metadata.gz: '02461962ba174678a5b4a6ec550a8faa2f643fe87234e41513f7b49d798e3f3b2ade02adcfb0fa4961124a74484ddddea9437cb02eec98e9e897721729c0ef63'
7
+ data.tar.gz: f99728bb218382a040f67cbf2fd9652c33b3e0648efefbc695ceee708006758b6ec249748f3e3d41b065bf3b2fb28014b1ae61e02f7d3b01231e928f028e6ebd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 0.24 2022-03-19
2
+
3
+ - Fix usage of const components (#13)
4
+ - Fix formatting of HTML/XML attributes for non-string values
5
+
6
+ ## 0.23 2022-02-15
7
+
8
+ - Remove unused `Encoding` module
9
+ - Add SOAP extension (#11, thanks [@aemadrid](https://github.com/aemadrid))
10
+
11
+ ## 0.22 2022-02-14
12
+
13
+ - Fix behaviour of call to `#p` in an extension (#10)
14
+
1
15
  ## 0.21 2022-02-13
2
16
 
3
17
  - Refactor and improve documentation
data/README.md CHANGED
@@ -42,6 +42,10 @@ Papercraft includes built-in support for rendering Markdown (using
42
42
  creating template extensions in order to allow the creation of component
43
43
  libraries.
44
44
 
45
+ Papercraft automatically escapes all text emitted in templates according to the
46
+ template type. For more information see the section on [escaping
47
+ content](#escaping-content).
48
+
45
49
  ```ruby
46
50
  require 'papercraft'
47
51
 
@@ -59,27 +63,30 @@ hello.render('world')
59
63
  #=> "<html><head><title>Title</title></head><body><h1>Hello, world!</h1></body></html>"
60
64
  ```
61
65
 
62
- ## Table of 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 templates](#higher-order-templates)
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)
66
+ ## Table of Content
67
+
68
+ - [Installing Papercraft](#installing-papercraft)
69
+ - [Basic Usage](#basic-usage)
70
+ - [Adding Tags](#adding-tags)
71
+ - [Tag and Attribute Formatting](#tag-and-attribute-formatting)
72
+ - [Escaping Content](#escaping-content)
73
+ - [Template Parameters](#template-parameters)
74
+ - [Template Logic](#template-logic)
75
+ - [Template Blocks](#template-blocks)
76
+ - [Plain Procs as Templates](#plain-procs-as-templates)
77
+ - [Template Composition](#template-composition)
78
+ - [Parameter and Block Application](#parameter-and-block-application)
79
+ - [Higher-Order Templates](#higher-order-templates)
80
+ - [Layout Template Composition](#layout-template-composition)
81
+ - [Emitting Raw HTML](#emitting-raw-html)
82
+ - [Emitting a String with HTML Encoding](#emitting-a-string-with-html-encoding)
77
83
  - [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)
84
+ - [Working with MIME Types](#working-with-mime-types)
85
+ - [Deferred Evaluation](#deferred-evaluation)
86
+ - [XML Templates](#xml-templates)
87
+ - [JSON Templates](#json-templates)
88
+ - [Papercraft Extensions](#papercraft-extensions)
89
+ - [Bundled Extensions](#bundled-extensions)
83
90
  - [API Reference](#api-reference)
84
91
 
85
92
  ## Installing Papercraft
@@ -96,7 +103,7 @@ Or manually:
96
103
  $ gem install papercraft
97
104
  ```
98
105
 
99
- ## Basic usage
106
+ ## Basic Usage
100
107
 
101
108
  To create an HTML template use `Papercraft.html`:
102
109
 
@@ -117,7 +124,7 @@ Rendering a template is done using `#render`:
117
124
  html.render #=> "<div id="greeter"><p>Hello!</p></div>"
118
125
  ```
119
126
 
120
- ## Adding tags
127
+ ## Adding Tags
121
128
 
122
129
  Tags are added using unqualified method calls, and can be nested using blocks:
123
130
 
@@ -154,7 +161,60 @@ Papercraft.html { img src: '/my.gif' }.render #=> "<img src="/my.gif"/>
154
161
  Papercraft.html { p "foobar", class: 'important' }.render #=> "<p class=\"important\">foobar</p>"
155
162
  ```
156
163
 
157
- ## Template parameters
164
+ ## Tag and Attribute Formatting
165
+
166
+ Papercraft does not make any presumption about what tags and attributes you can
167
+ use. You can mix upper and lower case letters, and you can include arbitrary
168
+ characters in tag and attribute names. However, in order to best adhere to the
169
+ HTML and XML specs and common practices, tag names and attributes will be
170
+ formatted according to the following rules, depending on the template type:
171
+
172
+ - HTML: underscores are converted to dashes:
173
+
174
+ ```ruby
175
+ Papercraft.html {
176
+ foo_bar { p 'Hello', data_name: 'world' }
177
+ }.render #=> '<foo-bar><p data-name="world">Hello</p></foo-bar>'
178
+ ```
179
+
180
+ - XML: underscores are converted to dashes, double underscores are converted to
181
+ colons:
182
+
183
+ ```ruby
184
+ Papercraft.xml {
185
+ soap__Envelope(
186
+ xmlns__soap: 'http://schemas.xmlsoap.org/soap/envelope/',
187
+ ) { }
188
+ }.render #=> '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Envelope>'
189
+ ```
190
+
191
+ If you need more precise control over tag names, you can use the `#tag` method,
192
+ which takes the tag name as its first parameter, then the rest of the parameters
193
+ normally used for tags:
194
+
195
+ ```ruby
196
+ Papercraft.html {
197
+ tag 'cra_zy__:!tag', 'foo'
198
+ }.render #=> '<cra_zy__:!tag>foo</cra_zy__:!tag>'
199
+ ```
200
+
201
+ ## Escaping Content
202
+
203
+ Papercraft automatically escapes all text content emitted in a template. The
204
+ specific escaping algorithm depends on the template type. For both HTML and XML
205
+ templates, Papercraft uses
206
+ [escape_utils](https://github.com/brianmario/escape_utils), specifically:
207
+
208
+ - HTML: `escape_utils.escape_html`
209
+ - XML: `escape_utils.escape_xml`
210
+
211
+ In order to emit raw HTML/XML, you can use the `#emit` method as [described
212
+ below](#emitting-raw-html).
213
+
214
+ JSON templates are rendered using the `json` gem bundled with Ruby, which takes
215
+ care of escaping text values.
216
+
217
+ ## Template Parameters
158
218
 
159
219
  In Papercraft, parameters are always passed explicitly. This means that template
160
220
  parameters are specified as block parameters, and are passed to the template on
@@ -172,7 +232,7 @@ greeting = Papercraft.html { |name:| h1 "Hello, #{name}!" }
172
232
  greeting.render(name: 'world') #=> "<h1>Hello, world!</h1>"
173
233
  ```
174
234
 
175
- ## Template logic
235
+ ## Template Logic
176
236
 
177
237
  Since Papercraft templates are just a bunch of Ruby, you can easily write your
178
238
  view logic right in the template:
@@ -187,7 +247,7 @@ Papercraft.html { |user = nil|
187
247
  }
188
248
  ```
189
249
 
190
- ## Template blocks
250
+ ## Template Blocks
191
251
 
192
252
  Templates can also accept and render blocks by using `emit_yield`:
193
253
 
@@ -202,7 +262,7 @@ page = Papercraft.html {
202
262
  page.render { h1 'hi' }
203
263
  ```
204
264
 
205
- ## Plain procs as templates
265
+ ## Plain Procs as Templates
206
266
 
207
267
  With Papercraft you can write a template as a plain Ruby proc, and later render
208
268
  it by passing it as a block to `Papercraft.html`:
@@ -219,7 +279,7 @@ greeting = ->(name) { h1 "Hello, #{name}!" }
219
279
  Papercraft.html(&greeting).render('world')
220
280
  ```
221
281
 
222
- ## Template composition
282
+ ## Template Composition
223
283
 
224
284
  Papercraft makes it easy to compose multiple templates into a whole HTML
225
285
  document. A Papercraft template can contain other templates, as the following
@@ -269,7 +329,7 @@ Papercraft.html {
269
329
  }
270
330
  ```
271
331
 
272
- ## Parameter and block application
332
+ ## Parameter and Block Application
273
333
 
274
334
  Parameters and blocks can be applied to a template without it being rendered, by
275
335
  using `#apply`. This mechanism is what allows template composition and the
@@ -294,7 +354,7 @@ wrapped_hello_world = div_wrap.apply(&hello_world)
294
354
  wrapped_hello_world.render #=> "<div><h1>Hello, world!</h1></div>"
295
355
  ```
296
356
 
297
- ## Higher-order templates
357
+ ## Higher-Order Templates
298
358
 
299
359
  Papercraft also lets you create higher-order templates, that is,
300
360
  templates that take other templates as parameters, or as blocks. Higher-order
@@ -318,7 +378,7 @@ wrapped_greeter = div_wrap.apply { h1 'hi' }
318
378
  wrapped_greeter.render #=> "<div><h1>hi</h1></div>"
319
379
  ```
320
380
 
321
- ## Layout template composition
381
+ ## Layout Template Composition
322
382
 
323
383
  One of the principal uses of higher-order templates is the creation of nested
324
384
  layouts. Suppose we have a website with a number of different layouts, and we'd
@@ -351,7 +411,7 @@ article_layout.render(
351
411
  )
352
412
  ```
353
413
 
354
- ## Emitting raw HTML
414
+ ## Emitting Raw HTML
355
415
 
356
416
  Raw HTML can be emitted using `#emit`:
357
417
 
@@ -360,13 +420,13 @@ wrapped = Papercraft.html { |html| div { emit html } }
360
420
  wrapped.render("<h1>hi</h1>") #=> "<div><h1>hi</h1></div>"
361
421
  ```
362
422
 
363
- ## Emitting a string with HTML Encoding
423
+ ## Emitting a String with HTML Encoding
364
424
 
365
425
  To emit a string with proper HTML encoding, without wrapping it in an HTML
366
426
  element, use `#text`:
367
427
 
368
428
  ```ruby
369
- Papercraft.html { str 'hi&lo' }.render #=> "hi&amp;lo"
429
+ Papercraft.html { text 'hi&lo' }.render #=> "hi&amp;lo"
370
430
  ```
371
431
 
372
432
  ## Emitting Markdown
@@ -415,7 +475,7 @@ The deafult options can be configured by accessing
415
475
  Papercraft.default_kramdown_options[:auto_ids] = false
416
476
  ```
417
477
 
418
- ## Working with MIME types
478
+ ## Working with MIME Types
419
479
 
420
480
  Papercraft lets you set and interrogate a template's MIME type, in order to be
421
481
  able to dynamically set the `Content-Type` HTTP response header. A template's
@@ -431,7 +491,7 @@ def serve_template(req, template)
431
491
  end
432
492
  ```
433
493
 
434
- ## Deferred evaluation
494
+ ## Deferred Evaluation
435
495
 
436
496
  Deferred evaluation allows deferring the rendering of parts of a template until
437
497
  the last moment, thus allowing an inner template to manipulate the state of the
@@ -483,7 +543,73 @@ page = default_layout.apply {
483
543
  }
484
544
  ```
485
545
 
486
- ## Papercraft extensions
546
+ ## XML Templates
547
+
548
+ XML templates behave largely the same as HTML templates, with a few minor
549
+ differences. XML templates employ a different encoding algorithm, and lack some
550
+ specific HTML functionality, such as emitting Markdown.
551
+
552
+ Here's an example showing how to create an RSS feed:
553
+
554
+ ```ruby
555
+ rss = Papercraft.xml(mime_type: 'text/xml; charset=utf-8') { |resource:, **props|
556
+ rss(version: '2.0', 'xmlns:atom' => 'http://www.w3.org/2005/Atom') {
557
+ channel {
558
+ title 'Noteflakes'
559
+ link 'https://noteflakes.com/'
560
+ description 'A website by Sharon Rosner'
561
+ language 'en-us'
562
+ pubDate Time.now.httpdate
563
+ emit '<atom:link href="https://noteflakes.com/feeds/rss" rel="self" type="application/rss+xml" />'
564
+
565
+ article_entries = resource.page_list('/articles').reverse
566
+
567
+ article_entries.each { |e|
568
+ item {
569
+ title e[:title]
570
+ link "https://noteflakes.com#{e[:url]}"
571
+ guid "https://noteflakes.com#{e[:url]}"
572
+ pubDate e[:date].to_time.httpdate
573
+ description e[:html_content]
574
+ }
575
+ }
576
+ }
577
+ }
578
+ }
579
+ ```
580
+
581
+ ## JSON Templates
582
+
583
+ JSON templates behave largely the same as HTML and XML templates. The only major
584
+ difference is that for adding array items you'll need to use the `#item` method:
585
+
586
+ ```ruby
587
+ Papercraft.json {
588
+ item 1
589
+ item 2
590
+ item 3
591
+ }.render #=> "[1,2,3]"
592
+ ```
593
+
594
+ Otherwise, you can create arbitrarily complex JSON structures by mixing hashes
595
+ and arrays:
596
+
597
+ ```Ruby
598
+ Papercraft.json {
599
+ foo {
600
+ bar {
601
+ item nil
602
+ item true
603
+ item 123.456
604
+ }
605
+ }
606
+ }.render #=> "{\"foo\":{\"bar\":[null,true,123.456]}}"
607
+ ```
608
+
609
+ Papercraft uses the [JSON gem](https://rubyapi.org/3.1/o/json) under the hood in
610
+ order to generate actual JSON.
611
+
612
+ ## Papercraft Extensions
487
613
 
488
614
  Papercraft extensions are modules that contain one or more methods that can be
489
615
  used to render complex HTML components. Extension modules can be used by
@@ -513,21 +639,27 @@ and other associated methods:
513
639
 
514
640
  ```ruby
515
641
  module BootstrapComponents
516
- ...
517
-
518
- def card(**props)
642
+ def card(**props, &block)
519
643
  div(class: 'card', **props) {
520
- div(class: 'card-body') {
521
- emit_yield
522
- }
644
+ div(class: 'card-body', &block)
523
645
  }
524
646
  end
525
-
647
+
526
648
  def card_title(title)
527
- h5 title, class: 'card-title'
649
+ h4(title, class: 'card-title')
650
+ end
651
+
652
+ def card_subtitle(subtitle)
653
+ h5(subtitle, class: 'card-subtitle')
528
654
  end
529
655
 
530
- ...
656
+ def card_text(text)
657
+ p(text, class: 'card-text')
658
+ end
659
+
660
+ def card_link(text, **opts)
661
+ a(text, class: 'card-link', **opts)
662
+ end
531
663
  end
532
664
 
533
665
  Papercraft.extension(bootstrap: BootstrapComponents)
@@ -543,81 +675,63 @@ Papercraft.html {
543
675
  bootstrap.card_title 'Card title'
544
676
  bootstrap.card_subtitle 'Card subtitle'
545
677
  bootstrap.card_text 'Some quick example text to build on the card title and make up the bulk of the card''s content.'
546
- bootstrap.card_link '#', 'Card link'
547
- bootstrap.card_link '#', 'Another link'
678
+ bootstrap.card_link 'Card link', href: '#foo'
679
+ bootstrap.card_link 'Another link', href: '#bar'
548
680
  }
549
681
  }
550
682
  ```
551
683
 
684
+ ## Bundled Extensions
552
685
 
686
+ Papercraft comes bundled with a few extensions that address common use cases.
687
+ All bundled extensions are namespaced under `Papercraft::Extensions`, and must
688
+ be specifically required in order to be available to templates.
553
689
 
554
- ## XML templates
690
+ For all bundled Papercraft extensions, there's no need to call
691
+ `Papercraft.extension`, requiring the extension is sufficient.
555
692
 
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.
693
+ ### SOAP Extension
559
694
 
560
- Here's an example showing how to create an RSS feed:
695
+ > The SOAP extension was contributed by [@aemadrid](https://github.com/aemadrid).
561
696
 
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
697
+ The SOAP extension provides common tags for building SOAP payloads. To load the
698
+ SOAP extensions, require `polyphony/extensions/soap`. The extension provides the
699
+ following methods:
574
700
 
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
- ```
701
+ - `soap.Body(...)` - emits a `soap:Body` tag.
702
+ - `soap.Envelope(...)` - emits a `soap:Envelope` tag.
703
+ - `soap.Fault(...)` - emits a `soap:Fault` tag.
704
+ - `soap.Header(...)` - emits a `soap:Header` tag.
588
705
 
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:
706
+ As mentioned above, namespaced tags and attributes may be specified by using
707
+ double underscores for colons. Other tags that contain special characters may be
708
+ emitted using the `#tag` method:
593
709
 
594
710
  ```ruby
595
- Papercraft.json {
596
- item 1
597
- item 2
598
- item 3
599
- }.render #=> "[1,2,3]"
600
- ```
711
+ require 'polyphony/extensions/soap'
601
712
 
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
713
+ xml = Papercraft.xml {
714
+ soap.Envelope(
715
+ xmlns__xsd: 'http://www.w3.org/2001/XMLSchema',
716
+ xmlns__xsi: 'http://www.w3.org/2001/XMLSchema-instance'
717
+ ) {
718
+ soap.Body {
719
+ PosRequest(xmlns: 'http://Some.Site') {
720
+ tag('Ver1.0') {
721
+ Header {
722
+ SecretAPIKey 'some_secret_key'
723
+ }
724
+ Transaction {
725
+ SomeData {}
726
+ }
727
+ }
728
+ }
612
729
  }
613
730
  }
614
- }.render #=> "{\"foo\":{\"bar\":[null,true,123.456]}}"
731
+ }
615
732
  ```
616
733
 
617
- Papercraft uses the [JSON gem](https://rubyapi.org/3.1/o/json) under the hood in
618
- order to generate actual JSON.
619
-
620
734
  ## API Reference
621
735
 
622
736
  The API reference for this library can be found
623
- [here](https://www.rubydoc.info/gems/papercraft).
737
+ [here](https://www.rubydoc.info/gems/papercraft).
@@ -23,10 +23,21 @@ module Papercraft
23
23
  #
24
24
  # @param sym [Symbol] method name
25
25
  # @param *args [Array] arguments
26
+ # @param *props [Array] named arguments
26
27
  # @param &block [Proc] block
27
28
  # @return void
28
- def method_missing(sym, *args, &block)
29
- @renderer.send(sym, *args, &block)
29
+ def method_missing(sym, *args, **props, &block)
30
+ @renderer.send(sym, *args, **props, &block)
31
+ end
32
+
33
+ # Overrides the `Kernel#p` method to emit a p tag.
34
+ #
35
+ # @param *args [Array] arguments
36
+ # @param *props [Array] named arguments
37
+ # @param &block [Proc] block
38
+ # @return void
39
+ def p(text = nil, **props, &block)
40
+ @renderer.p(text, **props, &block)
30
41
  end
31
42
  end
32
43
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Papercraft
4
+ module Extensions
5
+ module Soap
6
+ # Emits a SOAP XML tag that identifies the XML document as a SOAP message.
7
+ #
8
+ # @param **props [Hash] tag attributes
9
+ # @param &block [Proc] optional inner XML
10
+ # @return [void]
11
+ def Envelope(**props, &block)
12
+ props[:xmlns__soap] ||= 'http://schemas.xmlsoap.org/soap/envelope/'
13
+ tag('soap:Envelope', **props, &block)
14
+ end
15
+
16
+ # Emits a SOAP XML tag that contains header information.
17
+ #
18
+ # @param **props [Hash] tag attributes
19
+ # @param &block [Proc] optional inner XML
20
+ # @return [void]
21
+ def Header(**props, &blk)
22
+ tag('soap:Header', **props, &blk)
23
+ end
24
+
25
+ # Emits a SOAP XML tag that contains header information.
26
+ #
27
+ # @param **props [Hash] tag attributes
28
+ # @param &block [Proc] optional inner XML
29
+ # @return [void]
30
+ def Body(**props, &blk)
31
+ tag('soap:Body', **props, &blk)
32
+ end
33
+
34
+ # Emits a SOAP XML tag that contains errors and status information.
35
+ #
36
+ # @param **props [Hash] tag attributes
37
+ # @param &block [Proc] optional inner XML
38
+ # @return [void]
39
+ def Fault(**props, &blk)
40
+ tag('soap:Fault', **props, &blk)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ Papercraft.extension(soap: Papercraft::Extensions::Soap)
@@ -47,17 +47,17 @@ module Papercraft
47
47
  # components. In cases where method names in the module clash with XML
48
48
  # tag names, you can use the `#tag` method to emit the relevant tag.
49
49
  #
50
- # module ComponentLibrary
51
- # def card(title, content)
52
- # div(class: 'card') {
53
- # h3 title
54
- # div(class: 'card-content') { emit_markdown content }
55
- # }
50
+ # module ComponentLibrary
51
+ # def card(title, content)
52
+ # div(class: 'card') {
53
+ # h3 title
54
+ # div(class: 'card-content') { emit_markdown content }
55
+ # }
56
+ # end
56
57
  # end
57
- # end
58
58
  #
59
- # Papercraft.extension(components: ComponentLibrary)
60
- # Papercraft.html { components.card('Foo', '**Bar**') }
59
+ # Papercraft.extension(components: ComponentLibrary)
60
+ # Papercraft.html { components.card('Foo', '**Bar**') }
61
61
  #
62
62
  # @param map [Hash] hash mapping methods to extension modules
63
63
  # @return [void]
@@ -160,16 +160,14 @@ module Papercraft
160
160
  # @param &block [Proc] block passed to method
161
161
  # @return [void]
162
162
  def method_missing(sym, *args, **opts, &block)
163
- # p method_missing: sym, self: self
164
163
  tag = sym.to_s
165
- repr = tag_repr(tag)
166
- code = S_TAG_METHOD % {
167
- tag: tag,
168
- TAG: tag.upcase,
169
- tag_pre: "<#{repr}".inspect,
170
- tag_close: "</#{repr}>".inspect
171
- }
172
- self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
164
+ if tag =~ /^[A-Z]/ && (Object.const_defined?(tag))
165
+ define_const_tag_method(tag)
166
+ # return send(tag, *args, **opts)
167
+ else
168
+ define_tag_method(tag)
169
+ end
170
+
173
171
  send(sym, *args, **opts, &block)
174
172
  end
175
173
 
@@ -184,6 +182,33 @@ module Papercraft
184
182
 
185
183
  private
186
184
 
185
+ # Defines a method that emits the given tag based on a constant. The
186
+ # constant must be defined on the main (Object) binding.
187
+ #
188
+ # @param tag [Symbol, String] tag/method name
189
+ # @return [void]
190
+ def define_const_tag_method(tag)
191
+ const = Object.const_get(tag)
192
+ self.class.define_method(tag) { |*a, **b, &blk|
193
+ emit const, *a, **b, &blk
194
+ }
195
+ end
196
+
197
+ # Defines a normal tag method.
198
+ #
199
+ # @param tag [Symbol, String] tag/method name
200
+ # @return [void]
201
+ def define_tag_method(tag)
202
+ repr = tag_repr(tag)
203
+ code = S_TAG_METHOD % {
204
+ tag: tag,
205
+ TAG: tag.upcase,
206
+ tag_pre: "<#{repr}".inspect,
207
+ tag_close: "</#{repr}>".inspect
208
+ }
209
+ self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
210
+ end
211
+
187
212
  # Emits an arbitrary object by converting it to string, then adding it to
188
213
  # the internal buffer. This method is called internally by `Renderer#emit`.
189
214
  #
@@ -252,7 +277,7 @@ module Papercraft
252
277
  # emit nothing
253
278
  else
254
279
  @buffer << S_SPACE << att_repr(k) <<
255
- S_EQUAL_QUOTE << v << S_QUOTE
280
+ S_EQUAL_QUOTE << escape_text(v) << S_QUOTE
256
281
  end
257
282
  end
258
283
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Papercraft
4
- VERSION = '0.21'
4
+ VERSION = '0.24'
5
5
  end
data/lib/papercraft.rb CHANGED
@@ -6,7 +6,6 @@ require 'kramdown-parser-gfm'
6
6
 
7
7
  require_relative 'papercraft/template'
8
8
  require_relative 'papercraft/renderer'
9
- require_relative 'papercraft/encoding'
10
9
  # require_relative 'papercraft/compiler'
11
10
 
12
11
 
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.21'
4
+ version: '0.24'
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-02-13 00:00:00.000000000 Z
11
+ date: 2022-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: escape_utils
@@ -134,8 +134,8 @@ files:
134
134
  - README.md
135
135
  - lib/papercraft.rb
136
136
  - lib/papercraft/compiler.rb
137
- - lib/papercraft/encoding.rb
138
137
  - lib/papercraft/extension_proxy.rb
138
+ - lib/papercraft/extensions/soap.rb
139
139
  - lib/papercraft/html.rb
140
140
  - lib/papercraft/json.rb
141
141
  - lib/papercraft/renderer.rb
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Papercraft
4
- # Papercraft::Encoding includes common encoding methods
5
- module Encoding
6
- # Encodes the given string to safe HTML text, converting special characters
7
- # into the respective HTML entities. If a non-string value is given, it is
8
- # converted to `String` using `#to_s`.
9
- #
10
- # @param text [String] string to be encoded
11
- # @return [String] HTML-encoded string
12
- def __html_encode__(text)
13
- EscapeUtils.escape_html(text.to_s)
14
- end
15
-
16
- # Encodes the given string to safe URI component, converting special
17
- # characters to URI entities. If a non-string value is given, it is
18
- # converted to `String` using `#to_s`.
19
- #
20
- # @param text [String] string to be encoded
21
- # @return [String] URI-encoded string
22
- def __uri_encode__(text)
23
- EscapeUtils.escape_uri(text.to_s)
24
- end
25
- end
26
- end