class Knj::Eruby

Uses Rubinius, Knj::Compiler, RubyVM::InstructionSequence and eval to convert and execute .rhtml-files.

Attributes

connects[R]
cookies[R]
error[R]
fcgi[R]
headers[R]

Public Class Methods

new(args = {}) click to toggle source

Sets various arguments and prepares for parsing.

# File lib/knj/eruby.rb, line 6
def initialize(args = {})
  @args = args
  
  @tmpdir = "#{Knj::Os.tmpdir}/knj_erb"
  if !File.exists?(@tmpdir)
    Dir.mkdir(@tmpdir, 0777)
    File.chmod(0777, @tmpdir)
  end
  
  
  #This argument can be used if a shared cache should be used to speed up performance.
  if @args[:cache_hash]
    @cache = @args[:cache_hash]
  else
    @cache = {}
  end
  
  if RUBY_PLATFORM == "java" or RUBY_ENGINE == "rbx"
    @cache_mode = :code_eval
    #@cache_mode = :compile_knj
  elsif RUBY_VERSION.slice(0..2) == "1.9" #and RubyVM::InstructionSequence.respond_to?(:compile_file)
    @cache_mode = :code_eval
    #@cache_mode = :inseq
    #@cache_mode = :compile_knj
  end
  
  if @cache_mode == :compile_knj
    require "#{$knjpath}compiler"
    @compiler = Knj::Compiler.new(:cache_hash => @cache)
  end
  
  self.reset_headers
  self.reset_connects
end

Public Instance Methods

connect(signal, &block) click to toggle source

Connects a block to a certain event.

# File lib/knj/eruby.rb, line 170
def connect(signal, &block)
  @connects[signal] = [] if !@connects.key?(signal)
  @connects[signal] << block
  return nil
end
destroy() click to toggle source

Destroyes this object unsetting all variables and clearing all cache.

# File lib/knj/eruby.rb, line 102
def destroy
  @connects.clear if @connects.is_a?(Hash)
  @headers.clear if @headers.is_a?(Array)
  @cookies.clear if @cookies.is_a?(Array)
  
  @cache.clear if @cache.is_a?(Hash) and @args and !@args.key?(:cache_hash)
  @args.clear if @args.is_a?(Hash)
  @args = nil
  @cache = nil
  @connects = nil
  @headers = nil
  @cookies = nil
  
  return nil
end
handle_error(e) click to toggle source

This method will handle an error without crashing simply adding the error to the print-queue.

# File lib/knj/eruby.rb, line 240
def handle_error(e)
  begin
    if @connects and @connects.key?("error")
      @connects["error"].each do |block|
        block.call(e)
      end
    end
  rescue SystemExit => e
    raise e
  rescue => e
    #An error occurred while trying to run the on-error-block - show this as an normal error.
    print "\n\n<pre>\n\n"
    print "<b>#{Knj::Web.html(e.class.name)}: #{Knj::Web.html(e.message)}</b>\n\n"
    
    e.backtrace.each do |line|
      print "#{Knj::Web.html(line)}\n"
    end
    
    print "</pre>"
  end
  
  print "\n\n<pre>\n\n"
  print "<b>#{Knj::Web.html(e.class.name)}: #{Knj::Web.html(e.message)}</b>\n\n"
  
  e.backtrace.each do |line|
    print "#{Knj::Web.html(line)}\n"
  end
  
  print "</pre>"
  
  return nil
end
has_status_header?() click to toggle source

Returns true if containing a status-header.

# File lib/knj/eruby.rb, line 136
def has_status_header?
  @headers.each do |header|
    return true if header[0] == "Status"
  end
  
  return false
end
header(key, value) click to toggle source

Adds a new header to the list.

# File lib/knj/eruby.rb, line 158
def header(key, value)
  @headers << [key, value]
  return nil
end
import(filename) click to toggle source

Imports and evaluates a new .rhtml-file.

Examples

