tina4ruby 3.10.4 → 3.10.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: deb48b3053a6cde8d4d7fef6645b5e4a25eaff05c1d11b8b255c9c5ff42e7759
4
- data.tar.gz: 5c7a65aa85b1a3d39676cf90b404cae1fbb3731c4e5c1fbbbbbae02ed97b468f
3
+ metadata.gz: 1e9679c01c6e303af77a6c9a73c595991c14010af16e36d1b4471eaf0caa6ed3
4
+ data.tar.gz: 11cb40c1733ec3b360f4c9ad047558f7548b68fe8dc452dcaa7764a2f0a2d33f
5
5
  SHA512:
6
- metadata.gz: a1d8a2d31f0b1be83d4974190a6e7bf55aad671f7b8945444fc39335f14ddb537b98c887f975fba1f1d3f020f461703936000f33855845b3058de00c5147a377
7
- data.tar.gz: 5b1c9e819c1b771c3d6308e23b9fbd1246906d0f96fce21b2a54ea38c27e5bb4af3a0032313101529960498b70f8be6283137d50ee5f172326f9070d681a1ee2
6
+ metadata.gz: 9ee5400333e5662e0f812887d75d1c95f3c00af5ea2ae64ece651acc0430f27131653510bd1239d262fda5ce39652957f6a796e141f5530fe1424c67527840e4
7
+ data.tar.gz: e7fa0c88df994957e0836fa0d9437320e7f03cac2f804cd54f55e66f6702294bf9a942fb259aa1e9d7febfed1ffda8a682ed759266bdb53eb78a58682efac0e9
@@ -368,9 +368,85 @@ module Tina4
368
368
  end
369
369
  end
370
370
 
371
+ # Find the first occurrence of +needle+ outside quotes and parentheses.
372
+ # Returns the index, or -1 if not found.
373
+ def find_outside_quotes(expr, needle)
374
+ in_q = nil
375
+ depth = 0
376
+ i = 0
377
+ while i <= expr.length - needle.length
378
+ ch = expr[i]
379
+ if (ch == '"' || ch == "'") && depth == 0
380
+ if in_q.nil?
381
+ in_q = ch
382
+ elsif ch == in_q
383
+ in_q = nil
384
+ end
385
+ i += 1
386
+ next
387
+ end
388
+ if in_q
389
+ i += 1
390
+ next
391
+ end
392
+ if ch == "("
393
+ depth += 1
394
+ elsif ch == ")"
395
+ depth -= 1
396
+ end
397
+ if depth == 0 && expr[i, needle.length] == needle
398
+ return i
399
+ end
400
+ i += 1
401
+ end
402
+ -1
403
+ end
404
+
405
+ # Split +expr+ on +sep+ only when +sep+ is outside quotes and parentheses.
406
+ def split_outside_quotes(expr, sep)
407
+ parts = []
408
+ current_start = 0
409
+ in_q = nil
410
+ depth = 0
411
+ i = 0
412
+ while i <= expr.length - sep.length
413
+ ch = expr[i]
414
+ if (ch == '"' || ch == "'") && depth == 0
415
+ if in_q.nil?
416
+ in_q = ch
417
+ elsif ch == in_q
418
+ in_q = nil
419
+ end
420
+ i += 1
421
+ next
422
+ end
423
+ if in_q
424
+ i += 1
425
+ next
426
+ end
427
+ if ch == "("
428
+ depth += 1
429
+ elsif ch == ")"
430
+ depth -= 1
431
+ end
432
+ if depth == 0 && expr[i, sep.length] == sep
433
+ parts << expr[current_start...i]
434
+ i += sep.length
435
+ current_start = i
436
+ next
437
+ end
438
+ i += 1
439
+ end
440
+ parts << expr[current_start..]
441
+ parts
442
+ end
443
+
371
444
  def evaluate_expression(expr)
372
445
  expr = expr.strip
446
+
447
+ # String literal early-return
373
448
  return Regexp.last_match(1) if expr =~ /\A"([^"]*)"\z/ || expr =~ /\A'([^']*)'\z/
449
+
374
450
  return expr.to_i if expr =~ /\A-?\d+\z/
375
451
  return expr.to_f if expr =~ /\A-?\d+\.\d+\z/
376
452
  return true if expr == "true"
@@ -382,10 +458,30 @@ module Tina4
382
458
  if expr =~ /\A(\d+)\.\.(\d+)\z/
383
459
  return (Regexp.last_match(1).to_i..Regexp.last_match(2).to_i)
384
460
  end
385
- if expr.include?("~")
386
- parts = expr.split("~").map { |p| evaluate_expression(p.strip) }
387
- return parts.map(&:to_s).join
461
+
462
+ # Null coalescing: value ?? "default"
463
+ if find_outside_quotes(expr, "??") >= 0
464
+ pos = find_outside_quotes(expr, "??")
465
+ left = expr[0...pos]
466
+ right = expr[(pos + 2)..]
467
+ val = evaluate_expression(left.strip)
468
+ return val unless val.nil?
469
+ return evaluate_expression(right.strip)
470
+ end
471
+
472
+ # String concatenation with ~ (only outside quotes/parens)
473
+ if find_outside_quotes(expr, "~") >= 0
474
+ parts = split_outside_quotes(expr, "~")
475
+ return parts.map { |p| (evaluate_expression(p.strip) || "").to_s }.join
476
+ end
477
+
478
+ # Comparison operators (only outside quotes/parens)
479
+ [" not in ", " in ", " is not ", " is ", "!=", "==", ">=", "<=", ">", "<", " and ", " or ", " not "].each do |op|
480
+ if find_outside_quotes(expr, op) >= 0
481
+ return evaluate_condition(expr)
482
+ end
388
483
  end
484
+
389
485
  if expr =~ /\A(.+?)\s*(\+|-|\*|\/|%)\s*(.+)\z/
390
486
  left = evaluate_expression(Regexp.last_match(1))
391
487
  op = Regexp.last_match(2)
data/lib/tina4/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tina4
4
- VERSION = "3.10.4"
4
+ VERSION = "3.10.5"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.4
4
+ version: 3.10.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team