berns 3.3.1 → 4.0.0

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: 8befdd27a627569fd4d81d583c107e97af40e9b8f29423c4178fffa1decb92e9
4
- data.tar.gz: e268d19c3fafd596d310fefddcda6e9ca2393f06f668d52c3d92a7d748e41c77
3
+ metadata.gz: 5cfbcf19e2450ffa23b283ad0bb24717cde0bf6191bd8db538bf2cbb3936f205
4
+ data.tar.gz: f2639cdade9f1a3ee7b55a66666d23ce9843f5988567d3a630fc7403476825e8
5
5
  SHA512:
6
- metadata.gz: d14dbff87be26716aa466fab088ac036e25e27e72fd2893c4fb67f02422560c88d8bd2d15c08b176c6c9b4fa706ed3a4098edcfe54af273a43eef5cacd295142
7
- data.tar.gz: 34c7b95ee33095ea4e8712e280ad90cfe7d79d983996c72c0c245bb63ee9c10c28150a8bfbc3da0f56236ec5ac7df35f61a11f1f4a5e5f0255c167896e4bae5c
6
+ metadata.gz: f36bec9a6378fa664cc254a24700c63fc4a44720cfd5aad2b7e882dc6aa6ffa523031ec165270cb50d792c85dbcf0e1c0942d3ad22b64b4ec47ee29572170c03
7
+ data.tar.gz: a520befecc81e00cb2ae6c4a8b973965ee10cbdca0adb003d49ee6464478302ac97391651412f3945a5e6d92f76eaa2f5b51c5d5ef186a3c463c5b6928de564c
data/README.org CHANGED
@@ -1,6 +1,7 @@
1
1
  * Berns
2
2
 
