Class: Aldebaran::Base

Inherits:
Object
  • Object
show all
Includes:
Helpers, Templates, Rack::Utils
Defined in:
lib/aldebaran/base.rb

Overview

Base class for all aldebaran applications and middleware.

Direct Known Subclasses

Application

Constant Summary collapse

CALLERS_TO_IGNORE =

:nodoc:

[ # :nodoc:
  /\/aldebaran(\/(base|main|showexceptions))?\.rb$/, # all aldebaran 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
]

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Templates

#builder, #coffee, #creole, #erb, #erubis, #find_template, #haml, #less, #liquid, #markaby, #markdown, #nokogiri, #radius, #rdoc, #sass, #scss, #slim, #textile

Methods included from Helpers

#attachment, #back, #body, #cache_control, #client_error?, #content_type, #error, #etag, #expires, #headers, #informational?, #last_modified, #logger, #mime_type, #not_found, #not_found?, #redirect, #redirect?, #send_file, #server_error?, #session, #status, #stream, #success?, #time_for, #uri

Constructor Details

#initialize(app = nil) {|_self| ... } ⇒ Base

Returns a new instance of Base.

Yields:

  • (_self)

Yield Parameters:



652
653
654
655
656
657
# File 'lib/aldebaran/base.rb', line 652

def initialize(app=nil)
  super()
  @app = app
  @template_cache = Tilt::Cache.new
  yield self if block_given?
end

Class Attribute Details

.errorsObject (readonly)

Returns the value of attribute errors.



901
902
903
# File 'lib/aldebaran/base.rb', line 901

def errors
  @errors
end

.filtersObject (readonly)

Returns the value of attribute filters.



901
902
903
# File 'lib/aldebaran/base.rb', line 901

def filters
  @filters
end

.routesObject (readonly)

Returns the value of attribute routes.



901
902
903
# File 'lib/aldebaran/base.rb', line 901

def routes
  @routes
end

.templatesObject (readonly)

Returns the value of attribute templates.



901
902
903
# File 'lib/aldebaran/base.rb', line 901

def templates
  @templates
end

Instance Attribute Details

#appObject

Returns the value of attribute app.



649
650
651
# File 'lib/aldebaran/base.rb', line 649

def app
  @app
end

#envObject

Returns the value of attribute env.



664
665
666
# File 'lib/aldebaran/base.rb', line 664

def env
  @env
end

#paramsObject

Returns the value of attribute params.



664
665
666
# File 'lib/aldebaran/base.rb', line 664

def params
  @params
end

#requestObject

Returns the value of attribute request.



664
665
666
# File 'lib/aldebaran/base.rb', line 664

def request
  @request
end

#responseObject

Returns the value of attribute response.



664
665
666
# File 'lib/aldebaran/base.rb', line 664

def response
  @response
end

#template_cacheObject (readonly)

Returns the value of attribute template_cache.



650
651
652
# File 'lib/aldebaran/base.rb', line 650

def template_cache
  @template_cache
end

Class Method Details

.add_filter(type, path = nil, options = {}, &block) ⇒ Object

add a filter



1082
1083
1084
1085
# File 'lib/aldebaran/base.rb', line 1082

