Class: Closure::Script

Inherits:
Rack::Request
  • Object
show all
Defined in:
lib/closure/script.rb

Overview

A Closure::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

Constant Summary collapse

ENV_ERROR_CONTENT_TYPE =
'closure.error.content_type'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, sources, filename) ⇒ Script

Returns a new instance of Script.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/closure/script.rb', line 32

def initialize(env, sources, filename)
  super(env)
  @render_stack = []
  @goog = Goog.new(env, sources, @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]
    env[ENV_ERROR_CONTENT_TYPE] = @response.finish[1]["Content-Type"] rescue nil
    raise e
  end
  @response.status = 404
  @response.write "404 Not Found\n"
  @response.header["X-Cascade"] = "pass"
  @response.header["Content-Type"] = "text/plain"
rescue StandardError, LoadError, SyntaxError => e
  env[ENV_ERROR_CONTENT_TYPE] = @response.finish[1]["Content-Type"] rescue nil
  raise e
end

Instance Attribute Details

#googGoog

All the cool stuff lives here.

Returns:



65
66
67
# File 'lib/closure/script.rb', line 65

def goog
  @goog
end

#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>)


76
77
78
# File 'lib/closure/script.rb', line 76

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)


61
62
63
# File 'lib/closure/script.rb', line 61

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



127
128
129
130
# File 'lib/closure/script.rb', line 127

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

#expand_src(filename, dir = nil) ⇒ String

Helper to locate a file as a file server path.

Parameters:

  • filename (String)

Returns:

  • (String)

    absolute http path

Raises:

  • (Errno::ENOENT)


135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/closure/script.rb', line 135

def expand_src(filename, dir=nil)
  filename = expand_path filename, dir
  src = nil
  @goog.each do |directory, path|
    dir_range = (directory.length..-1)
    if filename.index(directory) == 0
      src = "#{path}#{filename.slice(dir_range)}"
      break
    end
  end
  raise Errno::ENOENT unless src
  src
end

#relative_src(filename, dir = nil) ⇒ String

Helper to locate a file as a file server path.

Parameters:

  • filename (String)

Returns:

  • (String)

    relative http path



152
153
154
155
156
# File 'lib/closure/script.rb', line 152

def relative_src(filename, dir=nil)
  file = expand_src filename, dir
  base = Pathname.new File.dirname path_info
  Pathname.new(file).relative_path_from(base).to_s
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:



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
119
120
121
122
# File 'lib/closure/script.rb', line 83

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
  fext = File.extname(filename)
  files1 = [filename]
  files1 << filename + '.html' if fext == ''
  files1 << filename.sub(/.html$/,'') if fext == '.html'
  files1.each do |filename1|
    Closure.config.engines.each do |ext, engine|
      files2 = [filename1+ext]
      files2 << filename1.gsub(/.html$/, ext) 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
          @goog.add_dependency filename2
          result = engine.call self, locals
          render_stack.pop
          return result
        end
      end
    end
  end
  raise NotFound
end