luoma 0.1.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 +7 -0
- checksums.yaml.gz.sig +2 -0
- data/.rdoc_options +16 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +68 -0
- data/Rakefile +69 -0
- data/Steepfile +41 -0
- data/certs/jgrp.pem +27 -0
- data/docs/configuration.md +180 -0
- data/docs/custom_filters.md +3 -0
- data/docs/custom_tags.md +3 -0
- data/docs/expressions.md +3 -0
- data/docs/extension_types.md +41 -0
- data/docs/filter_reference.md +1702 -0
- data/docs/index.md +73 -0
- data/docs/luoma_for_template_authors.md +3 -0
- data/docs/markdown.md +111 -0
- data/docs/predicate_reference.md +3 -0
- data/docs/static_analysis.md +3 -0
- data/docs/tag_reference.md +352 -0
- data/docs/template_loaders.md +177 -0
- data/docs/undefined_variables.md +3 -0
- data/docs-requirements.txt +11 -0
- data/docs_/cycle.md +17 -0
- data/docs_/font_rendering_example.md +157 -0
- data/docs_/header_block_example.md +51 -0
- data/docs_/increment_and_decrement.md +49 -0
- data/docs_/logo_style_example.md +40 -0
- data/docs_/migration.md +11 -0
- data/docs_/notes.md +19 -0
- data/lib/luoma/cache.rb +80 -0
- data/lib/luoma/chain_hash.rb +54 -0
- data/lib/luoma/context.rb +227 -0
- data/lib/luoma/drop.rb +84 -0
- data/lib/luoma/drops/block.rb +33 -0
- data/lib/luoma/drops/expression.rb +29 -0
- data/lib/luoma/drops/html_safe.rb +36 -0
- data/lib/luoma/drops/range.rb +69 -0
- data/lib/luoma/drops/undefined.rb +119 -0
- data/lib/luoma/environment.rb +479 -0
- data/lib/luoma/errors.rb +79 -0
- data/lib/luoma/escape.rb +35 -0
- data/lib/luoma/expression.rb +1271 -0
- data/lib/luoma/filter.rb +97 -0
- data/lib/luoma/filters/array.rb +372 -0
- data/lib/luoma/filters/date.rb +19 -0
- data/lib/luoma/filters/default.rb +16 -0
- data/lib/luoma/filters/json.rb +14 -0
- data/lib/luoma/filters/math.rb +84 -0
- data/lib/luoma/filters/size.rb +13 -0
- data/lib/luoma/filters/slice.rb +52 -0
- data/lib/luoma/filters/sort.rb +113 -0
- data/lib/luoma/filters/string.rb +186 -0
- data/lib/luoma/fnv.rb +15 -0
- data/lib/luoma/lexer.rb +106 -0
- data/lib/luoma/lexer_legacy.rb +396 -0
- data/lib/luoma/lexer_unified.rb +279 -0
- data/lib/luoma/loader.rb +50 -0
- data/lib/luoma/loaders/choice_loader.rb +20 -0
- data/lib/luoma/loaders/file_system_loader.rb +75 -0
- data/lib/luoma/loaders/mixins.rb +52 -0
- data/lib/luoma/markup.rb +109 -0
- data/lib/luoma/parser.rb +252 -0
- data/lib/luoma/parser_unified.rb +979 -0
- data/lib/luoma/predicates/blank.rb +19 -0
- data/lib/luoma/predicates/defined.rb +10 -0
- data/lib/luoma/predicates/empty.rb +15 -0
- data/lib/luoma/predicates/type.rb +35 -0
- data/lib/luoma/static_analysis.rb +427 -0
- data/lib/luoma/tags/assign.rb +63 -0
- data/lib/luoma/tags/break.rb +23 -0
- data/lib/luoma/tags/capture.rb +43 -0
- data/lib/luoma/tags/case.rb +137 -0
- data/lib/luoma/tags/comment.rb +17 -0
- data/lib/luoma/tags/continue.rb +23 -0
- data/lib/luoma/tags/define.rb +42 -0
- data/lib/luoma/tags/else.rb +30 -0
- data/lib/luoma/tags/for.rb +108 -0
- data/lib/luoma/tags/if.rb +109 -0
- data/lib/luoma/tags/import.rb +91 -0
- data/lib/luoma/tags/include.rb +77 -0
- data/lib/luoma/tags/output.rb +20 -0
- data/lib/luoma/tags/raw.rb +26 -0
- data/lib/luoma/tags/render.rb +92 -0
- data/lib/luoma/tags/with.rb +55 -0
- data/lib/luoma/template.rb +178 -0
- data/lib/luoma/token.rb +84 -0
- data/lib/luoma/version.rb +5 -0
- data/lib/luoma.rb +75 -0
- data/sig/luoma/cache.rbs +44 -0
- data/sig/luoma/chain_hash.rbs +26 -0
- data/sig/luoma/context.rbs +115 -0
- data/sig/luoma/drop.rbs +44 -0
- data/sig/luoma/drops/block.rbs +10 -0
- data/sig/luoma/drops/expression.rbs +10 -0
- data/sig/luoma/drops/html_safe.rbs +14 -0
- data/sig/luoma/drops/range.rbs +15 -0
- data/sig/luoma/drops/undefined.rbs +27 -0
- data/sig/luoma/environment.rbs +212 -0
- data/sig/luoma/errors.rbs +67 -0
- data/sig/luoma/escape.rbs +15 -0
- data/sig/luoma/expression.rbs +514 -0
- data/sig/luoma/filter.rbs +66 -0
- data/sig/luoma/filters/array.rbs +74 -0
- data/sig/luoma/filters/date.rbs +9 -0
- data/sig/luoma/filters/default.rbs +8 -0
- data/sig/luoma/filters/json.rbs +7 -0
- data/sig/luoma/filters/math.rbs +37 -0
- data/sig/luoma/filters/size.rbs +6 -0
- data/sig/luoma/filters/slice.rbs +10 -0
- data/sig/luoma/filters/sort.rbs +17 -0
- data/sig/luoma/filters/string.rbs +103 -0
- data/sig/luoma/fnv.rbs +3 -0
- data/sig/luoma/lexer.rbs +42 -0
- data/sig/luoma/lexer_legacy.rbs +81 -0
- data/sig/luoma/lexer_unified.rbs +49 -0
- data/sig/luoma/loader.rbs +40 -0
- data/sig/luoma/loaders/choice_loader.rbs +9 -0
- data/sig/luoma/loaders/file_system_loader.rbs +19 -0
- data/sig/luoma/loaders/mixins.rbs +16 -0
- data/sig/luoma/markup.rbs +68 -0
- data/sig/luoma/parser.rbs +105 -0
- data/sig/luoma/parser_unified.rbs +150 -0
- data/sig/luoma/predicates/blank.rbs +6 -0
- data/sig/luoma/predicates/defined.rbs +6 -0
- data/sig/luoma/predicates/empty.rbs +6 -0
- data/sig/luoma/predicates/type.rbs +21 -0
- data/sig/luoma/static_analysis.rbs +141 -0
- data/sig/luoma/tags/assign.rbs +12 -0
- data/sig/luoma/tags/break.rbs +11 -0
- data/sig/luoma/tags/capture.rbs +14 -0
- data/sig/luoma/tags/case.rbs +36 -0
- data/sig/luoma/tags/comment.rbs +11 -0
- data/sig/luoma/tags/continue.rbs +11 -0
- data/sig/luoma/tags/define.rbs +16 -0
- data/sig/luoma/tags/else.rbs +17 -0
- data/sig/luoma/tags/for.rbs +26 -0
- data/sig/luoma/tags/if.rbs +45 -0
- data/sig/luoma/tags/import.rbs +13 -0
- data/sig/luoma/tags/include.rbs +13 -0
- data/sig/luoma/tags/output.rbs +13 -0
- data/sig/luoma/tags/raw.rbs +11 -0
- data/sig/luoma/tags/render.rbs +13 -0
- data/sig/luoma/tags/with.rbs +15 -0
- data/sig/luoma/template.rbs +117 -0
- data/sig/luoma/token.rbs +81 -0
- data/sig/luoma.rbs +11 -0
- data/zensical.toml +363 -0
- data.tar.gz.sig +0 -0
- metadata +233 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: acb537ba303e1ce24a308b621d0ea4f878531d04d321d0ead9e2a261c2b76832
|
|
4
|
+
data.tar.gz: cc19b11460124b48b80766259d508408570323e596b6dbea5ee120edb874d298
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 05e51ff2461365ee5b41c0bd50545dc5c7444e44ee18da6fe4b15aa058cf9cc4d6d1e43420a41c61d9e37fa9fcdce096842212dd54f52f4ecd0cd34434799b04
|
|
7
|
+
data.tar.gz: 76bc4f2e919b162257b4eaf55331e7b436614442433d40056bb759ead9392a7099e195185cb8bed78219dbcd14380c93e2a89117c3d2ddfbe63e3396cdaab2e3
|
checksums.yaml.gz.sig
ADDED
data/.rdoc_options
ADDED
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 James Prior
|
|
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.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<h1 align="center">Luoma - Ruby</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">A modern template engine for Ruby.</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/jg-rp/luoma-ruby/blob/main/LICENSE.txt">
|
|
7
|
+
<img alt="GitHub License" src="https://img.shields.io/github/license/jg-rp/luoma-ruby?style=flat-square">
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://github.com/jg-rp/luoma-ruby/actions">
|
|
10
|
+
<img src="https://img.shields.io/github/actions/workflow/status/jg-rp/luoma-ruby/main.yml?branch=main&label=tests&style=flat-square" alt="Tests">
|
|
11
|
+
</a>
|
|
12
|
+
<br>
|
|
13
|
+
<a href="https://rubygems.org/gems/luoma">
|
|
14
|
+
<img alt="Gem Version" src="https://img.shields.io/gem/v/luoma?style=flat-square">
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://github.com/jg-rp/luoma-ruby">
|
|
17
|
+
<img alt="Static Badge" src="https://img.shields.io/badge/Ruby-3.1%20%7C%203.2%20%7C%203.3%20%7C%203.4-CC342D?style=flat-square">
|
|
18
|
+
</a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
**Table of Contents**
|
|
22
|
+
|
|
23
|
+
- [Install](#install)
|
|
24
|
+
- [Example](#example)
|
|
25
|
+
- [Links](#links)
|
|
26
|
+
- [License](#license)
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
Add `'luoma'` to your Gemfile:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
gem 'luoma', '~> 0.1.0'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
gem install luoma
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
bundle add luoma
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Example
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
require "luoma"
|
|
52
|
+
|
|
53
|
+
template = Luoma.parse("Hello, {{ you }}!")
|
|
54
|
+
puts template.render("you" => "World") # Hello, World!
|
|
55
|
+
puts template.render("you" => "Luoma") # Hello, Luoma!
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Links
|
|
59
|
+
|
|
60
|
+
- Documentation: https://jg-rp.github.io/luoma/
|
|
61
|
+
- Change log: https://github.com/jg-rp/luoma-ruby/blob/main/CHANGELOG.md
|
|
62
|
+
- RubyGems: https://rubygems.org/gems/luoma
|
|
63
|
+
- Source code: https://github.com/jg-rp/luoma-ruby
|
|
64
|
+
- Issue tracker: https://github.com/jg-rp/luoma-ruby/issues
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
|
|
6
|
+
require "bundler/gem_tasks"
|
|
7
|
+
require "minitest/test_task"
|
|
8
|
+
|
|
9
|
+
Minitest::TestTask.create
|
|
10
|
+
|
|
11
|
+
require "rubocop/rake_task"
|
|
12
|
+
|
|
13
|
+
RuboCop::RakeTask.new do |task|
|
|
14
|
+
task.plugins << "rubocop-minitest"
|
|
15
|
+
task.plugins << "rubocop-rake"
|
|
16
|
+
task.plugins << "rubocop-performance"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require "steep/rake_task"
|
|
20
|
+
|
|
21
|
+
Steep::RakeTask.new do |t|
|
|
22
|
+
t.check.severity_level = :error
|
|
23
|
+
t.watch.verbose
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
namespace :docs do
|
|
27
|
+
desc "Build the documentation using Zensical"
|
|
28
|
+
task :build do
|
|
29
|
+
puts "Building documentation with Zensical..."
|
|
30
|
+
build_success = system("zensical build --clean")
|
|
31
|
+
abort("Error: Failed to build documentation.") unless build_success
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc "Build and publish documentation to GitHub Pages"
|
|
35
|
+
task deploy: :build do
|
|
36
|
+
site_dir = "site"
|
|
37
|
+
|
|
38
|
+
abort("Error: Output directory '#{site_dir}' missing. Build may have failed.") unless Dir.exist?(site_dir)
|
|
39
|
+
|
|
40
|
+
# Retrieve the remote URL of your main Git repository
|
|
41
|
+
remote = `git config --get remote.origin.url`.strip
|
|
42
|
+
abort("Error: Could not determine Git remote URL for 'origin'.") if remote.empty?
|
|
43
|
+
|
|
44
|
+
target_branch = "gh-pages"
|
|
45
|
+
|
|
46
|
+
puts "Publishing '#{site_dir}' to #{target_branch} branch on #{remote}..."
|
|
47
|
+
|
|
48
|
+
# Use a temporary directory to avoid touching local working tree state
|
|
49
|
+
Dir.mktmpdir do |tmp_dir|
|
|
50
|
+
# Copy all contents of the build folder into the temp directory
|
|
51
|
+
FileUtils.cp_r(File.join(site_dir, "."), tmp_dir)
|
|
52
|
+
|
|
53
|
+
# Initialize a temporary git repo and push to the remote branch
|
|
54
|
+
Dir.chdir(tmp_dir) do
|
|
55
|
+
system("git init -q")
|
|
56
|
+
system("git checkout -b #{target_branch}")
|
|
57
|
+
system("git add .")
|
|
58
|
+
system("git commit -q -m 'Deploy documentation updates [skip ci]'")
|
|
59
|
+
|
|
60
|
+
pushed = system("git push --force #{remote} #{target_branch}")
|
|
61
|
+
abort("Error: Failed to push to GitHub Pages.") unless pushed
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
puts "Successfully deployed documentation to GitHub Pages!"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
task default: %i[test rubocop steep]
|
data/Steepfile
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
D = Steep::Diagnostic
|
|
4
|
+
|
|
5
|
+
target :lib do
|
|
6
|
+
signature "sig"
|
|
7
|
+
# ignore_signature "sig/test"
|
|
8
|
+
|
|
9
|
+
check "lib" # Directory name
|
|
10
|
+
# check "path/to/source.rb" # File name
|
|
11
|
+
# check "app/models/**/*.rb" # Glob
|
|
12
|
+
# ignore "lib/templates/*.rb"
|
|
13
|
+
|
|
14
|
+
library "base64"
|
|
15
|
+
library "bigdecimal"
|
|
16
|
+
library "cgi"
|
|
17
|
+
library "json"
|
|
18
|
+
library "strscan"
|
|
19
|
+
library "stringio"
|
|
20
|
+
library "time"
|
|
21
|
+
library "pathname"
|
|
22
|
+
library "monitor"
|
|
23
|
+
|
|
24
|
+
# configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
|
25
|
+
# configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
|
26
|
+
# configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
|
|
27
|
+
# configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
|
|
28
|
+
# configure_code_diagnostics do |hash| # You can setup everything yourself
|
|
29
|
+
# hash[D::Ruby::NoMethod] = :information
|
|
30
|
+
# end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# target :test do
|
|
34
|
+
# unreferenced! # Skip type checking the `lib` code when types in `test` target is changed
|
|
35
|
+
# signature "sig/test" # Put RBS files for tests under `sig/test`
|
|
36
|
+
# check "test" # Type check Ruby scripts under `test`
|
|
37
|
+
#
|
|
38
|
+
# configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
|
|
39
|
+
#
|
|
40
|
+
# # library "pathname" # Standard libraries
|
|
41
|
+
# end
|
data/certs/jgrp.pem
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIEhTCCAu2gAwIBAgIBATANBgkqhkiG9w0BAQsFADBEMRYwFAYDVQQDDA1qYW1l
|
|
3
|
+
c2dyLnByaW9yMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
|
|
4
|
+
FgNjb20wHhcNMjUxMDI1MDc0ODI4WhcNMjYxMDI1MDc0ODI4WjBEMRYwFAYDVQQD
|
|
5
|
+
DA1qYW1lc2dyLnByaW9yMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJ
|
|
6
|
+
k/IsZAEZFgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDYTvQW
|
|
7
|
+
0JzsHenYu4w0iHgJRtU9uK8vkDx1wlMioKlPFkaiMfxqUcTTfg80U/n8n/KKmpdq
|
|
8
|
+
y2rpUqv+VPE2nrfCUncf7ukqs+gF8uehbciMXV4iOzsZmqmtlPUJiGuSyO8REe/O
|
|
9
|
+
ERAyxYV8y5psF+WnW4uQzsWCKTnKbexIc6rf237veuYvYoBpnodJu0mJ0m9tBCFU
|
|
10
|
+
qH3Nk1sHBRIEEwn+nTiIiOMb+QMU5p0NIQkIhJO3el5nEQgIGxMPnie7PnwxPquQ
|
|
11
|
+
1rouuISbLmQy5oKYc9kScwnHdAu2PtnnJFNNuQ37vED375iQgMem/tK8EgMm9/Qr
|
|
12
|
+
Qxd2DQqqehgtEySWntGHTxNLXQouqHIRyqzkbcCatJqC+PBBql1x2N1KqgyvbLM3
|
|
13
|
+
B0dZCdJECr5J8zrluMxYsy7uGMmLz3LZ7PskGaJg4XxXP3j/B/e03/AxDj0neZZu
|
|
14
|
+
xuDLIfMDSNILO1pskMc+Xp0xdnkbS4IjiMDTrhqABuEcdNYH/GpyTiA/I0cCAwEA
|
|
15
|
+
AaOBgTB/MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBR4j7UhnpT9
|
|
16
|
+
mLcAkshwkFtwVpMdejAiBgNVHREEGzAZgRdqYW1lc2dyLnByaW9yQGdtYWlsLmNv
|
|
17
|
+
bTAiBgNVHRIEGzAZgRdqYW1lc2dyLnByaW9yQGdtYWlsLmNvbTANBgkqhkiG9w0B
|
|
18
|
+
AQsFAAOCAYEAbTkg946BsGPQFX3jskBjwINeFnMP0IppuStonPQv3SNQu1SWP0xS
|
|
19
|
+
o1Qji1dxkWDfOcp1ffrRMUo7ecrJbTqQ5Sdx+7zw0OLodSVqSu1LMIVDw/T73smg
|
|
20
|
+
ADO2r3eZ8vxCKh7z4wUeKXvmBXi5NvpmvhH7D+qeG4OMLI8jnfmfbSHZQZbe2tpd
|
|
21
|
+
tJC+MYVok/m91fBrfv5wqLsR5QiJl3vcVhG+xACd46gr3JZFOxBqpSJrCYL8Gwqx
|
|
22
|
+
BaKEySCLGqkb0d1Rnt2/zTR2KtW2QJVH9rBMnJ+LsPEFKs1UHH4qHzxmwmmaQLon
|
|
23
|
+
MoE4UJ51GHGrjJ4WsHOUSOy5UbjaQec3kuIDwTXKbHws0J0Ut9S4S38opZKdQHDD
|
|
24
|
+
PUBpY0QA1CgE/VjKAYEDHOJyfUCNOl+sEESM+WxEXZAUVZLrFF7MljJqyQq+JyTD
|
|
25
|
+
vFKHe1ZAA76NFrPscB/ODPTBK8i+u4gwrD1UAsVAHuIbOpQu4LYAujluCu5cl2A8
|
|
26
|
+
HhmlCT7sTkqG
|
|
27
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Setup
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Luoma environments
|
|
6
|
+
|
|
7
|
+
Template parsing and rendering behavior is configured using an instance of `Luoma::Environment`. Once configured, parse templates with `Environment#parse(source)` or `Environment#get_template(name)`, both of which return an instance of `Luoma::Template`.
|
|
8
|
+
|
|
9
|
+
An `Environment` is where you'd register custom filters or tags, or define variables that should be available to all templates, for example.
|
|
10
|
+
|
|
11
|
+
!!! tip
|
|
12
|
+
|
|
13
|
+
In addition to the environment options shown here, `Luoma::Environment` is designed to be extended. You can, for example, override `Luoma::Environment#eq?` to redefine expression equality, or override `Luoma::Environment#serialize` to change the way objects are rendered. See [environment.rb](https://github.com/jg-rp/luoma-ruby/blob/main/lib/luoma/expression.rb) for a complete method reference and default implementations.
|
|
14
|
+
|
|
15
|
+
## The default environment
|
|
16
|
+
|
|
17
|
+
The default Luoma environment and new instances of `Luoma::Environment` constructed without any arguments are equivalent to passing the following arguments to `Environment.new`.
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
env = Luoma::Environment.new(
|
|
21
|
+
auto_trim: nil,
|
|
22
|
+
globals: nil,
|
|
23
|
+
lexer: Luoma::UnifiedLexer,
|
|
24
|
+
loader: Luoma::HashLoader.new({}),
|
|
25
|
+
max_assign_score_cumulative: nil,
|
|
26
|
+
max_assign_score: nil,
|
|
27
|
+
max_context_depth: 30,
|
|
28
|
+
max_render_score_cumulative: nil,
|
|
29
|
+
max_render_score: nil,
|
|
30
|
+
max_render_size: nil,
|
|
31
|
+
parser: Luoma::UnifiedParser,
|
|
32
|
+
strict: false,
|
|
33
|
+
suppress_blank_control_flow_blocks: true,
|
|
34
|
+
undefined: Luoma::UndefinedDrop
|
|
35
|
+
)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Top-level convenience methods `Luoma.parse` and `Luoma.render` always use the default environment.
|
|
39
|
+
|
|
40
|
+
## Managing tags, filters and predicates
|
|
41
|
+
|
|
42
|
+
New instances of `Luoma::Environment` and the [default Luoma environment](#the-default-environment) have all standard tags, filters and predicates enabled by default. `Environment.tags`, `Environment.filters` and `Environment.predicates` are hashes mapping strings to `_Tag`, filter callables and predicate callables, respectively. You can add, remove, replace or alias tags, filters and predicates in an environment by updating these mappings after environment initialization.
|
|
43
|
+
|
|
44
|
+
This example removes th `{% include %}` tag and renames `downcase` to `lower` and `upcase` to `upper`.
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
|
|
48
|
+
require "luoma"
|
|
49
|
+
|
|
50
|
+
env = Luoma::Environment.new
|
|
51
|
+
env.tags.delete("include")
|
|
52
|
+
env.filters["lower"] = env.tags.delete("downcase")
|
|
53
|
+
env.filters["upper"] = env.tags.delete("upcase")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Alternatively, you can extend `Luoma::Environment` and override `setup_tags_filters_and_predicates`.
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
require "luoma"
|
|
60
|
+
|
|
61
|
+
class MyLuomaEnv < Luoma::Environment
|
|
62
|
+
#: () -> void
|
|
63
|
+
def setup_tags_filters_and_predicates
|
|
64
|
+
super
|
|
65
|
+
@tags.delete("include")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
env = MyLuomaEnv.new
|
|
70
|
+
# ...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Auto trim
|
|
74
|
+
|
|
75
|
+
The `auto_trim` option sets the default whitespace trimming mode. Setting `auto_trim: "-"` or `auto_trim: "~"` is equivalent to adding `-` or `~` before every closing markup delimiter.
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
require "luoma"
|
|
79
|
+
|
|
80
|
+
source = <<~SOURCE.chomp
|
|
81
|
+
<ul>
|
|
82
|
+
{% for x in (1..4) %}
|
|
83
|
+
<li>{{ x }}</li>
|
|
84
|
+
{% endfor %}
|
|
85
|
+
</ul>
|
|
86
|
+
---
|
|
87
|
+
SOURCE
|
|
88
|
+
|
|
89
|
+
puts Luoma::Environment.new.render(source)
|
|
90
|
+
puts Luoma::Environment.new(auto_trim: "~").render(source)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```html title="output"
|
|
94
|
+
<ul>
|
|
95
|
+
<li>1</li>
|
|
96
|
+
|
|
97
|
+
<li>2</li>
|
|
98
|
+
|
|
99
|
+
<li>3</li>
|
|
100
|
+
|
|
101
|
+
<li>4</li>
|
|
102
|
+
</ul>
|
|
103
|
+
---
|
|
104
|
+
<ul>
|
|
105
|
+
<li>1</li>
|
|
106
|
+
<li>2</li>
|
|
107
|
+
<li>3</li>
|
|
108
|
+
<li>4</li>
|
|
109
|
+
</ul>
|
|
110
|
+
---
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Global variables
|
|
114
|
+
|
|
115
|
+
Global template variables are those added by application developers, as opposed to local variables created by template authors with tags such as `{% assign %}` and `{% capture %}`. Globals can come from the following places, in order of highest to lowest priority.
|
|
116
|
+
|
|
117
|
+
1. The _data_ argument to `Luoma.render`, `Luoma::Environment#render` or `Luoma::Template#render`.
|
|
118
|
+
2. "overlay" or "matter" data provided by a template loader and bound to a `Luoma::Template` instance. This could be front matter parsed from the beginning of a template source file, or data from a database, for example.
|
|
119
|
+
3. The `globals` argument to `Luoma.parse` or `Luoma::Environment#parse`. These variables are pinned to the resulting template.
|
|
120
|
+
4. The `globals` argument when constructing a new `Luoma::Environment`. These variables are pinned to the environment and will be merged into other global data for every template rendered from the environment.
|
|
121
|
+
|
|
122
|
+
You can change the global variable source priority by extending and overriding `Luoma::Environment#makeGlobals` and/or `Luoma::Template#makeGlobals`.
|
|
123
|
+
|
|
124
|
+
## Resource limits
|
|
125
|
+
|
|
126
|
+
For deployments where template authors are untrusted, you can set limits on some resources to avoid malicious templates from consuming too much memory or too many CPU cycles. If any limit is exceeded, a `Luoma::ResourceLimitError` is raised.
|
|
127
|
+
|
|
128
|
+
!!! note
|
|
129
|
+
|
|
130
|
+
The following "scores" are non-specific measures of usage modelled on Shopify/liquid resource limits.
|
|
131
|
+
|
|
132
|
+
These numbers are for illustration purposes. You'll need to do a bit of trial and error to find the limits that work best for you.
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
require "luoma"
|
|
136
|
+
|
|
137
|
+
env = Luoma::Environment.new(
|
|
138
|
+
# Maximum of 2000 "bytes" assigned with the assign/capture tags per template
|
|
139
|
+
# or partial template.
|
|
140
|
+
max_assign_score: 2000,
|
|
141
|
+
|
|
142
|
+
# Maximum of 10,000 "bytes" assigned with the assign/capture tags for the
|
|
143
|
+
# root template and all partial templates combined.
|
|
144
|
+
max_assign_score_cumulative: 10000,
|
|
145
|
+
|
|
146
|
+
# Maximum nesting of 30 `for` loops and/or `render` tags, for example.
|
|
147
|
+
max_context_depth: 30,
|
|
148
|
+
|
|
149
|
+
# Maximum of 1000 nodes (text and markup in the template syntax tree) rendered
|
|
150
|
+
# per template.
|
|
151
|
+
max_render_score: 1000,
|
|
152
|
+
|
|
153
|
+
# Maximum of 5000 nodes (text and markup in the template syntax tree) rendered
|
|
154
|
+
# for the root template and any rendered partial templates combined.
|
|
155
|
+
max_render_score_cumulative: 5000,
|
|
156
|
+
|
|
157
|
+
# Maximum of 15,000 bytes written to the output buffer.
|
|
158
|
+
max_render_size: 15000,
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Strict mode
|
|
163
|
+
|
|
164
|
+
When `strict: false` (the default) unknown filters, unknown predicates and filter argument errors are silently ignored at render time. When `strict: true`, `Luoma::FilterNotFoundError`, `Luoma::PredicateNotFoundError` or `Luoma::FilterArgumentError` is raised, all of which inherit from `Luoma::LuomaError`.
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
require "luoma"
|
|
168
|
+
|
|
169
|
+
source = "Hello, {{ you | title }}"
|
|
170
|
+
|
|
171
|
+
puts Luoma::Environment.new.render(source)
|
|
172
|
+
puts Luoma::Environment.new(strict: true).render(source)
|
|
173
|
+
|
|
174
|
+
# Hello,
|
|
175
|
+
# /home/james/projects/luoma-ruby/lib/luoma/expression.rb:195:in 'Luoma::FilteredExpression#evaluate_filter': Luoma::FilterNotFoundError: unknown filter "title"
|
|
176
|
+
# -> "Hello, {{ you | title }}":1:17
|
|
177
|
+
# |
|
|
178
|
+
# 1 | Hello, {{ you | title }}
|
|
179
|
+
# | ^^^^^ unknown filter "title"
|
|
180
|
+
```
|
data/docs/custom_tags.md
ADDED
data/docs/expressions.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Extension types
|
|
2
|
+
|
|
3
|
+
A drop is a developer-defined type that plays nicely with Luoma tags, filters, predicates and operators. Drops are often used to implement lazy data retrieval or context sensitive logic.
|
|
4
|
+
|
|
5
|
+
The base drop, `Luoma::Drop`, is falsy, is an empty iterable/enumerable, is equal to nothing (including itself) and renders as an empty string.
|
|
6
|
+
|
|
7
|
+
TODO: document the complete Drop API.
|
|
8
|
+
|
|
9
|
+
## Built-in drops
|
|
10
|
+
|
|
11
|
+
### `BlockDrop`
|
|
12
|
+
|
|
13
|
+
A `Luoma::BlockDrop` encapsulates a block of Luoma markup. When an instance of `BlockDrop` is rendered, its internal markup is rendered to the output stream using variables from the current context, in the scope where it is "called".
|
|
14
|
+
|
|
15
|
+
Similarly, if a `BlockDrop` is coerced to a string - passed to a filter or tag that expects a string value - its internal markup is rendered into a new string using variables from the current scope.
|
|
16
|
+
|
|
17
|
+
Instances of `BlockDrop` are produced by the built-in `{% define %}` tag. When rendered, `{% define some_name %}...{% enddefine %}` binds a `BlockDrop` to the given name without writing to the output stream. This means blocks can be passed around and rendered multiple times in different contexts without loading a separate template.
|
|
18
|
+
|
|
19
|
+
By default, Luoma has special rules for rendering **arrays** of `BlockDrop`. Given an array of `BlockDrop` instances and no other types, Luoma will render each block to the output stream separated by a single newline character. If an array contains `BlockDrop` instances mixed with strings, those blocks and strings are rendered in order without a separating newline. Otherwise the array is considered data and is output in JSON.
|
|
20
|
+
|
|
21
|
+
### `ExpressionDrop`
|
|
22
|
+
|
|
23
|
+
A `Luoma::ExpressionDrop` encapsulates a single Luoma expression for later evaluation. When rendered or coerced to a string, `ExpressionDrop` produces a textual representation of its expression.
|
|
24
|
+
|
|
25
|
+
Lambda literals (`(a, b) -> expression`) evaluate to an instance of `ExpressionDrop`, without capturing anything about the scope in which it is defined. Internally, Luoma's filter application operator (`|`) recognizes instances of `ExpressionDrop` as user-defined filters, and some built-in filters accept instances of `ExpressionDrop` as arguments.
|
|
26
|
+
|
|
27
|
+
### `RangeDrop`
|
|
28
|
+
|
|
29
|
+
Range literals (`(1..5)`) evaluate to instances of `Luoma::RangeDrop`. When iterated, `RangeDrop` yields integers from its range of integer values.
|
|
30
|
+
|
|
31
|
+
When rendered or coerced to a string, `RangeDrop` produces a JSON-like array of integers.
|
|
32
|
+
|
|
33
|
+
### `UndefinedDrop`
|
|
34
|
+
|
|
35
|
+
Undefined variables resolve to an instance of of `Luoma::UndefinedDrop`, or one of its subclasses. Undefined variable behavior is configured by passing a `Luoma::UndefinedDrop` singleton to `Luoma::Environment.new`.
|
|
36
|
+
|
|
37
|
+
See [Undefined variables](./undefined_variables.md) for a breakdown of the built-in `Undefined` types.
|
|
38
|
+
|
|
39
|
+
## Custom drops
|
|
40
|
+
|
|
41
|
+
TODO:
|