def add_filter(type, path = nil, options = {}, &block)
  path, options = //, path if path.respond_to?(:each_pair)
  filters[type] << compile!(type, path || //, block, options)
end

.after(path = nil, options = {}, &block) ⇒ Object

Define an after filter; runs after all requests within the same context as route handlers and may access/modify the request and response.



1077
1078
1079
# File 'lib/aldebaran/base.rb', line 1077

def after(path = nil, options = {}, &block)
  add_filter(:after, path, options, &block)
end

.before(path = nil, options = {}, &block) ⇒ Object

Define a before filter; runs before all requests within the same context as route handlers and may access/modify the request and response.



1070
1071
1072
# File 'lib/aldebaran/base.rb', line 1070

def before(path = nil, options = {}, &block)
  add_filter(:before, path, options, &block)
end

.build(builder, *args, &bk) ⇒ Object

Creates a Rack::Builder instance with all the middleware set up and an instance of this class as end point.



1296
1297
1298
1299
1300
1301
# File 'lib/aldebaran/base.rb', line 1296

def build(builder, *args, &bk)
  setup_default_middleware builder
  setup_middleware builder
  builder.run new!(*args, &bk)
  builder
end

.call(env) ⇒ Object



1303
1304
1305
# File 'lib/aldebaran/base.rb', line 1303

def call(env)
  synchronize { prototype.call(env) }
end

.caller_filesObject

Like Kernel#caller but excluding certain magic entries and without line / method information; the resulting array contains filenames only.



1394
1395
1396
# File 'lib/aldebaran/base.rb', line 1394

def caller_files
  cleaned_caller(1).flatten
end

.caller_locationsObject

Like caller_files, but containing Arrays rather than strings with the first element being the file, and the second being the line.



1400
1401
1402
# File 'lib/aldebaran/base.rb', line 1400

def caller_locations
  cleaned_caller 2
end

.condition(name = "#{caller.first[/`.*'/]} condition", &block) ⇒ Object

Add a route condition. The route is considered non-matching when the block returns false.



1089
1090
1091
# File 'lib/aldebaran/base.rb', line 1089

def condition(name = "#{caller.first[/`.*'/]} condition", &block)
  @conditions << generate_method(name, &block)
end

.configure(*envs) {|_self| ... } ⇒ Object

Set configuration options for aldebaran and/or the app. Allows scoping of settings for certain environments.

Yields:

  • (_self)

Yield Parameters:



1242
1243
1244
# File 'lib/aldebaran/base.rb', line 1242

def configure(*envs, &block)
  yield self if envs.empty? || envs.include?(environment.to_sym)
end

.delete(path, opts = {}, &bk) ⇒ Object



1145
# File 'lib/aldebaran/base.rb', line 1145

def delete(path, opts={}, &bk)  route 'DELETE',  path, opts, &bk end

.development?Boolean

Returns:

  • (Boolean)


1236
# File 'lib/aldebaran/base.rb', line 1236

def development?; environment == :development end

.disable(*opts) ⇒ Object

Same as calling ‘set :option, false` for each of the given options.



988
989
990
# File 'lib/aldebaran/base.rb', line 988

def disable(*opts)
  opts.each { |key| set(key, false) }
end

.enable(*opts) ⇒ Object

Same as calling ‘set :option, true` for each of the given options.



983
984
985
# File 'lib/aldebaran/base.rb', line 983

def enable(*opts)
  opts.each { |key| set(key, true) }
end

.error(*codes, &block) ⇒ Object

Define a custom error handler. Optionally takes either an Exception class, or an HTTP status code to specify which errors should be handled.



995
996
997
998
999
1000
# File 'lib/aldebaran/base.rb', line 995

def error(*codes, &block)
  args  = compile! "ERROR", //, block
  codes = codes.map { |c| Array(c) }.flatten
  codes << Exception if codes.empty?
  codes.each { |c| @errors[c] = args }
end

.extensionsObject

Extension modules registered on this class and all superclasses.



922
923
924
925
926
927
928
# File 'lib/aldebaran/base.rb', line 922

def extensions
  if superclass.respond_to?(:extensions)
    (@extensions + superclass.extensions).uniq
  else
    @extensions
  end
end

.get(path, opts = {}, &block) ⇒ Object

Defining a ‘GET` handler also automatically defines a `HEAD` handler.



1135
1136
1137
1138
1139
1140
1141
# File 'lib/aldebaran/base.rb', line 1135

def get(path, opts={}, &block)
  conditions = @conditions.dup
  route('GET', path, opts, &block)

  @conditions = conditions
  route('HEAD', path, opts, &block)
end

.head(path, opts = {}, &bk) ⇒ Object



1146
# File 'lib/aldebaran/base.rb', line 1146

def head(path, opts={}, &bk)    route 'HEAD',    path, opts, &bk end

.helpers(*extensions, &block) ⇒ Object

Makes the methods defined in the block and in the Modules given in ‘extensions` available to the handlers and templates



1220
1221
1222
1223
# File 'lib/aldebaran/base.rb', line 1220

def helpers(*extensions, &block)
  class_eval(&block)   if block_given?
  include(*extensions) if extensions.any?
end

.inline_templates=(file = nil) ⇒ Object

Load embeded templates from the file; uses the caller’s __FILE__ when no file is specified.



1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
# File 'lib/aldebaran/base.rb', line 1020

def inline_templates=(file=nil)
  file = (file.nil? || file == true) ? (caller_files.first || File.expand_path($0)) : file

  begin
    io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
    app, data = io.gsub("\r\n", "\n").split(/^__END__$/, 2)
  rescue Errno::ENOENT
    app, data = nil
  end

  if data
    if app and app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
      encoding = $2
    else
      encoding = settings.default_encoding
    end
    lines = app.count("\n") + 1
    template = nil
    force_encoding data, encoding
    data.each_line do |line|
      lines += 1
      if line =~ /^@@\s*(.*\S)\s*$/
        template = force_encoding('', encoding)
        templates[$1.to_sym] = [template, file, lines]
      elsif template
        template << line
      end
    end
  end
end

.layout(name = :layout, &block) ⇒ Object

Define the layout template. The block must return the template source.



1014
1015
1016
# File 'lib/aldebaran/base.rb', line 1014

def layout(name=:layout, &block)
  template name, &block
end

.middlewareObject

Middleware used in this class and all superclasses.



931
932
933
934
935
936
937
# File 'lib/aldebaran/base.rb', line 931

def middleware
  if superclass.respond_to?(:middleware)
    superclass.middleware + @middleware
  else
    @middleware
  end
end

.mime_type(type, value = nil) ⇒ Object

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



1052
1053
1054
1055
1056
1057
# File 'lib/aldebaran/base.rb', line 1052

def 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']


1062
1063
1064
1065
# File 'lib/aldebaran/base.rb', line 1062

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

.new(*args, &bk) ⇒ Object

Create a new instance of the class fronted by its middleware pipeline. The object is guaranteed to respond to #call but may not be an instance of the class new was called on.



1290
1291
1292
# File 'lib/aldebaran/base.rb', line 1290

def new(*args, &bk)
  build(Rack::Builder.new, *args, &bk).to_app
end

.not_found(&block) ⇒ Object

Sugar for ‘error(404) { … }`



1003
1004
1005
# File 'lib/aldebaran/base.rb', line 1003

def not_found(&block)
  error 404, &block
end

.options(path, opts = {}, &bk) ⇒ Object



1147
# File 'lib/aldebaran/base.rb', line 1147

def options(path, opts={}, &bk) route 'OPTIONS', path, opts, &bk end

.patch(path, opts = {}, &bk) ⇒ Object



1148
# File 'lib/aldebaran/base.rb', line 1148

def patch(path, opts={}, &bk)   route 'PATCH',   path, opts, &bk end

.post(path, opts = {}, &bk) ⇒ Object



1144
# File 'lib/aldebaran/base.rb', line 1144

def post(path, opts={}, &bk)    route 'POST',    path, opts, &bk end

.production?Boolean

Returns:

  • (Boolean)


1237
# File 'lib/aldebaran/base.rb', line 1237

def production?;  environment == :production  end

.prototypeObject

The prototype instance used to process requests.



1280
1281
1282
# File 'lib/aldebaran/base.rb', line 1280

def prototype
  @prototype ||= new
end

.public=(value) ⇒ Object



1093
1094
1095
1096
# File 'lib/aldebaran/base.rb', line 1093

def public=(value)
  warn ":public is no longer used to avoid overloading Module#public, use :public_folder instead"
  set(:public_folder, value)
end

.put(path, opts = {}, &bk) ⇒ Object



1143
# File 'lib/aldebaran/base.rb', line 1143

def put(path, opts={}, &bk)     route 'PUT',     path, opts, &bk end

.quit!(server, handler_name) ⇒ Object



1252
1253
1254
1255
1256
# File 'lib/aldebaran/base.rb', line 1252

def quit!(server, handler_name)
  # Use Thin's hard #stop! if available, otherwise just #stop.
  server.respond_to?(:stop!) ? server.stop! : server.stop
  $stderr.puts "\n== aldebaran has ended his set (crowd applauds)" unless handler_name =~/cgi/i
end

.register(*extensions, &block) ⇒ Object

Register an extension. Alternatively take a block from which an extension will be created and registered on the fly.



1227
1228
1229
1230
1231
1232
1233
1234
# File 'lib/aldebaran/base.rb', line 1227

def register(*extensions, &block)
  extensions << Module.new(&block) if block_given?
  @extensions += extensions
  extensions.each do |extension|
    extend extension
    extension.registered(self) if extension.respond_to?(:registered)
  end
end

.reset!Object

Removes all routes, filters, middleware and extension hooks from the current class (not routes/filters/… defined by its superclass).



905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
# File 'lib/aldebaran/base.rb', line 905

def reset!
  @conditions     = []
  @routes         = {}
  @filters        = {:before => [], :after => []}
  @errors         = {}
  @middleware     = []
  @prototype      = nil
  @extensions     = []

  if superclass.respond_to?(:templates)
    @templates = Hash.new { |hash,key| superclass.templates[key] }
  else
    @templates = {}
  end
end

.run!(options = {}) ⇒ Object

Run the aldebaran app as a self-hosted server using Thin, Mongrel or WEBrick (in that order). If given a block, will call with the constructed handler once we have taken the stage.



1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
# File 'lib/aldebaran/base.rb', line 1261

def run!(options={})
  set options
  handler      = detect_rack_handler
  handler_name = handler.name.gsub(/.*::/, '')
  handler.run self, :Host => bind, :Port => port do |server|
    unless handler_name =~ /cgi/i
      $stderr.puts "== aldebaran/#{Aldebaran::VERSION} has taken the stage " +
      "on #{port} for #{environment} with backup from #{handler_name}"
    end
    [:INT, :TERM].each { |sig| trap(sig) { quit!(server, handler_name) } }
    server.threaded = settings.threaded if server.respond_to? :threaded=
    set :running, true
    yield server if block_given?
  end
rescue Errno::EADDRINUSE => e
  $stderr.puts "== Someone is already performing on port #{port}!"
end

.set(option, value = (not_set = true), ignore_setter = false, &block) ⇒ Object

Sets an option to the given value. If the value is a proc, the proc will be called every time the option is accessed.

Raises:

  • (ArgumentError)


941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
# File 'lib/aldebaran/base.rb', line 941

def set(option, value = (not_set = true), ignore_setter = false, &block)
  raise ArgumentError if block and !not_set
  value, not_set = block, false if block

  if not_set
    raise ArgumentError unless option.respond_to?(:each)
    option.each { |k,v| set(k, v) }
    return self
  end

  if respond_to?("#{option}=") and not ignore_setter
    return __send__("#{option}=", value)
  end

  setter = proc { |val| set option, val, true }
  getter = proc { value }

  case value
  when Proc
    getter = value
  when Symbol, Fixnum, FalseClass, TrueClass, NilClass
    # we have a lot of enable and disable calls, let's optimize those
    class_eval "def self.#{option}() #{value.inspect} end"
    getter = nil
  when Hash
    setter = proc do |val|
      val = value.merge val if Hash === val
      set option, val, true
    end
  end

  (class << self; self; end).class_eval do
    define_method("#{option}=", &setter) if setter
    define_method(option,       &getter) if getter
    unless method_defined? "#{option}?"
      class_eval "def #{option}?() !!#{option} end"
    end
  end
  self
end

.settingsObject

Access settings defined with Base.set.



690
691
692
# File 'lib/aldebaran/base.rb', line 690

def self.settings
  self
end

.template(name, &block) ⇒ Object

Define a named template. The block must return the template source.



1008
1009
1010
1011
# File 'lib/aldebaran/base.rb', line 1008

def template(name, &block)
  filename, line = caller_locations.first
  templates[name] = [block, filename, line.to_i]
end

.test?Boolean

Returns:

  • (Boolean)


1238
# File 'lib/aldebaran/base.rb', line 1238

def test?;        environment == :test        end

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

Use the specified Rack middleware



1247
1248
1249
1250
# File 'lib/aldebaran/base.rb', line 1247

def use(middleware, *args, &block)
  @prototype = nil
  @middleware << [middleware, args, block]
end

Instance Method Details

#call(env) ⇒ Object

Rack call interface.



660
661
662
# File 'lib/aldebaran/base.rb', line 660

def call(env)
  dup.call!(env)
end

#call!(env) ⇒ Object

:nodoc:



666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
# File 'lib/aldebaran/base.rb', line 666

def call!(env) # :nodoc:
  @env      = env
  @request  = Request.new(env)
  @response = Response.new
  @params   = indifferent_params(@request.params)
  template_cache.clear if settings.reload_templates
  force_encoding(@params)

  @response['Content-Type'] = nil
  invoke { dispatch! }
  invoke { error_block!(response.status) }

  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

  @response.finish
end

#forwardObject

Forward the request to the downstream app – middleware only.



720
721
722
723
724
725
726
727
# File 'lib/aldebaran/base.rb', line 720

def forward
  fail "downstream app not set" unless @app.respond_to? :call
  status, headers, body = @app.call env
  @response.status = status
  @response.body = body
  @response.headers.merge! headers
  nil
end

#halt(*response) ⇒ Object

Exit the current block, halts any further processing of the request, and returns the specified response.



707
708
709
710
# File 'lib/aldebaran/base.rb', line 707

def halt(*response)
  response = response.first if response.length == 1
  throw :halt, response
end

#new!Object

Create a new instance without middleware in front of it.



1285
# File 'lib/aldebaran/base.rb', line 1285

alias new! new

#optionsObject



699
700
701
702
703
# File 'lib/aldebaran/base.rb', line 699

def options
  warn "Aldebaran::Base#options is deprecated and will be removed, " \
    "use #settings instead."
  settings
end

#pass(&block) ⇒ Object

Pass control to the next matching route. If there are no more matching routes, aldebaran will return a 404 response.



715
716
717
# File 'lib/aldebaran/base.rb', line 715

def pass(&block)
  throw :pass, block
end

#settingsObject

Access settings defined with Base.set.



695
696
697
# File 'lib/aldebaran/base.rb', line 695

def settings
  self.class.settings
end