Class: SmokeSignals

Inherits:
Object
  • Object
show all
Defined in:
lib/smoke_signals.rb

Defined Under Namespace

Classes: Condition, Extensible, NoRestartError, RescueException, RestartException, StackUnwindException, UnhandledSignalError

Class Method Summary (collapse)

Class Method Details

+ (Object) handle(*new_handlers, &block)

Establishes one or more signal handlers for the given block and executes it. Returns either the return value of the block or the value passed to Condition#rescue in a handler.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/smoke_signals.rb', line 128

def handle(*new_handlers, &block)
  orig_handlers = handlers
  nonce = Object.new
  if new_handlers.last.is_a?(Hash)
    new_handlers.pop.reverse_each {|entry| new_handlers.push(entry) }
  end
  self.handlers = orig_handlers + new_handlers.map {|entry| [entry,nonce] }.reverse
  begin
    block.call
  rescue RescueException => e
    if nonce.equal?(e.nonce)
      e.return_value
    else
      raise e
    end
  ensure
    self.handlers = orig_handlers
  end
end

+ (Object) restart(name, *args)

Raises:



189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/smoke_signals.rb', line 189

def restart(name, *args)
  restarts.reverse_each do |restarts_obj, nonce|
    obj, all_args = case restarts_obj
                    when Extensible
                      restarts_obj.respond_to?(name) ? [restarts_obj, [name] + args] : nil
                    else
                      fn = restarts_obj[name]
                      fn ? [fn, [:call] + args] : nil
                    end
    next unless obj
    raise RestartException.new(nonce, obj, all_args)
  end
  raise NoRestartError.new(name)
end

+ (Object) signal(c, raise_unless_handled)



148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/smoke_signals.rb', line 148

def signal(c, raise_unless_handled)
  # Most recently set handlers are run first.
  handlers.reverse_each do |handler, nonce|
    # Check if the condition being signaled applies to this
    # handler.
    handler_fn = c.handle_by(handler)
    next unless handler_fn

    c.nonce = nonce
    handler_fn.call(c)
  end
  raise UnhandledSignalError.new(c) if raise_unless_handled
end

+ (Object) with_restarts(extension, &block)

Establishes one or more restarts for the given block and executes it. Returns either the return value of the block or that of the restart if one was run.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/smoke_signals.rb', line 165

def with_restarts(extension, &block)
  orig_restarts = restarts
  nonce = Object.new
  if extension.is_a?(Proc)
    new_restarts = Extensible.new
    new_restarts.metaclass.instance_eval { include Module.new(&extension) }
  else
    new_restarts = extension
  end

  self.restarts = orig_restarts + [[new_restarts,nonce]]
  begin
    block.call
  rescue RestartException => e
    if nonce.equal?(e.nonce)
      e.restart_receiver.send(*e.restart_args)
    else
      raise e
    end
  ensure
    self.restarts = orig_restarts
  end
end