Class: Gin::App

Inherits:
Object
  • Object
show all
Extended by:
GinClass
Includes:
Constants
Defined in:
lib/gin/app.rb,
lib/gin/test.rb

Overview

:nodoc:

Constant Summary collapse

CALLERS_TO_IGNORE =

:nodoc:

[ # :nodoc:
  /lib\/gin(\/(.*?))?\.rb/,           # all gin code
  /lib\/tilt.*\.rb/,                  # all tilt code
  /^\(.*\)$/,                         # generated code
  /rubygems\/custom_require\.rb/,     # rubygems require hacks
  /active_support/,                   # active_support require hacks
  /bundler(\/runtime)?\.rb/,          # bundler require hacks
  /<internal:/,                       # internal in ruby >= 1.9.2
  /src\/kernel\/bootstrap\/[A-Z]/     # maglev kernel files
]
DEFAULT_ASSET_PATHS =

:nodoc:

[  #:nodoc:
%w{assets */},
%w{lib ** assets */},
%w{vendor ** assets */},
%w{assets/},
%w{lib ** assets/},
%w{vendor ** assets/}
STATIC_PATH_CLEANER =

:nodoc:

%r{\.+/|/\.+}
@@app_klasses =

:nodoc:

{}

Constants included from Constants

Constants::ASYNC_CALLBACK, Constants::CACHE_CTRL, Constants::CNT_DISPOSITION, Constants::CNT_LENGTH, Constants::CNT_TYPE, Constants::ENV_DEV, Constants::ENV_PROD, Constants::ENV_STAGE, Constants::ENV_TEST, Constants::EPOCH, Constants::ETAG, Constants::EXPIRES, Constants::FWD_FOR, Constants::FWD_HOST, Constants::GIN_APP, Constants::GIN_CTRL, Constants::GIN_ERRORS, Constants::GIN_PATH_PARAMS, Constants::GIN_RELOADED, Constants::GIN_ROUTE, Constants::GIN_STACK, Constants::GIN_STATIC, Constants::GIN_TARGET, Constants::GIN_TEMPLATES, Constants::GIN_TIMESTAMP, Constants::HOST_NAME, Constants::HTTP_VERSION, Constants::IF_MATCH, Constants::IF_MOD_SINCE, Constants::IF_NONE_MATCH, Constants::IF_UNMOD_SINCE, Constants::LAST_MOD, Constants::LOCATION, Constants::PATH_INFO, Constants::PRAGMA, Constants::QUERY_STRING, Constants::RACK_INPUT, Constants::REMOTE_ADDR, Constants::REMOTE_USER, Constants::REQ_METHOD, Constants::SERVER_NAME, Constants::SERVER_PORT, Constants::SESSION_SECRET

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rack_app = nil, options = {}) ⇒ App

Create a new Rack-mountable Gin::App instance, with an optional rack_app and options.



622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
# File 'lib/gin/app.rb', line 622

def initialize rack_app=nil, options={}
  if Hash === rack_app
    options   = rack_app
    @rack_app = nil
  else
    @rack_app = rack_app
  end

  @options = {
    :config_dir   => self.class.config_dir,
    :public_dir   => self.class.public_dir,
    :assets_dir   => self.class.assets_dir,
    :asset_paths  => self.class.asset_paths,
    :layouts_dir  => self.class.layouts_dir,
    :views_dir    => self.class.views_dir,
    :config       => self.class.config
  }.merge(self.class.options).merge(options)

  @options[:config] = self.class.make_config(@options) if
    @options[:environment]   != @options[:config].environment ||
    @options[:config_dir]    != @options[:config].dir ||
    @options[:config_reload] != @options[:config].ttl

  @override_options = options if autoreload

  validate_all_controllers!

  @app   = self
  @stack = build_app Rack::Builder.new

  setup_asset_pipeline
end

Instance Attribute Details

#optionsObject (readonly)

Options applied to the Gin::App instance. Typically a result of class-level configuration methods, such as Gin::App.environment.



613
614
615
# File 'lib/gin/app.rb', line 613

def options
  @options
end

#rack_appObject (readonly)