erb.import("/path/to/some_file.rhtml")
# File lib/knj/eruby.rb, line 44
def import(filename)
  @error = false
  Dir.mkdir(@tmpdir) if !File.exists?(@tmpdir)
  filename = File.expand_path(filename)
  raise "File does not exist: #{filename}" unless File.exists?(filename)
  cachename = "#{@tmpdir}/#{filename.gsub("/", "_").gsub(".", "_")}.cache"
  filetime = File.mtime(filename)
  cachetime = File.mtime(cachename) if File.exists?(cachename)
  
  if !File.exists?(cachename) or filetime > cachetime
    Knj::Eruby::Handler.load_file(filename, :cachename => cachename)
    File.chmod(0777, cachename)
    cachetime = File.mtime(cachename)
    reload_cache = true
  end
  
  begin
    case @cache_mode
      when :compile_knj
        @compiler.eval_file(:filepath => cachename, :fileident => filename)
      when :code_eval
        if @args[:binding_callback]
          binding_use = @args[:binding_callback].call
        else
          eruby_binding = Knj::Eruby::Binding.new
          binding_use = eruby_binding.get_binding
        end
        
        #No reason to cache contents of files - benchmarking showed little to no differene performance-wise, but caching took up a lot of memory, when a lot of files were cached - knj.
        eval(File.read(cachename), binding_use, filename)
      when :inseq
        reload_cache = true if !@cache.key?(cachename)
        
        if reload_cache or @cache[cachename][:time] < cachetime
          @cache[cachename] = {
            :inseq => RubyVM::InstructionSequence.compile(File.read(cachename), filename, nil, 1),
            :time => Time.now
          }
        end
        
        @cache[cachename][:inseq].eval
      else
        loaded_content = Knj::Eruby::Handler.load_file(filename, {:cachename => cachename})
        print loaded_content.evaluate
    end
  rescue SystemExit
    #do nothing.
  rescue Interrupt => e
    raise e
  rescue Exception => e
    @error = true
    self.handle_error(e)
  end
  
  return nil
end
load_filename(filename, args = {}) click to toggle source
# File lib/knj/eruby.rb, line 213
def load_filename(filename, args = {})
  begin
    if !args[:custom_io]
      tmp_out = StringIO.new
      $stdout = tmp_out
    end
    
    self.import(filename)
    
    if @connects["exit"]
      @connects["exit"].each do |block|
        block.call
      end
    end
    
    self.printcont(tmp_out, args)
  rescue SystemExit => e
    self.printcont(tmp_out, args)
  rescue => e
    self.handle_error(e)
    self.printcont(tmp_out, args)
  end
  
  return nil
end
load_return(filename, args = {}) click to toggle source
# File lib/knj/eruby.rb, line 199
def load_return(filename, args = {})
  if !args[:io]
    retio = StringIO.new
    args[:io] = retio
  end
  
  self.load_filename(filename, args)
  
  if !args[:custom_io]
    retio.rewind
    return retio.read
  end
end
print_headers(args = {}) click to toggle source

Returns various headers as one complete string ready to be used in a HTTP-request.

printcont(tmp_out, args = {}) click to toggle source
# File lib/knj/eruby.rb, line 176
def printcont(tmp_out, args = {})
  if @fcgi
    @fcgi.print self.print_headers
    tmp_out.rewind
    @fcgi.print tmp_out.read.to_s
  else
    if args[:io] and !args[:custom_io]
      old_out = $stdout
      $stdout = args[:io]
    elsif !args[:custom_io]
      $stdout = STDOUT
    end
    
    if !args[:custom_io]
      print self.print_headers if !args.key?(:with_headers) or args[:with_headers]
      tmp_out.rewind
      print tmp_out.read
    end
  end
  
  return nil
end
reset_connects() click to toggle source

Resets all connections.

# File lib/knj/eruby.rb, line 145
def reset_connects
  @connects = {}
  return nil
end
reset_headers() click to toggle source

Resets all headers.

# File lib/knj/eruby.rb, line 151
def reset_headers
  @headers = []
  @cookies = []
  return nil
end