luoma 0.2.0 → 0.3.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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +5 -0
- data/README.md +2 -2
- data/lib/luoma/context.rb +2 -1
- data/lib/luoma/drop.rb +2 -3
- data/lib/luoma/drops/range.rb +1 -1
- data/lib/luoma/drops/undefined.rb +1 -1
- data/lib/luoma/environment.rb +13 -14
- data/lib/luoma/escape.rb +53 -0
- data/lib/luoma/expression.rb +8 -8
- data/lib/luoma/filter.rb +3 -3
- data/lib/luoma/filters/escape_js.rb +12 -0
- data/lib/luoma/filters/slice.rb +1 -1
- data/lib/luoma/filters/sort.rb +0 -25
- data/lib/luoma/filters/string.rb +2 -2
- data/lib/luoma/loaders/file_system_loader.rb +10 -9
- data/lib/luoma/parser_unified.rb +2 -1
- data/lib/luoma/tags/assign.rb +4 -0
- data/lib/luoma/tags/case.rb +1 -1
- data/lib/luoma/template.rb +0 -2
- data/lib/luoma/version.rb +1 -1
- data/lib/luoma.rb +2 -0
- data/sig/luoma/drop.rbs +2 -2
- data/sig/luoma/environment.rbs +8 -8
- data/sig/luoma/escape.rbs +7 -0
- data/sig/luoma/filters/escape_js.rbs +6 -0
- data/sig/luoma/filters/sort.rbs +0 -4
- data/sig/luoma/loaders/file_system_loader.rbs +4 -0
- data.tar.gz.sig +1 -2
- metadata +4 -26
- metadata.gz.sig +0 -0
- data/docs/configuration.md +0 -180
- data/docs/custom_filters.md +0 -3
- data/docs/custom_tags.md +0 -3
- data/docs/expressions.md +0 -3
- data/docs/extension_types.md +0 -41
- data/docs/filter_reference.md +0 -1884
- data/docs/index.md +0 -77
- data/docs/luoma_for_template_authors.md +0 -3
- data/docs/markdown.md +0 -111
- data/docs/predicate_reference.md +0 -3
- data/docs/static_analysis.md +0 -3
- data/docs/tag_reference.md +0 -352
- data/docs/template_loaders.md +0 -177
- data/docs/undefined_variables.md +0 -3
- data/docs-requirements.txt +0 -11
- data/docs_/cycle.md +0 -17
- data/docs_/font_rendering_example.md +0 -157
- data/docs_/header_block_example.md +0 -51
- data/docs_/increment_and_decrement.md +0 -49
- data/docs_/logo_style_example.md +0 -40
- data/docs_/migration.md +0 -11
- data/docs_/notes.md +0 -19
- data/zensical.toml +0 -363
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9fc9f4fa3b7794116a4de61966341ef712606e0c97b5834cc5c115701471bea2
|
|
4
|
+
data.tar.gz: d6b462a7b470daca6feb3df50e43867404e2e3e50ae10810c3883e9e8e32065d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 40a51ce357387f02f253e454d20b3523d1373916ae067e5ece624f4abcef3195a68711c54080f899aea74af2f02180b47e28dbf30243d6ba68f7eef748240ac4
|
|
7
|
+
data.tar.gz: '03938e09549fbab02058a08fd8678d6845a08174eee1f9865fd3fdadd4e8b13790e21456d91825bd5f22d3bb4c5cca0da1454f06e631dcefa9b817be1d98de7e'
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## [0.3.0] - 2026-08-04
|
|
2
|
+
|
|
3
|
+
- Added the `escape_js` filter ([docs](https://jg-rp.github.io/luoma-ruby/filter_reference/#escape_js)).
|
|
4
|
+
- Removed the `sort_natural` filter. Use `a | sort: i -> (i | upcase)` instead.
|
|
5
|
+
|
|
1
6
|
## [0.2.0] - 2026-07-29
|
|
2
7
|
|
|
3
8
|
- Added the `take` filter. `a | take: 5` is equivalent to `a | slice: stop=6`.
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<h1 align="center">Luoma - Ruby</h1>
|
|
2
2
|
|
|
3
|
-
<p align="center">A modern template engine with a well-defined, composable
|
|
3
|
+
<p align="center">A modern template engine with a well-defined, composable expression language.</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="https://github.com/jg-rp/luoma-ruby/blob/main/LICENSE.txt">
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
Add `'luoma'` to your Gemfile:
|
|
31
31
|
|
|
32
32
|
```
|
|
33
|
-
gem 'luoma', '~> 0.
|
|
33
|
+
gem 'luoma', '~> 0.3.0'
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Or
|
data/lib/luoma/context.rb
CHANGED
data/lib/luoma/drop.rb
CHANGED
|
@@ -51,9 +51,8 @@ module Luoma
|
|
|
51
51
|
0
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def slice(start, stop, step)
|
|
54
|
+
#: (Integer, Integer, Integer, RenderContext) -> Enumerable[untyped]
|
|
55
|
+
def slice(start, stop, step, context)
|
|
57
56
|
self
|
|
58
57
|
end
|
|
59
58
|
|
data/lib/luoma/drops/range.rb
CHANGED
data/lib/luoma/environment.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
module Luoma
|
|
6
|
+
# Luoma template parsing and render configuration.
|
|
6
7
|
class Environment
|
|
7
8
|
attr_reader :persistent_registers
|
|
8
9
|
|
|
@@ -164,6 +165,7 @@ module Luoma
|
|
|
164
165
|
register_filter("default", Luoma::Filters.method(:default))
|
|
165
166
|
register_filter("divided_by", Luoma::Filters.method(:divided_by))
|
|
166
167
|
register_filter("downcase", Luoma::Filters.method(:downcase))
|
|
168
|
+
register_filter("escape_js", Luoma::Filters.method(:escape_js))
|
|
167
169
|
register_filter("escape_once", Luoma::Filters.method(:escape_once))
|
|
168
170
|
register_filter("escape", Luoma::Filters.method(:escape))
|
|
169
171
|
register_filter("find_index", Luoma::Filters.method(:find_index))
|
|
@@ -198,7 +200,6 @@ module Luoma
|
|
|
198
200
|
register_filter("size", Luoma::Filters.method(:size))
|
|
199
201
|
register_filter("slice", Luoma::Filters.method(:slice))
|
|
200
202
|
register_filter("sort", Luoma::Filters.method(:sort))
|
|
201
|
-
register_filter("sort_natural", Luoma::Filters.method(:sort_natural))
|
|
202
203
|
register_filter("sort_numeric", Luoma::Filters.method(:sort_numeric))
|
|
203
204
|
register_filter("split", Luoma::Filters.method(:split))
|
|
204
205
|
register_filter("strip_html", Luoma::Filters.method(:strip_html))
|
|
@@ -228,8 +229,8 @@ module Luoma
|
|
|
228
229
|
register_predicate("string", Luoma::Predicates.method(:string?))
|
|
229
230
|
end
|
|
230
231
|
|
|
231
|
-
#: (untyped, untyped, RenderContext
|
|
232
|
-
def contains?(left, right, context
|
|
232
|
+
#: (untyped, untyped, RenderContext) -> bool
|
|
233
|
+
def contains?(left, right, context)
|
|
233
234
|
return left.contains?(right, context) if left.is_a?(Drop)
|
|
234
235
|
|
|
235
236
|
right = right.to_primitive(:data, context) if right.is_a?(Drop)
|
|
@@ -241,18 +242,16 @@ module Luoma
|
|
|
241
242
|
end
|
|
242
243
|
end
|
|
243
244
|
|
|
244
|
-
#: (untyped, untyped, RenderContext
|
|
245
|
-
def eq?(left, right, context
|
|
246
|
-
# TODO: Don't accepts token
|
|
245
|
+
#: (untyped, untyped, RenderContext) -> bool
|
|
246
|
+
def eq?(left, right, context)
|
|
247
247
|
return left.eq?(right, context) if left.is_a?(Drop)
|
|
248
248
|
return right.eq?(left, context) if right.is_a?(Drop)
|
|
249
249
|
|
|
250
250
|
left == right
|
|
251
251
|
end
|
|
252
252
|
|
|
253
|
-
#: (untyped, untyped, RenderContext
|
|
254
|
-
def lt?(left, right, context
|
|
255
|
-
# TODO: Don't accepts token
|
|
253
|
+
#: (untyped, untyped, RenderContext) -> bool?
|
|
254
|
+
def lt?(left, right, context)
|
|
256
255
|
return left.lt?(right, context) if left.is_a?(Drop)
|
|
257
256
|
return right.gt?(left, context) if right.is_a?(Drop)
|
|
258
257
|
|
|
@@ -261,11 +260,11 @@ module Luoma
|
|
|
261
260
|
nil
|
|
262
261
|
end
|
|
263
262
|
|
|
264
|
-
#: (untyped, untyped, RenderContext
|
|
265
|
-
def cmp(left, right, context
|
|
266
|
-
return -1 if lt?(left, right, context
|
|
267
|
-
return 1 if lt?(right, left, context
|
|
268
|
-
return 0 if eq?(left, right, context
|
|
263
|
+
#: (untyped, untyped, RenderContext) -> (-1 | 1 | 0 | nil)
|
|
264
|
+
def cmp(left, right, context)
|
|
265
|
+
return -1 if lt?(left, right, context)
|
|
266
|
+
return 1 if lt?(right, left, context)
|
|
267
|
+
return 0 if eq?(left, right, context)
|
|
269
268
|
|
|
270
269
|
if left.nil? || nothing?(left)
|
|
271
270
|
1
|
data/lib/luoma/escape.rb
CHANGED
|
@@ -23,6 +23,55 @@ module Luoma
|
|
|
23
23
|
"`" => "`"
|
|
24
24
|
}.freeze #: Hash[String, String]
|
|
25
25
|
|
|
26
|
+
ESCAPE_JS_MAP = {
|
|
27
|
+
"\\" => "\\u005C",
|
|
28
|
+
"'" => "\\u0027",
|
|
29
|
+
"\"" => "\\u0022",
|
|
30
|
+
">" => "\\u003E",
|
|
31
|
+
"<" => "\\u003C",
|
|
32
|
+
"&" => "\\u0026",
|
|
33
|
+
"=" => "\\u003D",
|
|
34
|
+
"-" => "\\u002D",
|
|
35
|
+
";" => "\\u003B",
|
|
36
|
+
"`" => "\\u0060",
|
|
37
|
+
"\u2028" => "\\u2028",
|
|
38
|
+
"\u2029" => "\\u2029",
|
|
39
|
+
"\x00" => "\\u0000",
|
|
40
|
+
"\x01" => "\\u0001",
|
|
41
|
+
"\x02" => "\\u0002",
|
|
42
|
+
"\x03" => "\\u0003",
|
|
43
|
+
"\x04" => "\\u0004",
|
|
44
|
+
"\x05" => "\\u0005",
|
|
45
|
+
"\x06" => "\\u0006",
|
|
46
|
+
"\x07" => "\\u0007",
|
|
47
|
+
"\x08" => "\\u0008",
|
|
48
|
+
"\t" => "\\u0009",
|
|
49
|
+
"\n" => "\\u000A",
|
|
50
|
+
"\x0b" => "\\u000B",
|
|
51
|
+
"\x0c" => "\\u000C",
|
|
52
|
+
"\r" => "\\u000D",
|
|
53
|
+
"\x0e" => "\\u000E",
|
|
54
|
+
"\x0f" => "\\u000F",
|
|
55
|
+
"\x10" => "\\u0010",
|
|
56
|
+
"\x11" => "\\u0011",
|
|
57
|
+
"\x12" => "\\u0012",
|
|
58
|
+
"\x13" => "\\u0013",
|
|
59
|
+
"\x14" => "\\u0014",
|
|
60
|
+
"\x15" => "\\u0015",
|
|
61
|
+
"\x16" => "\\u0016",
|
|
62
|
+
"\x17" => "\\u0017",
|
|
63
|
+
"\x18" => "\\u0018",
|
|
64
|
+
"\x19" => "\\u0019",
|
|
65
|
+
"\x1a" => "\\u001A",
|
|
66
|
+
"\x1b" => "\\u001B",
|
|
67
|
+
"\x1c" => "\\u001C",
|
|
68
|
+
"\x1d" => "\\u001D",
|
|
69
|
+
"\x1e" => "\\u001E",
|
|
70
|
+
"\x1f" => "\\u001F"
|
|
71
|
+
}.freeze #: Hash[String, String]
|
|
72
|
+
|
|
73
|
+
RE_ESCAPE_JS = Regexp.new(ESCAPE_JS_MAP.keys.map { |k| Regexp.escape(k) }.join("|"))
|
|
74
|
+
|
|
26
75
|
#: (String) -> String
|
|
27
76
|
def self.escape(s)
|
|
28
77
|
s.gsub(RE_ESCAPE) { |m| ESCAPE_MAP[m] }
|
|
@@ -32,4 +81,8 @@ module Luoma
|
|
|
32
81
|
def self.unescape(s)
|
|
33
82
|
s.gsub(RE_UNESCAPE) { |m| UNESCAPE_MAP[m] }
|
|
34
83
|
end
|
|
84
|
+
|
|
85
|
+
def self.escape_js(s)
|
|
86
|
+
s.gsub(RE_ESCAPE_JS) { |m| ESCAPE_JS_MAP[m] }
|
|
87
|
+
end
|
|
35
88
|
end
|
data/lib/luoma/expression.rb
CHANGED
|
@@ -450,7 +450,7 @@ module Luoma
|
|
|
450
450
|
class EqExpression < InfixExpression
|
|
451
451
|
#: (RenderContext) -> untyped
|
|
452
452
|
def evaluate(context)
|
|
453
|
-
context.env.eq?(@left.evaluate(context), @right.evaluate(context), context
|
|
453
|
+
context.env.eq?(@left.evaluate(context), @right.evaluate(context), context)
|
|
454
454
|
end
|
|
455
455
|
|
|
456
456
|
#: () -> String
|
|
@@ -462,7 +462,7 @@ module Luoma
|
|
|
462
462
|
class NeExpression < InfixExpression
|
|
463
463
|
#: (RenderContext) -> untyped
|
|
464
464
|
def evaluate(context)
|
|
465
|
-
!context.env.eq?(@left.evaluate(context), @right.evaluate(context), context
|
|
465
|
+
!context.env.eq?(@left.evaluate(context), @right.evaluate(context), context)
|
|
466
466
|
end
|
|
467
467
|
|
|
468
468
|
#: () -> String
|
|
@@ -474,7 +474,7 @@ module Luoma
|
|
|
474
474
|
class LtExpression < InfixExpression
|
|
475
475
|
#: (RenderContext) -> untyped
|
|
476
476
|
def evaluate(context)
|
|
477
|
-
context.env.lt?(@left.evaluate(context), @right.evaluate(context), context
|
|
477
|
+
context.env.lt?(@left.evaluate(context), @right.evaluate(context), context)
|
|
478
478
|
end
|
|
479
479
|
|
|
480
480
|
#: () -> String
|
|
@@ -488,7 +488,7 @@ module Luoma
|
|
|
488
488
|
def evaluate(context)
|
|
489
489
|
left = @left.evaluate(context)
|
|
490
490
|
right = @right.evaluate(context)
|
|
491
|
-
context.env.lt?(left, right, context
|
|
491
|
+
context.env.lt?(left, right, context) || context.env.eq?(left, right, context)
|
|
492
492
|
end
|
|
493
493
|
|
|
494
494
|
#: () -> String
|
|
@@ -500,7 +500,7 @@ module Luoma
|
|
|
500
500
|
class GtExpression < InfixExpression
|
|
501
501
|
#: (RenderContext) -> untyped
|
|
502
502
|
def evaluate(context)
|
|
503
|
-
context.env.lt?(@right.evaluate(context), @left.evaluate(context), context
|
|
503
|
+
context.env.lt?(@right.evaluate(context), @left.evaluate(context), context)
|
|
504
504
|
end
|
|
505
505
|
|
|
506
506
|
#: () -> String
|
|
@@ -514,7 +514,7 @@ module Luoma
|
|
|
514
514
|
def evaluate(context)
|
|
515
515
|
left = @left.evaluate(context)
|
|
516
516
|
right = @right.evaluate(context)
|
|
517
|
-
context.env.lt?(right, left, context
|
|
517
|
+
context.env.lt?(right, left, context) || context.env.eq?(left, right, context)
|
|
518
518
|
end
|
|
519
519
|
|
|
520
520
|
#: () -> String
|
|
@@ -526,7 +526,7 @@ module Luoma
|
|
|
526
526
|
class ContainsExpression < InfixExpression
|
|
527
527
|
#: (RenderContext) -> untyped
|
|
528
528
|
def evaluate(context)
|
|
529
|
-
context.env.contains?(@left.evaluate(context), @right.evaluate(context), context
|
|
529
|
+
context.env.contains?(@left.evaluate(context), @right.evaluate(context), context)
|
|
530
530
|
end
|
|
531
531
|
|
|
532
532
|
#: () -> String
|
|
@@ -538,7 +538,7 @@ module Luoma
|
|
|
538
538
|
class InExpression < InfixExpression
|
|
539
539
|
#: (RenderContext) -> untyped
|
|
540
540
|
def evaluate(context)
|
|
541
|
-
context.env.contains?(@right.evaluate(context), @left.evaluate(context), context
|
|
541
|
+
context.env.contains?(@right.evaluate(context), @left.evaluate(context), context)
|
|
542
542
|
end
|
|
543
543
|
|
|
544
544
|
#: () -> String
|
data/lib/luoma/filter.rb
CHANGED
|
@@ -71,17 +71,17 @@ module Luoma
|
|
|
71
71
|
|
|
72
72
|
#: (untyped, untyped) -> bool
|
|
73
73
|
def eq?(obj, other)
|
|
74
|
-
@env.eq?(obj, other, @render_context
|
|
74
|
+
@env.eq?(obj, other, @render_context)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
#: (untyped, untyped) -> bool
|
|
78
78
|
def lt?(obj, other)
|
|
79
|
-
@env.lt?(obj, other, @render_context
|
|
79
|
+
@env.lt?(obj, other, @render_context)
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
#: (untyped, untyped) -> (-1 | 1 | 0 | nil)
|
|
83
83
|
def cmp(left, right)
|
|
84
|
-
@env.cmp(left, right, @render_context
|
|
84
|
+
@env.cmp(left, right, @render_context)
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
#: (untyped) -> bool
|
data/lib/luoma/filters/slice.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Luoma
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
if left.is_a?(Drop)
|
|
42
|
-
left.slice(normalized_start, normalized_stop, step)
|
|
42
|
+
left.slice(normalized_start, normalized_stop, step, context.render_context)
|
|
43
43
|
else
|
|
44
44
|
# This does not work for strings.
|
|
45
45
|
# left[(normalized_start...normalized_stop).step(step)]
|
data/lib/luoma/filters/sort.rb
CHANGED
|
@@ -54,21 +54,6 @@ module Luoma
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
def self.sort_natural(context, left, key = :nothing)
|
|
58
|
-
left = context.to_enumerable(left)
|
|
59
|
-
|
|
60
|
-
if key.nil? || context.nothing?(key)
|
|
61
|
-
left.sort { |a, b| nil_safe_casecmp(a, b) }
|
|
62
|
-
elsif key.is_a?(ExpressionDrop)
|
|
63
|
-
key.expr.broadcast_with_index(left).zip(left).sort do |a, b|
|
|
64
|
-
nil_safe_casecmp(a.first, b.first)
|
|
65
|
-
end.map(&:last)
|
|
66
|
-
else
|
|
67
|
-
key = context.to_string(key)
|
|
68
|
-
left.sort { |a, b| nil_safe_casecmp(context.fetch(a, key), context.fetch(b, key)) }
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
57
|
def self.sort_numeric(context, left, key = :nothing)
|
|
73
58
|
left = context.to_enumerable(left)
|
|
74
59
|
|
|
@@ -84,16 +69,6 @@ module Luoma
|
|
|
84
69
|
end
|
|
85
70
|
end
|
|
86
71
|
|
|
87
|
-
def self.nil_safe_casecmp(left, right)
|
|
88
|
-
if !left.nil? && !right.nil?
|
|
89
|
-
left.to_s.casecmp(right.to_s)
|
|
90
|
-
elsif left.nil? && right.nil?
|
|
91
|
-
0
|
|
92
|
-
else
|
|
93
|
-
left.nil? ? 1 : -1
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
72
|
def self.numeric_compare(left, right, context)
|
|
98
73
|
res = ints(left, context) <=> ints(right, context)
|
|
99
74
|
res || -1
|
data/lib/luoma/filters/string.rb
CHANGED
|
@@ -31,7 +31,7 @@ module Luoma
|
|
|
31
31
|
# Return _left_ with special HTML characters replaced with their HTML-safe escape sequences.
|
|
32
32
|
# Coerce _left_ to a string if it is not one already.
|
|
33
33
|
def self.escape(context, left)
|
|
34
|
-
CGI.
|
|
34
|
+
CGI.escapeHTML(context.to_string(left)) unless left.nil?
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
# Return _left_ with special HTML characters replaced with their HTML-safe escape sequences.
|
|
@@ -39,7 +39,7 @@ module Luoma
|
|
|
39
39
|
#
|
|
40
40
|
# It is safe to use `escape_once` on string values that already contain HTML-escape sequences.
|
|
41
41
|
def self.escape_once(context, left)
|
|
42
|
-
CGI.
|
|
42
|
+
CGI.escapeHTML(CGI.unescapeHTML(context.to_string(left)))
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Return _left_ with leading whitespace removed.
|
|
@@ -31,23 +31,24 @@ module Luoma
|
|
|
31
31
|
template_path = template_path.sub_ext(@default_extension || raise)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# TODO: better relative path check
|
|
35
|
-
|
|
36
|
-
# Don't alow template names to escape the search path with "../".
|
|
37
|
-
template_path.each_filename do |part|
|
|
38
|
-
next unless part == ".."
|
|
39
|
-
|
|
40
|
-
raise TemplateNotFoundError.new("template not found #{template_name}")
|
|
41
|
-
end
|
|
42
|
-
|
|
43
34
|
# Search each path in turn.
|
|
44
35
|
@search_path.each do |path|
|
|
45
36
|
source_path = path.join(template_path)
|
|
37
|
+
next unless child_path?(source_path, path)
|
|
46
38
|
return source_path if source_path.file?
|
|
47
39
|
end
|
|
48
40
|
|
|
49
41
|
raise TemplateNotFoundError.new("template not found #{template_name}")
|
|
50
42
|
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
#: (Pathname, Pathname) -> bool
|
|
47
|
+
def child_path?(child, parent)
|
|
48
|
+
child_ = child.expand_path
|
|
49
|
+
parent_ = parent.expand_path
|
|
50
|
+
child_.ascend.drop(1).include?(parent_)
|
|
51
|
+
end
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
# A file system template loader that caches parsed templates.
|
data/lib/luoma/parser_unified.rb
CHANGED
|
@@ -770,7 +770,8 @@ module Luoma
|
|
|
770
770
|
#: () -> Expression
|
|
771
771
|
def parse_int_literal
|
|
772
772
|
token = self.next
|
|
773
|
-
|
|
773
|
+
# Float first for scientific notation
|
|
774
|
+
IntegerLiteral.new(token, Float(Luoma.get_token_value(token, @source)).to_i)
|
|
774
775
|
end
|
|
775
776
|
|
|
776
777
|
#: () -> Expression
|
data/lib/luoma/tags/assign.rb
CHANGED
data/lib/luoma/tags/case.rb
CHANGED
|
@@ -51,7 +51,7 @@ module Luoma
|
|
|
51
51
|
block.right.each do |expr|
|
|
52
52
|
right = expr.evaluate(context)
|
|
53
53
|
if (right.is_a?(PredicateFunction) && context.env.truthy?(right.call(context, left), context)) ||
|
|
54
|
-
context.env.eq?(left, right, context
|
|
54
|
+
context.env.eq?(left, right, context)
|
|
55
55
|
return Luoma.render_block(block.block, context, buffer)
|
|
56
56
|
end
|
|
57
57
|
end
|
data/lib/luoma/template.rb
CHANGED
data/lib/luoma/version.rb
CHANGED
data/lib/luoma.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative "luoma/context"
|
|
|
7
7
|
require_relative "luoma/drop"
|
|
8
8
|
require_relative "luoma/environment"
|
|
9
9
|
require_relative "luoma/errors"
|
|
10
|
+
require_relative "luoma/escape"
|
|
10
11
|
require_relative "luoma/expression"
|
|
11
12
|
require_relative "luoma/filter"
|
|
12
13
|
require_relative "luoma/fnv"
|
|
@@ -29,6 +30,7 @@ require_relative "luoma/drops/undefined"
|
|
|
29
30
|
require_relative "luoma/filters/array"
|
|
30
31
|
require_relative "luoma/filters/date"
|
|
31
32
|
require_relative "luoma/filters/default"
|
|
33
|
+
require_relative "luoma/filters/escape_js"
|
|
32
34
|
require_relative "luoma/filters/json"
|
|
33
35
|
require_relative "luoma/filters/math"
|
|
34
36
|
require_relative "luoma/filters/size"
|
data/sig/luoma/drop.rbs
CHANGED
|
@@ -29,8 +29,8 @@ module Luoma
|
|
|
29
29
|
# (RenderContext) -> Integer
|
|
30
30
|
def length: (Luoma::RenderContext context) -> Integer
|
|
31
31
|
|
|
32
|
-
# (Integer, Integer, Integer) -> Enumerable[untyped]
|
|
33
|
-
def slice: (Integer start, Integer stop, Integer step) -> untyped
|
|
32
|
+
# (Integer, Integer, Integer, RenderContext) -> Enumerable[untyped]
|
|
33
|
+
def slice: (Integer start, Integer stop, Integer step, RenderContext context) -> untyped
|
|
34
34
|
|
|
35
35
|
# (:data | :numeric | :string | :boolean, RenderContext) -> untyped
|
|
36
36
|
def to_primitive: (:data | :numeric | :string | :boolean hint, Luoma::RenderContext context) -> untyped
|
data/sig/luoma/environment.rbs
CHANGED
|
@@ -157,17 +157,17 @@ module Luoma
|
|
|
157
157
|
# () -> void
|
|
158
158
|
def setup_tags_filters_and_predicates: () -> void
|
|
159
159
|
|
|
160
|
-
# (untyped, untyped, RenderContext
|
|
161
|
-
def contains?: (untyped left, untyped right, RenderContext context
|
|
160
|
+
# (untyped, untyped, RenderContext) -> bool
|
|
161
|
+
def contains?: (untyped left, untyped right, RenderContext context) -> bool
|
|
162
162
|
|
|
163
|
-
# (untyped, untyped, RenderContext
|
|
164
|
-
def eq?: (untyped left, untyped right, RenderContext context
|
|
163
|
+
# (untyped, untyped, RenderContext) -> bool
|
|
164
|
+
def eq?: (untyped left, untyped right, RenderContext context) -> bool
|
|
165
165
|
|
|
166
|
-
# (untyped, untyped, RenderContext
|
|
167
|
-
def lt?: (untyped left, untyped right, RenderContext context
|
|
166
|
+
# (untyped, untyped, RenderContext) -> bool?
|
|
167
|
+
def lt?: (untyped left, untyped right, RenderContext context) -> bool?
|
|
168
168
|
|
|
169
|
-
# (untyped, untyped, RenderContext
|
|
170
|
-
def cmp: (untyped left, untyped right, RenderContext context
|
|
169
|
+
# (untyped, untyped, RenderContext) -> (-1 | 1 | 0 | nil)
|
|
170
|
+
def cmp: (untyped left, untyped right, RenderContext context) -> (-1 | 1 | 0 | nil)
|
|
171
171
|
|
|
172
172
|
# (untyped) -> bool
|
|
173
173
|
def nothing?: (untyped obj) -> bool
|
data/sig/luoma/escape.rbs
CHANGED
|
@@ -7,9 +7,16 @@ module Luoma
|
|
|
7
7
|
|
|
8
8
|
UNESCAPE_MAP: Hash[String, String]
|
|
9
9
|
|
|
10
|
+
RE_ESCAPE_JS: ::Regexp
|
|
11
|
+
|
|
12
|
+
ESCAPE_JS_MAP: Hash[String, String]
|
|
13
|
+
|
|
10
14
|
# (String) -> String
|
|
11
15
|
def self.escape: (String s) -> String
|
|
12
16
|
|
|
13
17
|
# (String) -> String
|
|
14
18
|
def self.unescape: (String s) -> String
|
|
19
|
+
|
|
20
|
+
# (String) -> String
|
|
21
|
+
def self.escape_js: (String s) -> String
|
|
15
22
|
end
|
data/sig/luoma/filters/sort.rbs
CHANGED
|
@@ -4,12 +4,8 @@ module Luoma
|
|
|
4
4
|
|
|
5
5
|
def self.sort: (FilterContext context, untyped left, ?untyped? key) -> untyped
|
|
6
6
|
|
|
7
|
-
def self.sort_natural: (FilterContext context, untyped left, ?untyped? key) -> untyped
|
|
8
|
-
|
|
9
7
|
def self.sort_numeric: (FilterContext context, untyped left, ?untyped? key) -> untyped
|
|
10
8
|
|
|
11
|
-
def self.nil_safe_casecmp: (untyped left, untyped right) -> (untyped | 0 | 1 | -1)
|
|
12
|
-
|
|
13
9
|
def self.numeric_compare: (untyped left, untyped right, FilterContext context) -> untyped
|
|
14
10
|
|
|
15
11
|
def self.ints: (untyped obj, FilterContext context) -> (::Array[untyped] | untyped)
|
|
@@ -8,6 +8,10 @@ module Luoma
|
|
|
8
8
|
def initialize: (String | Array[String] search_path, ?default_extension: String?) -> void
|
|
9
9
|
|
|
10
10
|
def resolve_path: (String template_name) -> Pathname
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def child_path?: (Pathname child, Pathname parent) -> bool
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
# A file system template loader that caches parsed templates.
|
data.tar.gz.sig
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
�p��O�I+�Һ]D,K�� ;�&"��@��W�h��寴R�V�,d��t�r��5�8����f/�8�)%|�Anv?����+���#�D��_��~W>����K�C>2����Έ?�*$H��E��0_�P����<Q�αi���@�Gq��h����ョۓ�c�˕]=!�|���}G�3&]g�+������6��;��Ÿh�<�a����+�M���f�E�8_nٍ�'l`EY��f���'i�#��ǂ���Vx�)��_��{�M��w
|
|
1
|
+
V��!Y�D�Ã́eZb�*t\�G&J���0�@��B�����)x��*�C����������Ҳ�`�� ���Q|:��g����'Bsd��ʪ�w�͌6NB��F����W��J u7��±�`���c�ö`���d*�e<�('#�����Np�d+o�2�1-�� ��7)��"6�Y�N��n�!�F��ǀjՅ�����%��ٖ ?�������Nk�Qe6wqqͅM���Ǐ�aV`����ɻ���s��:a��J*�*Z�3��.�Ey�X�s�:*�m�� ��o"7=���dO��K�ɣ��̱.ɶ�:��&���U�2�����# Be���R;�u9q�]pgB�}�5~AD��Q����aD{귌;�x
|