papercraft 0.25 → 0.27

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: f23902f7431dcbd6c1180e26f612ae5099d4e7f2ba468dd0e0e5e9a76e324ef4
4
- data.tar.gz: 5bf38e4faea0ab6c6145d769b24b416e467836b29c6d8856bb96442f86b43bfe
3
+ metadata.gz: bd2f4f4d1ebc2cfc5718079d68c9393b3d95def9c02b057107425ddd5b45eaf3
4
+ data.tar.gz: f3f82f29227e22e5e31b0d685bcab211ebbef0ecf8a4433d251cb1f204875cf7
5
5
  SHA512:
6
- metadata.gz: 69ed90f079f1db073bbc18b1b631c13cbcd2db5dae9e512781046fb7fa5ab0a164653137b28c201f48671d77e4d08ff1da3818381aca5d3686d61eb185f8a586
7
- data.tar.gz: 85681c583e3e145ca27a52638e0d3370fa94462d5baaae8cccb477a1a2938ad56f3040ee4f6cceb2757b49019890bcae505bcdc008e2ff0931987f09ab9eb91a
6
+ metadata.gz: 7389861bea04a92e06ce1a53a682ef3b4db1bf975bb7f5e63cef0ed6c1a4ebb4b92920a0bb4ea04eba24dc72b41c70ba8fac0d8aa605a2b5a720d7860198b7e0
7
+ data.tar.gz: 2a617260deef291c56cd0c3fc1b275d47dd1dc95bdeeafc69289d630260480e49126c29f0ec77c177fd6c1032c633ba2568be1ffb767e13f91e51b5a9c298831
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.27 2023-01-19
2
+
3
+ - Fix rendering of HTML void element tags
4
+
5
+ ## 0.26 2023-01-13
6
+
7
+ - Add support for namespaced local extensions using `#extend`
8
+
1
9
  ## 0.25 2023-01-12
2
10
 
3
11
  - Implement `#def_tag` for defining custom tags inline
