Class: Knj::Eruby

Inherits:
Object show all
Defined in:
lib/knj/eruby.rb

Overview

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

Defined Under Namespace

Classes: Binding, Handler

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args = {}) ⇒ Eruby

Sets various arguments and prepares for parsing.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 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

Instance Attribute Details

#connectsObject (readonly)

Returns the value of attribute connects.



3
4
5
# File 'lib/knj/eruby.rb', line 3

def connects
  @connects
end

#cookiesObject (readonly)

Returns the value of attribute cookies.



3
4
5
# File 'lib/knj/eruby.rb', line 3

def cookies
  @cookies
end

#errorObject (readonly)

Returns the value of attribute error.



3
4
5
# File 'lib/knj/eruby.rb', line 3

def error
  @error
end

#fcgiObject (readonly)

Returns the value of attribute fcgi.



3
4
5
# File 'lib/knj/eruby.rb', line 3

def fcgi
  @fcgi
end

#headersObject (readonly)

Returns the value of attribute headers.



3
4
5
# File 'lib/knj/eruby.rb', line 3

def headers
  @headers
end

Instance Method Details

#connect(signal, &block) ⇒ Object

Connects a block to a certain event.



162
163
164
165
# File 'lib/knj/eruby.rb', line 162

def connect(signal, &block)
  @connects[signal] = [] if !@connects.key?(signal)
  @connects[signal] << block
end

Adds a new cookie to the list.



157
158
159
# File 'lib/knj/eruby.rb', line 157

def cookie(cookie_data)
  @cookies << cookie_data
end

#destroyObject

Destroyes this object unsetting all variables and clearing all cache.



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/knj/eruby.rb', line 100

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
end

#handle_error(e) ⇒ Object

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



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/knj/eruby.rb', line 227

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>"
end

#has_status_header?Boolean

Returns true if containing a status-header.

Returns:

  • (Boolean)


132
133
134
135
136
137
138
# File 'lib/knj/eruby.rb', line 132

def has_status_header?
  @headers.each do |header|
    return true if header[0] == "Status"
  end
  
  return false
end

#header(key, value) ⇒ Object

Adds a new header to the list.



152
153
154
# File 'lib/knj/eruby.rb', line 152

def header(key, value)
  @headers << [key, value]
end

#import(filename) ⇒ Object

Imports and evaluates a new .rhtml-file.

Examples

erb.import(“/path/to/some_file.rhtml”)



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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# 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
end

#load_filename(filename, args = {}) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/knj/eruby.rb', line 202

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
end

#load_return(filename, args = {}) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/knj/eruby.rb', line 188

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

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



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/knj/eruby.rb', line 115

def print_headers(args = {})
  header_str = ""
  
  @headers.each do |header|
    header_str << "#{header[0]}: #{header[1]}\n"
  end
  
  @cookies.each do |cookie|
    header_str << "Set-Cookie: #{Knj::Web.cookie_str(cookie)}\n"
  end
  
  header_str << "\n"
  self.reset_headers if @fcgi
  return header_str
end

#printcont(tmp_out, args = {}) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/knj/eruby.rb', line 167

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
end

#reset_connectsObject

Resets all connections.



141
142
143
# File 'lib/knj/eruby.rb', line 141

def reset_connects
  @connects = {}
end

#reset_headersObject

Resets all headers.



146
147
148
149
# File 'lib/knj/eruby.rb', line 146

def reset_headers
  @headers = []
  @cookies = []
end