App to fallback on if Gin::App is used as middleware and no route is found.



609
610
611
# File 'lib/gin/app.rb', line 609

def rack_app
  @rack_app
end

#stackObject (readonly)

Internal Rack stack.



616
617
618
# File 'lib/gin/app.rb', line 616

def stack
  @stack
end

Class Method Details

.app_name(name = nil) ⇒ Object

Get or set the app name.



95
96
97
98
# File 'lib/gin/app.rb', line 95

def self.app_name name=nil
  @app_name = name if name
  @app_name
end

.asset_host(host = nil, &block) ⇒ Object

Get or set the CDN asset host (and path). If block is given, evaluates the block on every read.



285
286
287
288
289
# File 'lib/gin/app.rb', line 285

def self.asset_host host=nil, &block
  @options[:asset_host] = host  if host
  @options[:asset_host] = block if block_given?
  @options[:asset_host]
end

.asset_paths(*paths) ⇒ Object

Get or set the globs to find asset files.

asset_paths "/path/to/other/shared/assets/*/"

These globs will be expanded and added to the asset_pipeline Sprockets instance.

Default globs are:

<root_dir>/assets/
<root_dir>/assets/*/
<root_dir>/lib/**/assets/
<root_dir>/lib/**/assets/*/
<root_dir>/vendor/**/assets/
<root_dir>/vendor/**/assets/*/


254
255
256
257
258
259
# File 'lib/gin/app.rb', line 254

def self.asset_paths *paths
  @options[:asset_paths] ||=
    DEFAULT_ASSET_PATHS.map{|pa| File.join(root_dir, *pa) }
  @options[:asset_paths].concat(paths) if !paths.empty?
  @options[:asset_paths]
end

.asset_pipeline(val = nil, &block) ⇒ Object

Turn asset pipelining on or off. Defaults to turned on if any asset paths are present at boot time.

asset_pipeline true   # Force ON
asset_pipeline false  # Force OFF

If you would rather handle asset generation manually through the ‘gin -A` command for production purposes, you can set asset_pipieline to false. The app will still know where to look for rendered assets.

asset_pipeline ENV['RACK_ENV'] == 'development'

Passing a block will allow for configuration for Sprockets asset pipelining. Passed block yields a Sprockets::Environment instance.

asset_pipeline do |sprockets|
  sprockets.append_path 'foo/assets'
end

To keep memory usage low, Gin avoids loading Sprockets during the App runtime. If you however need Sprockets at runtime for your app, you may also pass a Sprockets::Environment instance to the asset_pipeline method:

sprockets = Sprockets::Environment.new
asset_pipeline sprockets


232
233
234
235
236
# File 'lib/gin/app.rb', line 232

def self.asset_pipeline val=nil, &block
  @options[:force_asset_pipeline] = val if !val.nil?
  @options[:asset_config] = block if block_given?
  @options[:force_asset_pipeline]
end

.assets_dir(dir = nil) ⇒ Object

Directory where the asset pipeline should render static assets to. Defaults to <public_dir>/assets



275
276
277
278
# File 'lib/gin/app.rb', line 275

def self.assets_dir dir=nil
  @options[:assets_dir] = dir if dir
  @options[:assets_dir] || File.join(public_dir, "assets")
end

.autoreload(val = nil) ⇒ Object

Enable or disable auto-app reloading. On by default in development mode.

In order for an app to be reloadable, the libs and controllers must be required from the Gin::App class context, or use MyApp.require(“lib”).

Gin::App class reloading is not supported for applications defined in the config.ru file. Dependencies will, however, still be reloaded.

Autoreload must be enabled before any calls to Gin::App.require for those files to be reloaded.

class MyApp < Gin::App

  # Only reloaded in development mode
  require 'nokogiri'

  autoreload false
  # Never reloaded
  require 'static_thing'

  autoreload true
  # Reloaded every request
  require 'my_app/home_controller'
end


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

def self.autoreload val=nil
  @autoreload = val unless val.nil?
  reload = @autoreload.nil? ? self.environment == ENV_DEV : @autoreload

  if reload
    Object.send :require, 'gin/reloadable' unless defined?(Gin::Reloadable)
    include Gin::Reloadable                unless self < Gin::Reloadable
  end

  reload
end

.call(env) ⇒ Object

Create a new instance of the app and call it.



77
78
79
80
# File 'lib/gin/app.rb', line 77

def self.call env
  @instance ||= self.new
  @instance.call env
end

.configObject

Access the config for your application, loaded from the config_dir.

# config/memcache.yml
default: &default
  host: example.com
  connections: 1
development: *default
  host: localhost

# access from App class
CACHE = Memcache.new( MyApp.config['memcache.host'] )

The config object is shared across all instances of the App and has thread-safety built-in.



315
316
317
# File 'lib/gin/app.rb', line 315

def self.config
  @options[:config] ||= make_config
end

.config_dir(dir = nil) ⇒ Object

Get or set the path to the config directory. Defaults to “<root_dir>/config”

Configs are expected to be YAML files following this pattern:

default: &default
  key: value

development: *default
  other_key: value

production: *default
  ...

Configs will be named according to the filename, and only the config for the current environment will be accessible.



337
338
339
340
341
342
343
344
# File 'lib/gin/app.rb', line 337

def self.config_dir dir=nil
  if String === dir
    @options[:config_dir] = dir
    @options[:config].dir = dir if @options[:config]
  end

  @options[:config_dir] || File.join(self.root_dir, "config")
end

.config_reload(ttl = nil) ⇒ Object

Get or set the config max age for auto-reloading in seconds. Turns config reloading off if set to false. Defaults to false. Config only gets reloaded on demand.

# Set to 10 minutes
config_reload 600

# Set to never reload
config_reload false


358
359
360
361
362
363
364
# File 'lib/gin/app.rb', line 358

def self.config_reload ttl=nil
  unless ttl.nil?
    @options[:config_reload] = ttl
    @options[:config].ttl = ttl if @options[:config]
  end
  @options[:config_reload]
end

.default_template(klass, *extensions) ⇒ Object

Set the default templating engine to use for various file extensions, or by default:

# Default for .markdown and .md files
default_template Tilt::MarukuTemplate, 'markdown', 'md'

# Default for files without preset default
default_template Tilt::BlueClothTemplate


376
377
378
379
380
# File 'lib/gin/app.rb', line 376

def self.default_template klass, *extensions
  extensions = [nil] if extensions.empty?
  extensions.each{|ext|
    (@options[:template_engines][ext] ||= []).unshift klass }
end

.define_test_helperObject



682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
# File 'lib/gin/test.rb', line 682

def self.define_test_helper
  return const_get(:TestHelper) if const_defined?(:TestHelper)
  class_eval <<-STR
    module TestHelper
      include Gin::Test::Helpers

      def self.included subclass
        Gin::Test::Helpers.setup_klass(subclass)
        subclass.app_klass #{self}
      end
    end
  STR

  const_get :TestHelper
end

.each(&block) ⇒ Object

:nodoc:



32
33
34
# File 'lib/gin/app.rb', line 32

def self.each &block    #:nodoc:
  @@app_klasses.values.each(&block)
end

.environment(env = nil) ⇒ Object

Get or set the current environment name, by default ENV [‘RACK_ENV’], or “development”.



387
388
389
390
391
392
393
# File 'lib/gin/app.rb', line 387

def self.environment env=nil
  if env
    @options[:environment] = env
    @options[:config].environment = env if @options[:config]
  end
  @options[:environment]
end

.error_delegate(ctrl = nil) ⇒ Object

Define a Gin::Controller as a catch-all error rendering controller. This can be a dedicated controller, or a parent controller such as AppController. Defaults to Gin::Controller.

The error delegate should handle the following errors for creating custom pages for Gin errors:

Gin::NotFound, Gin::BadRequest, ::Exception


405
406
407
408
# File 'lib/gin/app.rb', line 405

def self.error_delegate ctrl=nil
  @options[:error_delegate] = ctrl if ctrl
  @options[:error_delegate]
end

.hostname(host = nil, opts = {}) ⇒ Object

Get or set the Host header on responses if not set by the called action. If the enforce options is given, the app will only respond to requests that explicitly match the specified host, or regexp. This is useful for running multiple apps on the same middleware stack that might have conflicting routes, or need explicit per-host routing (such as an admin app).

hostname 'host.com'
hostname 'admin.host.com:443', :enforce => true
hostname 'admin.host.com', :enforce => /^admin\.(localhost|host\.com)/


422
423
424
425
# File 'lib/gin/app.rb', line 422

def self.hostname host=nil, opts={}
  @options[:host] = {:name => host}.merge(opts) if host
  @options[:host][:name] if @options[:host]
end

.inherited(subclass) ⇒ Object

:nodoc:



37
38
39
# File 'lib/gin/app.rb', line 37

def self.inherited subclass   #:nodoc:
  subclass.setup
end

.layout(name = nil) ⇒ Object

Get or set the layout name. Layout file location is assumed to be in the views_dir. If the views dir has a controller wildcard ‘*’, the layout is assumed to be one level above the controller-specific directory.

Defaults to :layout.



435
436
437
438
# File 'lib/gin/app.rb', line 435

def self.layout name=nil
  @options[:layout] = name if name
  @options[:layout]
end

.layouts_dir(dir = nil) ⇒ Object

Get or set the directory for view layouts. Defaults to the “<root_dir>/layouts”.



445
446
447
448
# File 'lib/gin/app.rb', line 445

def self.layouts_dir dir=nil
  @options[:layouts_dir] = dir if dir
  @options[:layouts_dir] || File.join(root_dir, 'layouts')
end

.logger(new_logger = nil) ⇒ Object

Get or set the logger for your application. Loggers must respond to the << method.



455
456
457
458
459
460
461
# File 'lib/gin/app.rb', line 455

def self.logger new_logger=nil
  if new_logger
    @options[:logger] = new_logger
    @options[:config].logger = new_logger if @options[:config]
  end
  @options[:logger]
end

.make_config(opts = {}) ⇒ Object

:nodoc:



292
293
294
295
296
297
# File 'lib/gin/app.rb', line 292

def self.make_config opts={}  # :nodoc:
  Gin::Config.new opts[:environment] || self.environment,
      :dir    => opts[:config_dir]    || self.config_dir,
      :logger => opts[:logger]        || self.logger,
      :ttl    => opts[:config_reload] || self.config_reload
end

.md5sObject

Cache of file md5s shared across all instances of an App class. Used for static asset versioning.



468
469
470
# File 'lib/gin/app.rb', line 468

def self.md5s
  @md5s
end

.middlewareObject

List of internal app middleware.



476
477
478
# File 'lib/gin/app.rb', line 476

def self.middleware
  @options[:middleware]
end

.mime_type(type, value = nil) ⇒ Object

Lookup or register a mime type in Rack’s mime registry.



484
485
486
487
488
489
# File 'lib/gin/app.rb', line 484

def self.mime_type type, value=nil
  return type if type.nil? || type.to_s.include?('/')
  type = ".#{type}" unless type.to_s[0] == ?.
  return Rack::Mime.mime_type(type, nil) unless value
  Rack::Mime::MIME_TYPES[type] = value
end

.mime_types(type) ⇒ Object

Provides all mime types matching type, including deprecated types:

mime_types :html # => ['text/html']
mime_types :js   # => ['application/javascript', 'text/javascript']


497
498
499
500
# File 'lib/gin/app.rb', line 497

def self.mime_types type
  type = mime_type type
  type =~ /^application\/(xml|javascript)$/ ? [type, "text/#$1"] : [type]
end

.mount(ctrl, base_path = nil, &block) ⇒ Object

Mount a Gin::Controller into the App and specify a base path. If controller mounts at root, use “/” as the base path.

mount UserController, "/user" do
  get  :index,  "/"
  get  :show,   "/:id"
  post :create, "/"
  get  :stats        # mounts to "/stats" by default
  any  :logged_in    # any HTTP verb will trigger this action
end

Controllers with non-mounted actions will throw a warning at boot time.

Restful routes are automatically mounted when no block is given:

mount UserController
# restfully mounted to /user
# non-canonical actions are mounted to /user/<action_name>

Mount blocks also support routing whatever actions are left to their restful defaults:

mount UserController do
  get :foo, "/"
  defaults
end

All Gin::Controller methods are considered actions and will be mounted in restful mode. For helper methods, include a module into your controller.



203
204
205
# File 'lib/gin/app.rb', line 203

def self.mount ctrl, base_path=nil, &block
  router.add ctrl, base_path, &block
end

.namespaceObject

:nodoc:



109
110
111
112
# File 'lib/gin/app.rb', line 109

def self.namespace #:nodoc:
  # Parent namespace of the App class. Used for reloading purposes.
  Gin.const_find(@source_class.split("::")[0..-2]) if @source_class
end

.old_inheritedObject

:nodoc:



673
674
675
# File 'lib/gin/test.rb', line 673

def self.inherited subclass   #:nodoc:
  subclass.setup
end

.optionsObject

Hash of the full Gin::App configuration. Result of using class-level setter methods such as Gin::App.environment.



87
88
89
# File 'lib/gin/app.rb', line 87

def self.options
  @options
end

.protection(opts = nil) ⇒ Object

Use rack-protection or not. Supports assigning hash for options. Defaults to false.



507
508
509
510
# File 'lib/gin/app.rb', line 507

def self.protection opts=nil
  @options[:protection] = opts unless opts.nil?
  @options[:protection]
end

.public_dir(dir = nil) ⇒ Object

Get or set the path to the public directory. Defaults to “<root_dir>/public”



517
518
519
520
# File 'lib/gin/app.rb', line 517

def self.public_dir dir=nil
  @options[:public_dir] = dir if dir
  @options[:public_dir] || File.join(root_dir, "public")
end

.reload_lockObject

:nodoc:



523
524
525
# File 'lib/gin/app.rb', line 523

def self.reload_lock # :nodoc:
  @reload_lock
end

.require(file) ⇒ Object

Custom require used for auto-reloading.



164
165
166
167
168
169
170
# File 'lib/gin/app.rb', line 164

def self.require file
  if autoreload
    track_require file
  else
    super file
  end
end

.root_dir(dir = nil) ⇒ Object

Get or set the root directory of the application. Defaults to the app file’s directory.



532
533
534
535
# File 'lib/gin/app.rb', line 532

def self.root_dir dir=nil
  @options[:root_dir] = File.expand_path(dir) if dir
  @options[:root_dir]
end

.routerObject

Router instance that handles mapping Rack-env -> Controller#action.



541
542
543
# File 'lib/gin/app.rb', line 541

def self.router
  @options[:router]
end

.session_secret(val = nil) ⇒ Object

Get or set the session secret String. Defaults to a new random value on boot.



560
561
562
563
# File 'lib/gin/app.rb', line 560

def self.session_secret val=nil
  @options[:session_secret] = val if val
  @options[:session_secret]
end

.sessions(opts = nil) ⇒ Object

Use rack sessions or not. Supports assigning hash for options. Defaults to false.



550
551
552
553
# File 'lib/gin/app.rb', line 550

def self.sessions opts=nil
  @options[:sessions] = opts unless opts.nil?
  @options[:sessions]
end

.setupObject

:nodoc:



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/gin/app.rb', line 42

def self.setup   # :nodoc:
  caller_line = caller.find{|line| !CALLERS_TO_IGNORE.any?{|m| line =~ m} }
  filepath = File.expand_path(caller_line.split(/:\d+:in `/).first)
  dir = File.dirname(filepath)

  @@app_klasses[self.name] = self unless self.name == "Gin::App"

  @source_file  = filepath
  @app_name     = Gin.underscore(self.name).gsub("/", ".")
  @source_class = self.to_s
  @templates    = Gin::Cache.new
  @md5s         = Gin::Cache.new
  @reload_lock  = Gin::RWLock.new
  @autoreload   = nil
  @instance     = nil

  @options = {}
  @options[:root_dir]       = dir
  @options[:environment]    = ENV['RACK_ENV'] || ENV_DEV
  @options[:error_delegate] = Gin::Controller
  @options[:middleware]     = []
  @options[:logger]         = Logger.new($stdout)
  @options[:router]         = Gin::Router.new
  @options[:session_secret] = SESSION_SECRET
  @options[:protection]     = false
  @options[:sessions]       = false
  @options[:config_reload]  = false
  @options[:layout]         = :layout
  @options[:template_engines] = Tilt.mappings.merge(nil => [Tilt::ERBTemplate])
end

.source_classObject

:nodoc:



115
116
117
118
# File 'lib/gin/app.rb', line 115

def self.source_class #:nodoc:
  # Lookup the class from its name. Used for reloading purposes.
  Gin.const_find(@source_class) if @source_class
end

.source_fileObject

Returns the source file of the current app.



104
105
106
# File 'lib/gin/app.rb', line 104

def self.source_file
  @source_file
end

.templatesObject

Cache of precompiled templates, shared across all instances of a given App class.



570
571
572
# File 'lib/gin/app.rb', line 570

def self.templates
  @templates
end

.use(middleware, *args, &block) ⇒ Object

Add middleware internally to the app. Middleware statuses and Exceptions will NOT be handled by the error_delegate.



580
581
582
583
584
# File 'lib/gin/app.rb', line 580

def self.use middleware, *args, &block
  ary = [middleware, *args]
  ary << block if block_given?
  self.middleware << ary
end

.views_dir(dir = nil) ⇒ Object

Get or set the path to the views directory. The wildcard ‘*’ will be replaced by the controller name.

Defaults to “<root_dir>/views”



593
594
595
596
# File 'lib/gin/app.rb', line 593

def self.views_dir dir=nil
  @options[:views_dir] = dir if dir
  @options[:views_dir] || File.join(root_dir, 'views')
end

Instance Method Details

#asset(path) ⇒ Object

Check if an asset exists. Returns the full path to the asset if found, otherwise nil. Does not support ./ or ../ for security reasons.



715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
# File 'lib/gin/app.rb', line 715

def asset path
  path = path.gsub STATIC_PATH_CLEANER, ""

  pub_filepath = File.expand_path(File.join(public_dir, path))
  return pub_filepath if File.file? pub_filepath

  ast_filepath = File.expand_path(File.join(assets_dir, path))
  return ast_filepath if File.file? ast_filepath

  pub_filepath.sub!(/(\.\w+)$/, '-*\1')
  ast_filepath.sub!(/(\.\w+)$/, '-*\1')
  filepath = Dir[pub_filepath, ast_filepath].first
  return filepath if filepath

  gin_filepath = File.expand_path(File.join(Gin::PUBLIC_DIR, path))
  return gin_filepath if File.file? gin_filepath
end

#asset_hostObject

Returns the default asset host.



747
748
749
# File 'lib/gin/app.rb', line 747

def asset_host
  asset_host_for(nil)
end

#asset_host_for(asset_name) ⇒ Object

Returns the asset host for a given asset name. This is useful when assigning a block for the asset_host. The asset_name argument is passed to the block.



738
739
740
741
# File 'lib/gin/app.rb', line 738

def asset_host_for asset_name
   @options[:asset_host].respond_to?(:call) ?
    @options[:asset_host].call(asset_name) : @options[:asset_host]
end

#asset_version(path) ⇒ Object

Returns the first 8 bytes of the asset file’s md5. File path is assumed relative to the public_dir.



756
757
758
759
# File 'lib/gin/app.rb', line 756

def asset_version path
  path = File.expand_path(File.join(public_dir, path))
  md5(path)
end

#call(env) ⇒ Object

Default Rack call method.



841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
# File 'lib/gin/app.rb', line 841

def call env
  try_autoreload(env) do
    valid_host = valid_host?(env)

    resp =
      if valid_host && @app.route!(env)
        @app.call!(env)

      elsif valid_host && @app.static!(env)
        @app.call_static(env)

      elsif @rack_app
        @rack_app.call(env)

      elsif !valid_host
        bt  = caller
        msg = "No route for host '%s:%s'" % [env[SERVER_NAME], env[SERVER_PORT]]
        err = Gin::BadRequest.new(msg)
        err.set_backtrace(bt)
        handle_error(err, env)

      else
        @app.call!(env)
      end

    resp[1][HOST_NAME] ||=
      (hostname || env[SERVER_NAME]).sub(/(:[0-9]+)?$/, ":#{env[SERVER_PORT]}")

    resp
  end
end

#call!(env) ⇒ Object

Call App instance stack without static file lookup or reloading.



889
890
891
892
893
894
895
896
897
898
899
# File 'lib/gin/app.rb', line 889

def call! env
  if env[GIN_STACK]
    dispatch env

  else
    env[GIN_STACK] = true
    with_log_request(env) do
      @stack.call env
    end
  end
end

#call_static(env) ⇒ Object

Returns a static file Rack response Array from the filename set in env.



906
907
908
909
910
# File 'lib/gin/app.rb', line 906

def call_static env
  with_log_request(env) do
    error_delegate.exec(self, env){ send_file env[GIN_STATIC] }
  end
end

#configObject

Access the config for your application, loaded from the config_dir.

# config/memcache.yml
default: &default
  host: example.com
  connections: 1
development: *default
  host: localhost

# access from App instance
@app.config['memcache.host']

The config object is shared across all instances of the App and has thread-safety built-in.



671
672
673
# File 'lib/gin/app.rb', line 671

def config
  @options[:config]
end

#development?Boolean

Check if running in development mode.

Returns:

  • (Boolean)


679
680
681
# File 'lib/gin/app.rb', line 679

def development?
  self.environment == ENV_DEV
end

#dispatch(env) ⇒ Object

Dispatch the Rack env to the given controller and action.



986
987
988
989
990
991
992
993
994
995
996
# File 'lib/gin/app.rb', line 986

def dispatch env
  raise Gin::NotFound,
    "No route exists for: #{env[REQ_METHOD]} #{env[PATH_INFO]}" unless
    env[GIN_TARGET]

  env[GIN_APP] = self
  env[GIN_TARGET][0].call(env)

rescue ::Exception => err
  handle_error(err, env)
end

#handle_error(err, env) ⇒ Object

Handle error with error_delegate if available, otherwise re-raise.



1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
# File 'lib/gin/app.rb', line 1002

def handle_error err, env
  delegate = error_delegate

  begin
    delegate.exec(self, env){ handle_error(err) }

  rescue ::Exception => err
    delegate = Gin::Controller and retry unless delegate == Gin::Controller
    raise
  end
end

#hostnameObject

The name defined by App.hostname.



775
776
777
# File 'lib/gin/app.rb', line 775

def hostname
  @options[:host][:name] if @options[:host]
end

#md5(path) ⇒ Object

Returns the first 8 characters of a file’s MD5 hash. Values are cached for future reference.



766
767
768
769
# File 'lib/gin/app.rb', line 766

def md5 path
  return unless File.file?(path)
  self.md5s[path] ||= Digest::MD5.file(path).hexdigest[0...8]
end

#production?Boolean

Check if running in production mode.

Returns:

  • (Boolean)


703
704
705
# File 'lib/gin/app.rb', line 703

def production?
  self.environment == ENV_PROD
end

#reload!Object

Used for auto reloading the whole app in development mode. Will only reload if Gin::App.autoreload is set to true.

If you use this in production, you’re gonna have a bad time.



822
823
824
825
826
827
828
829
830
831
832
833
834
835
# File 'lib/gin/app.rb', line 822

def reload!
  reload_lock.write_sync do
    self.class.erase_dependencies!

    if File.extname(self.class.source_file) != ".ru"
      self.class.erase! [self.class.source_file],
                        [self.class.name.split("::").last],
                        self.class.namespace
      require self.class.source_file
    end

    @app = self.class.source_class.new @rack_app, @override_options
  end
end

#rewrite!(env, *args) ⇒ Object

Rewrites the given Rack env and processes the new request. You’re probably looking for Gin::Controller#rewrite or Gin::Controller#reroute.



973
974
975
976
977
978
979
980
# File 'lib/gin/app.rb', line 973

def rewrite! env, *args
  new_env = rewrite_env(env, *args)

  logger << "[REWRITE] %s %s -> %s %s\n" %
    [env[REQ_METHOD], env[PATH_INFO], new_env[REQ_METHOD], new_env[PATH_INFO]]

  call(new_env)
end

#rewrite_env(env, *args) ⇒ Object

:nodoc:



947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
# File 'lib/gin/app.rb', line 947

def rewrite_env env, *args  # :nodoc:
  headers = args.pop if Hash === args.last && Hash === args[-2] && args[-2] != args[-1]
  params  = args.pop if Hash === args.last

  route = if String === args.first
            verb = (headers && headers[REQ_METHOD] || 'GET').upcase
            Gin::Router::Route.new(verb, args[0])
          else
            @app.router.route_to(*args)
          end

  new_env = env.dup
  new_env.delete_if{|k, v| k.start_with?('gin.') }
  new_env[GIN_RELOADED]  = env[GIN_RELOADED]
  new_env[GIN_TIMESTAMP] = env[GIN_TIMESTAMP]

  new_env.merge!(headers) if headers
  route.to_env(params, new_env)
end

#route!(env) ⇒ Object

Check if the request routes to a controller and action and set gin.target, gin.path_query_hash, and gin.http_route env variables. Returns true if a route is found, otherwise false.



934
935
936
937
938
939
940
941
942
943
944
# File 'lib/gin/app.rb', line 934

def route! env
  http_route = "#{env[REQ_METHOD]} #{env[PATH_INFO]}"
  return true if env[GIN_ROUTE] == http_route

  env[GIN_TARGET], env[GIN_PATH_PARAMS] =
    router.resources_for env[REQ_METHOD], env[PATH_INFO]

  env[GIN_ROUTE] = http_route

  !!env[GIN_TARGET]
end

#staging?Boolean

Check if running in staging mode.

Returns:

  • (Boolean)


695
696
697
# File 'lib/gin/app.rb', line 695

def staging?
  self.environment == ENV_STAGE
end

#static!(env) ⇒ Object

Check if the request is for a static file and set the gin.static env variable to the filepath. Returns true if request is to a static asset, otherwise false.



918
919
920
921
922
923
924
925
926
# File 'lib/gin/app.rb', line 918

def static! env
  filepath = %w{GET HEAD}.include?(env[REQ_METHOD]) &&
             asset(env[PATH_INFO])

  filepath ? (env[GIN_STATIC] = filepath) :
              env.delete(GIN_STATIC)

  !!env[GIN_STATIC]
end

#template_files(path) ⇒ Object

Returns an Array of file paths that match a valid path and maps to a known template engine.

app.template_files 'views/foo'
#=> ['views/foo.erb', 'views/foo.md']


810
811
812
813
# File 'lib/gin/app.rb', line 810

def template_files path
  exts = template_engines.keys.map{|e| "." << e if e }.join(",")
  Dir["#{path}{#{exts}}"]
end

#template_for(path, engine = nil) ⇒ Object

Returns the tilt template for the given template name. Returns nil if no template file is found.

template_for 'user/show'
#=> <Tilt::ERBTemplate @file="views/user/show.erb" ...>

template_for 'user/show.haml'
#=> <Tilt::HamlTemplate @file="views/user/show.haml" ...>

template_for 'non-existant'
#=> nil


792
793
794
795
796
797
798
799
800
801
# File 'lib/gin/app.rb', line 792

def template_for path, engine=nil
  templates.cache([path, engine]) do
    if file = template_files(path).first
      ext = File.extname(file)
      ext = ext.empty? ? nil : ext[1..-1]
      engine ||= template_engines[ext].first
      engine.new(file) if engine
    end
  end
end

#test?Boolean

Check if running in test mode.

Returns:

  • (Boolean)


687
688
689
# File 'lib/gin/app.rb', line 687

def test?
  self.environment == ENV_TEST
end

#try_autoreload(env, &block) ⇒ Object

Check if autoreload is needed, reload, and/or run block in a thread-safe manner.



878
879
880
881
882
883
# File 'lib/gin/app.rb', line 878

def try_autoreload env, &block
  return block.call if env[GIN_RELOADED] || !autoreload
  env[GIN_RELOADED] = true
  reload!
  reload_lock.read_sync{ block.call }
end