data/README.md CHANGED
@@ -86,6 +86,7 @@ hello.render('world')
86
86
  - [XML Templates](#xml-templates)
87
87
  - [JSON Templates](#json-templates)
88
88
  - [Papercraft Extensions](#papercraft-extensions)
89
+ - [Extending Specific Templates](#extending-specific-templates)
89
90
  - [Inline Helper Methods](#inline-helper-methods)
90
91
  - [Bundled Extensions](#bundled-extensions)
91
92
  - [API Reference](#api-reference)
@@ -682,7 +683,40 @@ Papercraft.html {
682
683
  }
683
684
  ```
684
685
 
685
- ## Inline Helper Methods
686
+ ### Extending Specific Templates
687
+
688
+ Sometimes you wish to extend a specific template locally, without the extension
689
+ API being available to other templates. To do this you can use `#extend`:
690
+
691
+ ```ruby
692
+ module CustomTags
693
+ def label(text)
694
+ span text, class: 'label'
695
+ end
696
+ end
697
+
698
+ Papercraft.html {
699
+ extend CustomTags
700
+
701
+ label 'foo'
702
+ }
703
+ ```
704
+
705
+ The extension is in effect as long as the template is processing, so it is also
706
+ accessible to any sub templates that are emitted.
707
+
708
+ Local extensions can also be namespaced by passing `#extend` a hash mapping
709
+ namespaces to modules:
710
+
711
+ ```ruby
712
+ Papercraft.html {
713
+ extend custom: CustomTags
714
+
715
+ custom.label 'foo'
716
+ }
717
+ ```
718
+
719
+ ### Inline Helper Methods
686
720
 
687
721
  In addition to proper extensions defined in modules, you can also define
688
722
  individual extension methods inline in your Papercraft templates. You can do
@@ -733,7 +767,7 @@ def_tag(:section) do |title, &inner|
733
767
  end
734
768
  ```
735
769
 
736
- ## Bundled Extensions
770
+ ### Bundled Extensions
737
771
 
738
772
  Papercraft comes bundled with a few extensions that address common use cases.
739
773
  All bundled extensions are namespaced under `Papercraft::Extensions`, and must
@@ -742,7 +776,7 @@ be specifically required in order to be available to templates.
742
776
  For all bundled Papercraft extensions, there's no need to call
743
777
  `Papercraft.extension`, requiring the extension is sufficient.
744
778
 
745
- ### SOAP Extension
779
+ #### SOAP Extension
746
780
 
747
781
  > The SOAP extension was contributed by [@aemadrid](https://github.com/aemadrid).
748
782
 
@@ -88,6 +88,21 @@ module Papercraft
88
88
 
89
89
  private
90
90
 
91
+ # Returns true if the given tag is a void element, in order to render a self
92
+ # closing tag. See spec: https://html.spec.whatwg.org/multipage/syntax.html#void-elements.
93
+ #
94
+ # @param text [String] tag
95
+ # @return [Bool] is it a void element
96
+ def is_void_element_tag?(tag)
97
+ case tag
98
+ #
99
+ when 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'source', 'track', 'wbr'
100
+ true
101
+ else
102
+ false
103
+ end
104
+ end
105
+
91
106
  # Escapes the given text using HTML entities.
92
107
  #
93
108
  # @param text [String] text
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './extension_proxy'
4
+
3
5
  module Papercraft
4
6
  # Markup (HTML/XML) extensions
5
7
  module Tags
@@ -8,6 +10,7 @@ module Papercraft
8
10
  S_LT_SLASH = '</'
9
11
  S_SPACE_LT_SLASH = ' </'
10
12
  S_SLASH_GT = '/>'
13
+ S_GT_LT_SLASH = '></'
11
14
  S_SPACE = ' '
12
15
  S_EQUAL_QUOTE = '="'
13
16
  S_QUOTE = '"'
@@ -19,6 +22,36 @@ module Papercraft
19
22
  S_TAG_%<TAG>s_PRE = %<tag_pre>s
20
23
  S_TAG_%<TAG>s_CLOSE = %<tag_close>s
21
24
 
25
+ def %<tag>s(text = nil, **props, &block)
26
+ if text.is_a?(Hash) && props.empty?
27
+ props = text
28
+ text = nil
29
+ end
30
+
31
+ @buffer << S_TAG_%<TAG>s_PRE
32
+ emit_props(props) unless props.empty?
33
+
34
+ if block
35
+ @buffer << S_GT
36
+ instance_eval(&block)
37
+ @buffer << S_TAG_%<TAG>s_CLOSE
38
+ elsif Proc === text
39
+ @buffer << S_GT
40
+ emit(text)
41
+ @buffer << S_TAG_%<TAG>s_CLOSE
42
+ elsif text
43
+ @buffer << S_GT << escape_text(text.to_s) << S_TAG_%<TAG>s_CLOSE
44
+ else
45
+ @buffer << S_GT << S_TAG_%<TAG>s_CLOSE
46
+ end
47
+ end
48
+ EOF
49
+
50
+ S_VOID_TAG_METHOD_LINE = __LINE__ + 2
51
+ S_VOID_TAG_METHOD = <<~EOF
52
+ S_TAG_%<TAG>s_PRE = %<tag_pre>s
53
+ S_TAG_%<TAG>s_CLOSE = %<tag_close>s
54
+
22
55
  def %<tag>s(text = nil, **props, &block)
23
56
  if text.is_a?(Hash) && props.empty?
24
57
  props = text
@@ -147,8 +180,10 @@ module Papercraft
147
180
  @buffer << S_LT_SLASH << tag << S_GT
148
181
  elsif text
149
182
  @buffer << S_GT << escape_text(text.to_s) << S_LT_SLASH << tag << S_GT
150
- else
183
+ elsif is_void_element_tag?(sym)
151
184
  @buffer << S_SLASH_GT
185
+ else
186
+ @buffer << S_GT_LT_SLASH << tag << S_GT
152
187
  end
153
188
  end
154
189
 
@@ -203,6 +238,43 @@ module Papercraft
203
238
  self.class.define_method(sym, &block)
204
239
  end
205
240
 
241
+ alias_method :orig_extend, :extend
242
+
243
+ # Extends the template with the provided module or map of modules. When
244
+ # given a module, the template body will be extended with the module,
245
+ # and will have access to all the module's methods:
246
+ #
247
+ # module CustomTags
248
+ # def label(text)
249
+ # span text, class: 'label'
250
+ # end
251
+ # end
252
+ #
253
+ # Papercraft.html {
254
+ # extend CustomTags
255
+ # label('foo')
256
+ # }
257
+ #
258
+ # When given a hash, each module in the hash is namespaced, and can be
259
+ # accessed using its key:
260
+ #
261
+ # Papercraft.html {
262
+ # extend custom: CustomTags
263
+ # custom.label('foo')
264
+ # }
265
+ #
266
+ # @param ext [Module, Hash] extension module or hash mapping symbols to modules
267
+ # @return [Object] self
268
+ def extend(ext)
269
+ if ext.is_a?(Module)
270
+ orig_extend(ext)
271
+ else
272
+ ext.each do |sym, mod|
273
+ define_extension_method(sym, mod)
274
+ end
275
+ end
276
+ end
277
+
206
278
  private
207
279
 
208
280
  # Defines a method that emits the given tag based on a constant. The
@@ -223,13 +295,31 @@ module Papercraft
223
295
  # @return [void]
224
296
  def define_tag_method(tag)
225
297
  repr = tag_repr(tag)
226
- code = S_TAG_METHOD % {
298
+ if is_void_element_tag?(tag)
299
+ tmpl = S_VOID_TAG_METHOD
300
+ line = S_VOID_TAG_METHOD_LINE
301
+ else
302
+ tmpl = S_TAG_METHOD
303
+ line = S_TAG_METHOD_LINE
304
+ end
305
+ code = tmpl % {
227
306
  tag: tag,
228
307
  TAG: tag.upcase,
229
308
  tag_pre: "<#{repr}".inspect,
230
309
  tag_close: "</#{repr}>".inspect
231
310
  }
232
- self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
311
+ self.class.class_eval(code, __FILE__, line)
312
+ end
313
+
314
+ # Defines a namespace referring to the given module.
315
+ #
316
+ # @param sym [Symbol] namespace
317
+ # @param mod [Module] module
318
+ # @return [void]
319
+ def define_extension_method(sym, mod)
320
+ self.singleton_class.define_method(sym) do
321
+ (@extension_proxies ||= {})[mod] ||= ExtensionProxy.new(self, mod)
322
+ end
233
323
  end
234
324
 
235
325
  # Emits an arbitrary object by converting it to string, then adding it to
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Papercraft
4
- VERSION = '0.25'
4
+ VERSION = '0.27'
5
5
  end
@@ -10,7 +10,15 @@ module Papercraft
10
10
 
11
11
  private
12
12
 
13
- # Converts a tag to its string representation. Underscores will be converted
13
+ # Returns false (no void elements in XML)
14
+ #
15
+ # @param tag [String] tag
16
+ # @return [false] false
17
+ def is_void_element_tag?(tag)
18
+ false
19
+ end
20
+
21
+ # Converts a tag to its string representation. Underscores will be converted
14
22
  # to dashes, double underscores will be converted to colon.
15
23
  #
16
24
  # @param tag [Symbol, String] tag
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.25'
4
+ version: '0.27'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-12 00:00:00.000000000 Z
11
+ date: 2023-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: escape_utils