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 |
# 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).
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/omq/cli/expression_evaluator.rb', line 79 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).
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/omq/cli/expression_evaluator.rb', line 102 def self.extract_block(expr, keyword) start = expr.index(/#{keyword}\s*\{/) return [expr, nil] unless start 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.
66 67 68 69 70 71 |
# File 'lib/omq/cli/expression_evaluator.rb', line 66 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.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/omq/cli/expression_evaluator.rb', line 43 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 |