-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
You can execute a classic Sinatra app as a ruby program, how does this work? #4
Comments
Thought it might be helpful to have the code in front of us.... https://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb require 'sinatra/base'
module Sinatra
class Application < Base
# we assume that the first file that requires 'sinatra' is the
# app_file. all other path related options are calculated based
# on this path by default.
set :app_file, caller_files.first || $0
set :run, Proc.new { File.expand_path($0) == File.expand_path(app_file) }
if run? && ARGV.any?
require 'optparse'
OptionParser.new { |op|
op.on('-p port', 'set the port (default is 4567)') { |val| set :port, Integer(val) }
op.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| set :bind, val }
op.on('-e env', 'set the environment (default is development)') { |val| set :environment, val.to_sym }
op.on('-s server', 'specify rack server/handler (default is thin)') { |val| set :server, val }
op.on('-x', 'turn on the mutex lock (default is off)') { set :lock, true }
}.parse!(ARGV.dup)
end
end
at_exit { Application.run! if $!.nil? && Application.run? }
end
# include would include the module in Object
# extend only extends the `main` object
extend Sinatra::Delegator |
If you write some ruby code that uses requie 'sinatra' then you run
it should automatically start the server and run the application on port 4567 by default. |
Yes - our aim is to explain how that works in the code above - can you explain it? |
Not all of it. But I'll try: So skipping the require and module/class declarations...
is setting the environment variable
is setting the :run environment variable to the location of the app and the surrounding directory, I think. There may be more going on here.
This is the option parser for command line switches. The defaults must live elsewhere since I don't see them declared here. However I didn't know you could call "require" in the middle of a ruby file. I guess there's no reason you can't, but I hadn't seen it done this way before where it's declared directly before it's needed like this.
These last few lines I'm not positive about. |
at_exit { Application.run! if $!.nil? && Application.run? } This line is an interesting part, it registers a hook to execute this block of code before exiting your app. So when the app was executed the interpreter goes through all of program source code and finish the program, but this block of code was executed before exiting the program. It checks I can't find where does @codereading/readers |
Nice! set :app_file, caller_files.first || $0 Didn't quite understand It seems like the difference from the set :run, Proc.new { File.expand_path($0) == File.expand_path(app_file) } This sets a condition which gets used in the So say you are testing your classic app, and you require the app file. When you To answer Samnang's question, when you call Which brings up another nice feature, when you set something to a Proc, it gets lazily-evaluated. But it's not memoized -- the Proc gets evaluated each time you get the setting. Cf. sinatra/base # include would include the module in Object
# extend only extends the `main` object
extend Sinatra::Delegator A remaining question is what these lines above do? |
Could |
@samnang The |
@thekungfuman @ericgj Yes I was wondering why
was guarding against a scenario of caller_files returning nil. I was just about to ask the group under what situation would caller_files return nil and I guess kungfumans scenario could be one - albeit a quite unusual one. Perhaps there is another case. Any ideas? |
If an exception has been raised, then I assume your sinatra app would never run anyway. So why check for an exception here at_exit { Application.run! if $!.nil? && Application.run? } ( for those unaware $! is a predefined global variable in ruby which holds the value of any exception raised inside of a rescue block ) |
Exceptions can be suppressed can't they? Perhaps the developer suppressed an exception, but it's still logged in the |
@ericgj re:
thats a cool feature. Im wondering what benefit it would have here in
during runtime would $0 and app_file ever change? Why not just set run like so set :run, (File.expand_path($0) == File.expand_path(app_file) )` probably not very important to the overall code reading session but it is something that puzzled me. |
I think the difference between |
Yes - I think because your classic app could explicitly set In general, (correct me if I'm wrong), it looks like the default settings that Sinatra makes that are based on other settings, are lazily-evaluated like this, so that the app could change the underlying settings. |
@ericgj @thekungfuman @kgrz Thanks for your input on those. Makes things a bit easier to understand. Now as @ericgj said, what's this delegator all about? # Sinatra delegation mixin. Mixing this module into an object causes all
# methods to be delegated to the Sinatra::Application class. Used primarily
# at the top-level.
module Delegator #:nodoc:
def self.delegate(*methods)
methods.each do |method_name|
define_method(method_name) do |*args, &block|
return super(*args, &block) if respond_to? method_name
Delegator.target.send(method_name, *args, &block)
end
private method_name
end
end
delegate :get, :patch, :put, :post, :delete, :head, :options, :template, :layout,
:before, :after, :error, :not_found, :configure, :set, :mime_type,
:enable, :disable, :use, :development?, :test?, :production?,
:helpers, :settings
class << self
attr_accessor :target
end
self.target = Application
end |
Yes, and why didn't they use the stdlib DelegateClass or some other tool in the delegate library? |
No description provided.
The text was updated successfully, but these errors were encountered: