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.



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

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.



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

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.



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

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.



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

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



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

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.



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

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.



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

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.



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

def template_name
  @template_name
end

#template_textObject (readonly)

The text of the template to use for this page.



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

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
64
# 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))
  arr
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.



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

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.



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

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.



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

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.



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

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.



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

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.



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

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.



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

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