Module: Sinatra::Async::Helpers

Defined in:
lib/sinatra/async.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#aparamsObject (readonly)

aparams are used when inside of something that has been scheduled asynchronously in an asynchronous route. Essentially it is the last parameters to be set by the router (for example, containing the route captures).



85
86
87
# File 'lib/sinatra/async.rb', line 85

def aparams
  @aparams
end

Instance Method Details

#ahalt(*args) ⇒ Object

Asynchronous halt must be used when the halt is occuring outside of the original call stack.



188
189
190
191
# File 'lib/sinatra/async.rb', line 188

def ahalt(*args)
  invoke { halt(*args) }
  invoke { error_block! response.status } unless @env['sinatra.error']
end

#async_catch_execute(&b) ⇒ Object



160
161
162
163
164
165
166
167
168
169
# File 'lib/sinatra/async.rb', line 160

def async_catch_execute(&b)
  @async_running = true
  async_handle_exception do
    if h = catch(:halt, &b)
      invoke { halt h }
      invoke { error_block! response.status }
      body(response.body)
    end
  end
end

#async_handle_exceptionObject



171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/sinatra/async.rb', line 171

def async_handle_exception
  yield
rescue ::Exception => boom
  if settings.show_exceptions?
    printer = Sinatra::ShowExceptions.new(proc{ raise boom })
    s, h, b = printer.call(request.env)
    response.status = s
    response.headers.replace(h)
    response.body = b
    body(response.body)
  else
    body(handle_exception!(boom))
  end
end

#async_responseObject

Defaults to throw async as that is most commonly used by servers.



143
144
145
# File 'lib/sinatra/async.rb', line 143

def async_response
  throw :async
end

#async_runner(meth, *bargs) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/sinatra/async.rb', line 147

def async_runner(meth, *bargs)
  @aparams = @params.dup
  async_schedule do
    begin
      original, @params = @params, @aparams
      method(meth).arity == 0 ? send(meth) : send(meth, *bargs)
    ensure
      @params = original
    end
    nil
  end
end

#async_schedule(&b) ⇒ Object

async_schedule is used to schedule work in a future context, the block is wrapped up so that exceptions and halts (redirect, etc) are handled correctly.



126
127
128
129
130
131
132
133
# File 'lib/sinatra/async.rb', line 126

def async_schedule(&b)
  if settings.environment == :test
    settings.set :async_schedules, [] unless settings.respond_to? :async_schedules
    settings.async_schedules << lambda { async_catch_execute(&b) }
  else
    native_async_schedule { async_catch_execute(&b) }
  end
end

#body(value = nil) ⇒ Object

Send the given body or block as the final response to the asynchronous request.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/sinatra/async.rb', line 89

def body(value = nil)
  if @async_running
    if block_given?
      super { async_handle_exception { yield } }
    else
      super
    end

    if response.body.respond_to?(:call)
      response.body = Array(async_handle_exception {response.body.call})
    end

    # Taken from Base#call
    unless @response['Content-Type']
      if Array === response.body and response.body[0].respond_to? :content_type
        content_type response.body[0].content_type
      else
        content_type :html
      end
    end

    result = response.finish

    # We don't get the HEAD middleware, so just do something convenient
    # here.
    result[-1] = [] if request.head?

    request.env['async.callback'][ result ]
    response.body
  else
    super
  end
end

#native_async_schedule(&b) ⇒ Object

By default native_async_schedule calls EventMachine#next_tick, if you’re using threads or some other scheduling mechanism, it must take the block passed here and schedule it for running in the future.



138
139
140
# File 'lib/sinatra/async.rb', line 138

def native_async_schedule(&b)
  EM.next_tick(&b)
end

#on_close(&blk) ⇒ Object

The given block will be executed if the user closes the connection prematurely (before we’ve sent a response). This is good for deregistering callbacks that would otherwise send the body (for example channel subscriptions).



197
198
199
# File 'lib/sinatra/async.rb', line 197

def on_close(&blk)
  env['async.close'].callback(&blk)
end