Class: Kiss::Template

Inherits:
Object show all
Includes:
ControllerAccessors, DatabaseAccessors, RequestAccessors, TemplateMethods
Defined in:
lib/kiss/template.rb

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TemplateMethods

#data, #data=, #set

Methods included from DatabaseAccessors

#database

Methods included from RequestAccessors

#app, #cookies, #debug, #env, #file_cache, #host, #login, #models, #path_info, #protocol, #pub, #query_string_with_params, #redirect_action, #redirect_url, #request_url_with_params, #response, #send_file, #send_response, #session, #set_cookie, #set_exception_cache, #start_benchmark, #stop_benchmark

Methods included from ControllerAccessors

#database, #environment, #models, #public_dir, #upload_dir

Constructor Details

#initialize(request, delegate = nil, predecessor = nil, locals = {}) ⇒ Template

Returns a new instance of Template.



197
198
199
200
201
202
203
# File 'lib/kiss/template.rb', line 197

def initialize(request, delegate = nil, predecessor = nil, locals = {})
  @_delegate = delegate
  @_request = request
  @_controller = delegate.controller if delegate
  @_predecessor = predecessor || delegate
  @_locals = locals
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object (private)



235
236
237
238
239
240
241
# File 'lib/kiss/template.rb', line 235

def method_missing(method, *args, &block)
  if method.to_s =~ /\A_class_(\d+)_(.*)/
    __send__ $2.to_sym, $1.to_i, *args, &block
  else
    @_delegate.__send__ method, *args, &block
  end
end

Class Attribute Details

.layoutObject (readonly)

Returns the value of attribute layout.



5
6
7
# File 'lib/kiss/template.rb', line 5

def layout
  @layout
end

Instance Attribute Details

#layoutObject

Returns the value of attribute layout.



192
193
194
# File 'lib/kiss/template.rb', line 192

def layout
  @layout
end

#titleObject

Returns the value of attribute title.



192
193
194
# File 'lib/kiss/template.rb', line 192

def title
  @title
end

Class Method Details

.create_child_class(attrs) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/kiss/template.rb', line 133

def create_child_class(attrs)
  instance_var_attrs = {
    :parent_class => self,
    :root_class => @_root_class,
    :template_dir => @_template_dir
  }.merge(attrs)
  
  klass = Class.new(self)
  klass._instance_variables_set_from_attrs(instance_var_attrs)
  klass
end

.get_child_class(dot_extension, subdir = '', filename = nil) ⇒ Object



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
# File 'lib/kiss/template.rb', line 87

def get_child_class(dot_extension, subdir = '', filename = nil)
  # each subdir must get a subclass of the parent dir class;
  # each subclass has its own @_child_classes hash of its subdirs
  
  is_directory_subclass = !filename
  
  if filename
    filename += dot_extension unless filename =~ /#{dot_extension}\Z/
  else
    filename = '_macros' + dot_extension
  end
  template_path = subdir + '/' + filename
  absolute_fs_path = @_template_dir + template_path
  template_body, template_cache_changed = @@controller.file_cache(absolute_fs_path, true)
  
  layout_path = subdir + '/_layout' + dot_extension
  layout_file, layout_cache_changed = @@controller.file_cache(@_template_dir + layout_path, true)
  
  # Inherit this class's layout path if no layout file in subdir.
  layout_path = @layout unless layout_file
  
  if template_cache_changed || !@_child_classes.has_key?(filename)
    child_class = create_child_class(
      :subdir => subdir,
      :filename => filename,
      :layout => layout_path,
      :path => template_path
    )
    Kiss.register_class_path(child_class, absolute_fs_path)
    if template_body
      source = get_ruby_source_from_erb(template_body)
      source = ('def erubis(content); ' + source + '; end') unless is_directory_subclass
      child_class.class_eval(source, absolute_fs_path)
    end
    @_child_classes[filename] = child_class
  elsif layout_cache_changed
    # Layout file either added or modified; in case it was newly added,
    # set the subclass's @layout (if it's not already set).
    @_child_classes[filename].class_eval do
      @layout ||= layout_path
    end
  end
         
  @_child_classes[filename]
end

.get_root_class(controller, root_dir) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/kiss/template.rb', line 35

def get_root_class(controller, root_dir)
  parent_class = self
  
  klass = Class.new(self)
  Kiss.register_class_path(klass, root_dir)
  klass.class_eval do
    @@controller = controller
    @_parent_class = parent_class
    @_root_class = klass
    @_template_dir = root_dir
    @layout = nil
  end
  klass
end

.get_ruby_source_from_erb(erb) ⇒ Object



145
146
147
148
149
# File 'lib/kiss/template.rb', line 145

def get_ruby_source_from_erb(erb)
  source = Erubis::Eruby.new(preprocess_erb(erb)).src
  source.gsub!(/\b_buf\b/, '@_buf')
  source
end

.get_subclass_from_path(path, default_extension = nil) ⇒ Object

