Class: RubyLLM::MCP::Handlers::Promise
- Inherits:
-
Object
- Object
- RubyLLM::MCP::Handlers::Promise
- Defined in:
- lib/ruby_llm/mcp/handlers/promise.rb
Overview
Promise implementation for async operations
Instance Method Summary collapse
-
#catch(&callback) ⇒ Promise
Register a callback for rejection.
-
#fulfilled? ⇒ Boolean
Check if promise is fulfilled.
-
#initialize ⇒ Promise
constructor
Initialize a new promise.
-
#pending? ⇒ Boolean
Check if promise is pending.
- #reason ⇒ Object
-
#reject(reason) ⇒ Object
Reject the promise with a reason.
-
#rejected? ⇒ Boolean
Check if promise is rejected.
-
#resolve(value) ⇒ Object
Resolve the promise with a value.
-
#settled? ⇒ Boolean
Check if promise is settled (fulfilled or rejected).
- #state ⇒ Object
-
#then(&callback) ⇒ Promise
Register a callback for successful resolution.
- #value ⇒ Object
-
#wait(timeout: nil) ⇒ Object
Wait for promise to settle with optional timeout.
Constructor Details
#initialize ⇒ Promise
Initialize a new promise
9 10 11 12 13 14 15 16 17 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 9 def initialize @state = :pending @value = nil @reason = nil @mutex = Mutex.new @condition = ConditionVariable.new @then_callbacks = [] @catch_callbacks = [] end |
Instance Method Details
#catch(&callback) ⇒ Promise
Register a callback for rejection
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 45 def catch(&callback) should_execute = false reason_to_use = nil @mutex.synchronize do if @state == :rejected # Already rejected, will execute immediately should_execute = true reason_to_use = @reason elsif @state == :pending # Still pending, register callback @catch_callbacks << callback end end # Execute outside mutex execute_callback_sync(callback, reason_to_use) if should_execute self end |
#fulfilled? ⇒ Boolean
Check if promise is fulfilled
125 126 127 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 125 def fulfilled? @mutex.synchronize { @state == :fulfilled } end |
#pending? ⇒ Boolean
Check if promise is pending
120 121 122 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 120 def pending? @mutex.synchronize { @state == :pending } end |
#reason ⇒ Object
173 174 175 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 173 def reason @mutex.synchronize { @reason } end |
#reject(reason) ⇒ Object
Reject the promise with a reason
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 94 def reject(reason) callbacks_to_execute = nil @mutex.synchronize do return unless @state == :pending @state = :rejected @reason = reason # Capture callbacks to execute outside mutex callbacks_to_execute = @catch_callbacks.dup @then_callbacks.clear @catch_callbacks.clear # Signal waiting threads @condition.broadcast end # Execute callbacks outside mutex to avoid deadlocks # Use synchronous execution to maintain order and allow tests to work callbacks_to_execute&.each do |callback| execute_callback_sync(callback, reason) end end |
#rejected? ⇒ Boolean
Check if promise is rejected
130 131 132 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 130 def rejected? @mutex.synchronize { @state == :rejected } end |
#resolve(value) ⇒ Object
Resolve the promise with a value
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 67 def resolve(value) callbacks_to_execute = nil @mutex.synchronize do return unless @state == :pending @state = :fulfilled @value = value # Capture callbacks to execute outside mutex callbacks_to_execute = @then_callbacks.dup @then_callbacks.clear @catch_callbacks.clear # Signal waiting threads @condition.broadcast end # Execute callbacks outside mutex to avoid deadlocks # Use synchronous execution to maintain order and allow tests to work callbacks_to_execute&.each do |callback| execute_callback_sync(callback, value) end end |
#settled? ⇒ Boolean
Check if promise is settled (fulfilled or rejected)
135 136 137 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 135 def settled? !pending? end |
#state ⇒ Object
165 166 167 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 165 def state @mutex.synchronize { @state } end |
#then(&callback) ⇒ Promise
Register a callback for successful resolution
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 22 def then(&callback) should_execute = false value_to_use = nil @mutex.synchronize do if @state == :fulfilled # Already fulfilled, will execute immediately should_execute = true value_to_use = @value elsif @state == :pending # Still pending, register callback @then_callbacks << callback end end # Execute outside mutex execute_callback_sync(callback, value_to_use) if should_execute self end |
#value ⇒ Object
169 170 171 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 169 def value @mutex.synchronize { @value } end |
#wait(timeout: nil) ⇒ Object
Wait for promise to settle with optional timeout
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/ruby_llm/mcp/handlers/promise.rb', line 142 def wait(timeout: nil) @mutex.synchronize do # Wait until promise is settled if timeout deadline = Time.now + timeout while @state == :pending remaining = deadline - Time.now if remaining <= 0 raise Timeout::Error, "Promise timed out after #{timeout} seconds" end @condition.wait(@mutex, remaining) end else @condition.wait(@mutex) while @state == :pending end # Return value or raise error return @value if @state == :fulfilled raise @reason if @state == :rejected end end |