Class: NNQ::CLI::ExpressionEvaluator
- Inherits:
-
Object
- Object
- NNQ::CLI::ExpressionEvaluator
- Defined in:
- lib/nnq/cli/expression_evaluator.rb
Overview
Compiles and evaluates a single Ruby expression string for use in –recv-eval / –send-eval. Handles BEGIN{}/END{} block extraction, proc compilation, and result normalisation.
One instance per direction (send or recv).
The expression sees the message body via the default block variable ‘it`, or callers can declare an explicit parameter with block-literal syntax: `-e ’|msg| msg.upcase’‘ compiles to `proc { |msg| msg.upcase }`.
Constant Summary collapse
- SENT =
Sentinel: eval proc returned the context object, meaning it already sent the reply itself.
Object.new.freeze
Instance Attribute Summary collapse
-
#begin_proc ⇒ Object
readonly
Returns the value of attribute begin_proc.
-
#end_proc ⇒ Object
readonly
Returns the value of attribute end_proc.
-
#eval_proc ⇒ Object
readonly
Returns the value of attribute eval_proc.
Class Method Summary collapse
-
.compile_inside_ractor(src) ⇒ Object
Compiles begin/end/eval procs inside a Ractor from a raw expression string.
-
.extract_block(expr, keyword) ⇒ Object
Strips a BEGIN {…} or END {…} block from
exprand returns [trimmed_expr, block_body_or_nil]. -
.normalize_result(result) ⇒ Object
Normalises an eval result to nil (skip) or a 1-element Array of strings.
Instance Method Summary collapse
-
#call(msg, context) ⇒ Object
Runs the eval proc against
msgusingcontextas self. -
#initialize(src, format:, fallback_proc: nil) ⇒ ExpressionEvaluator
constructor
A new instance of ExpressionEvaluator.
Constructor Details
#initialize(src, format:, fallback_proc: nil) ⇒ ExpressionEvaluator
Returns a new instance of ExpressionEvaluator.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 28 def initialize(src, format:, fallback_proc: nil) @format = format if src expr, begin_body, end_body = extract_blocks(src) @begin_proc = eval("proc { #{begin_body} }") if begin_body @end_proc = eval("proc { #{end_body} }") if end_body if expr && !expr.strip.empty? @eval_proc = eval("proc { #{expr} }") end elsif fallback_proc @eval_proc = proc { |msg| fallback_proc.call(msg) } end end |
Instance Attribute Details
#begin_proc ⇒ Object (readonly)
Returns the value of attribute begin_proc.
17 18 19 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 17 def begin_proc @begin_proc end |
#end_proc ⇒ Object (readonly)
Returns the value of attribute end_proc.
17 18 19 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 17 def end_proc @end_proc end |
#eval_proc ⇒ Object (readonly)
Returns the value of attribute eval_proc.
17 18 19 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 17 def eval_proc @eval_proc end |
Class Method Details
.compile_inside_ractor(src) ⇒ Object
Compiles begin/end/eval procs inside a Ractor from a raw expression string. Returns [begin_proc, end_proc, eval_proc], any may be nil. Must be called inside the Ractor block.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 74 def self.compile_inside_ractor(src) return [nil, nil, nil] unless src expr, begin_body = extract_block(src, "BEGIN") expr, end_body = extract_block(expr, "END") begin_proc = eval("proc { #{begin_body} }") if begin_body end_proc = eval("proc { #{end_body} }") if end_body eval_proc = nil if expr && !expr.strip.empty? eval_proc = eval("proc { #{expr} }") end [begin_proc, end_proc, eval_proc] end |
.extract_block(expr, keyword) ⇒ Object
Strips a BEGIN {…} or END {…} block from expr and returns [trimmed_expr, block_body_or_nil]. Brace-matched scan, so nested ‘{}` inside the block body are handled. Shared by instance and Ractor compile paths, so must be a class method (Ractors cannot call back into instance state).
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 98 def self.extract_block(expr, keyword) start = expr.index(/#{keyword}\s*\{/) or return [expr, nil] i = expr.index("{", start) depth = 1 j = i + 1 while j < expr.length && depth > 0 case expr[j] when "{" depth += 1 when "}" depth -= 1 end j += 1 end body = expr[(i + 1)..(j - 2)] trimmed = expr[0...start] + expr[j..] [trimmed, body] end |
.normalize_result(result) ⇒ Object
Normalises an eval result to nil (skip) or a 1-element Array of strings. Used inside Ractor worker blocks.
65 66 67 68 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 65 def self.normalize_result(result) return nil if result.nil? result.to_s end |
Instance Method Details
#call(msg, context) ⇒ Object
Runs the eval proc against msg using context as self. Returns the normalised result (as String), nil (filter/skip), or SENT.
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/nnq/cli/expression_evaluator.rb', line 48 def call(msg, context) return msg unless @eval_proc result = context.instance_exec(msg, &@eval_proc) return nil if result.nil? return SENT if result.equal?(context) return result if @format == :marshal result.to_s rescue => e $stderr.puts "nnq: eval error: #{e.} (#{e.class})" exit 3 end |