3
3
  [[https://badge.fury.io/rb/berns][https://badge.fury.io/rb/berns.svg]]
4
+ [[https://github.com/evanleck/berns/actions/workflows/main.yml][https://github.com/evanleck/berns/actions/workflows/main.yml/badge.svg]]
4
5
 
5
6
  A utility library for generating HTML strings.
6
7
 
@@ -95,10 +96,102 @@ Note that this is an extremely naive implementation of HTML sanitization that
95
96
  literally just looks for "<" and ">" characters and removes the contents between
96
97
  them. This should probably only be used on trusted strings.
97
98
 
99
+ *** =build { content }=
100
+
101
+ The =build= method uses =Berns::Builder= to let you create HTML strings using a DSL.
102
+
103
+ #+begin_src ruby
104
+ Berns.build { h1 { 'Heading' } } # => '<h1>Heading</h1>'
105
+ #+end_src
106
+
107
+ See below for more on =Berns::Builder=.
108
+
109
+ *** =Berns::Builder= HTML DSL
110
+
111
+ Added in version 3.4.0 and heavily inspired by the likes of [[https://github.com/digital-fabric/papercraft][Papercraft]], [[https://github.com/markaby/markaby][Markaby]],
112
+ and [[https://github.com/activeadmin/arbre][Arbre]], the =Berns::Builder= class lets you create HTML strings using a DSL.
113
+
114
+ #+begin_src ruby
115
+ template = Berns::Builder.new do
116
+ h1 { 'Heading' }
117
+ p(class: 'paragraph') do
118
+ text 'Bare text here.'
119
+
120
+ b { 'Bold text here' }
121
+ end
122
+ end
123
+ #+end_src
124
+
125
+ Within the block provided to =Berns::Builder.new= every standard element method,
126
+ void element method, =#element=, and =#void= are available as methods and each
127
+ time you use one of those methods the result is appended to an internal buffer.
128
+ In addition, the =#text= method can be used to append a plain text string to the
129
+ buffer and that text will be HTML escaped, so it's good for untrusted content.
130
+
131
+ Once initialized, rendering the template to a string can be done with the
132
+ =#call= method and any arguments, positional or keyword, will be passed through
133
+ as-is to the block provided to =#new=.
134
+
135
+ #+begin_src ruby
136
+ string = template.call # =>
137
+ # <h1>
138
+ # Heading
139
+ # </h1>
140
+ # <p class='paragraph'>
141
+ # Bare text here.
142
+ # <b>
143
+ # Bold text here.
144
+ # </b>
145
+ # </p>
146
+ #+end_src
147
+
148
+ In addition to initializing a new instance of =Berns::Builder=, you can
149
+ construct and render a template to a string all at once with =Berns.build=.
150
+
151
+ #+begin_src ruby
152
+ Berns.build do
153
+ h1 { 'Heading' }
154
+ p(class: 'paragraph') do
155
+ text 'Bare text here.'
156
+
157
+ b { 'Bold text here' }
158
+ end
159
+ end # =>
160
+ # <h1>
161
+ # Heading
162
+ # </h1>
163
+ # <p class='paragraph'>
164
+ # Bare text here.
165
+ # <b>
166
+ # Bold text here.
167
+ # </b>
168
+ # </p>
169
+ #+end_src
170
+
171
+ Lastly, the block provided to =Berns::Builder.new= can take both positional and
172
+ keyword arguments.
173
+
174
+ #+begin_src ruby
175
+ template = Berns::Builder.new do |content, title:|
176
+ h1 { title }
177
+ p(class: 'paragraph') { content }
178
+ end
179
+
180
+ template.call('Some text.', title: 'The title') # =>
181
+ # <h1>
182
+ # The title
183
+ # </h1>
184
+ # <p>
185
+ # Some text.
186
+ # </p>
187
+ #+end_src
188
+
98
189
  *** Standard and void elements
99
190
 
100
191
  All standard and void HTML elements are defined as methods on Berns, so you can
101
- create e.g. a link with =Berns.a=. Below is the full list of standard elements.
192
+ create e.g. a link with =Berns.a=. Below is the full list of standard elements
193
+ which are also available in the constant =Berns::STANDARD= as an array of
194
+ symbols.
102
195
 
103
196
  #+begin_example
104
197
  a abbr address article aside audio b bdi bdo blockquote body button
@@ -111,15 +204,33 @@ table tbody td template textarea tfoot th thead time title tr u ul var
111
204
  video
112
205
  #+end_example
113
206
 
114
-
115
207
  Below is the full list of void elements that are defined as singleton methods on
116
- Berns.
208
+ Berns which are also available in the constant =Berns::VOID= as an array of
209
+ symbols.
117
210
 
118
211
  #+begin_example
119
212
  area base br col embed hr img input link menuitem meta param source track wbr
120
213
  #+end_example
121
214
 
215
+ ** Performance
216
+
217
+ Berns 3 is about three times faster than the pure Ruby implementation used in
218
+ version 2. See the file [[file:benchmarks/performance.rb][benchmarks/performance.rb]] for the benchmark code.
219
+
220
+ #+begin_example
221
+ Warming up --------------------------------------
222
+ element 27.373k i/100ms
223
+ berns 94.118k i/100ms
224
+ Calculating -------------------------------------
225
+ element 314.078k (± 4.5%) i/s - 1.588M in 5.065539s
226
+ berns 935.528k (± 6.1%) i/s - 4.706M in 5.049718s
227
+
228
+ Comparison:
229
+ berns: 935527.9 i/s
230
+ element: 314078.4 i/s - 2.98x (± 0.00) slower
231
+ #+end_example
232
+
122
233
  ** Trivia
123
234
 
124
- The name "Berns" is taken from the name of [[https://en.wikipedia.org/wiki/HTML#Development][the inventor of HTML]], [[https://en.wikipedia.org/wiki/Tim_Berners-Lee][Sir Tim
125
- Berners-Lee]].
235
+ The name "Berns" is taken from the name of [[https://en.wikipedia.org/wiki/HTML#Development][the inventor of HTML]],
236
+ [[https://en.wikipedia.org/wiki/Tim_Berners-Lee][Sir Tim Berners-Lee]].
data/ext/berns/berns.c CHANGED
@@ -228,7 +228,7 @@ static char * hash_value_to_attribute(const char *attr, const size_t attrlen, VA
228
228
 
229
229
  Check_Type(value, T_HASH);
230
230
 
231
- if (rb_hash_size(value) == 1) {
231
+ if (RHASH_SIZE(value) == 0) {
232
232
  return strdup("");
233
233
  }
234
234
 
@@ -439,7 +439,7 @@ static VALUE external_to_attribute(RB_UNUSED_VAR(VALUE self), VALUE attr, VALUE
439
439
  static VALUE external_to_attributes(RB_UNUSED_VAR(VALUE self), VALUE attributes) {
440
440
  Check_Type(attributes, T_HASH);
441
441
 
442
- if (rb_hash_size(attributes) == 1) {
442
+ if (RHASH_SIZE(attributes) == 0) {
443
443
  return rb_utf8_str_new_cstr("");
444
444
  }
445
445
 
@@ -453,37 +453,32 @@ static VALUE external_to_attributes(RB_UNUSED_VAR(VALUE self), VALUE attributes)
453
453
  }
454
454
 
455
455
  static char * void_element(const char *tag, size_t tlen, VALUE attributes) {
456
- /* T_IMEMO is what we get if an optional argument was not passed. */
457
- if (TYPE(attributes) == T_IMEMO) {
458
- size_t total = tag_olen + tlen + tag_clen + 1;
459
- char *string = malloc(total);
460
- char *ptr;
461
- char *end = string + total;
456
+ const char *empty = "";
457
+ char *attrs = hash_value_to_attribute(empty, 0, attributes);
458
+ size_t alen = strlen(attrs);
462
459
 
463
- ptr = stecpy(string, tag_open, end);
464
- ptr = stecpy(ptr, tag, end);
465
- ptr = stecpy(ptr, tag_close, end);
460
+ size_t total = tag_olen + tlen + tag_clen + 1;
466
461
 
467
- return string;
468
- } else {
469
- const char *empty = "";
470
- char *attrs = hash_value_to_attribute(empty, 0, attributes);
462
+ /* If we have some attributes, add a space and the attributes' length. */
463
+ if (alen > 0) {
464
+ total += splen + alen;
465
+ }
471
466
 
472
- size_t total = tag_olen + tlen + splen + strlen(attrs) + tag_clen + 1;
473
- char *string = malloc(total);
474
- char *ptr;
475
- char *end = string + total;
467
+ char *dest = malloc(total);
468
+ char *ptr = NULL;
469
+ char *end = dest + total;
476
470
 
477
- ptr = stecpy(string, tag_open, end);
478
- ptr = stecpy(ptr, tag, end);
471
+ ptr = stecpy(dest, tag_open, end);
472
+ ptr = stecpy(ptr, tag, end);
473
+
474
+ if (alen > 0) {
479
475
  ptr = stecpy(ptr, space, end);
480
476
  ptr = stecpy(ptr, attrs, end);
481
- ptr = stecpy(ptr, tag_close, end);
477
+ }
482
478
 
483
- free(attrs);
479
+ ptr = stecpy(ptr, tag_close, end);
484
480
 
485
- return string;
486
- }
481
+ return dest;
487
482
  }
488
483
 
489
484
  /*
data/ext/berns/extconf.rb CHANGED
@@ -9,5 +9,6 @@ append_cflags '-Wstrict-overflow'
9
9
  append_cflags '-flto'
10
10
  append_cflags '-fno-strict-aliasing'
11
11
  append_cflags '-msse4'
12
+ append_cflags '-std=c99'
12
13
 
13
14
  create_makefile 'berns/berns'