class Webservice::Metal

Attributes

env[R]
params[R]
request[R]
response[R]

Public Class Methods

call( env ) click to toggle source
# File lib/webservice/metal.rb, line 139
def call( env )    ## note self.call(env) lets you use =>  run Base instead of run Base.new
  ## puts "calling #{self.name}.call"
  prototype.call( env )
end
delete( pattern, &block) click to toggle source
# File lib/webservice/metal.rb, line 165
def delete( pattern, &block)  route( DELETE,  pattern, &block ); end
development?() click to toggle source
# File lib/webservice/metal.rb, line 186
def development?() environment == :development; end
environment() click to toggle source
# File lib/webservice/metal.rb, line 180
def environment
  ## include APP_ENV why? why not?
  ##   todo -- cache value? why why not?  (see/follow sinatara set machinery ??)
  (ENV['APP_ENV'] || ENV['RACK_ENV'] || :development).to_sym
end
get( pattern, &block ) click to toggle source

Note: for now defining a `GET` handler also automatically defines a `HEAD` handler (follows sinatra convention)

# File lib/webservice/metal.rb, line 157
def get( pattern, &block )
  route( GET,   pattern, &block )
  route( HEAD,  pattern, &block )
end
head( pattern, &block) click to toggle source
# File lib/webservice/metal.rb, line 166
def head( pattern, &block)    route( HEAD,    pattern, &block ); end
options( pattern, &block) click to toggle source
# File lib/webservice/metal.rb, line 167
def options( pattern, &block) route( OPTIONS, pattern, &block ); end
patch( pattern, &block) click to toggle source
# File lib/webservice/metal.rb, line 163
def patch( pattern, &block)   route( PATCH,   pattern, &block ); end
post( pattern, &block) click to toggle source
# File lib/webservice/metal.rb, line 162
def post( pattern, &block)    route( POST,    pattern, &block ); end
production?() click to toggle source
# File lib/webservice/metal.rb, line 187
def production?()  environment == :production;  end
prototype() click to toggle source
# File lib/webservice/metal.rb, line 144
def prototype
  ## puts "calling #{self.name}.prototype"
  @prototype ||= self.new
  ## pp @prototype
  ## @prototype
end
put( pattern, &block) click to toggle source
# File lib/webservice/metal.rb, line 164
def put( pattern, &block)     route( PUT,     pattern, &block ); end
route( method, pattern, &block ) click to toggle source
# File lib/webservice/metal.rb, line 169
def route( method, pattern, &block )
  puts "[debug] Webservice::Metal.#{method.downcase} - add route #{method} '#{pattern}' to #<#{self.name}:#{self.object_id}> : #{self.class.name}"

  ## note: for now use (default to) the sintatra-style patterns (with mustermann)
  routes[method] << [Mustermann::Sinatra.new(pattern), block]
end
routes() click to toggle source
# File lib/webservice/metal.rb, line 176
def routes
  @routes ||= Hash.new { |hash, key| hash[key]=[] }
end
run!() click to toggle source

convenience method

# File lib/webservice/metal.rb, line 191
def run!
  puts "[debug] Webservice::Metal.run! - self = #<#{self.name}:#{self.object_id}> : #{self.class.name}"  # note: assumes self is class
  app    = self     ## note: use self; will be derived class (e.g. App and not Base)
  port   = 4567
  Rack::Handler::WEBrick.run( app, Port:port ) do |server|
    ## todo: add traps here - why, why not??
  end
end
test?() click to toggle source
# File lib/webservice/metal.rb, line 188
def test?()        environment == :test;        end

Public Instance Methods

call( env ) click to toggle source
# File lib/webservice/metal.rb, line 208
def call( env )
  dup.call!( env )
end
call!( env ) click to toggle source
# File lib/webservice/metal.rb, line 212
def call!( env )
  env['PATH_INFO'] = '/'  if env['PATH_INFO'].empty?

  @request   = Rack::Request.new( env )
  @response  = Rack::Response.new
  @params    = request.params
  @env       = env

  catch(:halt) do
    ## call before if defined in derived (sub)classes
    before  if respond_to? :before

    route!
  end

  @response.finish
end
halt( *args ) click to toggle source
# File lib/webservice/metal.rb, line 231
def halt( *args )
  response.status = args.detect{ |arg| arg.is_a?(Fixnum) } || 200
  response.header.merge!( args.detect{ |arg| arg.is_a?(Hash) } || {} )
  response.body = [args.detect{ |arg| arg.is_a?(String) } || '']
  throw :halt, response           ## todo/check response arg used - what for??
end

Private Instance Methods

route!( base=self.class ) click to toggle source
# File lib/webservice/metal.rb, line 259
def route!( base=self.class )

  puts "  [#{base.name}] try matching route >#{request.request_method} #{request.path_info}<..."

    routes = base.routes[ request.request_method ]
    routes.each do |pattern, block|
      ## puts "trying matching route >#{request.path_info}<..."
      url_params = pattern.params( request.path_info )
      if url_params   ## note: params returns nil if no match
        ## puts "  BINGO! url_params: #{url_params.inspect}"
        if !url_params.empty?   ## url_params hash NOT empty (e.g. {}) merge with req params
          ## todo/fix: check merge order - params overwrites url_params - why? why not??

          ## todo/fix: check params - params works with string keys only - check for indiffent keys - why? why not?
          ##   check rack params - works with indifferent keys by default??
          @params = url_params.merge( @params )
        end
        route_eval( &block )
        ##  todo/check: keep return - why? why not?  - note: route_eval will always throw :halt
        ## handler.handle_response( instance_eval( &block ))
        ## return
      end
    end

    ## check recursive - all super(parent)classes too (e.g. App > Base > Metal etc.)
    ##   note: superclass is the parent class (returns nil if no more parent class)
    if base.superclass.respond_to? :routes
      route!( base.superclass )
      return
    end

    # no match found for route/request
    halt 404
end
route_eval( &block ) click to toggle source

run a route block and throw :halt

# File lib/webservice/metal.rb, line 242
def route_eval( &block )
  obj = instance_eval( &block )    ## return result - for now assumes a single object

  if respond_to? :handle_response
    handle_response( obj )    ## prepare response
  else
    ## default response; string expected
    ##   if string pass it along
    ##   if NOT string for debugging / dump to string with inspect
    response.status = 200
    response.body   = [obj.is_a?(String) ? obj.to_s : obj.inspect]
  end

  throw :halt
end