Class: Rote::Page

Inherits:
Object
  • Object
show all
Defined in:
lib/rote/page.rb

Overview

A Page object represents an individual template source file, taking input from that file and (optionally) some ruby code, and producing rendered (or ‘merged’) output as a String. All user-supplied code (COMMON.rb or page code, for example) is executed in the binding of an instance of this class.

When a page is created, ruby source will be sought alongside the file, with same basename and an ‘.rb’ extension. If found it will run through instance_eval. That source can call methods and set any instance variables, for use later in the template. Such variables or methods may also be defined in a COMMON.rb file in or above the page’s directory, in code associated with the layout applied to a page, or (less often) in a block supplied to new.

Rendering happens only once for a given page object, when the render method is first called. Once a page has been rendered it is frozen.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(template_name, pages_dir = '.', layout_dir = pages_dir, &blk) ⇒ Page

Reads the template, and evaluates the global and page scripts, if available, using the current binding. You may define any instance variables or methods you like in that code for use in the template, as well as accessing the predefined @template and @template_text variables.

If specified, the layout path will be used to find layouts referenced from templates.

If a block is supplied, it is executed before the global / page code. This will be the block supplied by the file-extension mapping.



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
# File 'lib/rote/page.rb', line 99

def initialize(template_name, pages_dir = '.', layout_dir = pages_dir, &blk) 
  @template_text = nil
  @template_name = nil
  @layout_text = nil
  @layout_name = nil
  @content_for_layout = nil
  @result = nil
  @layout_defext = File.extname(template_name)
  @layout_path = layout_dir[STRIP_SLASHES,1]
  @base_path = pages_dir[STRIP_SLASHES,1]
  
  @page_filters, @post_filters = [], []

  # read in the template. Layout _may_ get configured later in page code
  # We only add the pages_dir if it's not already there, because it's
  # easier to pass the whole relative fn from rake...
  # template_name always needs with no prefix.
  tfn = template_name
  read_template(tfn)
  
  blk[self] if blk
  
  # Eval COMMON.rb's
  eval_common_rubys
  
  # get script filenames, and eval them if found
  tfn = ruby_filename # nil if no file      
  instance_eval(File.read(tfn),tfn) if tfn      
end

Instance Attribute Details

#base_pathObject (readonly)

The base paths for this page’s template and layout. These point to the directories configured in the Rake tasks.



79
80
81
# File 'lib/rote/page.rb', line 79

def base_path
  @base_path
end

#layout_nameObject (readonly)

The names from which this page’s template and layout (if any) were read, relative to the base_path.



75
76
77
# File 'lib/rote/page.rb', line 75

def layout_name
  @layout_name
end

#layout_pathObject (readonly)

The base paths for this page’s template and layout. These point to the directories configured in the Rake tasks.



79
80
81
# File 'lib/rote/page.rb', line 79

def layout_path
  @layout_path
end

#layout_textObject (readonly)

The text of the layout to use for this page. This is read in when (if) the page source calls layout(basename).



71
72
73
# File 'lib/rote/page.rb', line 71

def layout_text
  @layout_text
end

#page_filtersObject (readonly)

The array of page filters (applied to this page output before layout is applied) and post filters (three gueses). You can use append_page_filter and append_post_filter to add new filters, which gives implicit block => Filters::Proc conversion and checks for nil.



86
87
88
# File 'lib/rote/page.rb', line 86

def page_filters
  @page_filters
end

#post_filtersObject (readonly)

The array of page filters (applied to this page output before layout is applied) and post filters (three gueses). You can use append_page_filter and append_post_filter to add new filters, which gives implicit block => Filters::Proc conversion and checks for nil.



86
87
88
# File 'lib/rote/page.rb', line 86

def post_filters
  @post_filters
end

#template_nameObject (readonly)

The names from which this page’s template and layout (if any) were read, relative to the base_path.



75
76
77
# File 'lib/rote/page.rb', line 75

def template_name
  @template_name
end

