papercraft 0.19 → 0.20

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: f0f4910bd26625ca0349b1c471338fb4d13e8055e88367b5cad16f91cdee7531
4
- data.tar.gz: 38e43978278ba069e3767abd94d83c676f42692f5eb55f1be4b4067fae2f935e
3
+ metadata.gz: 2eaf6ba31b9300176af0bf55b76f7bbdc16508d0e495ed1d76f9f273ea88f250
4
+ data.tar.gz: 90e132928ebfe78e577e71c8dc498f0ce1b1f2c58f453fbedaad96121c448a48
5
5
  SHA512:
6
- metadata.gz: b096452cebe7b6bb34a428f4920a5940e5b745c86b54188a984a77df6175145cf6645753e6ae58b3df89813919920a17a96610e010724bc50077c6f9accc7293
7
- data.tar.gz: 8d1cd5b2d6b70ee9ef0a748a064bbd6d1630cfa926663aded95a01c26ce289a159e2548068bf8210c5e8d37ba26c9671eb4a00fe4790a47bec6dd822b4de5d5d
6
+ metadata.gz: fcada325a3f8cd1c4cbe38674efaf6a86d0eb947ad5815d07778e2a09a54bee2c7d6b731e87d110390e9c87abc0a61f81cbc4cb30fdce11a4fc8a8cd322466a0
7
+ data.tar.gz: 031c86f7dade95af3dca979b4543fcb26e1fab2eb98c5642746d6efcf8b4bd56fe30b70f2f5aa8309352f421cae9f116a901f464216f54a0be50630dcc52815f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.20 2022-02-13
2
+
3
+ - Add support for XML namespaced tags and attributes (#9)
4
+ - Move and refactor HTML/XML common code to Tags module
5
+
1
6
  ## 0.19 2022-02-05
2
7
 
3
8
  - Rename `Papercraft::Component` to `Papercraft::Template`
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './tags'
4
+
3
5
  module Papercraft
4
6
  # HTML Markup extensions
5
7
  module HTML
8
+ include Tags
9
+
6
10
  # Emits the p tag (overrides Object#p)
7
11
  #
8
12
  # @param text [String] text content of tag
@@ -81,5 +85,12 @@ module Papercraft
81
85
  def emit_markdown(markdown, **opts)
82
86
  emit Papercraft.markdown(markdown, **opts)
83
87
  end
88
+
89
+ private
90
+
91
+ # Escapes the given text using XML entities.
92
+ def escape_text(text)
93
+ EscapeUtils.escape_html(text.to_s)
94
+ end
84
95
  end
85
96
  end
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'escape_utils'
4
-
5
3
  require_relative './html'
4
+ require_relative './xml'
6
5
  require_relative './json'
7
6
  require_relative './extension_proxy'
8
7
 
@@ -10,7 +9,7 @@ module Papercraft
10
9
 
11
10
  # A Renderer renders a Papercraft template into a string
12
11
  class Renderer
13
-
12
+
14
13
  class << self
15
14
 
16
15
  # Verifies that the given template proc can be called with the given
@@ -45,7 +44,7 @@ module Papercraft
45
44
  # methods to extension modules. The methods will be available to all
46
45
  # Papercraft templates. Extension methods are executed in the context of
47
46
  # the the renderer instance, so they can look just like normal proc
48
- # components. In cases where method names in the module clash with HTML
47
+ # components. In cases where method names in the module clash with XML
49
48
  # tag names, you can use the `#tag` method to emit the relevant tag.
50
49
  #
51
50
  # module ComponentLibrary
@@ -113,99 +112,6 @@ module Papercraft
113
112
  @buffer
114
113
  end
115
114
 
116
- # The tag method template below is optimized for performance. Do not touch!
117
-
118
- S_TAG_METHOD_LINE = __LINE__ + 2
119
- S_TAG_METHOD = <<~EOF
120
- S_TAG_%<TAG>s_PRE = %<tag_pre>s
121
- S_TAG_%<TAG>s_CLOSE = %<tag_close>s
122
-
123
- def %<tag>s(text = nil, **props, &block)
124
- if text.is_a?(Hash) && props.empty?
125
- props = text
126
- text = nil
127
- end
128
-
129
- @buffer << S_TAG_%<TAG>s_PRE
130
- emit_props(props) unless props.empty?
131
-
132
- if block
133
- @buffer << S_GT
134
- instance_eval(&block)
135
- @buffer << S_TAG_%<TAG>s_CLOSE
136
- elsif Proc === text
137
- @buffer << S_GT
138
- emit(text)
139
- @buffer << S_TAG_%<TAG>s_CLOSE
140
- elsif text
141
- @buffer << S_GT << escape_text(text.to_s) << S_TAG_%<TAG>s_CLOSE
142
- else
143
- @buffer << S_SLASH_GT
144
- end
145
- end
146
- EOF
147
-
148
- # Emits an HTML tag with the given content, properties and optional block.
149
- # This method is an alternative to emitting HTML tags using dynamically
150
- # created methods. This is particularly useful when using extensions that
151
- # have method names that clash with HTML tags, such as `button` or `a`, or
152
- # when you need to override the behaviour of a particular HTML tag.
153
- #
154
- # The following two method calls have the same effect:
155
- #
156
- # button 'text', id: 'button1'
157
- # tag :button, 'text', id: 'button1'
158
- #
159
- # @param sym [Symbol, String] HTML tag
160
- # @param text [String, nil] tag content
161
- # @param **props [Hash] tag attributes
162
- # @param &block [Proc] optional inner HTML
163
- # @return [void]
164
- def tag(sym, text = nil, **props, &block)
165
- if text.is_a?(Hash) && props.empty?
166
- props = text
167
- text = nil
168
- end
169
-
170
- tag = sym.to_s.tr('_', '-')
171
-
172
- @buffer << S_LT << tag
173
- emit_props(props) unless props.empty?
174
-
175
- if block
176
- @buffer << S_GT
177
- instance_eval(&block)
178
- @buffer << S_LT_SLASH << tag << S_GT
179
- elsif Proc === text
180
- @buffer << S_GT
181
- emit(text)
182
- @buffer << S_LT_SLASH << tag << S_GT
183
- elsif text
184
- @buffer << S_GT << escape_text(text.to_s) << S_LT_SLASH << tag << S_GT
185
- else
186
- @buffer << S_SLASH_GT
187
- end
188
- end
189
-
190
- # Catches undefined tag method call and handles it by defining the method.
191
- #
192
- # @param sym [Symbol] HTML tag or component identifier
193
- # @param args [Array] method arguments
194
- # @param opts [Hash] named method arguments
195
- # @param &block [Proc] block passed to method
196
- # @return [void]
197
- def method_missing(sym, *args, **opts, &block)
198
- tag = sym.to_s
199
- code = S_TAG_METHOD % {
200
- tag: tag,
201
- TAG: tag.upcase,
202
- tag_pre: "<#{tag.tr('_', '-')}".inspect,
203
- tag_close: "</#{tag.tr('_', '-')}>".inspect
204
- }
205
- self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
206
- send(sym, *args, **opts, &block)
207
- end
208
-
209
115
  # Emits the given object into the rendering buffer. If the given object is a
210
116
  # proc or a component, `emit` will passes any additional arguments and named
211
117
  # arguments to the object when rendering it. If the given object is nil,
@@ -256,7 +162,7 @@ module Papercraft
256
162
  # Papercraft templates to inject state into sibling components, regardless
257
163
  # of the component's order in the container component. For example, a nested
258
164
  # component may set an instance variable used by another component. This is
259
- # an elegant solution to the problem of setting the HTML page's title, or
165
+ # an elegant solution to the problem of setting the XML page's title, or
260
166
  # adding elements to the `<head>` section. Here's how a title can be
261
167
  # controlled from a nested component:
262
168
  #
@@ -288,24 +194,6 @@ module Papercraft
288
194
  @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY)
