trenni 3.7.1 → 3.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bake/trenni/entities.rb +57 -0
- data/bake/trenni/parsers.rb +66 -0
- data/ext/Rakefile +1 -0
- data/ext/tmp/x86_64-linux/lib/trenni/trenni.so +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/Makefile +263 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/escape.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/markup.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/mkmf.log +108 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/tag.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/template.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/trenni.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.4.0/trenni.so +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/Makefile +266 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/escape.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/markup.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/mkmf.log +113 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/query.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/tag.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/template.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/trenni.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.0/trenni.so +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/Makefile +266 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/escape.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/markup.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/mkmf.log +113 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/query.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/tag.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/template.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/trenni.o +0 -0
- data/ext/tmp/x86_64-linux/trenni/2.7.1/trenni.so +0 -0
- data/ext/trenni/extconf.rb +1 -0
- data/ext/trenni/markup.c +85 -85
- data/ext/trenni/markup.rl +11 -11
- data/ext/trenni/query.c +619 -0
- data/ext/trenni/query.h +6 -0
- data/ext/trenni/query.rl +82 -0
- data/ext/trenni/tag.c +8 -6
- data/ext/trenni/template.c +57 -57
- data/ext/trenni/template.rl +4 -4
- data/ext/trenni/trenni.c +9 -1
- data/ext/trenni/trenni.h +8 -3
- data/lib/trenni.rb +4 -0
- data/lib/trenni/buffer.rb +2 -0
- data/lib/trenni/builder.rb +64 -12
- data/lib/trenni/entities.rb +2082 -2082
- data/lib/trenni/entities.trenni +1 -3
- data/lib/trenni/{parse_error.rb → error.rb} +6 -1
- data/lib/trenni/fallback/markup.rb +1623 -1575
- data/lib/trenni/fallback/markup.rl +3 -2
- data/lib/trenni/fallback/markup.rl.dot +278 -0
- data/lib/trenni/fallback/markup.rl.pdf +0 -0
- data/lib/trenni/fallback/query.rb +565 -0
- data/lib/trenni/fallback/query.rl +105 -0
- data/lib/trenni/fallback/query.rl.dot +54 -0
- data/lib/trenni/fallback/query.rl.pdf +0 -0
- data/lib/trenni/fallback/template.rb +756 -747
- data/lib/trenni/fallback/template.rl +1 -1
- data/lib/trenni/fallback/template.rl.dot +270 -0
- data/lib/trenni/fallback/template.rl.pdf +0 -0
- data/lib/trenni/markup.rb +2 -0
- data/lib/trenni/native.rb +3 -1
- data/lib/trenni/parse_delegate.rb +2 -0
- data/lib/trenni/parsers.rb +2 -0
- data/lib/trenni/query.rb +94 -0
- data/lib/trenni/reference.rb +125 -0
- data/lib/trenni/strings.rb +17 -4
- data/lib/trenni/tag.rb +2 -0
- data/lib/trenni/template.rb +25 -22
- data/lib/trenni/trenni.so +0 -0
- data/lib/trenni/uri.rb +3 -0
- data/lib/trenni/version.rb +3 -1
- data/parsers/trenni/query.rl +23 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/trenni/builder_spec.rb +14 -1
- data/spec/trenni/corpus/large.rb +2 -0
- data/spec/trenni/markup_parser_spec.rb +1 -0
- data/spec/trenni/markup_performance_spec.rb +15 -2
- data/spec/trenni/markup_spec.rb +1 -0
- data/spec/trenni/parsers_performance_spec.rb +32 -0
- data/spec/trenni/query_spec.rb +51 -0
- data/spec/trenni/reference_spec.rb +87 -0
- data/spec/trenni/strings_spec.rb +1 -0
- data/spec/trenni/tag_spec.rb +2 -0
- data/spec/trenni/template_error_spec.rb +1 -0
- data/spec/trenni/template_performance_spec.rb +1 -0
- data/spec/trenni/template_spec.rb +1 -0
- data/spec/trenni/template_spec/builder.trenni +2 -2
- data/spec/trenni/uri_spec.rb +1 -0
- metadata +95 -62
- data/.gitignore +0 -19
- data/.rspec +0 -5
- data/.simplecov +0 -9
- data/.travis.yml +0 -23
- data/Gemfile +0 -20
- data/README.md +0 -312
- data/Rakefile +0 -19
- data/benchmark/call_vs_yield.rb +0 -51
- data/benchmark/interpolation_vs_concat.rb +0 -29
- data/benchmark/io_vs_string.rb +0 -90
- data/entities.json +0 -2233
- data/tasks/entities.rake +0 -33
- data/tasks/parsers.rake +0 -43
- data/trenni.gemspec +0 -33
data/spec/trenni/strings_spec.rb
CHANGED
data/spec/trenni/tag_spec.rb
CHANGED
data/spec/trenni/uri_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trenni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: bundler
|
28
|
+
name: bake-bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,21 +39,35 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: bake-modernize
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
70
|
+
name: covered
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - ">="
|
@@ -66,35 +80,66 @@ dependencies:
|
|
66
80
|
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.4'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.4'
|
97
|
+
description:
|
73
98
|
email:
|
74
|
-
- samuel.williams@oriontransfer.co.nz
|
75
99
|
executables: []
|
76
100
|
extensions:
|
77
101
|
- ext/Rakefile
|
78
102
|
extra_rdoc_files: []
|
79
103
|
files:
|
80
|
-
-
|
81
|
-
-
|
82
|
-
- ".simplecov"
|
83
|
-
- ".travis.yml"
|
84
|
-
- Gemfile
|
85
|
-
- README.md
|
86
|
-
- Rakefile
|
87
|
-
- benchmark/call_vs_yield.rb
|
88
|
-
- benchmark/interpolation_vs_concat.rb
|
89
|
-
- benchmark/io_vs_string.rb
|
90
|
-
- entities.json
|
104
|
+
- bake/trenni/entities.rb
|
105
|
+
- bake/trenni/parsers.rb
|
91
106
|
- ext/Rakefile
|
107
|
+
- ext/tmp/x86_64-linux/lib/trenni/trenni.so
|
108
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/Makefile
|
109
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/escape.o
|
110
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/markup.o
|
111
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/mkmf.log
|
112
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/tag.o
|
113
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/template.o
|
114
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/trenni.o
|
115
|
+
- ext/tmp/x86_64-linux/trenni/2.4.0/trenni.so
|
116
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/Makefile
|
117
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/escape.o
|
118
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/markup.o
|
119
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/mkmf.log
|
120
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/query.o
|
121
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/tag.o
|
122
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/template.o
|
123
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/trenni.o
|
124
|
+
- ext/tmp/x86_64-linux/trenni/2.7.0/trenni.so
|
125
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/Makefile
|
126
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/escape.o
|
127
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/markup.o
|
128
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/mkmf.log
|
129
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/query.o
|
130
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/tag.o
|
131
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/template.o
|
132
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/trenni.o
|
133
|
+
- ext/tmp/x86_64-linux/trenni/2.7.1/trenni.so
|
92
134
|
- ext/trenni/escape.c
|
93
135
|
- ext/trenni/escape.h
|
94
136
|
- ext/trenni/extconf.rb
|
95
137
|
- ext/trenni/markup.c
|
96
138
|
- ext/trenni/markup.h
|
97
139
|
- ext/trenni/markup.rl
|
140
|
+
- ext/trenni/query.c
|
141
|
+
- ext/trenni/query.h
|
142
|
+
- ext/trenni/query.rl
|
98
143
|
- ext/trenni/tag.c
|
99
144
|
- ext/trenni/tag.h
|
100
145
|
- ext/trenni/template.c
|
@@ -107,22 +152,34 @@ files:
|
|
107
152
|
- lib/trenni/builder.rb
|
108
153
|
- lib/trenni/entities.rb
|
109
154
|
- lib/trenni/entities.trenni
|
155
|
+
- lib/trenni/error.rb
|
110
156
|
- lib/trenni/fallback/markup.rb
|
111
157
|
- lib/trenni/fallback/markup.rl
|
158
|
+
- lib/trenni/fallback/markup.rl.dot
|
159
|
+
- lib/trenni/fallback/markup.rl.pdf
|
160
|
+
- lib/trenni/fallback/query.rb
|
161
|
+
- lib/trenni/fallback/query.rl
|
162
|
+
- lib/trenni/fallback/query.rl.dot
|
163
|
+
- lib/trenni/fallback/query.rl.pdf
|
112
164
|
- lib/trenni/fallback/template.rb
|
113
165
|
- lib/trenni/fallback/template.rl
|
166
|
+
- lib/trenni/fallback/template.rl.dot
|
167
|
+
- lib/trenni/fallback/template.rl.pdf
|
114
168
|
- lib/trenni/markup.rb
|
115
169
|
- lib/trenni/native.rb
|
116
170
|
- lib/trenni/parse_delegate.rb
|
117
|
-
- lib/trenni/parse_error.rb
|
118
171
|
- lib/trenni/parsers.rb
|
172
|
+
- lib/trenni/query.rb
|
173
|
+
- lib/trenni/reference.rb
|
119
174
|
- lib/trenni/strings.rb
|
120
175
|
- lib/trenni/tag.rb
|
121
176
|
- lib/trenni/template.rb
|
177
|
+
- lib/trenni/trenni.so
|
122
178
|
- lib/trenni/uri.rb
|
123
179
|
- lib/trenni/version.rb
|
124
180
|
- parsers/trenni/entities.rl
|
125
181
|
- parsers/trenni/markup.rl
|
182
|
+
- parsers/trenni/query.rl
|
126
183
|
- parsers/trenni/template.rl
|
127
184
|
- spec/spec_helper.rb
|
128
185
|
- spec/trenni/builder_spec.rb
|
@@ -132,6 +189,8 @@ files:
|
|
132
189
|
- spec/trenni/markup_performance_spec.rb
|
133
190
|
- spec/trenni/markup_spec.rb
|
134
191
|
- spec/trenni/parsers_performance_spec.rb
|
192
|
+
- spec/trenni/query_spec.rb
|
193
|
+
- spec/trenni/reference_spec.rb
|
135
194
|
- spec/trenni/strings_spec.rb
|
136
195
|
- spec/trenni/tag_spec.rb
|
137
196
|
- spec/trenni/template_error_spec.rb
|
@@ -149,13 +208,12 @@ files:
|
|
149
208
|
- spec/trenni/template_spec/lines.trenni
|
150
209
|
- spec/trenni/template_spec/nested.trenni
|
151
210
|
- spec/trenni/uri_spec.rb
|
152
|
-
- tasks/entities.rake
|
153
|
-
- tasks/parsers.rake
|
154
|
-
- trenni.gemspec
|
155
211
|
homepage: https://github.com/ioquatix/trenni
|
156
|
-
licenses:
|
157
|
-
|
158
|
-
|
212
|
+
licenses:
|
213
|
+
- MIT
|
214
|
+
metadata:
|
215
|
+
funding_uri: https://github.com/sponsors/ioquatix
|
216
|
+
post_install_message:
|
159
217
|
rdoc_options: []
|
160
218
|
require_paths:
|
161
219
|
- lib
|
@@ -163,40 +221,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
163
221
|
requirements:
|
164
222
|
- - "~>"
|
165
223
|
- !ruby/object:Gem::Version
|
166
|
-
version: '2.
|
224
|
+
version: '2.4'
|
167
225
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
226
|
requirements:
|
169
227
|
- - ">="
|
170
228
|
- !ruby/object:Gem::Version
|
171
229
|
version: '0'
|
172
230
|
requirements: []
|
173
|
-
rubygems_version: 3.
|
174
|
-
signing_key:
|
231
|
+
rubygems_version: 3.1.2
|
232
|
+
signing_key:
|
175
233
|
specification_version: 4
|
176
234
|
summary: A fast native templating system that compiles directly to Ruby code.
|
177
|
-
test_files:
|
178
|
-
- spec/spec_helper.rb
|
179
|
-
- spec/trenni/builder_spec.rb
|
180
|
-
- spec/trenni/corpus/large.rb
|
181
|
-
- spec/trenni/corpus/large.xhtml
|
182
|
-
- spec/trenni/markup_parser_spec.rb
|
183
|
-
- spec/trenni/markup_performance_spec.rb
|
184
|
-
- spec/trenni/markup_spec.rb
|
185
|
-
- spec/trenni/parsers_performance_spec.rb
|
186
|
-
- spec/trenni/strings_spec.rb
|
187
|
-
- spec/trenni/tag_spec.rb
|
188
|
-
- spec/trenni/template_error_spec.rb
|
189
|
-
- spec/trenni/template_performance_spec.rb
|
190
|
-
- spec/trenni/template_spec.rb
|
191
|
-
- spec/trenni/template_spec/basic.trenni
|
192
|
-
- spec/trenni/template_spec/buffer.trenni
|
193
|
-
- spec/trenni/template_spec/builder.trenni
|
194
|
-
- spec/trenni/template_spec/capture.trenni
|
195
|
-
- spec/trenni/template_spec/error.trenni
|
196
|
-
- spec/trenni/template_spec/escaped.trenni
|
197
|
-
- spec/trenni/template_spec/interpolations.trenni
|
198
|
-
- spec/trenni/template_spec/large.erb
|
199
|
-
- spec/trenni/template_spec/large.trenni
|
200
|
-
- spec/trenni/template_spec/lines.trenni
|
201
|
-
- spec/trenni/template_spec/nested.trenni
|
202
|
-
- spec/trenni/uri_spec.rb
|
235
|
+
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.simplecov
DELETED
data/.travis.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
cache: bundler
|
3
|
-
|
4
|
-
before_script:
|
5
|
-
- sh -c "cd ext && bundle exec rake compile"
|
6
|
-
|
7
|
-
matrix:
|
8
|
-
include:
|
9
|
-
- rvm: 2.3
|
10
|
-
- rvm: 2.4
|
11
|
-
- rvm: 2.5
|
12
|
-
- rvm: 2.6
|
13
|
-
- rvm: 2.6
|
14
|
-
env: TRENNI_PREFER_FALLBACK=y
|
15
|
-
- rvm: 2.6
|
16
|
-
env: COVERAGE=Summary
|
17
|
-
- rvm: ruby-head
|
18
|
-
- rvm: jruby-head
|
19
|
-
- rvm: truffleruby
|
20
|
-
allow_failures:
|
21
|
-
- rvm: "truffleruby"
|
22
|
-
- rvm: "ruby-head"
|
23
|
-
- rvm: "jruby-head"
|
data/Gemfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in trenni.gemspec
|
4
|
-
gemspec
|
5
|
-
|
6
|
-
group :development do
|
7
|
-
gem 'pry'
|
8
|
-
gem "rake-compiler"
|
9
|
-
gem "ruby-beautify"
|
10
|
-
end
|
11
|
-
|
12
|
-
group :test do
|
13
|
-
gem 'ruby-prof', platforms: [:mri]
|
14
|
-
gem "benchmark-ips"
|
15
|
-
|
16
|
-
gem 'covered'
|
17
|
-
|
18
|
-
# For comparisons:
|
19
|
-
gem "nokogiri"
|
20
|
-
end
|
data/README.md
DELETED
@@ -1,312 +0,0 @@
|
|
1
|
-
# Trenni
|
2
|
-
|
3
|
-
Trenni is a templating system built loosely on top of XHTML markup. It uses efficient native parsers where possible and compiles templates into efficient Ruby. It also includes a markup builder to assist with the generation of pleasantly formatted markup which is compatible with the included parsers.
|
4
|
-
|
5
|
-
[![Build Status](https://secure.travis-ci.org/ioquatix/trenni.svg)](http://travis-ci.org/ioquatix/trenni)
|
6
|
-
[![Code Climate](https://codeclimate.com/github/ioquatix/trenni.svg)](https://codeclimate.com/github/ioquatix/trenni)
|
7
|
-
[![Coverage Status](https://coveralls.io/repos/ioquatix/trenni/badge.svg)](https://coveralls.io/r/ioquatix/trenni)
|
8
|
-
|
9
|
-
## Motivation
|
10
|
-
|
11
|
-
Trenni was designed for [Utopia](https://github.com/ioquatix/utopia). When I originally looked at template engines, I was surprised by the level of complexity and the effort involved in processing a template to produce useful output. In particular, many template engines generate an AST and walk over it to generate output (e.g. ERB, at least at the time I last checked). This is exceedingly slow in Ruby.
|
12
|
-
|
13
|
-
At the time (around 2008?) I was playing around with [ramaze](https://github.com/Ramaze/ramaze) and found a template engine I really liked the design of, called [ezamar](https://github.com/manveru/ezamar). The template compilation process actually generates Ruby code which can then be compiled and executed efficiently. Another engine, by the same author, [nagoro](https://github.com/manveru/nagoro), also provided some inspiration.
|
14
|
-
|
15
|
-
More recently I was doing some investigation regarding using `eval` for executing the code. The problem is that it's [not possible to replace the binding](http://stackoverflow.com/questions/27391909/replace-evalcode-string-binding-with-lambda/27392437) of a `Proc` once it's created, so template engines that evaluate code in a given binding cannot use a compiled proc, they must parse the code every time. By using a `Proc` we can generate a Ruby function which *can* be compiled to a faster representation by the VM.
|
16
|
-
|
17
|
-
In addition, I wanted a simple markup parser and builder for HTML style markup. These are used heavily by Utopia for implementing it's tag based evaluation. `Trenni::Builder` is a simple and efficient way to generate markup, it's not particularly notable, except that it doesn't use `method_missing` to [implement normal behaviour](https://github.com/sparklemotion/nokogiri/blob/b6679e928924529b56dcc0f3164224c040d14555/lib/nokogiri/xml/builder.rb#L355) which is [sort of slow](http://franck.verrot.fr/blog/2015/07/12/benchmarking-ruby-method-missing-and-define-method/).
|
18
|
-
|
19
|
-
The 2nd release of Trenni in 2016 saw an overhaul of the internal parsers. I used [Ragel](http://www.colm.net/open-source/ragel/) to implement efficient event-based markup and template parsers, which can be compiled to both C and Ruby. This provides a native code path where possible giving speed-ups between 10x - 20x. In addition, the formal grammar is more robust.
|
20
|
-
|
21
|
-
The 3rd release of Trenni in 2017 was primarily focused on performance, by moving more of the critical parsing, escaping and tag generation functions to C. In practical usage, this gave about a 40-50% improvement in performance overall.
|
22
|
-
|
23
|
-
## Is it fast?
|
24
|
-
|
25
|
-
It's faster than Nokogiri for parsing markup:
|
26
|
-
|
27
|
-
Trenni::Native
|
28
|
-
Warming up --------------------------------------
|
29
|
-
Large (Trenni) 71.000 i/100ms
|
30
|
-
Large (Nokogiri) 28.000 i/100ms
|
31
|
-
Calculating -------------------------------------
|
32
|
-
Large (Trenni) 662.050 (± 3.9%) i/s - 3.337k in 5.048115s
|
33
|
-
Large (Nokogiri) 266.878 (±10.9%) i/s - 1.316k in 5.008464s
|
34
|
-
|
35
|
-
Comparison:
|
36
|
-
Large (Trenni): 662.1 i/s
|
37
|
-
Large (Nokogiri): 266.9 i/s - 2.48x slower
|
38
|
-
|
39
|
-
It's significantly faster than ERB:
|
40
|
-
|
41
|
-
Trenni::Template
|
42
|
-
Warming up --------------------------------------
|
43
|
-
Trenni (object) 75.667k i/100ms
|
44
|
-
ERB (binding) 6.940k i/100ms
|
45
|
-
Calculating -------------------------------------
|
46
|
-
Trenni (object) 1.095M (± 7.9%) i/s - 5.448M in 5.007244s
|
47
|
-
ERB (binding) 69.381k (± 7.1%) i/s - 347.000k in 5.027333s
|
48
|
-
|
49
|
-
Comparison:
|
50
|
-
Trenni (object): 1094979.9 i/s
|
51
|
-
ERB (binding): 69381.1 i/s - 15.78x slower
|
52
|
-
|
53
|
-
## Installation
|
54
|
-
|
55
|
-
Add this line to your application's Gemfile:
|
56
|
-
|
57
|
-
gem 'trenni'
|
58
|
-
|
59
|
-
And then execute:
|
60
|
-
|
61
|
-
$ bundle
|
62
|
-
|
63
|
-
Or install it yourself as:
|
64
|
-
|
65
|
-
$ gem install trenni
|
66
|
-
|
67
|
-
## Usage
|
68
|
-
|
69
|
-
### Markup Parser
|
70
|
-
|
71
|
-
The markup parser parses a loose super-set of HTML in a way that's useful for content processing, similar to an XSLT processor. It's designed to be faster and easier to use, and integrate directly into an output pipeline.
|
72
|
-
|
73
|
-
To invoke the markup parser:
|
74
|
-
|
75
|
-
```ruby
|
76
|
-
require 'trenni'
|
77
|
-
|
78
|
-
buffer = Trenni::Buffer(string)
|
79
|
-
|
80
|
-
# Custom entities, or could use Trenni::Entities::HTML5
|
81
|
-
entities = {'amp' => '&', 'lt', => '<', 'gt' => '>', 'quot' => '"'}
|
82
|
-
|
83
|
-
# Modify this class to accumulate events or pass them on somewhere else.
|
84
|
-
class Delegate
|
85
|
-
# Called when encountering an open tag: `<` name
|
86
|
-
def open_tag_begin(name, offset)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Called when encountering an attribute after open_tag_begin
|
90
|
-
def attribute(key, value)
|
91
|
-
end
|
92
|
-
|
93
|
-
# Called when encountering the end of the opening tag.
|
94
|
-
def open_tag_end(self_closing)
|
95
|
-
end
|
96
|
-
|
97
|
-
# Called when encountering the closing tag: '</' name '>'
|
98
|
-
def close_tag(name, offset)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Called with the full doctype: '<!DOCTYPE html>'
|
102
|
-
def doctype(string)
|
103
|
-
end
|
104
|
-
|
105
|
-
# Called with the full comment: '<!-- comment -->'
|
106
|
-
def comment(string)
|
107
|
-
end
|
108
|
-
|
109
|
-
# Called with the parsed instruction: '<?' identifier space+ body '?>'
|
110
|
-
def instruction(string)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Called with a cdata block: '<![CDATA[text]]>'
|
114
|
-
def cdata(string)
|
115
|
-
end
|
116
|
-
|
117
|
-
# Called with any arbitrary pcdata text (e.g. between tags).
|
118
|
-
def text(string)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# Do the actual work:
|
123
|
-
Trenni::Parsers.parse_markup(buffer, Delegate.new, entities)
|
124
|
-
```
|
125
|
-
|
126
|
-
### Templates
|
127
|
-
|
128
|
-
Trenni templates work essentially the same way as all other templating systems:
|
129
|
-
|
130
|
-
```ruby
|
131
|
-
buffer = Trenni::Buffer('<?r self.each do |item| ?>#{item}<?r end ?>')
|
132
|
-
template = Trenni::Template.new(buffer)
|
133
|
-
|
134
|
-
items = 1..4
|
135
|
-
|
136
|
-
template.to_string(items) # => "1234"
|
137
|
-
```
|
138
|
-
|
139
|
-
The code above demonstrate the only two constructs, `<?r expression ?>` and `#{output}`.
|
140
|
-
|
141
|
-
Trenni doesn't support using `binding` for evaluation, as this is a slow code path. It uses `instance_exec`
|
142
|
-
|
143
|
-
### Builder
|
144
|
-
|
145
|
-
Trenni can help construct XML/HTML using a simple DSL:
|
146
|
-
|
147
|
-
```ruby
|
148
|
-
Trenni::Builder.fragment do |builder|
|
149
|
-
builder.inline 'p' do
|
150
|
-
builder.tag 'strong' do
|
151
|
-
builder.text 'Hello'
|
152
|
-
end
|
153
|
-
builder.text ' World'
|
154
|
-
end
|
155
|
-
end.to_s
|
156
|
-
# => "<p><strong>Hello</strong> World</p>"
|
157
|
-
```
|
158
|
-
|
159
|
-
### Testing
|
160
|
-
|
161
|
-
To test the Ruby parsers:
|
162
|
-
|
163
|
-
rake generate_fallback_parsers && TRENNI_PREFER_FALLBACK=y rspec
|
164
|
-
|
165
|
-
To test the native C parsers:
|
166
|
-
|
167
|
-
rake generate_native_parsers && rake compile && rspec
|
168
|
-
|
169
|
-
### Benchmarks
|
170
|
-
|
171
|
-
Trenni has a pure Ruby implemenation, with performance critical operations implemented natively. All critical code paths have benchmark specs.
|
172
|
-
|
173
|
-
#### Parser Performance
|
174
|
-
|
175
|
-
You can evaluate and compare template performance with ERB:
|
176
|
-
|
177
|
-
```
|
178
|
-
rspec spec/trenni/parsers_performance_spec.rb
|
179
|
-
|
180
|
-
Trenni::Native
|
181
|
-
#parse_markup
|
182
|
-
Warming up --------------------------------------
|
183
|
-
Large (Trenni) 64.000 i/100ms
|
184
|
-
Large (Nokogiri) 30.000 i/100ms
|
185
|
-
Calculating -------------------------------------
|
186
|
-
Large (Trenni) 637.720 (± 6.4%) i/s - 3.200k in 5.038187s
|
187
|
-
Large (Nokogiri) 294.762 (± 5.8%) i/s - 1.470k in 5.004284s
|
188
|
-
|
189
|
-
Comparison:
|
190
|
-
Large (Trenni): 637.7 i/s
|
191
|
-
Large (Nokogiri): 294.8 i/s - 2.16x slower
|
192
|
-
|
193
|
-
should be fast to parse large documents
|
194
|
-
#parse_template
|
195
|
-
Warming up --------------------------------------
|
196
|
-
Large (Trenni) 7.791k i/100ms
|
197
|
-
Large (ERB) 488.000 i/100ms
|
198
|
-
Calculating -------------------------------------
|
199
|
-
Large (Trenni) 87.889k (± 9.5%) i/s - 436.296k in 5.024283s
|
200
|
-
Large (ERB) 4.844k (± 5.6%) i/s - 24.400k in 5.053247s
|
201
|
-
|
202
|
-
Comparison:
|
203
|
-
Large (Trenni): 87889.4 i/s
|
204
|
-
Large (ERB): 4844.5 i/s - 18.14x slower
|
205
|
-
|
206
|
-
should have better performance using instance
|
207
|
-
|
208
|
-
Finished in 28.2 seconds (files took 0.14204 seconds to load)
|
209
|
-
2 examples, 0 failures
|
210
|
-
```
|
211
|
-
|
212
|
-
To run this with the pure ruby implementation, use `TRENNI_PREFER_FALLBACK=y rspec spec/trenni/parsers_performance_spec.rb`.
|
213
|
-
|
214
|
-
#### Markup String Performance
|
215
|
-
|
216
|
-
Markup safe strings require escaping characters. Doing this natively makes sense, and in MRI, `CGI.escape_html` is implemented in C. Strings that include characters that need to be escaped are a bit slower because a new string must be allocated and modified. So, we test these two cases.
|
217
|
-
|
218
|
-
```
|
219
|
-
rspec spec/trenni/markup_performance_spec.rb
|
220
|
-
|
221
|
-
Trenni::Markup
|
222
|
-
Warming up --------------------------------------
|
223
|
-
General String 179.396k i/100ms
|
224
|
-
Code String 85.050k i/100ms
|
225
|
-
Calculating -------------------------------------
|
226
|
-
General String 4.773M (±10.0%) i/s - 23.680M in 5.027576s
|
227
|
-
Code String 1.469M (± 5.7%) i/s - 7.399M in 5.052467s
|
228
|
-
|
229
|
-
Comparison:
|
230
|
-
General String: 4773201.3 i/s
|
231
|
-
Code String: 1469345.5 i/s - 3.25x slower
|
232
|
-
|
233
|
-
should be fast to parse large documents
|
234
|
-
|
235
|
-
Finished in 14.11 seconds (files took 0.09696 seconds to load)
|
236
|
-
1 example, 0 failures
|
237
|
-
```
|
238
|
-
|
239
|
-
#### Template Evaluation Performance
|
240
|
-
|
241
|
-
Evaluating templates and generating output is critical to performance. You can compare Trenni with ERB. The primary factor affecting performance, is the number of interpolations, because each interpolation requires evaluation and concatenation.
|
242
|
-
|
243
|
-
```
|
244
|
-
rspec spec/trenni/template_performance_spec.rb
|
245
|
-
|
246
|
-
Trenni::Template
|
247
|
-
Warming up --------------------------------------
|
248
|
-
Trenni 79.000 i/100ms
|
249
|
-
Calculating -------------------------------------
|
250
|
-
Trenni 817.703 (± 7.7%) i/s - 4.108k in 5.071586s
|
251
|
-
should be fast for lots of interpolations
|
252
|
-
Warming up --------------------------------------
|
253
|
-
Trenni (object) 79.149k i/100ms
|
254
|
-
ERB (binding) 5.416k i/100ms
|
255
|
-
Calculating -------------------------------------
|
256
|
-
Trenni (object) 1.081M (± 3.7%) i/s - 5.461M in 5.059151s
|
257
|
-
ERB (binding) 59.016k (± 4.7%) i/s - 297.880k in 5.058614s
|
258
|
-
|
259
|
-
Comparison:
|
260
|
-
Trenni (object): 1080909.2 i/s
|
261
|
-
ERB (binding): 59016.3 i/s - 18.32x slower
|
262
|
-
|
263
|
-
should be fast for basic templates
|
264
|
-
Warming up --------------------------------------
|
265
|
-
Trenni 34.204k i/100ms
|
266
|
-
Calculating -------------------------------------
|
267
|
-
Trenni 407.905k (± 9.0%) i/s - 2.018M in 5.001248s
|
268
|
-
should be fast with capture
|
269
|
-
|
270
|
-
Finished in 28.25 seconds (files took 0.09765 seconds to load)
|
271
|
-
3 examples, 0 failures
|
272
|
-
```
|
273
|
-
|
274
|
-
## See Also
|
275
|
-
|
276
|
-
- [language-trenni](https://atom.io/packages/language-trenni) package for the [Atom text editor](https://atom.io). It provides syntax highlighting and integration when Trenni is used with the [utopia web framework](https://github.com/ioquatix/utopia).
|
277
|
-
|
278
|
-
- [vim-trenni](https://github.com/huba/vim-trenni) package for Vim.
|
279
|
-
|
280
|
-
- [Trenni Formatters](https://github.com/ioquatix/trenni-formatters) is a separate gem that uses `Trenni::Builder` to generate HTML forms easily.
|
281
|
-
|
282
|
-
## Contributing
|
283
|
-
|
284
|
-
1. Fork it
|
285
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
286
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
287
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
288
|
-
5. Create new Pull Request
|
289
|
-
|
290
|
-
## License
|
291
|
-
|
292
|
-
Released under the MIT license.
|
293
|
-
|
294
|
-
Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
295
|
-
|
296
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
297
|
-
of this software and associated documentation files (the "Software"), to deal
|
298
|
-
in the Software without restriction, including without limitation the rights
|
299
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
300
|
-
copies of the Software, and to permit persons to whom the Software is
|
301
|
-
furnished to do so, subject to the following conditions:
|
302
|
-
|
303
|
-
The above copyright notice and this permission notice shall be included in
|
304
|
-
all copies or substantial portions of the Software.
|
305
|
-
|
306
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
307
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
308
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
309
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
310
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
311
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
312
|
-
THE SOFTWARE.
|