serialbench 0.9.2 → 0.11.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 +4 -4
- data/.github/scripts/push-to-data.sh +28 -6
- data/.github/workflows/benchmark.yml +51 -1
- data/.gitignore +1 -0
- data/README.adoc +3 -3
- data/config/benchmarks/full-html.yml +26 -0
- data/config/benchmarks/full-xml.yml +4 -0
- data/lib/serialbench/benchmark_runner.rb +168 -3
- data/lib/serialbench/models/benchmark_config.rb +2 -2
- data/lib/serialbench/models/benchmark_result.rb +10 -2
- data/lib/serialbench/serializers/html/base_html_serializer.rb +40 -0
- data/lib/serialbench/serializers/html/leptris_serializer.rb +58 -0
- data/lib/serialbench/serializers/html/nokogiri_serializer.rb +56 -0
- data/lib/serialbench/serializers/html/oga_serializer.rb +48 -0
- data/lib/serialbench/serializers/xml/base_xml_serializer.rb +4 -0
- data/lib/serialbench/serializers/xml/leptris_serializer.rb +20 -1
- data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +11 -1
- data/lib/serialbench/serializers/xml/saxon_serializer.rb +72 -0
- data/lib/serialbench/serializers.rb +14 -1
- data/lib/serialbench/test_data.rb +47 -0
- data/lib/serialbench/version.rb +1 -1
- data/serialbench.gemspec +1 -1
- metadata +11 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b2f980d28503e644be4c2f0807637b531c91640ad50af4eeb72c5cf41b26f3eb
|
|
4
|
+
data.tar.gz: 2e45051b18ab56d9a4fe2d569d3abc3206f151398dca094aa0a28fecd3ceb07f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35d305480351a282cf7cccc5c18874d1d5f053f2ee914452082c0abed7f1b92e66a63ba582a90ed898320d55c499a43b5207c3e4f12c529111223f7841e5d89b
|
|
7
|
+
data.tar.gz: 7441471432ba4b498ac91d7a4bdf4b21338c36789a231014f3f0bc49bb3858952f3627eeb2209442b9c266d4664e91515e677dda472003bb20614c25648c5010
|
|
@@ -29,12 +29,34 @@ CONTENT=$(base64 < "$RESULTS_FILE" | tr -d '\r\n')
|
|
|
29
29
|
|
|
30
30
|
echo "Pushing ${TARGET_PATH} to serialbench/data..."
|
|
31
31
|
|
|
32
|
-
# Try create;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
"
|
|
37
|
-
-
|
|
32
|
+
# Try create; 409 (branch race) and 422 (exists) both retry with fresh sha
|
|
33
|
+
put_file() {
|
|
34
|
+
local sha_arg=()
|
|
35
|
+
[ -n "${1:-}" ] && sha_arg=(-d "{\"message\": \"${PLATFORM} ruby-${RUBY_VERSION} ${FMT} (update)\", \"content\": \"${CONTENT}\", \"sha\": \"$1\", \"branch\": \"main\"}")
|
|
36
|
+
[ -n "${1:-}" ] || sha_arg=(-d "{\"message\": \"${PLATFORM} ruby-${RUBY_VERSION} ${FMT}\", \"content\": \"${CONTENT}\", \"branch\": \"main\"}")
|
|
37
|
+
curl -s -o /tmp/data-push-resp.json -w "%{http_code}" -X PUT \
|
|
38
|
+
-H "Authorization: Bearer ${DATA_TOKEN}" \
|
|
39
|
+
-H "Accept: application/vnd.github+json" \
|
|
40
|
+
"https://api.github.com/repos/serialbench/data/contents/${TARGET_PATH}" \
|
|
41
|
+
"${sha_arg[@]}"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
HTTP_CODE=$(put_file "")
|
|
45
|
+
for TRY in 1 2 3 4 5; do
|
|
46
|
+
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then break; fi
|
|
47
|
+
if [ "$HTTP_CODE" = "409" ] || [ "$HTTP_CODE" = "422" ]; then
|
|
48
|
+
SHA=$(curl -sf \
|
|
49
|
+
-H "Authorization: Bearer ${DATA_TOKEN}" \
|
|
50
|
+
"https://api.github.com/repos/serialbench/data/contents/${TARGET_PATH}" \
|
|
51
|
+
| grep -oE '"sha":\s*"[a-f0-9]+"' | head -1 | grep -oE '[a-f0-9]{40}')
|
|
52
|
+
[ -z "$SHA" ] && break
|
|
53
|
+
echo "attempt $TRY got $HTTP_CODE — refetching sha and retrying"
|
|
54
|
+
sleep $((TRY * 3))
|
|
55
|
+
HTTP_CODE=$(put_file "$SHA")
|
|
56
|
+
else
|
|
57
|
+
break
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
38
60
|
|
|
39
61
|
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then
|
|
40
62
|
echo "Pushed ${TARGET_PATH}"
|
|
@@ -116,6 +116,21 @@ jobs:
|
|
|
116
116
|
- name: Install gems
|
|
117
117
|
run: bundle install
|
|
118
118
|
|
|
119
|
+
- name: Fetch Saxon-HE (XSLT 2.0/3.0 comparison)
|
|
120
|
+
run: |
|
|
121
|
+
mkdir -p vendor
|
|
122
|
+
curl -sL -o vendor/saxonhe.jar "https://repo1.maven.org/maven2/net/sf/saxon/Saxon-HE/12.10/Saxon-HE-12.10.jar"
|
|
123
|
+
curl -sL -o vendor/xmlresolver.jar "https://repo1.maven.org/maven2/org/xmlresolver/xmlresolver/5.2.2/xmlresolver-5.2.2.jar"
|
|
124
|
+
echo "SAXON_JAR=$PWD/vendor/saxonhe.jar" >> "$GITHUB_ENV"
|
|
125
|
+
echo "XMLRESOLVER_JAR=$PWD/vendor/xmlresolver.jar" >> "$GITHUB_ENV"
|
|
126
|
+
shell: bash
|
|
127
|
+
|
|
128
|
+
- name: Load canonical fixtures
|
|
129
|
+
run: |
|
|
130
|
+
git clone --depth 1 https://github.com/serialbench/fixtures.git test_data
|
|
131
|
+
(cd test_data && sha256sum -c SHA256SUMS) || (cd test_data && shasum -a 256 -c SHA256SUMS)
|
|
132
|
+
shell: bash
|
|
133
|
+
|
|
119
134
|
- name: Point teptris at its vendored DLL (Windows)
|
|
120
135
|
if: startsWith(matrix.platform, 'windows-')
|
|
121
136
|
shell: bash
|
|
@@ -249,6 +264,41 @@ jobs:
|
|
|
249
264
|
run: .github/scripts/push-to-data.sh toml ${{ matrix.ruby-version }} ${{ matrix.platform }}
|
|
250
265
|
shell: bash
|
|
251
266
|
|
|
267
|
+
- name: Benchmark html
|
|
268
|
+
continue-on-error: true
|
|
269
|
+
shell: bash
|
|
270
|
+
env:
|
|
271
|
+
GITHUB_RUNNER_PLATFORM: ${{ matrix.platform }}
|
|
272
|
+
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
273
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
274
|
+
run: |
|
|
275
|
+
if [ "${{ github.run_attempt }}" -gt 1 ] && .github/scripts/format-status.sh html ${{ matrix.ruby-version }} ${{ matrix.platform }}; then
|
|
276
|
+
echo "html already in the data repo — skipping (gap-filling rerun)"
|
|
277
|
+
exit 0
|
|
278
|
+
fi
|
|
279
|
+
bundle exec serialbench environment execute \
|
|
280
|
+
config/environments/ci-ruby-${{ matrix.ruby-version }}.yml \
|
|
281
|
+
config/benchmarks/full-html.yml \
|
|
282
|
+
"results/runs/ci-ruby-${{ matrix.ruby-version }}-${{ matrix.platform }}/html"
|
|
283
|
+
|
|
284
|
+
- name: Upload html
|
|
285
|
+
if: ${{ !cancelled() }}
|
|
286
|
+
uses: actions/upload-artifact@v4
|
|
287
|
+
with:
|
|
288
|
+
name: benchmark-results-${{ matrix.platform }}-ruby-${{ matrix.ruby-version }}-html
|
|
289
|
+
path: results/runs/ci-ruby-${{ matrix.ruby-version }}-${{ matrix.platform }}/html
|
|
290
|
+
retention-days: 30
|
|
291
|
+
if-no-files-found: warn
|
|
292
|
+
|
|
293
|
+
- name: Push html to data repo
|
|
294
|
+
if: ${{ !cancelled() }}
|
|
295
|
+
continue-on-error: true
|
|
296
|
+
env:
|
|
297
|
+
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
298
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
299
|
+
run: .github/scripts/push-to-data.sh html ${{ matrix.ruby-version }} ${{ matrix.platform }}
|
|
300
|
+
shell: bash
|
|
301
|
+
|
|
252
302
|
# Each format is an independent checkpoint with its own upload.
|
|
253
303
|
# A failure in one format doesn't prevent the others from uploading.
|
|
254
304
|
- name: Benchmark xml
|
|
@@ -296,7 +346,7 @@ jobs:
|
|
|
296
346
|
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
297
347
|
run: |
|
|
298
348
|
MISSING=""
|
|
299
|
-
for FMT in json yaml toml xml; do
|
|
349
|
+
for FMT in json yaml toml html xml; do
|
|
300
350
|
if .github/scripts/format-status.sh "$FMT" "${{ matrix.ruby-version }}" "${{ matrix.platform }}"; then
|
|
301
351
|
echo "$FMT: in data repo"
|
|
302
352
|
else
|
data/.gitignore
CHANGED
data/README.adoc
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
= Serialbench: Ruby serialization library performance benchmarker
|
|
2
2
|
|
|
3
3
|
image:https://img.shields.io/gem/v/serialbench.svg["Gem Version", link="https://rubygems.org/gems/serialbench"]
|
|
4
|
-
image:https://github.com/
|
|
5
|
-
image:https://github.com/
|
|
6
|
-
image:https://img.shields.io/github/issues-pr-raw/
|
|
4
|
+
image:https://github.com/serialbench/serialbench/actions/workflows/ci.yml/badge.svg["Build Status", link="https://github.com/serialbench/serialbench/actions/workflows/ci.yml"]
|
|
5
|
+
image:https://github.com/serialbench/serialbench/actions/workflows/benchmark.yml/badge.svg["Benchmark Status", link="https://github.com/serialbench/serialbench/actions/workflows/benchmark.yml"]
|
|
6
|
+
image:https://img.shields.io/github/issues-pr-raw/serialbench/serialbench.svg["Pull Requests", link="https://github.com/serialbench/serialbench/pulls"]
|
|
7
7
|
|
|
8
8
|
== Overview
|
|
9
9
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Per-format split of full.yml: each format runs in its own process so
|
|
2
|
+
# memory profiling of large documents cannot compound across formats
|
|
3
|
+
# (windows runners OOMed with all four formats in one process).
|
|
4
|
+
name: full-html
|
|
5
|
+
|
|
6
|
+
data_sizes:
|
|
7
|
+
- small
|
|
8
|
+
- medium
|
|
9
|
+
- large
|
|
10
|
+
|
|
11
|
+
formats:
|
|
12
|
+
- html
|
|
13
|
+
|
|
14
|
+
iterations:
|
|
15
|
+
small: 10
|
|
16
|
+
medium: 3
|
|
17
|
+
large: 1
|
|
18
|
+
|
|
19
|
+
operations:
|
|
20
|
+
- parsing
|
|
21
|
+
- generation
|
|
22
|
+
- streaming
|
|
23
|
+
- xpath
|
|
24
|
+
- memory
|
|
25
|
+
|
|
26
|
+
warmup: 2
|
|
@@ -26,15 +26,170 @@ module Serialbench
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# Each operation maps to a lambda. Adding an operation = one entry.
|
|
29
|
+
_DEFAULT_RNG_SCHEMA = <<'RNG'.freeze
|
|
30
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
31
|
+
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
|
32
|
+
<start>
|
|
33
|
+
<choice>
|
|
34
|
+
<ref name="config"/>
|
|
35
|
+
<ref name="users"/>
|
|
36
|
+
<ref name="dataset"/>
|
|
37
|
+
</choice>
|
|
38
|
+
</start>
|
|
39
|
+
|
|
40
|
+
<define name="config">
|
|
41
|
+
<element name="config">
|
|
42
|
+
<element name="database">
|
|
43
|
+
<element name="host"><text/></element>
|
|
44
|
+
<element name="port"><data type="integer"/></element>
|
|
45
|
+
<element name="name"><text/></element>
|
|
46
|
+
<element name="user"><text/></element>
|
|
47
|
+
<element name="password"><text/></element>
|
|
48
|
+
</element>
|
|
49
|
+
<element name="cache">
|
|
50
|
+
<element name="enabled"><data type="boolean"/></element>
|
|
51
|
+
<element name="ttl"><data type="integer"/></element>
|
|
52
|
+
</element>
|
|
53
|
+
</element>
|
|
54
|
+
</define>
|
|
55
|
+
|
|
56
|
+
<define name="users">
|
|
57
|
+
<element name="users">
|
|
58
|
+
<oneOrMore>
|
|
59
|
+
<ref name="user"/>
|
|
60
|
+
</oneOrMore>
|
|
61
|
+
</element>
|
|
62
|
+
</define>
|
|
63
|
+
|
|
64
|
+
<define name="user">
|
|
65
|
+
<element name="user">
|
|
66
|
+
<attribute name="id"><data type="integer"/></attribute>
|
|
67
|
+
<element name="name"><text/></element>
|
|
68
|
+
<element name="email"><text/></element>
|
|
69
|
+
<element name="created_at"><text/></element>
|
|
70
|
+
<element name="profile">
|
|
71
|
+
<element name="age"><data type="integer"/></element>
|
|
72
|
+
<element name="city"><text/></element>
|
|
73
|
+
<element name="preferences">
|
|
74
|
+
<element name="theme"><text/></element>
|
|
75
|
+
<element name="notifications"><data type="boolean"/></element>
|
|
76
|
+
</element>
|
|
77
|
+
</element>
|
|
78
|
+
</element>
|
|
79
|
+
</define>
|
|
80
|
+
|
|
81
|
+
<define name="dataset">
|
|
82
|
+
<element name="dataset">
|
|
83
|
+
<element name="header">
|
|
84
|
+
<element name="created"><text/></element>
|
|
85
|
+
<element name="count"><data type="integer"/></element>
|
|
86
|
+
<element name="format"><text/></element>
|
|
87
|
+
</element>
|
|
88
|
+
<element name="records">
|
|
89
|
+
<oneOrMore>
|
|
90
|
+
<ref name="record"/>
|
|
91
|
+
</oneOrMore>
|
|
92
|
+
</element>
|
|
93
|
+
</element>
|
|
94
|
+
</define>
|
|
95
|
+
|
|
96
|
+
<define name="record">
|
|
97
|
+
<element name="record">
|
|
98
|
+
<attribute name="id"><data type="integer"/></attribute>
|
|
99
|
+
<element name="timestamp"><text/></element>
|
|
100
|
+
<element name="data">
|
|
101
|
+
<element name="field1"><text/></element>
|
|
102
|
+
<element name="field2"><data type="integer"/></element>
|
|
103
|
+
<element name="field3"><text/></element>
|
|
104
|
+
<element name="nested">
|
|
105
|
+
<oneOrMore><element name="item"><text/></element></oneOrMore>
|
|
106
|
+
</element>
|
|
107
|
+
</element>
|
|
108
|
+
<element name="metadata">
|
|
109
|
+
<element name="source"><text/></element>
|
|
110
|
+
<element name="version"><text/></element>
|
|
111
|
+
<element name="checksum"><text/></element>
|
|
112
|
+
</element>
|
|
113
|
+
</element>
|
|
114
|
+
</define>
|
|
115
|
+
</grammar>
|
|
116
|
+
RNG
|
|
117
|
+
|
|
118
|
+
_DEFAULT_XSLT_STYLESHEET = <<'XSL'.freeze
|
|
119
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
120
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
|
121
|
+
<xsl:output method="xml" indent="yes"/>
|
|
122
|
+
<xsl:template match="/">
|
|
123
|
+
<report>
|
|
124
|
+
<xsl:apply-templates select="//user | //record | //database | //cache"/>
|
|
125
|
+
<total>
|
|
126
|
+
<xsl:value-of select="count(//user) + count(//record)"/>
|
|
127
|
+
</total>
|
|
128
|
+
</report>
|
|
129
|
+
</xsl:template>
|
|
130
|
+
<xsl:template match="user">
|
|
131
|
+
<row kind="user" id="{@id}" label="{name}"/>
|
|
132
|
+
</xsl:template>
|
|
133
|
+
<xsl:template match="record">
|
|
134
|
+
<row kind="record" id="{@id}" label="{data/field1}"/>
|
|
135
|
+
</xsl:template>
|
|
136
|
+
<xsl:template match="database">
|
|
137
|
+
<row kind="database" label="{name}"/>
|
|
138
|
+
</xsl:template>
|
|
139
|
+
<xsl:template match="cache">
|
|
140
|
+
<row kind="cache" label="{ttl}"/>
|
|
141
|
+
</xsl:template>
|
|
142
|
+
</xsl:stylesheet>
|
|
143
|
+
XSL
|
|
144
|
+
|
|
145
|
+
_DEFAULT_XSLT30_STYLESHEET = <<'XSL30'.freeze
|
|
146
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
147
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
148
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
149
|
+
exclude-result-prefixes="xs"
|
|
150
|
+
version="3.0">
|
|
151
|
+
<xsl:output method="xml" indent="yes"/>
|
|
152
|
+
<xsl:template match="/">
|
|
153
|
+
<report30>
|
|
154
|
+
<xsl:iterate select="//user | //record | //database | //cache">
|
|
155
|
+
<xsl:param name="labels" as="xs:string*" select="()"/>
|
|
156
|
+
<xsl:on-completion>
|
|
157
|
+
<joined><xsl:value-of select="string-join($labels, ', ')"/></joined>
|
|
158
|
+
<count><xsl:value-of select="count($labels)"/></count>
|
|
159
|
+
</xsl:on-completion>
|
|
160
|
+
<xsl:variable name="label" select="string((name, data/field1, ttl)[1])"/>
|
|
161
|
+
<xsl:if test="$label != ''">
|
|
162
|
+
<row kind="{local-name()}" label="{upper-case($label)}"/>
|
|
163
|
+
</xsl:if>
|
|
164
|
+
<xsl:next-iteration>
|
|
165
|
+
<xsl:with-param name="labels" select="if ($label != '') then ($labels, $label) else $labels"/>
|
|
166
|
+
</xsl:next-iteration>
|
|
167
|
+
</xsl:iterate>
|
|
168
|
+
</report30>
|
|
169
|
+
</xsl:template>
|
|
170
|
+
</xsl:stylesheet>
|
|
171
|
+
XSL30
|
|
172
|
+
|
|
173
|
+
XPATH_QUERIES = ['//book', "//book[@id='101']", '//book[price > 30]/title'].freeze
|
|
174
|
+
XQUERY_EXPRESSIONS = ['count(//user | //record)', "//record[@id='101']/data/field1", '//user[profile/age > 40]/name'].freeze
|
|
175
|
+
RNG_SCHEMA = File.expand_path('test_data/schema.rng', Dir.pwd).then { |p| File.exist?(p) ? File.read(p) : _DEFAULT_RNG_SCHEMA }
|
|
176
|
+
XSLT_STYLESHEET = File.expand_path('test_data/transform.xsl', Dir.pwd).then { |p| File.exist?(p) ? File.read(p) : _DEFAULT_XSLT_STYLESHEET }
|
|
177
|
+
XSLT30_STYLESHEET = File.expand_path('test_data/transform30.xsl', Dir.pwd).then { |p| File.exist?(p) ? File.read(p) : _DEFAULT_XSLT30_STYLESHEET }
|
|
178
|
+
|
|
29
179
|
OPERATIONS = {
|
|
30
180
|
'parsing' => ->(s, data) { s.parse(data) },
|
|
31
181
|
'generation' => ->(s, data) { s.generate(s.parse(data)) },
|
|
32
182
|
'xpath' => lambda { |s, data|
|
|
33
183
|
doc = s.parse(data)
|
|
34
|
-
s.xpath_query(doc,
|
|
35
|
-
|
|
36
|
-
|
|
184
|
+
XPATH_QUERIES.each { |q| s.xpath_query(doc, q) }
|
|
185
|
+
},
|
|
186
|
+
'xquery' => lambda { |s, data|
|
|
187
|
+
doc = s.parse(data)
|
|
188
|
+
XQUERY_EXPRESSIONS.each { |x| s.xquery_eval(doc, x) }
|
|
37
189
|
},
|
|
190
|
+
'xslt' => ->(s, data) { s.xslt_apply(data, XSLT_STYLESHEET) },
|
|
191
|
+
'xslt30' => ->(s, data) { s.xslt_apply(data, XSLT30_STYLESHEET) },
|
|
192
|
+
'validation' => ->(s, data) { s.validate(s.parse(data), RNG_SCHEMA) },
|
|
38
193
|
'streaming' => ->(s, data) { s.stream_parse(data) { |_event, _data| } },
|
|
39
194
|
}.freeze
|
|
40
195
|
|
|
@@ -155,12 +310,22 @@ module Serialbench
|
|
|
155
310
|
serializers = Serializers.for_format(format)
|
|
156
311
|
|
|
157
312
|
case type_name
|
|
313
|
+
when 'parsing', 'memory'
|
|
314
|
+
serializers.select { |s| s.supports?(:parse) }
|
|
158
315
|
when 'generation'
|
|
159
316
|
serializers.select { |s| s.supports?(:generate) }
|
|
160
317
|
when 'streaming'
|
|
161
318
|
serializers.select { |s| s.supports?(:sax) || s.supports?(:streaming) }
|
|
162
319
|
when 'xpath'
|
|
163
320
|
serializers.select { |s| s.supports?(:xpath) }
|
|
321
|
+
when 'xquery'
|
|
322
|
+
serializers.select { |s| s.supports?(:xquery) }
|
|
323
|
+
when 'xslt'
|
|
324
|
+
serializers.select { |s| s.supports?(:xslt) }
|
|
325
|
+
when 'validation'
|
|
326
|
+
serializers.select { |s| s.supports?(:validation) }
|
|
327
|
+
when 'xslt30'
|
|
328
|
+
serializers.select { |s| s.supports?(:xslt30) }
|
|
164
329
|
else
|
|
165
330
|
serializers
|
|
166
331
|
end
|
|
@@ -48,10 +48,10 @@ module Serialbench
|
|
|
48
48
|
attribute :name, :string
|
|
49
49
|
attribute :description, :string
|
|
50
50
|
attribute :data_sizes, :string, collection: true, values: %w[small medium large]
|
|
51
|
-
attribute :formats, :string, collection: true, values: %w[xml json yaml toml]
|
|
51
|
+
attribute :formats, :string, collection: true, values: %w[xml html json yaml toml]
|
|
52
52
|
attribute :iterations, BenchmarkIteration
|
|
53
53
|
attribute :warmup, :integer, default: -> { 1 }
|
|
54
|
-
attribute :operations, :string, collection: true, values: %w[parsing generation xpath streaming memory]
|
|
54
|
+
attribute :operations, :string, collection: true, values: %w[parsing generation xpath xquery xslt xslt30 validation streaming memory]
|
|
55
55
|
|
|
56
56
|
key_value do
|
|
57
57
|
map 'name', to: :name
|
|
@@ -5,7 +5,7 @@ require 'lutaml/model'
|
|
|
5
5
|
module Serialbench
|
|
6
6
|
module Models
|
|
7
7
|
class SerializerInformation < Lutaml::Model::Serializable
|
|
8
|
-
attribute :format, :string, values: %w[xml json yaml toml]
|
|
8
|
+
attribute :format, :string, values: %w[xml html json yaml toml]
|
|
9
9
|
attribute :name, :string
|
|
10
10
|
attribute :version, :string
|
|
11
11
|
attribute :features, :hash
|
|
@@ -20,7 +20,7 @@ module Serialbench
|
|
|
20
20
|
|
|
21
21
|
class AdapterPerformance < Lutaml::Model::Serializable
|
|
22
22
|
attribute :adapter, :string
|
|
23
|
-
attribute :format, :string, values: %w[xml json yaml toml]
|
|
23
|
+
attribute :format, :string, values: %w[xml html json yaml toml]
|
|
24
24
|
attribute :data_size, :string, values: %w[small medium large]
|
|
25
25
|
|
|
26
26
|
key_value do
|
|
@@ -71,6 +71,10 @@ module Serialbench
|
|
|
71
71
|
attribute :memory, MemoryPerformance, collection: true
|
|
72
72
|
attribute :streaming, IterationPerformance, collection: true
|
|
73
73
|
attribute :xpath, IterationPerformance, collection: true
|
|
74
|
+
attribute :xquery, IterationPerformance, collection: true
|
|
75
|
+
attribute :xslt, IterationPerformance, collection: true
|
|
76
|
+
attribute :xslt30, IterationPerformance, collection: true
|
|
77
|
+
attribute :validation, IterationPerformance, collection: true
|
|
74
78
|
|
|
75
79
|
key_value do
|
|
76
80
|
map 'serializers', to: :serializers
|
|
@@ -79,6 +83,10 @@ module Serialbench
|
|
|
79
83
|
map 'memory', to: :memory
|
|
80
84
|
map 'streaming', to: :streaming
|
|
81
85
|
map 'xpath', to: :xpath
|
|
86
|
+
map 'xquery', to: :xquery
|
|
87
|
+
map 'xslt', to: :xslt
|
|
88
|
+
map 'xslt30', to: :xslt30
|
|
89
|
+
map 'validation', to: :validation
|
|
82
90
|
end
|
|
83
91
|
end
|
|
84
92
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../base_serializer'
|
|
4
|
+
|
|
5
|
+
module Serialbench
|
|
6
|
+
module Serializers
|
|
7
|
+
module Html
|
|
8
|
+
class BaseHtmlSerializer < BaseSerializer
|
|
9
|
+
def self.format
|
|
10
|
+
:html
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def capabilities
|
|
14
|
+
super | Set.new(%i[dom parse generate])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def features
|
|
18
|
+
{
|
|
19
|
+
html5: supports?(:html5),
|
|
20
|
+
xpath: supports?(:xpath)
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def generate(data)
|
|
25
|
+
data.is_a?(Hash) ? from_hash(data) : serialize_document(data)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def from_hash(hash)
|
|
29
|
+
rows = hash.flat_map do |key, value|
|
|
30
|
+
case value
|
|
31
|
+
when Hash then value.map { |k, v| "<tr><td>#{k}</td><td>#{v}</td></tr>" }
|
|
32
|
+
else ["<tr><td>#{key}</td><td>#{value}</td></tr>"]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
serialize_document(parse("<html><body><table>#{rows.join}</table></body></html>"))
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_html_serializer'
|
|
4
|
+
|
|
5
|
+
module Serialbench
|
|
6
|
+
module Serializers
|
|
7
|
+
module Html
|
|
8
|
+
class LeptrisSerializer < BaseHtmlSerializer
|
|
9
|
+
def name
|
|
10
|
+
'leptris'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def capabilities
|
|
14
|
+
super | Set.new(%i[xpath html5])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def parse(html_string)
|
|
18
|
+
require 'leptris'
|
|
19
|
+
require 'leptris/xml'
|
|
20
|
+
Leptris::XML.parse_html(html_string)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def xpath_query(document, expression)
|
|
24
|
+
document.xpath(expression).size
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def serialize_document(document)
|
|
28
|
+
document.to_xml
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def available?
|
|
32
|
+
return @available if defined?(@available)
|
|
33
|
+
|
|
34
|
+
@available = begin
|
|
35
|
+
require 'leptris'
|
|
36
|
+
require 'leptris/xml'
|
|
37
|
+
Leptris::XML.parse_html('<p>probe</p>')
|
|
38
|
+
true
|
|
39
|
+
rescue StandardError, LoadError => e
|
|
40
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def version
|
|
46
|
+
return 'unknown' unless available?
|
|
47
|
+
|
|
48
|
+
require 'leptris'
|
|
49
|
+
Leptris::VERSION
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def library_require_name
|
|
53
|
+
'leptris'
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_html_serializer'
|
|
4
|
+
|
|
5
|
+
module Serialbench
|
|
6
|
+
module Serializers
|
|
7
|
+
module Html
|
|
8
|
+
class NokogiriSerializer < BaseHtmlSerializer
|
|
9
|
+
def name
|
|
10
|
+
'nokogiri'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def capabilities
|
|
14
|
+
super | Set.new(%i[xpath html5])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def parse(html_string)
|
|
18
|
+
require 'nokogiri'
|
|
19
|
+
Nokogiri::HTML5(html_string)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def xpath_query(document, expression)
|
|
23
|
+
document.xpath(expression).size
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def serialize_document(document)
|
|
27
|
+
document.to_html
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def available?
|
|
31
|
+
return @available if defined?(@available)
|
|
32
|
+
|
|
33
|
+
@available = begin
|
|
34
|
+
require 'nokogiri'
|
|
35
|
+
Nokogiri::HTML5('<p>probe</p>')
|
|
36
|
+
true
|
|
37
|
+
rescue StandardError, LoadError => e
|
|
38
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def version
|
|
44
|
+
return 'unknown' unless available?
|
|
45
|
+
|
|
46
|
+
require 'nokogiri'
|
|
47
|
+
Nokogiri::VERSION
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def library_require_name
|
|
51
|
+
'nokogiri'
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_html_serializer'
|
|
4
|
+
|
|
5
|
+
module Serialbench
|
|
6
|
+
module Serializers
|
|
7
|
+
module Html
|
|
8
|
+
class OgaSerializer < BaseHtmlSerializer
|
|
9
|
+
def name
|
|
10
|
+
'oga'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def parse(html_string)
|
|
14
|
+
require 'oga'
|
|
15
|
+
Oga.parse_html(html_string)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def serialize_document(document)
|
|
19
|
+
document.to_xml
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def available?
|
|
23
|
+
return @available if defined?(@available)
|
|
24
|
+
|
|
25
|
+
@available = begin
|
|
26
|
+
require 'oga'
|
|
27
|
+
Oga.parse_html('<p>probe</p>')
|
|
28
|
+
true
|
|
29
|
+
rescue StandardError, LoadError => e
|
|
30
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def version
|
|
36
|
+
return 'unknown' unless available?
|
|
37
|
+
|
|
38
|
+
require 'oga'
|
|
39
|
+
Oga::VERSION
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def library_require_name
|
|
43
|
+
'oga'
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -37,7 +37,26 @@ module Serialbench
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def capabilities
|
|
40
|
-
super | Set.new(%i[xpath sax stax])
|
|
40
|
+
super | Set.new(%i[xpath xquery xslt xslt30 validation sax stax])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def xquery_eval(document, expression)
|
|
44
|
+
require 'leptris'
|
|
45
|
+
require 'leptris/xml'
|
|
46
|
+
result = Leptris::XML::XQuery.parse(expression).eval(document)
|
|
47
|
+
result.respond_to?(:length) ? result.length : 1
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def xslt_transform(document, stylesheet)
|
|
51
|
+
require 'leptris'
|
|
52
|
+
require 'leptris/xml'
|
|
53
|
+
Leptris::XML::XSLT.parse(stylesheet).apply_to(document).serialize
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def validate(document, schema)
|
|
57
|
+
require 'leptris'
|
|
58
|
+
require 'leptris/xml'
|
|
59
|
+
Leptris::XML::RelaxNG.parse(schema).valid?(document)
|
|
41
60
|
end
|
|
42
61
|
|
|
43
62
|
def xpath_query(document, expression)
|
|
@@ -39,7 +39,17 @@ module Serialbench
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def capabilities
|
|
42
|
-
super | Set.new(%i[xpath sax stax])
|
|
42
|
+
super | Set.new(%i[xpath xslt validation sax stax])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def xslt_transform(document, stylesheet)
|
|
46
|
+
require 'nokogiri'
|
|
47
|
+
Nokogiri::XSLT(stylesheet).transform(document).to_s
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def validate(document, schema)
|
|
51
|
+
require 'nokogiri'
|
|
52
|
+
Nokogiri::XML::RelaxNG(schema).valid?(document)
|
|
43
53
|
end
|
|
44
54
|
|
|
45
55
|
def xpath_query(document, expression)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_xml_serializer'
|
|
4
|
+
require 'open3'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
|
|
7
|
+
module Serialbench
|
|
8
|
+
module Serializers
|
|
9
|
+
module Xml
|
|
10
|
+
# Saxon-HE via its Java CLI: the reference XSLT 2.0/3.0 engine.
|
|
11
|
+
# Cold-process semantics: every iteration is a full JVM + compile +
|
|
12
|
+
# transform, so ips is comparable to leptris only end-to-end, never
|
|
13
|
+
# per-transform — features record cold_process: true.
|
|
14
|
+
class SaxonSerializer < BaseXmlSerializer
|
|
15
|
+
def name
|
|
16
|
+
'saxon-he'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def capabilities
|
|
20
|
+
Set.new(%i[xslt xslt30])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def features
|
|
24
|
+
{ 'xslt_version' => '3.0', 'cold_process' => true }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def classpath
|
|
28
|
+
jars = [ENV['SAXON_JAR'], ENV['XMLRESOLVER_JAR']].compact
|
|
29
|
+
jars.empty? ? nil : jars.join(File::PATH_SEPARATOR)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def xslt_apply(source_xml, stylesheet)
|
|
33
|
+
Dir.mktmpdir('saxonbench') do |dir|
|
|
34
|
+
src = File.join(dir, 's.xml')
|
|
35
|
+
xsl = File.join(dir, 's.xsl')
|
|
36
|
+
File.write(src, source_xml)
|
|
37
|
+
File.write(xsl, stylesheet)
|
|
38
|
+
out, _err, _st = Open3.capture3('java', '-cp', classpath, 'net.sf.saxon.Transform',
|
|
39
|
+
"-xsl:#{xsl}", "-s:#{src}")
|
|
40
|
+
raise Error, "saxon transform failed: #{out}#{_err}"[0, 200] unless _st.success?
|
|
41
|
+
|
|
42
|
+
out
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def available?
|
|
47
|
+
return @available if defined?(@available)
|
|
48
|
+
|
|
49
|
+
@available = begin
|
|
50
|
+
cp = classpath
|
|
51
|
+
raise LoadError, 'SAXON_JAR / XMLRESOLVER_JAR not set' unless cp
|
|
52
|
+
|
|
53
|
+
out, _err, st = Open3.capture3('java', '-cp', cp, 'net.sf.saxon.Version')
|
|
54
|
+
raise LoadError, 'java failed' unless st.success?
|
|
55
|
+
|
|
56
|
+
true
|
|
57
|
+
rescue StandardError, LoadError => e
|
|
58
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
59
|
+
false
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def version
|
|
64
|
+
return 'unknown' unless available?
|
|
65
|
+
|
|
66
|
+
out, = Open3.capture3('java', '-cp', classpath, 'net.sf.saxon.Version')
|
|
67
|
+
out[/Saxon-HE (\S+)/, 1] || out.strip[0, 40]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -11,6 +11,13 @@ require_relative 'serializers/xml/nokogiri_serializer'
|
|
|
11
11
|
require_relative 'serializers/xml/oga_serializer'
|
|
12
12
|
require_relative 'serializers/xml/libxml_serializer'
|
|
13
13
|
require_relative 'serializers/xml/leptris_serializer'
|
|
14
|
+
require_relative 'serializers/xml/saxon_serializer'
|
|
15
|
+
|
|
16
|
+
# HTML Serializers
|
|
17
|
+
require_relative 'serializers/html/base_html_serializer'
|
|
18
|
+
require_relative 'serializers/html/nokogiri_serializer'
|
|
19
|
+
require_relative 'serializers/html/oga_serializer'
|
|
20
|
+
require_relative 'serializers/html/leptris_serializer'
|
|
14
21
|
|
|
15
22
|
# JSON Serializers
|
|
16
23
|
require_relative 'serializers/json/base_json_serializer'
|
|
@@ -43,7 +50,8 @@ module Serialbench
|
|
|
43
50
|
Xml::NokogiriSerializer,
|
|
44
51
|
Xml::OgaSerializer,
|
|
45
52
|
Xml::LibxmlSerializer,
|
|
46
|
-
Xml::LeptrisSerializer
|
|
53
|
+
Xml::LeptrisSerializer,
|
|
54
|
+
Xml::SaxonSerializer
|
|
47
55
|
],
|
|
48
56
|
json: [
|
|
49
57
|
Json::JsonSerializer,
|
|
@@ -52,6 +60,11 @@ module Serialbench
|
|
|
52
60
|
Json::YajlSerializer,
|
|
53
61
|
Json::YeptrisSerializer
|
|
54
62
|
],
|
|
63
|
+
html: [
|
|
64
|
+
Html::NokogiriSerializer,
|
|
65
|
+
Html::OgaSerializer,
|
|
66
|
+
Html::LeptrisSerializer
|
|
67
|
+
],
|
|
55
68
|
yaml: [
|
|
56
69
|
Yaml::PsychSerializer,
|
|
57
70
|
Yaml::SyckSerializer,
|
|
@@ -38,8 +38,11 @@ module Serialbench
|
|
|
38
38
|
when 'medium.yaml' then generate_medium_yaml
|
|
39
39
|
when 'large.yaml' then generate_large_yaml
|
|
40
40
|
when 'small.toml' then generate_small_toml
|
|
41
|
+
when 'small.html' then generate_small_html
|
|
41
42
|
when 'medium.toml' then generate_medium_toml
|
|
43
|
+
when 'medium.html' then generate_medium_html
|
|
42
44
|
when 'large.toml' then generate_large_toml
|
|
45
|
+
when 'large.html' then generate_large_html
|
|
43
46
|
else raise ArgumentError, "no test data generator for #{key}"
|
|
44
47
|
end
|
|
45
48
|
end
|
|
@@ -205,6 +208,50 @@ module Serialbench
|
|
|
205
208
|
XML
|
|
206
209
|
end
|
|
207
210
|
|
|
211
|
+
# HTML test data generators (same dataset as XML, as tables)
|
|
212
|
+
def generate_small_html
|
|
213
|
+
data = small_test_data_structure
|
|
214
|
+
rows = data[:config].flat_map do |_section, entries|
|
|
215
|
+
entries.flat_map do |_k, v|
|
|
216
|
+
case v
|
|
217
|
+
when Hash then v.map { |k2, v2| "<tr><td>#{k2}</td><td>#{v2}</td></tr>" }
|
|
218
|
+
else []
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
html_page('config', rows)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def generate_medium_html
|
|
226
|
+
data = medium_test_data_structure
|
|
227
|
+
rows = data[:users].map do |u|
|
|
228
|
+
"<tr><td>#{u[:id]}</td><td>#{u[:name][0, 30]}</td></tr>"
|
|
229
|
+
end
|
|
230
|
+
html_page('users', rows)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def generate_large_html
|
|
234
|
+
data = large_test_data_structure
|
|
235
|
+
rows = data[:dataset][:records].map do |r|
|
|
236
|
+
"<tr><td>#{r[:id]}</td><td>#{r[:data][:field1][0, 30]}</td></tr>"
|
|
237
|
+
end
|
|
238
|
+
html_page('dataset', rows)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def html_page(title, rows)
|
|
242
|
+
<<~HTML
|
|
243
|
+
<!DOCTYPE html>
|
|
244
|
+
<html>
|
|
245
|
+
<head><meta charset="utf-8"><title>serialbench #{title}</title></head>
|
|
246
|
+
<body>
|
|
247
|
+
<table>
|
|
248
|
+
#{rows.join("\n")}
|
|
249
|
+
</table>
|
|
250
|
+
</body>
|
|
251
|
+
</html>
|
|
252
|
+
HTML
|
|
253
|
+
end
|
|
254
|
+
|
|
208
255
|
# JSON test data generators
|
|
209
256
|
def generate_small_json
|
|
210
257
|
JSON.generate(small_test_data_structure)
|
data/lib/serialbench/version.rb
CHANGED
data/serialbench.gemspec
CHANGED
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
|
|
15
15
|
spec.summary = 'Comprehensive serialization benchmarking tool for Ruby'
|
|
16
16
|
spec.description = 'A benchmarking suite for comparing performance of various serialization libraries in Ruby, including XML, JSON, and TOML parsers/generators.'
|
|
17
|
-
spec.homepage = 'https://github.com/serialbench/serialbench'
|
|
17
|
+
spec.homepage = 'https://github.com/serialbench/serialbench-ruby'
|
|
18
18
|
spec.license = 'BSD-2-Clause'
|
|
19
19
|
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
|
|
20
20
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: serialbench
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
@@ -270,6 +270,7 @@ files:
|
|
|
270
270
|
- Gemfile
|
|
271
271
|
- README.adoc
|
|
272
272
|
- Rakefile
|
|
273
|
+
- config/benchmarks/full-html.yml
|
|
273
274
|
- config/benchmarks/full-json.yml
|
|
274
275
|
- config/benchmarks/full-toml.yml
|
|
275
276
|
- config/benchmarks/full-xml.yml
|
|
@@ -323,6 +324,10 @@ files:
|
|
|
323
324
|
- lib/serialbench/runners/local_runner.rb
|
|
324
325
|
- lib/serialbench/serializers.rb
|
|
325
326
|
- lib/serialbench/serializers/base_serializer.rb
|
|
327
|
+
- lib/serialbench/serializers/html/base_html_serializer.rb
|
|
328
|
+
- lib/serialbench/serializers/html/leptris_serializer.rb
|
|
329
|
+
- lib/serialbench/serializers/html/nokogiri_serializer.rb
|
|
330
|
+
- lib/serialbench/serializers/html/oga_serializer.rb
|
|
326
331
|
- lib/serialbench/serializers/json/base_json_serializer.rb
|
|
327
332
|
- lib/serialbench/serializers/json/json_serializer.rb
|
|
328
333
|
- lib/serialbench/serializers/json/oj_serializer.rb
|
|
@@ -341,6 +346,7 @@ files:
|
|
|
341
346
|
- lib/serialbench/serializers/xml/oga_serializer.rb
|
|
342
347
|
- lib/serialbench/serializers/xml/ox_serializer.rb
|
|
343
348
|
- lib/serialbench/serializers/xml/rexml_serializer.rb
|
|
349
|
+
- lib/serialbench/serializers/xml/saxon_serializer.rb
|
|
344
350
|
- lib/serialbench/serializers/yaml/base_yaml_serializer.rb
|
|
345
351
|
- lib/serialbench/serializers/yaml/psych_serializer.rb
|
|
346
352
|
- lib/serialbench/serializers/yaml/syck_serializer.rb
|
|
@@ -349,13 +355,13 @@ files:
|
|
|
349
355
|
- lib/serialbench/version.rb
|
|
350
356
|
- lib/serialbench/yaml_validator.rb
|
|
351
357
|
- serialbench.gemspec
|
|
352
|
-
homepage: https://github.com/serialbench/serialbench
|
|
358
|
+
homepage: https://github.com/serialbench/serialbench-ruby
|
|
353
359
|
licenses:
|
|
354
360
|
- BSD-2-Clause
|
|
355
361
|
metadata:
|
|
356
|
-
homepage_uri: https://github.com/serialbench/serialbench
|
|
357
|
-
source_code_uri: https://github.com/serialbench/serialbench
|
|
358
|
-
bug_tracker_uri: https://github.com/serialbench/serialbench/issues
|
|
362
|
+
homepage_uri: https://github.com/serialbench/serialbench-ruby
|
|
363
|
+
source_code_uri: https://github.com/serialbench/serialbench-ruby
|
|
364
|
+
bug_tracker_uri: https://github.com/serialbench/serialbench-ruby/issues
|
|
359
365
|
rdoc_options: []
|
|
360
366
|
require_paths:
|
|
361
367
|
- lib
|