#template_textObject (readonly)

The text of the template to use for this page.



67
68
69
# File 'lib/rote/page.rb', line 67

def template_text
  @template_text
end

Class Method Details

.page_ruby_filename(template_fn) ⇒ Object

Helper that returns a page-code filename given a template filename. This does not check that the source exists - use the ruby_filename instance method to get the actual filename (if any) of source associated with a given page instance.



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rote/page.rb', line 44

def page_ruby_filename(template_fn)
  fn = nil
  if (template_fn) 
    if (fn = template_fn.dup) =~ FILE_EXT
      fn[FILE_EXT] = '.rb'
    else
      fn << '.rb' unless fn.empty?
    end            
  end        
  fn
end

.resolve_common_rubys(dir, arr = []) ⇒ Object

Find all COMMON.rb files from given dir up to FS root.



57
58
59
60
61
62
63
# File 'lib/rote/page.rb', line 57

def resolve_common_rubys(dir, arr = [])
  # defer to parent dir first
  parent = File.expand_path(File.join(dir, '..'))
  resolve_common_rubys(parent,arr) unless parent == dir # at root    
  fn = File.join(dir,'COMMON.rb')    
  arr << fn if (File.exists?(fn) && File.readable?(fn))
end

Instance Method Details

#layout(basename) ⇒ Object

Sets the layout from the specified file, or disables layout if nil is passed in. The specified basename should be the name of the layout file relative to the layout_dir, with no extension.

The layout is not read by this method. It, and it’s source, are loaded only at rendering time. This prevents multiple calls by various scoped COMMON code, for example, from making a mess in the Page binding.

This can only be called before the first call to render. After that the instance is frozen.



194
195
196
197
198
199
200
201
# File 'lib/rote/page.rb', line 194

def layout(basename)
  if basename
    # layout text
    @layout_name = "#{basename}#{@layout_defext if File.extname(basename).empty?}"
  else
    @layout_name = nil
  end
end

#layout_filenameObject

Returns the full filename of this Page’s template. This is obtained by joining the base path with template name.



137
138
139
# File 'lib/rote/page.rb', line 137

def layout_filename
  layout_name ? File.join(layout_path,layout_name) : nil
end

#page_filter(filter = nil, &block) ⇒ Object

Append filter to this page’s page-filter chain, or create a new Rote::Filters::TextFilter with the supplied block. This method should be preferred over direct manipulation of the filters array if you are simply building a chain.



152
153
154
155
156
157
158
159
160
# File 'lib/rote/page.rb', line 152

def page_filter(filter = nil, &block)
  if filter
    page_filters << filter
  else
    if block
      page_filters << Filters::Proc.new(block)
    end
  end
end

#post_filter(filter = nil, &block) ⇒ Object

Append filter to this page’s post-filter chain. Behaviour is much the same as append_page_filter.



164
165
166
167
168
169
170
171
172
# File 'lib/rote/page.rb', line 164

def post_filter(filter = nil, &block)
  if filter
    post_filters << filter
  else
    if block
      post_filters << Filters::Proc.new(block)
    end
  end
end

#renderObject Also known as: to_s

Render this page’s textile and ERB, and apply layout. This is only done once - after that, it’s cached for next time. You can also circumvent rendering by setting @result yourself in your page’s ruby.



177
178
179
# File 'lib/rote/page.rb', line 177

def render
  @result or do_render!   # sets up result for next time...
end

#ruby_filenameObject

Returns the full filename of this Page’s ruby source. If no source is found for this page (not including common source) this returns nil.



143
144
145
146
# File 'lib/rote/page.rb', line 143

def ruby_filename
  fn = Page::page_ruby_filename(template_filename) 
  File.exists?(fn) ? fn : nil
end

#template_filenameObject

Returns the full filename of this Page’s template. This is obtained by joining the base path with template name.



131
132
133
# File 'lib/rote/page.rb', line 131

def template_filename
  template_name ? File.join(base_path,template_name) : nil
end