berns 2.0.0 → 3.0.4
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 +4 -4
- data/.editorconfig +20 -0
- data/.github/workflows/main.yml +24 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +58 -0
- data/CHANGELOG.org +146 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.org +117 -0
- data/Rakefile +20 -0
- data/berns.gemspec +38 -0
- data/ext/berns/berns.c +1060 -0
- data/ext/berns/extconf.rb +5 -0
- data/lib/berns.rb +6 -118
- data/lib/berns/version.rb +4 -0
- metadata +74 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b17c389fd9277b84a7a5487f94b4d6d8aa9adc2c1cccc50dc13eb9a10b7e01be
|
4
|
+
data.tar.gz: 80c4ee01ddc5c20fd967ef0d7255bd503865448f647a102e3aeb0fd8b2865763
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3c69c8aa9006e3c45f300e1816b3b961f1edfe9193705bef835391c0acdc13c5fcf7282b1655f5a69c3361b6d6e9b63df76cecaf56b3ca42d288bc42c8f321e
|
7
|
+
data.tar.gz: d1c4597fe85b8240903ba691281c55353f9a70842c55a9305af0456ae0d8d2246551d2f648d221e99aa1dec958bbdff436bcec9be763846972144a1befdc3dfe
|
data/.editorconfig
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# http://EditorConfig.org
|
2
|
+
# This is the top most config file.
|
3
|
+
root = true
|
4
|
+
|
5
|
+
# All files
|
6
|
+
[*]
|
7
|
+
|
8
|
+
# Unix-style newlines with a newline ending every file
|
9
|
+
end_of_line = lf
|
10
|
+
insert_final_newline = true
|
11
|
+
|
12
|
+
# Character set
|
13
|
+
charset = utf-8
|
14
|
+
|
15
|
+
# Trim extra whitespace.
|
16
|
+
trim_trailing_whitespace = true
|
17
|
+
|
18
|
+
# Soft tabs and 2 spaces.
|
19
|
+
indent_style = space
|
20
|
+
indent_size = 2
|
@@ -0,0 +1,24 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on: [push,pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
strategy:
|
8
|
+
fail-fast: false
|
9
|
+
matrix:
|
10
|
+
os: [ubuntu-latest, macos-latest]
|
11
|
+
ruby-version: ['3.0', 2.7, 2.6, 2.5]
|
12
|
+
|
13
|
+
runs-on: ${{ matrix.os }}
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
|
17
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
18
|
+
uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
bundler-cache: true
|
21
|
+
ruby-version: ${{ matrix.ruby-version }}
|
22
|
+
|
23
|
+
- name: Run tests & lint
|
24
|
+
run: bundle exec rake
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# http://rubocop.readthedocs.io
|
2
|
+
# https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml
|
3
|
+
require:
|
4
|
+
- rubocop-minitest
|
5
|
+
- rubocop-performance
|
6
|
+
- rubocop-rake
|
7
|
+
|
8
|
+
AllCops:
|
9
|
+
DisplayCopNames: true
|
10
|
+
DisplayStyleGuide: true
|
11
|
+
ExtraDetails: true
|
12
|
+
NewCops: enable
|
13
|
+
TargetRubyVersion: 2.5
|
14
|
+
|
15
|
+
Layout/ParameterAlignment:
|
16
|
+
EnforcedStyle: with_fixed_indentation
|
17
|
+
|
18
|
+
Layout/EmptyLineAfterMagicComment:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Layout/FirstHashElementIndentation:
|
22
|
+
EnforcedStyle: consistent
|
23
|
+
|
24
|
+
Layout/MultilineOperationIndentation:
|
25
|
+
EnforcedStyle: indented
|
26
|
+
|
27
|
+
Layout/SpaceInsideStringInterpolation:
|
28
|
+
EnforcedStyle: space
|
29
|
+
|
30
|
+
Layout/LineLength:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Metrics/AbcSize:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Metrics/BlockLength:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Metrics/ClassLength:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Metrics/CyclomaticComplexity:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Metrics/MethodLength:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Metrics/ModuleLength:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Metrics/PerceivedComplexity:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
Style/IfUnlessModifier:
|
55
|
+
Enabled: false
|
56
|
+
|
57
|
+
Style/Next:
|
58
|
+
MinBodyLength: 8
|
data/CHANGELOG.org
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
* Berns Changelog
|
2
|
+
|
3
|
+
** 3.0.4
|
4
|
+
|
5
|
+
Fix an =ArgumentError= when passing a nested empty hash to =to_attribute=.
|
6
|
+
|
7
|
+
** 3.0.3
|
8
|
+
|
9
|
+
Fix a buffer overflow error.
|
10
|
+
|
11
|
+
** 3.0.2
|
12
|
+
|
13
|
+
Ensure all returned strings are UTF-8 encoded.
|
14
|
+
|
15
|
+
** 3.0.1
|
16
|
+
|
17
|
+
Fix a regression when content blocks are nil. They should be treated the same as
|
18
|
+
if they are not there instead of throwing an error.
|
19
|
+
|
20
|
+
** 3.0.0
|
21
|
+
|
22
|
+
Version 3.0 is another mostly API-compatible refactor of Berns, this time in
|
23
|
+
blazing fast C! I debated simply calling this version 2.1.0 but because it's a
|
24
|
+
complete rewrite it didn't seem right to do a simple point release and there may
|
25
|
+
be corner cases that I've not accounted for in this new C-backed version.
|
26
|
+
|
27
|
+
Running the same benchmarks as from 2.0 but pitting 2.0 against 3.0 yields some
|
28
|
+
great speed improvements, particularly for the =empty= and =simple= cases.
|
29
|
+
|
30
|
+
/These benchmarks were performed on a desktop with a AMD Ryzen 5 3600X 6-Core
|
31
|
+
Processor running Linux Mint 20.1 and kernel 5.4./
|
32
|
+
|
33
|
+
Before:
|
34
|
+
|
35
|
+
#+begin_example
|
36
|
+
empty 1.668M (± 0.6%) i/s - 8.356M in 5.011099s
|
37
|
+
simple 442.102k (± 1.3%) i/s - 2.214M in 5.008068s
|
38
|
+
nested 267.716k (± 0.4%) i/s - 1.357M in 5.068747s
|
39
|
+
#+end_example
|
40
|
+
|
41
|
+
After:
|
42
|
+
|
43
|
+
#+begin_example
|
44
|
+
empty 3.573M (± 1.2%) i/s - 17.881M in 5.005001s
|
45
|
+
simple 840.631k (± 0.6%) i/s - 4.253M in 5.059771s
|
46
|
+
nested 267.281k (± 0.5%) i/s - 1.347M in 5.037887s
|
47
|
+
#+end_example
|
48
|
+
|
49
|
+
With both empty and simple attributes we see performance effectively double, and
|
50
|
+
with nested attributes performance remains more or less the same.
|
51
|
+
|
52
|
+
This is another set of fairly contrived benchmarks, testing a singleton method,
|
53
|
+
=void= call, and =element= call against each other.
|
54
|
+
|
55
|
+
Before:
|
56
|
+
|
57
|
+
#+begin_example
|
58
|
+
br 3.061M (± 0.8%) i/s - 15.613M in 5.100154s
|
59
|
+
void("br") 6.141M (± 1.4%) i/s - 30.990M in 5.047338s
|
60
|
+
element("div") 2.789M (± 0.6%) i/s - 14.171M in 5.080626s
|
61
|
+
#+end_example
|
62
|
+
|
63
|
+
After:
|
64
|
+
|
65
|
+
#+begin_example
|
66
|
+
br 8.155M (± 1.0%) i/s - 41.339M in 5.069681s
|
67
|
+
void("br") 9.782M (± 1.5%) i/s - 49.096M in 5.020114s
|
68
|
+
element("div") 6.769M (± 1.1%) i/s - 33.983M in 5.021362s
|
69
|
+
#+end_example
|
70
|
+
|
71
|
+
Lastly, benchmarking =to_attributes= with the following hash as the only
|
72
|
+
argument shows about double the performance with 3.0.
|
73
|
+
|
74
|
+
#+begin_src ruby
|
75
|
+
ATTRS = { this: 'tag', should: 'work', data: { foo: 'bar', bar: { baz: 'foo' } } }.freeze
|
76
|
+
#+end_src
|
77
|
+
|
78
|
+
Before:
|
79
|
+
|
80
|
+
#+begin_example
|
81
|
+
to_attributes 228.829k (± 1.3%) i/s - 1.159M in 5.065714s
|
82
|
+
#+end_example
|
83
|
+
|
84
|
+
After:
|
85
|
+
|
86
|
+
#+begin_example
|
87
|
+
to_attributes 457.387k (± 1.2%) i/s - 2.305M in 5.041036s
|
88
|
+
#+end_example
|
89
|
+
|
90
|
+
** 2.0.0
|
91
|
+
|
92
|
+
Version 2.0 is a mostly API-compatible refactor of all of the core
|
93
|
+
methods that make up Berns. The goal is to improve performance, mostly
|
94
|
+
using mutable strings and inlining variables that were otherwise short
|
95
|
+
lived.
|
96
|
+
|
97
|
+
In addition, the target Ruby version has been raised to 2.5 or later.
|
98
|
+
2.4 has reached its end of life.
|
99
|
+
|
100
|
+
Running this benchmarking code:
|
101
|
+
|
102
|
+
#+begin_src ruby
|
103
|
+
Benchmark.ips do |x|
|
104
|
+
x.report('empty') { Berns.element(:a) { 'Link to something' } }
|
105
|
+
x.report('simple') { Berns.element(:a, { href: 'Something', class: 'my-class' }) { 'Link to something' } }
|
106
|
+
x.report('nested') { Berns.element(:a, { href: 'Something', class: 'my-class', data: { something: 'Else' } }) { 'Link to something' } }
|
107
|
+
|
108
|
+
x.compare!
|
109
|
+
end
|
110
|
+
#+end_src
|
111
|
+
|
112
|
+
Before:
|
113
|
+
|
114
|
+
#+begin_example
|
115
|
+
empty 993.521k (± 1.7%) i/s - 5.062M in 5.096368s
|
116
|
+
simple 340.795k (± 0.4%) i/s - 1.729M in 5.074101s
|
117
|
+
nested 215.160k (± 1.0%) i/s - 1.081M in 5.025324s
|
118
|
+
#+end_example
|
119
|
+
|
120
|
+
After:
|
121
|
+
|
122
|
+
#+begin_example
|
123
|
+
empty 1.769M (± 1.9%) i/s - 9.012M in 5.094973s
|
124
|
+
simple 441.020k (± 1.0%) i/s - 2.233M in 5.063326s
|
125
|
+
nested 280.255k (± 3.0%) i/s - 1.400M in 5.001009s
|
126
|
+
#+end_example
|
127
|
+
|
128
|
+
With empty attributes we see ~ 100% increase in iterations per second,
|
129
|
+
with simple attributes we see ~ 30% increase in the same, and with
|
130
|
+
nested attributes we see ~ 30% increase as well.
|
131
|
+
|
132
|
+
** 1.3.0
|
133
|
+
|
134
|
+
With version 1.3, nested HTML attributes can be created with nil keys
|
135
|
+
and boolean values to produce e.g. "data-foo data-foo-bar='whatever'"
|
136
|
+
from =data: { foo: { nil => true, bar: 'whatever' } }=
|
137
|
+
|
138
|
+
** 1.2.0 - 1.2.2
|
139
|
+
|
140
|
+
Starting with version 1.2, Berns will now HTML-escape all attribute
|
141
|
+
values using =CGI.escapeHTML=. This should prevent attribute values from
|
142
|
+
escaping themselves and injecting HTML into the DOM.
|
143
|
+
|
144
|
+
** 1.1.0
|
145
|
+
|
146
|
+
- Add =#sanitize= method.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Taylor Beck
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
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,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.org
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
* Berns
|
2
|
+
|
3
|
+
[[https://badge.fury.io/rb/berns][https://badge.fury.io/rb/berns.svg]]
|
4
|
+
|
5
|
+
A utility library for generating HTML strings.
|
6
|
+
|
7
|
+
** Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
#+begin_src ruby
|
12
|
+
gem 'berns'
|
13
|
+
#+end_src
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
#+begin_src sh
|
18
|
+
bundle
|
19
|
+
#+end_src
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
#+begin_src sh
|
24
|
+
gem install berns
|
25
|
+
#+end_src
|
26
|
+
|
27
|
+
** Usage
|
28
|
+
|
29
|
+
All standard and void HTML elements are defined as methods on Berns, so you can
|
30
|
+
create e.g. a link with =Berns.a=. In addition, there are methods to sanitize
|
31
|
+
strings i.e. remove HTML from them, convert hashes into a string of HTML
|
32
|
+
attributes, and more.
|
33
|
+
|
34
|
+
*** =void(tag, attributes)=
|
35
|
+
|
36
|
+
The =void= method generates a void HTML element i.e. one without any content. It
|
37
|
+
takes either a symbol or a string and an optional hash of HTML attributes.
|
38
|
+
|
39
|
+
#+begin_src ruby
|
40
|
+
Berns.void('br') # => '<br>'
|
41
|
+
Berns.void('br', class: 'br-class') # => '<br class="br-class">'
|
42
|
+
#+end_src
|
43
|
+
|
44
|
+
*** =element(tag, attributes) { content }=
|
45
|
+
|
46
|
+
The =element= method generates a standard HTML element i.e. one with optional
|
47
|
+
content. It takes either a symbol or a string, an optional hash of HTML
|
48
|
+
attributes, and an optional block of content. If provided, the block should
|
49
|
+
return a string.
|
50
|
+
|
51
|
+
#+begin_src ruby
|
52
|
+
Berns.element('div') # => '<div></div>'
|
53
|
+
Berns.element('div', class: 'div-class') # => '<div class="div-class"></div>'
|
54
|
+
Berns.element('div', class: 'div-class') { 'Content' } # => '<div class="div-class">Content</div>'
|
55
|
+
#+end_src
|
56
|
+
|
57
|
+
*** =to_attribute(attribute, value)=
|
58
|
+
|
59
|
+
The =to_attribute= method generates an HTML attribute string. If the value is a
|
60
|
+
hash then the attribute is treated as a prefix.
|
61
|
+
|
62
|
+
#+begin_src ruby
|
63
|
+
Berns.to_attribute('class', 'my-class another-class') # => 'class="my-class another-class"'
|
64
|
+
Berns.to_attribute('data', { foo: 'bar' }) # => 'data-foo="bar"'
|
65
|
+
#+end_src
|
66
|
+
|
67
|
+
All attribute values are HTML-escaped using =CGI.escapeHTML=.
|
68
|
+
|
69
|
+
*** =to_attributes(attributes)=
|
70
|
+
|
71
|
+
The =to_attributes= method generates an HTML attribute string from a hash by
|
72
|
+
calling =to_attribute= for each key/value pair.
|
73
|
+
|
74
|
+
#+begin_src ruby
|
75
|
+
Berns.to_attributes({ 'data' => { foo: 'bar' }, 'class' => 'my-class another-class' }) # => 'data-foo="bar" class="my-class another-class"'
|
76
|
+
#+end_src
|
77
|
+
|
78
|
+
*** =escape_html(string)=
|
79
|
+
|
80
|
+
The =escape_html= method is a passthrough to =CGI.escapeHTML= and does what it
|
81
|
+
says on the tin.
|
82
|
+
|
83
|
+
#+begin_src ruby
|
84
|
+
Berns.escape_html('<"tag"') # => '<"tag"'
|
85
|
+
#+end_src
|
86
|
+
|
87
|
+
*** =sanitize(string)=
|
88
|
+
|
89
|
+
The =sanitize= method strips HTML tags from strings.
|
90
|
+
|
91
|
+
#+begin_src ruby
|
92
|
+
Berns.sanitize('This <span>should be clean</span>') # => 'This should be clean'
|
93
|
+
#+end_src
|
94
|
+
|
95
|
+
*** Standard and void elements
|
96
|
+
|
97
|
+
As mentioned above, all standard and void HTML elements are defined as singleton
|
98
|
+
methods on the Berns module. Below is the full list of standard elements.
|
99
|
+
|
100
|
+
#+begin_example
|
101
|
+
a abbr address article aside audio b bdi bdo blockquote body button
|
102
|
+
canvas caption cite code colgroup datalist dd del details dfn dialog div
|
103
|
+
dl dt em fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head
|
104
|
+
header html i iframe ins kbd label legend li main map mark menu meter nav
|
105
|
+
noscript object ol optgroup option output p picture pre progress q rp rt
|
106
|
+
ruby s samp script section select small span strong style sub summary
|
107
|
+
table tbody td template textarea tfoot th thead time title tr u ul var
|
108
|
+
video
|
109
|
+
#+end_example
|
110
|
+
|
111
|
+
|
112
|
+
Below is the full list of void elements that are defined as singleton methods on
|
113
|
+
Berns.
|
114
|
+
|
115
|
+
#+begin_example
|
116
|
+
area base br col embed hr img input link menuitem meta param source track wbr
|
117
|
+
#+end_example
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/extensiontask'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
Rake::ExtensionTask.new 'berns' do |ext|
|
8
|
+
ext.lib_dir = 'lib/berns'
|
9
|
+
end
|
10
|
+
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.deps = :compile
|
13
|
+
t.libs << 'test'
|
14
|
+
t.libs << 'lib'
|
15
|
+
t.test_files = FileList['test/**/*_test.rb']
|
16
|
+
end
|
17
|
+
|
18
|
+
RuboCop::RakeTask.new
|
19
|
+
|
20
|
+
task default: %i[test rubocop]
|