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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +5 -0
  4. data/README.md +2 -2
  5. data/lib/luoma/context.rb +2 -1
  6. data/lib/luoma/drop.rb +2 -3
  7. data/lib/luoma/drops/range.rb +1 -1
  8. data/lib/luoma/drops/undefined.rb +1 -1
  9. data/lib/luoma/environment.rb +13 -14
  10. data/lib/luoma/escape.rb +53 -0
  11. data/lib/luoma/expression.rb +8 -8
  12. data/lib/luoma/filter.rb +3 -3
  13. data/lib/luoma/filters/escape_js.rb +12 -0
  14. data/lib/luoma/filters/slice.rb +1 -1
  15. data/lib/luoma/filters/sort.rb +0 -25
  16. data/lib/luoma/filters/string.rb +2 -2
  17. data/lib/luoma/loaders/file_system_loader.rb +10 -9
  18. data/lib/luoma/parser_unified.rb +2 -1
  19. data/lib/luoma/tags/assign.rb +4 -0
  20. data/lib/luoma/tags/case.rb +1 -1
  21. data/lib/luoma/template.rb +0 -2
  22. data/lib/luoma/version.rb +1 -1
  23. data/lib/luoma.rb +2 -0
  24. data/sig/luoma/drop.rbs +2 -2
  25. data/sig/luoma/environment.rbs +8 -8
  26. data/sig/luoma/escape.rbs +7 -0
  27. data/sig/luoma/filters/escape_js.rbs +6 -0
  28. data/sig/luoma/filters/sort.rbs +0 -4
  29. data/sig/luoma/loaders/file_system_loader.rbs +4 -0
  30. data.tar.gz.sig +1 -2
  31. metadata +4 -26
  32. metadata.gz.sig +0 -0
  33. data/docs/configuration.md +0 -180
  34. data/docs/custom_filters.md +0 -3
  35. data/docs/custom_tags.md +0 -3
  36. data/docs/expressions.md +0 -3
  37. data/docs/extension_types.md +0 -41
  38. data/docs/filter_reference.md +0 -1884
  39. data/docs/index.md +0 -77
  40. data/docs/luoma_for_template_authors.md +0 -3
  41. data/docs/markdown.md +0 -111
  42. data/docs/predicate_reference.md +0 -3
  43. data/docs/static_analysis.md +0 -3
  44. data/docs/tag_reference.md +0 -352
  45. data/docs/template_loaders.md +0 -177
  46. data/docs/undefined_variables.md +0 -3
  47. data/docs-requirements.txt +0 -11
  48. data/docs_/cycle.md +0 -17
  49. data/docs_/font_rendering_example.md +0 -157
  50. data/docs_/header_block_example.md +0 -51
  51. data/docs_/increment_and_decrement.md +0 -49
  52. data/docs_/logo_style_example.md +0 -40
  53. data/docs_/migration.md +0 -11
  54. data/docs_/notes.md +0 -19
  55. data/zensical.toml +0 -363
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f24da19a06edd7781345b3b0e4d9aa73c616404472c24e50e068d9acb0a8e463
4
- data.tar.gz: 97b49239b9ac0de992568860034dd7f8a5735739b3ee42f345508377a3c38eea
3
+ metadata.gz: 9fc9f4fa3b7794116a4de61966341ef712606e0c97b5834cc5c115701471bea2
4
+ data.tar.gz: d6b462a7b470daca6feb3df50e43867404e2e3e50ae10810c3883e9e8e32065d
5
5
  SHA512:
