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).



78
79
80
# File 'lib/sinatra/async.rb', line 78

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.



181
182
183
184
185
# File 'lib/sinatra/async.rb', line 181

def ahalt(*args)
  invoke { halt(*args) }
  invoke { error_block! response.status }
  body response.body
end

#async_catch_execute(&b) ⇒ Object



153
154
155
156
157
158
159
160
161
162
# File 'lib/sinatra/async.rb', line 153

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



164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/sinatra/async.rb', line 164

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.



136
137
138
# File 'lib/sinatra/async.rb', line 136

def async_response
  throw :async
end

#async_runner(meth, *bargs) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/sinatra/async.rb', line 140

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.



119
120
121
122
123
124
125
126
# File 'lib/sinatra/async.rb', line 119

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.



82
83
84
85
86
87
88
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
# File 'lib/sinatra/async.rb', line 82

def body(value = nil)
  if @async_running && (value || block_given?)
    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 === body and body[0].respond_to? :content_type
        content_type 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 ]
    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.



131
132
133
# File 'lib/sinatra/async.rb', line 131

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).



191
192
193
# File 'lib/sinatra/async.rb', line 191

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