Class: Arrow::Template::RenderDirective

Inherits:
AttributeDirective show all
Includes:
Parser::Patterns
Defined in:
lib/arrow/template/render.rb

Overview

The Arrow::Template::RenderDirective class, a derivative of Arrow::Template::Directive. This is the class which defines the behaviour of the ‘render’ template directive.

Syntax

VCS Id

$Id$

Authors

  • Michael Granger

Please see the file LICENSE in the top-level directory for licensing details.

Constant Summary

AS =

Parse tokens

/\s+as\s+/i
IN =
/in/i

Constants included from Parser::Patterns

ALTERNATION, ARGDEFAULT, ARGUMENT, CAPTURE, COMMA, DBLQSTRING, DOT, EQUALS, IDENTIFIER, INFIX, LBRACKET, NUMBER, PATHNAME, QUOTEDSTRING, RBRACKET, REBINDOP, REGEXP, SLASHQSTRING, SYMBOL, TAGCLOSE, TAGMIDDLE, TAGOPEN, TICKQSTRING, VARIABLE, WHITESPACE

Constants inherited from AttributeDirective

SVNId, SVNRev

Constants inherited from Directive

SVNId, SVNRev

Constants inherited from Node

SVNId, SVNRev

Constants included from Arrow::HTMLUtilities

ARRAY_HTML_CONTAINER, HASH_HTML_CONTAINER, HASH_PAIR_HTML, IMMEDIATE_OBJECT_HTML_CONTAINER, IVAR_HTML_FRAGMENT, OBJECT_HTML_CONTAINER, THREAD_DUMP_KEY

Instance Attribute Summary

Class Method Summary

Instance Method Summary

Methods inherited from AttributeDirective

#before_rendering, #build_rendering_proc, #call_methodchain, #is_rendering_node?, #render, #to_html

Methods inherited from Directive

create, derivativeDirs, #render, #to_html

Methods inherited from Node

#add_to_template, #css_class, #is_rendering_node?, #render, #to_a, #to_html, #to_s

Methods included from Arrow::HTMLUtilities

#escape_html, #make_html_for_object, #make_object_html_wrapper

Methods inherited from Arrow::Object

deprecate_class_method, deprecate_method, inherited

Methods included from Arrow::Loggable

#log

Constructor Details

- (RenderDirective) initialize(type, parser, state)

Create a new RenderDirective object.



46
47
48
49
50
51
52
53
# File 'lib/arrow/template/render.rb', line 46

def initialize( type, parser, state )
  @target = nil
  @subtemplate = nil

  state[:templateCache] ||= {}

  super
end

Instance Attribute Details

- (Object) subtemplate (readonly)

An Array of Regexp objects which match the names of attributes to be rendered.



62
63
64
# File 'lib/arrow/template/render.rb', line 62

def subtemplate
  @subtemplate
end

Class Method Details

+ (Boolean) allows_format?

Disallow formats

Returns:

  • (Boolean)


38
# File 'lib/arrow/template/render.rb', line 38

def self::allows_format?; false end

Instance Method Details

- (Object) inspect

Return a human-readable version of the object suitable for debugging messages.



67
68
69
70
71
72
73
74
75
# File 'lib/arrow/template/render.rb', line 67

def inspect
  %Q{<%s %s%s as %s in %s>} % [
    @type.capitalize,
    @name,
    @methodchain.strip.empty? ? "" : "." + @methodchain,
    @target,
    @subtemplate._file,
  ]
end

- (Object) loadSubtemplate(filename, parser, state) (protected)

Load and parse a subtemplate from the given filename using the specified parser.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/arrow/template/render.rb', line 154

def loadSubtemplate( filename, parser, state )
  nodes = nil
  load_path = state.template._load_path
  path = Arrow::Template.find_file( filename, load_path )
  subtemplate = nil

  # If the template has already been loaded, just reuse the nodelist
  state.data[:loadCache] ||= {}
  if state.data[:loadCache].include?( path )
    self.log.debug "Re-using cache template instance for %p" % path
    subtemplate = state.data[:loadCache][ path ]

  else
    # Load the content of the file and untaint it
    self.log.debug "Loading %p for the first time" % path
    content = File.read( path )
    content.untaint

    # Load a blank template object, cache it, then parse the content
    # into nodes and install the resulting syntax tree in the
    # template. The template object is created before parsing so that
    # recursive renders work.
    initialData = state.data.dup
    subtemplate = initialData[:loadCache][ path ] = Arrow::Template.new()
    nodes = parser.parse( content, state.template, initialData )
    subtemplate.install_syntax_tree( nodes )
  end

  return subtemplate
rescue Arrow::TemplateError, ::IOError => err
  msg = "#{err.class.name}: Render with #{filename}: #{err.message}"
  @nodes = [ Arrow::Template::CommentNode.new(msg) ]
end

- (Object) parse_directive_contents(parser, state) (protected)

Parse the contents of the directive.



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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/arrow/template/render.rb', line 84

def parse_directive_contents( parser, state )
  scanner = state.scanner

  @name = parser.scan_for_identifier( state, true ) or
    raise Arrow::ParseError, "missing or malformed identifier"

  # If there's an infix operator, the rest of the tag up to the 'as' is
  # the methodchain. Can't use the parser's
  # #scan_for_methodchain because it just scans the rest of the tag.
  if scanner.scan( INFIX )
    # If the 'infix' was actually the left side of an index operator,
    # include it in the methodchain.
    start = scanner.matched == "[" ? scanner.pos - 1 : scanner.pos

    # Find the end of the methodchain
    # :FIXME: This will screw up if the methodchain itself has an ' as ' in it.
    scanner.scan_until( AS ) or
      raise Arrow::ParseError, "invalid render tag: no 'as' found"

    # StringScanner#pre_match is broken, so we have to do the equivalent
    # ourselves.
    offset = scanner.pos - scanner.matched.length - 1
    @methodchain = scanner.string[ start..offset ]

  # No methodchain
  else
    scanner.scan_until( AS ) or
      raise Arrow::ParseError, "invalid render tag: no 'as' found"
    @methodchain = ''
    self.log.debug "No methodchain parsed"
  end

  # Parse the target identifier
  @target = parser.scan_for_identifier( state ) or
    raise Arrow::ParseError, "missing or malformed target identifier"
  self.log.debug "Parsed target identifier: %p" % [@target]

  # Skip over the ' in ' bit
  scanner.skip( WHITESPACE )
  scanner.skip( IN ) or
    raise Arrow::ParseError, "invalid render tag: no 'in'"
  scanner.skip( WHITESPACE )

  # Parse the filename of the subtemplate to load
  filename = parser.scan_for_pathname( state ) or
    raise Arrow::ParseError, "No filename found for 'render'"
  filename.untaint
  self.log.debug "Parsed subtemplate filename: %p" % [filename]

  # Load and parse the subtemplate
  @subtemplate = self.loadSubtemplate( filename, parser, state )
  self.log.debug "Subtemplate set to: %p" % [@subtemplate]

  return true
end

- (Object) render_contents(template, scope) (protected)

Render the directive’s value via the specified attribute in the delegate template.



143
144
145
146
147
148
149
# File 'lib/arrow/template/render.rb', line 143

def render_contents( template, scope )
  data = super

  @subtemplate.send( "#{@target}=", data )
  self.log.debug "Rendering %p" % [@subtemplate]
  return @subtemplate.render( nil, scope, template )
end