289
195
  end
290
196
 
291
- S_LT = '<'
292
- S_GT = '>'
293
- S_LT_SLASH = '</'
294
- S_SPACE_LT_SLASH = ' </'
295
- S_SLASH_GT = '/>'
296
- S_SPACE = ' '
297
- S_EQUAL_QUOTE = '="'
298
- S_QUOTE = '"'
299
-
300
- # Emits text into the rendering buffer, escaping any special characters to
301
- # the respective HTML entities.
302
- #
303
- # @param data [String] text
304
- # @return [void]
305
- def text(data)
306
- @buffer << escape_text(data)
307
- end
308
-
309
197
  private
310
198
 
311
199
  # Escapes text. This method must be overriden in descendant classes.
@@ -322,29 +210,6 @@ module Papercraft
322
210
  (@emit_yield_stack ||= []) << block
323
211
  end
324
212
 
325
- # Emits tag attributes into the rendering buffer
326
- # @param props [Hash] tag attributes
327
- # @return [void]
328
- def emit_props(props)
329
- props.each { |k, v|
330
- case k
331
- when :src, :href
332
- @buffer << S_SPACE << k.to_s << S_EQUAL_QUOTE <<
333
- EscapeUtils.escape_uri(v) << S_QUOTE
334
- else
335
- case v
336
- when true
337
- @buffer << S_SPACE << k.to_s.tr('_', '-')
338
- when false, nil
339
- # emit nothing
340
- else
341
- @buffer << S_SPACE << k.to_s.tr('_', '-') <<
342
- S_EQUAL_QUOTE << v << S_QUOTE
343
- end
344
- end
345
- }
346
- end
347
-
348
213
  # Renders a deferred proc by evaluating it, then adding the rendered result
