tina4ruby 3.10.15 → 3.10.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/tina4/frond.rb +92 -10
- data/lib/tina4/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b0dfa03a5f7986169a14d59895459e7ca50d70f0254789c36dbc29aca80b1b93
|
|
4
|
+
data.tar.gz: e248121b6577b8c5d0ec172ab47e2f82235b500d3508f75e8e0fedd3071ac657
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 164505c4f5449c7fbfa15ca1b21fbdffa3beac78a7d84e907407ed11881e3a4335d7df8dd6c46cb4bb4fb11ff3f9b89d2cd4b8cd02a77bdfb72a584b965f942e
|
|
7
|
+
data.tar.gz: b8797d3fd1abe7baf178c73a752b47357d8e56753a699d833a100940433884d036211cfc9942fcee481ca56d610efcb50169ec086df04f31e549e73971b7fb65
|
data/lib/tina4/frond.rb
CHANGED
|
@@ -495,6 +495,41 @@ module Tina4
|
|
|
495
495
|
eval_expr(arg, context)
|
|
496
496
|
end
|
|
497
497
|
|
|
498
|
+
# Find the first occurrence of +needle+ that is not inside quotes or
|
|
499
|
+
# parentheses. Returns the index, or -1 if not found.
|
|
500
|
+
def find_outside_quotes(expr, needle)
|
|
501
|
+
in_q = nil
|
|
502
|
+
depth = 0
|
|
503
|
+
i = 0
|
|
504
|
+
nlen = needle.length
|
|
505
|
+
while i <= expr.length - nlen
|
|
506
|
+
ch = expr[i]
|
|
507
|
+
if (ch == '"' || ch == "'") && depth == 0
|
|
508
|
+
if in_q.nil?
|
|
509
|
+
in_q = ch
|
|
510
|
+
elsif ch == in_q
|
|
511
|
+
in_q = nil
|
|
512
|
+
end
|
|
513
|
+
i += 1
|
|
514
|
+
next
|
|
515
|
+
end
|
|
516
|
+
if in_q
|
|
517
|
+
i += 1
|
|
518
|
+
next
|
|
519
|
+
end
|
|
520
|
+
if ch == "("
|
|
521
|
+
depth += 1
|
|
522
|
+
elsif ch == ")"
|
|
523
|
+
depth -= 1
|
|
524
|
+
end
|
|
525
|
+
if depth == 0 && expr[i, nlen] == needle
|
|
526
|
+
return i
|
|
527
|
+
end
|
|
528
|
+
i += 1
|
|
529
|
+
end
|
|
530
|
+
-1
|
|
531
|
+
end
|
|
532
|
+
|
|
498
533
|
# Find the index of a top-level ``?`` that is part of a ternary operator.
|
|
499
534
|
# Respects quoted strings, parentheses, and skips ``??`` (null coalesce).
|
|
500
535
|
# Returns -1 if not found.
|
|
@@ -690,18 +725,46 @@ module Tina4
|
|
|
690
725
|
return (Regexp.last_match(1).to_i..Regexp.last_match(2).to_i).to_a
|
|
691
726
|
end
|
|
692
727
|
|
|
693
|
-
#
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
728
|
+
# Parenthesized sub-expression: (expr) — strip parens and evaluate inner
|
|
729
|
+
if expr.start_with?("(") && expr.end_with?(")")
|
|
730
|
+
depth = 0
|
|
731
|
+
matched = true
|
|
732
|
+
expr.each_char.with_index do |ch, pi|
|
|
733
|
+
depth += 1 if ch == "("
|
|
734
|
+
depth -= 1 if ch == ")"
|
|
735
|
+
if depth == 0 && pi < expr.length - 1
|
|
736
|
+
matched = false
|
|
737
|
+
break
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
return eval_expr(expr[1..-2], context) if matched
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
# Ternary: condition ? "yes" : "no" — quote-aware
|
|
744
|
+
q_pos = find_outside_quotes(expr, "?")
|
|
745
|
+
if q_pos > 0
|
|
746
|
+
cond_part = expr[0...q_pos].strip
|
|
747
|
+
rest = expr[(q_pos + 1)..]
|
|
748
|
+
c_pos = find_outside_quotes(rest, ":")
|
|
749
|
+
if c_pos >= 0
|
|
750
|
+
true_part = rest[0...c_pos].strip
|
|
751
|
+
false_part = rest[(c_pos + 1)..].strip
|
|
752
|
+
cond = eval_expr(cond_part, context)
|
|
753
|
+
return truthy?(cond) ? eval_expr(true_part, context) : eval_expr(false_part, context)
|
|
754
|
+
end
|
|
698
755
|
end
|
|
699
756
|
|
|
700
|
-
# Jinja2-style inline if: value if condition else other_value
|
|
701
|
-
|
|
702
|
-
if
|
|
703
|
-
|
|
704
|
-
|
|
757
|
+
# Jinja2-style inline if: value if condition else other_value — quote-aware
|
|
758
|
+
if_pos = find_outside_quotes(expr, " if ")
|
|
759
|
+
if if_pos >= 0
|
|
760
|
+
else_pos = find_outside_quotes(expr, " else ")
|
|
761
|
+
if else_pos && else_pos > if_pos
|
|
762
|
+
value_part = expr[0...if_pos].strip
|
|
763
|
+
cond_part = expr[(if_pos + 4)...else_pos].strip
|
|
764
|
+
else_part = expr[(else_pos + 6)..].strip
|
|
765
|
+
cond = eval_expr(cond_part, context)
|
|
766
|
+
return truthy?(cond) ? eval_expr(value_part, context) : eval_expr(else_part, context)
|
|
767
|
+
end
|
|
705
768
|
end
|
|
706
769
|
|
|
707
770
|
# Null coalescing: value ?? "default"
|
|
@@ -1459,6 +1522,25 @@ module Tina4
|
|
|
1459
1522
|
},
|
|
1460
1523
|
"url_encode" => ->(v, *_a) { CGI.escape(v.to_s) },
|
|
1461
1524
|
|
|
1525
|
+
# -- JSON / JS --
|
|
1526
|
+
"to_json" => ->(v, *a) {
|
|
1527
|
+
indent = a[0] ? a[0].to_i : nil
|
|
1528
|
+
json = indent ? JSON.pretty_generate(v) : JSON.generate(v)
|
|
1529
|
+
# Escape <, >, & for safe HTML embedding
|
|
1530
|
+
Tina4::SafeString.new(json.gsub("<", '\u003c').gsub(">", '\u003e').gsub("&", '\u0026'))
|
|
1531
|
+
},
|
|
1532
|
+
"tojson" => ->(v, *a) {
|
|
1533
|
+
indent = a[0] ? a[0].to_i : nil
|
|
1534
|
+
json = indent ? JSON.pretty_generate(v) : JSON.generate(v)
|
|
1535
|
+
Tina4::SafeString.new(json.gsub("<", '\u003c').gsub(">", '\u003e').gsub("&", '\u0026'))
|
|
1536
|
+
},
|
|
1537
|
+
"js_escape" => ->(v, *_a) {
|
|
1538
|
+
Tina4::SafeString.new(
|
|
1539
|
+
v.to_s.gsub("\\", "\\\\").gsub("'", "\\'").gsub('"', '\\"')
|
|
1540
|
+
.gsub("\n", "\\n").gsub("\r", "\\r").gsub("\t", "\\t")
|
|
1541
|
+
)
|
|
1542
|
+
},
|
|
1543
|
+
|
|
1462
1544
|
# -- Hashing --
|
|
1463
1545
|
"md5" => ->(v, *_a) { Digest::MD5.hexdigest(v.to_s) },
|
|
1464
1546
|
"sha256" => ->(v, *_a) { Digest::SHA256.hexdigest(v.to_s) },
|
data/lib/tina4/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tina4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.10.
|
|
4
|
+
version: 3.10.18
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tina4 Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|