Class: OMQ::CLI::ExpressionEvaluator
- Inherits:
-
Object
- Object
- OMQ::CLI::ExpressionEvaluator
- Defined in:
- lib/omq/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).
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, format: nil) ⇒ Object
Normalises an eval result to nil (skip), an Array (text formats), or an arbitrary Ruby object (
:marshal).
Instance Method Summary collapse
-
#call(parts, context) ⇒ Object
Runs the eval proc against
partsusingcontextas 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.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/omq/cli/expression_evaluator.rb', line 24 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 { fallback_proc.call(it) } end end |
Instance Attribute Details
#begin_proc ⇒ Object (readonly)
Returns the value of attribute begin_proc.
12 13 14 |
# File 'lib/omq/cli/expression_evaluator.rb', line 12 def begin_proc @begin_proc end |
#end_proc ⇒ Object (readonly)
Returns the value of attribute end_proc.
12 13 14 |
# File 'lib/omq/cli/expression_evaluator.rb', line 12 def end_proc @end_proc end |
#eval_proc ⇒ Object (readonly)
Returns the value of attribute eval_proc.
12 13 14 |
# File 'lib/omq/cli/expression_evaluator.rb', line 12 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 (Procs are not Ractor-shareable).
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/omq/cli/expression_evaluator.rb', line 80 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).
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/omq/cli/expression_evaluator.rb', line 104 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, format: nil) ⇒ Object
Normalises an eval result to nil (skip), an Array (text formats), or an arbitrary Ruby object (:marshal).
Used inside Ractor worker blocks where instance methods are unavailable. When format is :marshal, the raw result is passed through — the wire path will Marshal.dump it into a single frame.
67 68 69 70 71 72 |
# File 'lib/omq/cli/expression_evaluator.rb', line 67 def self.normalize_result(result, format: nil) return nil if result.nil? return result if format == :marshal result = result.is_a?(Array) ? result : [result] result.map { |part| part.to_s } end |
Instance Method Details
#call(parts, context) ⇒ Object
Runs the eval proc against parts using context as self. Returns the normalised result Array, nil (filter/skip), or SENT.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/omq/cli/expression_evaluator.rb', line 44 def call(parts, context) return parts unless @eval_proc result = context.instance_exec(parts, &@eval_proc) return nil if result.nil? return SENT if result.equal?(context) return result if @format == :marshal result = result.is_a?(Array) ? result : [result] result.map { |part| part.to_s } rescue => e $stderr.puts "omq: eval error: #{e.} (#{e.class})" exit 3 end |