Class: Radio::HTTP::Script

Inherits:
Rack::Request
  • Object
show all
Includes:
ERB::Util
Defined in:
lib/radio/http/script.rb

Overview

A Script instance is the context in which scripts are rendered. It inherits everything from Rack::Request and supplies a Response instance you can use for redirects, cookies, and other controller actions.

Defined Under Namespace

Classes: NotFound, RenderStackOverflow

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, filename) ⇒ Script

Returns a new instance of Script.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/radio/http/script.rb', line 35

def initialize(env, filename)
  super(env)
  @render_stack = []
  @response = original_response = Rack::Response.new
  rendering = render(filename)
  if @response == original_response and @response.empty?
    @response.write rendering
  end
rescue RenderStackOverflow, NotFound => e
  if @render_stack.size > 0
    # Make errors appear from the render instead of the engine.call
    e.set_backtrace e.backtrace[1..-1]
    raise e 
  end
  @response.status = 404
  @response.write "404 Not Found\n"
  @response.header["X-Cascade"] = "pass"
  @response.header["Content-Type"] = "text/plain"
end

Instance Attribute Details

#render_stack<Array> (readonly)

An array of filenames representing the current render stack.

Examples:

<%= if render_stack.size == 1
      render 'html_version' 
    else
      render 'included_version'
    end 
%>

Returns:

  • (<Array>)


70
71
72
# File 'lib/radio/http/script.rb', line 70

def render_stack
  @render_stack
end

#responseRack::Response

After rendering, #finish will be sent to the client. If you replace the response or add to the response#body, the script engine rendering will not be added.

Returns:

  • (Rack::Response)


59
60
61
# File 'lib/radio/http/script.rb', line 59

def response
  @response
end

Instance Method Details

#expand_path(filename, dir = nil) ⇒ String

Helper for finding files relative to Scripts.

Parameters:

  • filename (String)

Returns:

  • (String)

    absolute filesystem path



123
124
125
126
# File 'lib/radio/http/script.rb', line 123

def expand_path(filename, dir=nil)
  dir ||= File.dirname render_stack.last
  File.expand_path filename, dir
end

#render(filename, locals = {}) ⇒ Object

Render another Script.

Examples:

view_test.erb

<%= render 'util/logger_popup' %>

Parameters:

  • filename (String)

    Relative to current Script.

  • locals (Hash) (defaults to: {})

    Local variables for the Script.

Raises:



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/radio/http/script.rb', line 77

def render(filename, locals = {})
  if render_stack.size > 100
    # Since nobody sane should recurse through here, this mainly
    # finds a render self that you might get after a copy and paste
    raise RenderStackOverflow 
  elsif render_stack.size > 0
    # Hooray for relative paths and easily movable files
    filename = File.expand_path(filename, File.dirname(render_stack.last))
  else
    # Underbar scripts are partials by convention; keep them from rendering at root
    filename = File.expand_path(filename)
    raise NotFound if File.basename(filename) =~ /^_/
  end
  ext = File.extname(filename)
  files1 = [filename]
  files1 << filename + '.html' if ext == ''
  files1 << filename.sub(/.html$/,'') if ext == '.html'
  files1.each do |filename1|
    files2 = [filename1+'.erb']
    files2 << filename1.gsub(/.html$/, '.erb') if File.extname(filename1) == '.html'
    unless filename1 =~ /^_/ or render_stack.empty?
      files2 = files2 + files2.collect {|f| "#{File.dirname(f)}/_#{File.basename(f)}"} 
    end
    files2.each do |filename2|
      if File.file?(filename2) and File.readable?(filename2)
        if render_stack.empty?
          response.header["Content-Type"] = Rack::Mime.mime_type(File.extname(filename1), 'text/html')
        end
        render_stack.push filename2
        erb = ::ERB.new(File.read(filename2), nil, '-')
        erb.filename = filename2
        set_locals = locals.keys.map { |k| "#{k}=locals[#{k.inspect}];" }.join
        instance_binding = instance_eval{binding}
        eval set_locals, instance_binding
        result = erb.result instance_binding
        render_stack.pop
        return result
      end
    end
  end
  raise NotFound
end