Select or create the matching template subclass for a given template path.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/kiss/template.rb', line 51

def get_subclass_from_path(path, default_extension = nil)
  # TODO: If Kiss configured not to modify template cache,
  # then we should check whether this path has a registered
  # class and, if so, return it.
  
  extension = (path =~ /\.(\w+)\Z/) ? $1 : default_extension
  dot_extension = extension ? ('.' + extension) : ''
  
  # If path starts with slash, get subclass from root template class for 
  # the same dot_extension. Else get subclass from this template class.
  klass = if path[0,1] == '/'
    path = path[1, path.length]
    root_class.get_child_class(dot_extension)
  else
    self
  end
  klass.get_subclass_from_path_parts(path.split(/\/+/), dot_extension)
end

.get_subclass_from_path_parts(parts, dot_extension = '') ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/kiss/template.rb', line 70

def get_subclass_from_path_parts(parts, dot_extension = '')
  part = parts.shift
  return self if !part
  raise 'bad template path' if part !~ /\A[\w\-\.]*\Z/i
  
  test_path = subdir + '/' + part
  klass = if @@controller.directory_exists?(@_template_dir + test_path)
    get_child_class(dot_extension, test_path).
      get_subclass_from_path_parts(parts, dot_extension)
  else
    raise 'bad template path' unless parts.empty?
    get_child_class(dot_extension, subdir, part)
  end
  
  klass
end

.get_template_path(options = {}) ⇒ Object

Gets path to template file according to specified options Options: template - template path, relative to current Template subclass subdirectory or,

if starting with '/', relative to root template directory

extension - template file extension, to be appended to template path unless

template path already contains a dot


24
25
26
27
28
29
30
31
32
33
# File 'lib/kiss/template.rb', line 24

def get_template_path(options = {})
  path = options[:template]
  unless path =~ /\./
    path += '.' + (options[:extension] || 'rhtml')
  end
  
  # If template doesn't start with '/', prepend current Template subclass
  # subdirectory path.
  (path =~ /\A\//) ? path : "#{options[:subdir] || self.subdir}/#{path}"
end

.include_macros(template_path) ⇒ Object



175
176
177
178
179
180
181
182
# File 'lib/kiss/template.rb', line 175

def include_macros(template_path)
  if template_path[0,1] != '/'
    template_path = subdir + '/' + template_path
  end
  template_body = @@controller.file_cache(@_template_dir + template_path)
  raise 'bad template path' if !template_body
  class_eval(get_ruby_source_from_erb(template_body))
end

.inherited(subclass) ⇒ Object

Called when this class or one of its subclasses is inherited. subclass (Class) - the new, inheriting subclass



9
10
11
# File 'lib/kiss/template.rb', line 9

def inherited(subclass)
  subclass.init_child_classes
end

.init_child_classesObject

Initialize the subclasses instance variable of this class (or subclass)



14
15
16
# File 'lib/kiss/template.rb', line 14

def init_child_classes
  @_child_classes = {}
end

.preprocess_erb(erb) ⇒ Object

Pre-process Kiss additions in ERB code.



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/kiss/template.rb', line 152

def preprocess_erb(erb)
  # macros
  result = erb.gsub(
    /\<\%\s*macro\s+(\w+)/,
    "<% def \\1(*args, &block); ob = swap_buf(''); _macro_\\1(*args, &block); swap_buf(ob); end; def _macro_\\1"
  ).gsub(
    /\<\%\s*end\s+macro\s*\%\>/,
    '<% end %>'
  )
  
  # may be DEPRECATED soon
  # generic loop iterator, using 'iterate'
  result.gsub!(/\<\%\s*iterate\s+(\w+)\s+(.*?)\s*\%\>/,
    "<% \\1 = Kiss::Iterator.new; \\2; \\1.increment %>")
  
  # DEPRECATED
  # for loop iterator
  result.gsub!(/\<\%\s*for\s+(\w+)\s+in\s+(.*?)\s*\%\>/,
    "<% \\1_loop = Kiss::Iterator.new(\\2); for \\1 in \\1_loop.collection; \\1_loop.increment %>")
  
  result
end

Instance Method Details

#call(content = nil) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/kiss/template.rb', line 211

def call(content = nil)
  import_instance_variables(@_predecessor)
  make_layout_absolute(@_predecessor)
  
  content = erubis(content)
  
  # self.class.no_more_macros
  
  make_layout_absolute(self)
  export_instance_variables(@_predecessor)
  
  content
end

#erubis(content, locals = {}) ⇒ Object



225
226
227
# File 'lib/kiss/template.rb', line 225

def erubis(content, locals = {})
  raise Kiss::FileNotFoundError::Template, "template not found: '#{self.class.path}'"
end

#make_layout_absolute(relative_object) ⇒ Object



205
206
207
208
209
# File 'lib/kiss/template.rb', line 205

def make_layout_absolute(relative_object)
  if @layout && @layout !~ /\A\//
    @layout = relative_object.class.subdir + '/' + @layout
  end
end