6
- metadata.gz: '09c958eadecea8638b9fe6ce31907e83640f44342b78978696564bf3128e625f7604d09db53d2f62a1831ca238811eee9baf98e505d5be968cd7a3467479f5bf'
7
- data.tar.gz: 19ce9bc9c86d34a65a1044803ec1627a916d92ad37bb9246166a2b4841f28dcfb53ebaf11e60eee9eff812dfda3854894a941e57ac0341c377f8bb3cf605c8ba
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, implementation agnostic expression language.</p>
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.1.0'
33
+ gem 'luoma', '~> 0.3.0'
34
34
  ```
35
35
 
36
36
  Or
data/lib/luoma/context.rb CHANGED
@@ -105,7 +105,8 @@ module Luoma
105
105
  :nothing
106
106
  end
107
107
 
108
- return [:nothing, segment_index] if obj == :nothing
108
+ # We must keep going in case we find a predicate.
109
+ # return [:nothing, segment_index] if obj == :nothing
109
110
  end
110
111
 
111
112
  [obj, segment_index]
data/lib/luoma/drop.rb CHANGED
@@ -51,9 +51,8 @@ module Luoma
51
51
  0
52
52
  end
53
53
 
54
- # TODO: pass context
55
- #: (Integer, Integer, Integer) -> Enumerable[untyped]
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
 
@@ -48,7 +48,7 @@ module Luoma
48
48
  @range.size
49
49
  end
50
50
 
51
- def slice(start, stop, step)
51
+ def slice(start, stop, step, context)
52
52
  @range.to_a[(start...stop).step(step)] # steep:ignore
53
53
  end
54
54
 
@@ -73,7 +73,7 @@ module Luoma
73
73
  error
74
74
  end
75
75
 
76
- def slice(start, stop, step)
76
+ def slice(start, stop, step, context)
77
77
  error
78
78
  end
79
79
 
@@ -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, t_token) -> bool
232
- def contains?(left, right, context, token)
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, t_token) -> bool
245
- def eq?(left, right, context, token)
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, t_token) -> bool?
254
- def lt?(left, right, context, token)
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, t_token) -> (-1 | 1 | 0 | nil)
265
- def cmp(left, right, context, token)
266
- return -1 if lt?(left, right, context, token)
267
- return 1 if lt?(right, left, context, token)
268
- return 0 if eq?(left, right, context, token)
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
  "&#96;" => "`"
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
@@ -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, @span)
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, @span)
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, @span)
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, @span) || context.env.eq?(left, right, context, @span)
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, @span)
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, @span) || context.env.eq?(left, right, context, @span)
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, @span)
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, @span)
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, @token)
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, @token)
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, @token)
84
+ @env.cmp(left, right, @render_context)
85
85
  end
86
86
 
87
87
  #: (untyped) -> bool
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi/escape"
4
+
5
+ module Luoma
6
+ module Filters
7
+ # Escape characters for safe use in JavaScript string literals.
8
+ def self.escape_js(context, left)
9
+ Luoma.escape_js(context.to_string(left))
10
+ end
11
+ end
12
+ end
@@ -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)]
@@ -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
@@ -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.escape_html(context.to_string(left)) unless left.nil?
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.escape_html(CGI.unescape_html(context.to_string(left)))
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.
@@ -770,7 +770,8 @@ module Luoma
770
770
  #: () -> Expression
771
771
  def parse_int_literal
772
772
  token = self.next
773
- IntegerLiteral.new(token, Luoma.get_token_value(token, @source).to_i)
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
@@ -18,6 +18,10 @@ module Luoma
18
18
 
19
19
  until parser.kind != :token_comma
20
20
  parser.next
21
+
22
+ # Trailing commas are OK.
23
+ break unless parser.kind == :token_ident
24
+
21
25
  name = parser.parse_ident
22
26
  assign_token = parser.eat(
23
27
  :token_assign,
@@ -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, expr.span)
54
+ context.env.eq?(left, right, context)
55
55
  return Luoma.render_block(block.block, context, buffer)
56
56
  end
57
57
  end
@@ -67,8 +67,6 @@ module Luoma
67
67
  @up_to_date&.call
68
68
  end
69
69
 
70
- # TODO: static analysis methods
71
-
72
70
  # Statically analyze this template and report variable, tag and filter usage.
73
71
  #
74
72
  #: (?include_partials: bool) -> Luoma::StaticAnalysis::Result
data/lib/luoma/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Luoma
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
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
@@ -157,17 +157,17 @@ module Luoma
157
157
  # () -> void
158
158
  def setup_tags_filters_and_predicates: () -> void
159
159
 
160
- # (untyped, untyped, RenderContext, t_token) -> bool
161
- def contains?: (untyped left, untyped right, RenderContext context, t_token token) -> bool
160
+ # (untyped, untyped, RenderContext) -> bool
161
+ def contains?: (untyped left, untyped right, RenderContext context) -> bool
162
162
 
163
- # (untyped, untyped, RenderContext, t_token) -> bool
164
- def eq?: (untyped left, untyped right, RenderContext context, t_token token) -> bool
163
+ # (untyped, untyped, RenderContext) -> bool
164
+ def eq?: (untyped left, untyped right, RenderContext context) -> bool
165
165
 
166
- # (untyped, untyped, RenderContext, t_token) -> bool?
167
- def lt?: (untyped left, untyped right, RenderContext context, t_token token) -> bool?
166
+ # (untyped, untyped, RenderContext) -> bool?
167
+ def lt?: (untyped left, untyped right, RenderContext context) -> bool?
168
168
 
169
- # (untyped, untyped, RenderContext, t_token) -> (-1 | 1 | 0 | nil)
170
- def cmp: (untyped left, untyped right, RenderContext context, t_token token) -> (-1 | 1 | 0 | nil)
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
@@ -0,0 +1,6 @@
1
+ module Luoma
2
+ module Filters
3
+ # Escape characters for safe use in JavaScript string literals.
4
+ def self.escape_js: (FilterContext context, untyped left) -> untyped
5
+ end
6
+ end
@@ -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���h;�c
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