berns 3.2.1 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +15 -16
- data/README.org +101 -3
- data/ext/berns/berns.c +37 -35
- data/lib/berns/berns.bundle +0 -0
- data/lib/berns/builder.rb +59 -0
- data/lib/berns/version.rb +1 -1
- data/lib/berns.rb +23 -0
- metadata +10 -8
- data/lib/berns/berns.so +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcded7fea247763fc7b27807c2c945943e0f08895b117ae086e4041bf1b08371
|
4
|
+
data.tar.gz: 965518819feb3eef689f19b7cc5470a973198b891e00f9d7f8ac7fd5b4620119
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f023bfcde5d5b272477d2dd7e7c2d6de430c4ec544d6a10da75f7ff72b5980349d282710796a2ac5c4bede5e72df5456dd733828c7869f3f1231b26314f450e4
|
7
|
+
data.tar.gz: d606bdeed6b199fa467c4f80236d9dab40ef0db13e3105397bbe411caffa71c00274ea5902e1ce3f4764ab915cada0a9574d133905f07e28a348e2e28f9b7cfa
|
data/LICENSE.txt
CHANGED
@@ -1,21 +1,20 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright
|
3
|
+
Copyright © 2021 Taylor Beck and Evan Lecklider
|
4
4
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the “Software”), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
11
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
13
|
-
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
14
|
|
15
|
-
THE SOFTWARE IS PROVIDED
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
THE SOFTWARE.
|
15
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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,84 @@ 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
|
+
|
98
171
|
*** Standard and void elements
|
99
172
|
|
100
173
|
All standard and void HTML elements are defined as methods on Berns, so you can
|
101
|
-
create e.g.
|
174
|
+
create e.g. a link with =Berns.a=. Below is the full list of standard elements
|
175
|
+
which are also available in the constant =Berns::STANDARD= as an array of
|
176
|
+
symbols.
|
102
177
|
|
103
178
|
#+begin_example
|
104
179
|
a abbr address article aside audio b bdi bdo blockquote body button
|
@@ -111,10 +186,33 @@ table tbody td template textarea tfoot th thead time title tr u ul var
|
|
111
186
|
video
|
112
187
|
#+end_example
|
113
188
|
|
114
|
-
|
115
189
|
Below is the full list of void elements that are defined as singleton methods on
|
116
|
-
Berns
|
190
|
+
Berns which are also available in the constant =Berns::VOID= as an array of
|
191
|
+
symbols.
|
117
192
|
|
118
193
|
#+begin_example
|
119
194
|
area base br col embed hr img input link menuitem meta param source track wbr
|
120
195
|
#+end_example
|
196
|
+
|
197
|
+
** Performance
|
198
|
+
|
199
|
+
Berns 3 is about three times faster than the pure Ruby implementation used in
|
200
|
+
version 2. See the file [[file:benchmarks/performance.rb][benchmarks/performance.rb]] for the benchmark code.
|
201
|
+
|
202
|
+
#+begin_example
|
203
|
+
Warming up --------------------------------------
|
204
|
+
element 27.373k i/100ms
|
205
|
+
berns 94.118k i/100ms
|
206
|
+
Calculating -------------------------------------
|
207
|
+
element 314.078k (± 4.5%) i/s - 1.588M in 5.065539s
|
208
|
+
berns 935.528k (± 6.1%) i/s - 4.706M in 5.049718s
|
209
|
+
|
210
|
+
Comparison:
|
211
|
+
berns: 935527.9 i/s
|
212
|
+
element: 314078.4 i/s - 2.98x (± 0.00) slower
|
213
|
+
#+end_example
|
214
|
+
|
215
|
+
** Trivia
|
216
|
+
|
217
|
+
The name "Berns" is taken from the name of [[https://en.wikipedia.org/wiki/HTML#Development][the inventor of HTML]],
|
218
|
+
[[https://en.wikipedia.org/wiki/Tim_Berners-Lee][Sir Tim Berners-Lee]].
|
data/ext/berns/berns.c
CHANGED
@@ -64,7 +64,7 @@ static const size_t sllen = 1;
|
|
64
64
|
static VALUE external_##element_name##_element(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { \
|
65
65
|
rb_check_arity(argc, 0, 1); \
|
66
66
|
\
|
67
|
-
CONTENT_FROM_BLOCK
|
67
|
+
CONTENT_FROM_BLOCK \
|
68
68
|
const char *tag = #element_name; \
|
69
69
|
char *string = element(tag, strlen(tag), RSTRING_PTR(content), RSTRING_LEN(content), argv[0]); \
|
70
70
|
VALUE rstring = rb_utf8_str_new_cstr(string); \
|
@@ -110,17 +110,24 @@ static VALUE external_sanitize(RB_UNUSED_VAR(VALUE self), VALUE string) {
|
|
110
110
|
char *str = RSTRING_PTR(string);
|
111
111
|
|
112
112
|
char dest[slen + 1];
|
113
|
-
|
114
|
-
int
|
115
|
-
int
|
113
|
+
|
114
|
+
unsigned int index = 0;
|
115
|
+
unsigned int open = 0;
|
116
|
+
unsigned int modified = 0;
|
117
|
+
unsigned int entity = 0;
|
116
118
|
|
117
119
|
for (unsigned int i = 0; i < slen; i++) {
|
118
120
|
if (str[i] == '<') {
|
119
121
|
open = 1;
|
120
|
-
|
122
|
+
modified = 1;
|
121
123
|
} else if (str[i] == '>') {
|
122
124
|
open = 0;
|
123
|
-
} else if (
|
125
|
+
} else if (str[i] == '&') {
|
126
|
+
entity = 1;
|
127
|
+
modified = 1;
|
128
|
+
} else if (str[i] == ';') {
|
129
|
+
entity = 0;
|
130
|
+
} else if (!open && !entity) {
|
124
131
|
dest[index++] = str[i];
|
125
132
|
}
|
126
133
|
}
|
@@ -128,10 +135,10 @@ static VALUE external_sanitize(RB_UNUSED_VAR(VALUE self), VALUE string) {
|
|
128
135
|
dest[index] = '\0';
|
129
136
|
|
130
137
|
/*
|
131
|
-
* If
|
132
|
-
* string from our destination buffer.
|
138
|
+
* If the string was never modified, return the original string, otherwise
|
139
|
+
* create a new string from our destination buffer.
|
133
140
|
*/
|
134
|
-
if (
|
141
|
+
if (modified) {
|
135
142
|
return rb_utf8_str_new_cstr(dest);
|
136
143
|
} else {
|
137
144
|
return string;
|
@@ -221,7 +228,7 @@ static char * hash_value_to_attribute(const char *attr, const size_t attrlen, VA
|
|
221
228
|
|
222
229
|
Check_Type(value, T_HASH);
|
223
230
|
|
224
|
-
if (
|
231
|
+
if (RHASH_SIZE(value) == 0) {
|
225
232
|
return strdup("");
|
226
233
|
}
|
227
234
|
|
@@ -432,7 +439,7 @@ static VALUE external_to_attribute(RB_UNUSED_VAR(VALUE self), VALUE attr, VALUE
|
|
432
439
|
static VALUE external_to_attributes(RB_UNUSED_VAR(VALUE self), VALUE attributes) {
|
433
440
|
Check_Type(attributes, T_HASH);
|
434
441
|
|
435
|
-
if (
|
442
|
+
if (RHASH_SIZE(attributes) == 0) {
|
436
443
|
return rb_utf8_str_new_cstr("");
|
437
444
|
}
|
438
445
|
|
@@ -446,37 +453,32 @@ static VALUE external_to_attributes(RB_UNUSED_VAR(VALUE self), VALUE attributes)
|
|
446
453
|
}
|
447
454
|
|
448
455
|
static char * void_element(const char *tag, size_t tlen, VALUE attributes) {
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
char *string = malloc(total);
|
453
|
-
char *ptr;
|
454
|
-
char *end = string + total;
|
456
|
+
const char *empty = "";
|
457
|
+
char *attrs = hash_value_to_attribute(empty, 0, attributes);
|
458
|
+
size_t alen = strlen(attrs);
|
455
459
|
|
456
|
-
|
457
|
-
ptr = stecpy(ptr, tag, end);
|
458
|
-
ptr = stecpy(ptr, tag_close, end);
|
460
|
+
size_t total = tag_olen + tlen + tag_clen + 1;
|
459
461
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
462
|
+
/* If we have some attributes, add a space and the attributes' length. */
|
463
|
+
if (alen > 0) {
|
464
|
+
total += splen + alen;
|
465
|
+
}
|
466
|
+
|
467
|
+
char *dest = malloc(total);
|
468
|
+
char *ptr = NULL;
|
469
|
+
char *end = dest + total;
|
464
470
|
|
465
|
-
|
466
|
-
|
467
|
-
char *ptr;
|
468
|
-
char *end = string + total;
|
471
|
+
ptr = stecpy(dest, tag_open, end);
|
472
|
+
ptr = stecpy(ptr, tag, end);
|
469
473
|
|
470
|
-
|
471
|
-
ptr = stecpy(ptr, tag, end);
|
474
|
+
if (alen > 0) {
|
472
475
|
ptr = stecpy(ptr, space, end);
|
473
476
|
ptr = stecpy(ptr, attrs, end);
|
474
|
-
|
477
|
+
}
|
475
478
|
|
476
|
-
|
479
|
+
ptr = stecpy(ptr, tag_close, end);
|
477
480
|
|
478
|
-
|
479
|
-
}
|
481
|
+
return dest;
|
480
482
|
}
|
481
483
|
|
482
484
|
/*
|
@@ -571,7 +573,7 @@ static VALUE external_element(int argc, VALUE *arguments, RB_UNUSED_VAR(VALUE se
|
|
571
573
|
|
572
574
|
StringValue(tag);
|
573
575
|
|
574
|
-
CONTENT_FROM_BLOCK
|
576
|
+
CONTENT_FROM_BLOCK
|
575
577
|
|
576
578
|
char *string = element(RSTRING_PTR(tag), RSTRING_LEN(tag), RSTRING_PTR(content), RSTRING_LEN(content), attributes);
|
577
579
|
VALUE rstring = rb_utf8_str_new_cstr(string);
|
Binary file
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'berns'
|
3
|
+
|
4
|
+
module Berns
|
5
|
+
# An HTML builder DSL using Berns' HTML methods.
|
6
|
+
class Builder
|
7
|
+
def initialize(&block)
|
8
|
+
@block = block
|
9
|
+
@buffer = +''
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [String]
|
13
|
+
def call(*args, **opts)
|
14
|
+
instance_exec(*args, **opts, &@block)
|
15
|
+
to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String]
|
19
|
+
def to_s
|
20
|
+
@buffer.freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
# Append text to the buffer.
|
24
|
+
#
|
25
|
+
# @param string [String]
|
26
|
+
# @return [String]
|
27
|
+
def text(string)
|
28
|
+
@buffer << Berns.escape_html(string.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Append an arbitrary standard element to the buffer.
|
32
|
+
#
|
33
|
+
# @return [String]
|
34
|
+
def element(*args, **opts, &block)
|
35
|
+
content = Builder.new.instance_exec(*args, **opts, &block) if block
|
36
|
+
@buffer << Berns.element(*args, **opts) { content }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Append an arbitrary void element to the buffer.
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
def void(*args, **opts)
|
43
|
+
@buffer << Berns.void(*args, **opts)
|
44
|
+
end
|
45
|
+
|
46
|
+
Berns::STANDARD.each do |meth|
|
47
|
+
define_method(meth) do |*args, **opts, &block|
|
48
|
+
content = Builder.new.instance_exec(*args, **opts, &block) if block
|
49
|
+
@buffer << Berns.send(meth, *args, **opts) { content }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Berns::VOID.each do |meth|
|
54
|
+
define_method(meth) do |*args, **opts|
|
55
|
+
@buffer << Berns.send(meth, *args, **opts)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/berns/version.rb
CHANGED
data/lib/berns.rb
CHANGED
@@ -1,3 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'berns/berns'
|
3
3
|
require 'berns/version'
|
4
|
+
|
5
|
+
module Berns # :nodoc:
|
6
|
+
autoload :Builder, 'berns/builder'
|
7
|
+
|
8
|
+
STANDARD = %i[
|
9
|
+
a abbr address article aside audio b bdi bdo blockquote body button canvas
|
10
|
+
caption cite code colgroup datalist dd del details dfn dialog div dl dt em
|
11
|
+
fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header html i
|
12
|
+
iframe ins kbd label legend li main map mark menu meter nav noscript object
|
13
|
+
ol optgroup option output p picture pre progress q rp rt ruby s samp script
|
14
|
+
section select small span strong style sub summary table tbody td template
|
15
|
+
textarea tfoot th thead time title tr u ul var video
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
VOID = %i[
|
19
|
+
area base br col embed hr img input link menuitem meta param source track wbr
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
# @return [String]
|
23
|
+
def self.build(*args, **opts, &block)
|
24
|
+
Builder.new(&block).call(*args, **opts)
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: berns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Taylor Beck
|
8
8
|
- Evan Lecklider
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-02-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: benchmark-ips
|
@@ -167,15 +167,17 @@ files:
|
|
167
167
|
- ext/berns/hescape.c
|
168
168
|
- ext/berns/hescape.h
|
169
169
|
- lib/berns.rb
|
170
|
-
- lib/berns/berns.
|
170
|
+
- lib/berns/berns.bundle
|
171
|
+
- lib/berns/builder.rb
|
171
172
|
- lib/berns/version.rb
|
172
173
|
homepage: https://github.com/evanleck/berns
|
173
174
|
licenses:
|
174
175
|
- MIT
|
175
176
|
metadata:
|
176
177
|
bug_tracker_uri: https://github.com/evanleck/berns/issues
|
178
|
+
rubygems_mfa_required: 'true'
|
177
179
|
source_code_uri: https://github.com/evanleck/berns
|
178
|
-
post_install_message:
|
180
|
+
post_install_message:
|
179
181
|
rdoc_options: []
|
180
182
|
require_paths:
|
181
183
|
- lib
|
@@ -188,10 +190,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
190
|
requirements:
|
189
191
|
- - ">="
|
190
192
|
- !ruby/object:Gem::Version
|
191
|
-
version: '0'
|
193
|
+
version: '2.0'
|
192
194
|
requirements: []
|
193
|
-
rubygems_version: 3.
|
194
|
-
signing_key:
|
195
|
+
rubygems_version: 3.3.3
|
196
|
+
signing_key:
|
195
197
|
specification_version: 4
|
196
198
|
summary: A utility library for generating HTML strings.
|
197
199
|
test_files: []
|
data/lib/berns/berns.so
DELETED
Binary file
|