Class: Shotgun::Loader
- Inherits:
-
Object
- Object
- Shotgun::Loader
- Includes:
- Rack::Utils
- Defined in:
- lib/shotgun/loader.rb
Overview
Rack app that forks, loads the rackup config in the child process, processes a single request, and exits. The response is communicated over a unidirectional pipe.
Defined Under Namespace
Classes: Body
Instance Attribute Summary (collapse)
-
- (Object) rackup_file
readonly
Returns the value of attribute rackup_file.
Instance Method Summary (collapse)
- - (Object) assemble_app
- - (Object) call(env)
- - (Object) call!(env)
- - (Object) camel_case(string)
- - (Object) format_error(error, backtrace)
-
- (Loader) initialize(rackup_file, &block)
constructor
A new instance of Loader.
- - (Object) inner_app
-
- (Object) proceed_as_child
Stuff that happens in the child process.
-
- (Object) proceed_as_parent
Stuff that happens in the parent process.
- - (Object) spec_body(body)
Constructor Details
- (Loader) initialize(rackup_file, &block)
A new instance of Loader
12 13 14 15 |
# File 'lib/shotgun/loader.rb', line 12 def initialize(rackup_file, &block) @rackup_file = rackup_file @config = block || Proc.new { } end |
Instance Attribute Details
- (Object) rackup_file (readonly)
Returns the value of attribute rackup_file
10 11 12 |
# File 'lib/shotgun/loader.rb', line 10 def rackup_file @rackup_file end |
Instance Method Details
- (Object) assemble_app
100 101 102 103 104 105 106 107 |
# File 'lib/shotgun/loader.rb', line 100 def assemble_app config = @config inner_app = self.inner_app Rack::Builder.new { instance_eval(&config) run inner_app }.to_app end |
- (Object) call(env)
17 18 19 |
# File 'lib/shotgun/loader.rb', line 17 def call(env) dup.call!(env) end |
- (Object) call!(env)
21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/shotgun/loader.rb', line 21 def call!(env) @env = env @reader, @writer = IO.pipe Shotgun.before_fork! if @child = fork proceed_as_parent else Shotgun.after_fork! proceed_as_child end end |
- (Object) camel_case(string)
126 127 128 |
# File 'lib/shotgun/loader.rb', line 126 def camel_case(string) string.split("_").map { |part| part.capitalize }.join end |
- (Object) format_error(error, backtrace)
73 74 75 76 77 78 |
# File 'lib/shotgun/loader.rb', line 73 def format_error(error, backtrace) "<h1>Boot Error</h1>" + "<p>Something went wrong while loading <tt>#{escape_html(rackup_file)}</tt></p>" + "<h3>#{escape_html(error)}</h3>" + "<pre>#{escape_html(backtrace.join("\n"))}</pre>" end |
- (Object) inner_app
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/shotgun/loader.rb', line 109 def inner_app if rackup_file =~ /\.ru$/ config = File.read(rackup_file) eval "Rack::Builder.new {( #{config}\n )}.to_app", nil, rackup_file else require File.(rackup_file) if defined? Sinatra::Application Sinatra::Application.set :reload, false Sinatra::Application.set :logging, false Sinatra::Application.set :raise_errors, true Sinatra::Application else Object.const_get(camel_case(File.basename(rackup_file, '.rb'))) end end end |
- (Object) proceed_as_child
Stuff that happens in the child process
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/shotgun/loader.rb', line 83 def proceed_as_child boom = false @reader.close status, headers, body = assemble_app.call(@env) Marshal.dump([:ok, status, headers.to_hash], @writer) spec_body(body).each { |chunk| @writer.write(chunk) } rescue Object => boom Marshal.dump([ :error, "#{boom.class.name}: #{boom.to_s}", boom.backtrace ], @writer) ensure @writer.close exit! boom ? 1 : 0 end |
- (Object) proceed_as_parent
Stuff that happens in the parent process
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/shotgun/loader.rb', line 38 def proceed_as_parent @writer.close rand result, status, headers = Marshal.load(@reader) body = Body.new(@child, @reader) case result when :ok [status, headers, body] when :error error, backtrace = status, headers body.close [ 500, {'Content-Type'=>'text/html;charset=utf-8'}, [format_error(error, backtrace)] ] else fail "unexpected response: #{result.inspect}" end end |
- (Object) spec_body(body)
130 131 132 133 134 135 136 137 138 |
# File 'lib/shotgun/loader.rb', line 130 def spec_body(body) if body.respond_to? :to_str [body] elsif body.respond_to?(:each) body else fail "body must respond to #each" end end |