349
214
  # to the buffer.
350
215
  #
@@ -366,23 +231,11 @@ module Papercraft
366
231
  # Implements an HTML renderer
367
232
  class HTMLRenderer < Renderer
368
233
  include HTML
369
-
370
- private
371
-
372
- # Escapes the given text using HTML entities.
373
- def escape_text(text)
374
- EscapeUtils.escape_html(text.to_s)
375
- end
376
234
  end
377
235
 
378
236
  # Implements an XML renderer
379
237
  class XMLRenderer < Renderer
380
- private
381
-
382
- # Escapes the given text using XML entities.
383
- def escape_text(text)
384
- EscapeUtils.escape_xml(text.to_s)
385
- end
238
+ include XML
386
239
  end
387
240
 
388
241
  class JSONRenderer < Renderer
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Papercraft
4
+ # Markup (HTML/XML) extensions
5
+ module Tags
6
+ S_LT = '<'
7
+ S_GT = '>'
8
+ S_LT_SLASH = '</'
9
+ S_SPACE_LT_SLASH = ' </'
10
+ S_SLASH_GT = '/>'
11
+ S_SPACE = ' '
12
+ S_EQUAL_QUOTE = '="'
13
+ S_QUOTE = '"'
14
+
15
+ # The tag method template below is optimized for performance. Do not touch!
16
+
17
+ S_TAG_METHOD_LINE = __LINE__ + 2
18
+ S_TAG_METHOD = <<~EOF
19
+ S_TAG_%<TAG>s_PRE = %<tag_pre>s
20
+ S_TAG_%<TAG>s_CLOSE = %<tag_close>s
21
+
22
+ def %<tag>s(text = nil, **props, &block)
23
+ if text.is_a?(Hash) && props.empty?
24
+ props = text
25
+ text = nil
26
+ end
27
+
28
+ @buffer << S_TAG_%<TAG>s_PRE
29
+ emit_props(props) unless props.empty?
30
+
31
+ if block
32
+ @buffer << S_GT
33
+ instance_eval(&block)
34
+ @buffer << S_TAG_%<TAG>s_CLOSE
35
+ elsif Proc === text
36
+ @buffer << S_GT
37
+ emit(text)
38
+ @buffer << S_TAG_%<TAG>s_CLOSE
39
+ elsif text
40
+ @buffer << S_GT << escape_text(text.to_s) << S_TAG_%<TAG>s_CLOSE
41
+ else
42
+ @buffer << S_SLASH_GT
43
+ end
44
+ end
45
+ EOF
46
+
47
+ # Emits an XML tag with the given content, properties and optional block.
48
+ # This method is an alternative to emitting XML tags using dynamically
49
+ # created methods. This is particularly useful when using extensions that
50
+ # have method names that clash with XML tags, such as `button` or `a`, or
51
+ # when you need to override the behaviour of a particular XML tag.
52
+ #
53
+ # The following two method calls have the same effect:
54
+ #
55
+ # button 'text', id: 'button1'
56
+ # tag :button, 'text', id: 'button1'
57
+ #
58
+ # @param sym [Symbol, String] XML tag
59
+ # @param text [String, nil] tag content
60
+ # @param **props [Hash] tag attributes
61
+ # @param &block [Proc] optional inner XML
62
+ # @return [void]
63
+ def tag(sym, text = nil, **props, &block)
64
+ if text.is_a?(Hash) && props.empty?
65
+ props = text
66
+ text = nil
67
+ end
68
+
69
+ tag = tag_repr(sym)
70
+
71
+ @buffer << S_LT << tag
72
+ emit_props(props) unless props.empty?
73
+
74
+ if block
75
+ @buffer << S_GT
76
+ instance_eval(&block)
77
+ @buffer << S_LT_SLASH << tag << S_GT
78
+ elsif Proc === text
79
+ @buffer << S_GT
80
+ emit(text)
81
+ @buffer << S_LT_SLASH << tag << S_GT
82
+ elsif text
83
+ @buffer << S_GT << escape_text(text.to_s) << S_LT_SLASH << tag << S_GT
84
+ else
85
+ @buffer << S_SLASH_GT
86
+ end
87
+ end
88
+
89
+ # Catches undefined tag method call and handles it by defining the method.
90
+ #
91
+ # @param sym [Symbol] XML tag or component identifier
92
+ # @param args [Array] method arguments
93
+ # @param opts [Hash] named method arguments
94
+ # @param &block [Proc] block passed to method
95
+ # @return [void]
96
+ def method_missing(sym, *args, **opts, &block)
97
+ # p method_missing: sym, self: self
98
+ tag = sym.to_s
99
+ repr = tag_repr(tag)
100
+ code = S_TAG_METHOD % {
101
+ tag: tag,
102
+ TAG: tag.upcase,
103
+ tag_pre: "<#{repr}".inspect,
104
+ tag_close: "</#{repr}>".inspect
105
+ }
106
+ self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
107
+ send(sym, *args, **opts, &block)
108
+ end
109
+
110
+ # Emits text into the rendering buffer, escaping any special characters to
111
+ # the respective XML entities.
112
+ #
113
+ # @param data [String] text
114
+ # @return [void]
115
+ def text(data)
116
+ @buffer << escape_text(data)
117
+ end
118
+
119
+ private
120
+
121
+ def tag_repr(tag)
122
+ tag.to_s.tr('_', '-')
123
+ end
124
+
125
+ def att_repr(att)
126
+ att.to_s.tr('_', '-')
127
+ end
128
+
129
+ # Emits tag attributes into the rendering buffer
130
+ # @param props [Hash] tag attributes
131
+ # @return [void]
132
+ def emit_props(props)
133
+ props.each { |k, v|
134
+ case k
135
+ when :src, :href
136
+ @buffer << S_SPACE << k.to_s << S_EQUAL_QUOTE <<
137
+ EscapeUtils.escape_uri(v) << S_QUOTE
138
+ else
139
+ case v
140
+ when true
141
+ @buffer << S_SPACE << att_repr(k)
142
+ when false, nil
143
+ # emit nothing
144
+ else
145
+ @buffer << S_SPACE << att_repr(k) <<
146
+ S_EQUAL_QUOTE << v << S_QUOTE
147
+ end
148
+ end
149
+ }
150
+ end
151
+ end
152
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Papercraft
4
- VERSION = '0.19'
4
+ VERSION = '0.20'
5
5
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'escape_utils'
4
+ require_relative './tags'
5
+
6
+ module Papercraft
7
+ # XML renderer extensions
8
+ module XML
9
+ include Tags
10
+
11
+ private
12
+
13
+ def tag_repr(tag)
14
+ tag.to_s.gsub('__', ':').tr('_', '-')
15
+ end
16
+
17
+ def att_repr(att)
18
+ att.to_s.gsub('__', ':').tr('_', '-')
19
+ end
20
+
21
+ # Escapes the given text using XML entities.
22
+ def escape_text(text)
23
+ EscapeUtils.escape_xml(text.to_s)
24
+ end
25
+ end
26
+ end
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.19'
4
+ version: '0.20'
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-05 00:00:00.000000000 Z
11
+ date: 2022-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: escape_utils
@@ -139,8 +139,10 @@ files:
139
139
  - lib/papercraft/html.rb
140
140
  - lib/papercraft/json.rb
141
141
  - lib/papercraft/renderer.rb
142
+ - lib/papercraft/tags.rb
142
143
  - lib/papercraft/template.rb
143
144
  - lib/papercraft/version.rb
145
+ - lib/papercraft/xml.rb
144
146
  - papercraft.png
145
147
  homepage: http://github.com/digital-fabric/papercraft
146
148
  licenses: