Class: Strelka::CMS::Page

Inherits:
Object
  • Object
show all
Extended by:
Loggability
Defined in:
lib/strelka/cms/page.rb

Overview

An abstraction of a page with markup. This class provides rendering and introspection facilities for page files on disk. A page file is a plain file with a .page extension that contains some content to be rendered for the docs site, and is of the form:

---                                     | - YAML document separator
title: My Brilliant Document            | - An optional YAML header, see
filters:                                |
  - apilinks                            |
  - links                               |
  - syntax                              |
  - editorial                           |
  - textile                             |
                                        |
---                                     | - Document separator
h1. My Brilliant Document               | - Document contents which will
                                        |   will be transformed by the
This is a document with some stuff in   |   configured filters.
it. It rules you. Like my teeth.        |
                                        |

Constant Summary collapse

PAGE_WITH_YAML_HEADER =

Pattern to match a source page with a YAML header

/
		\A---\s*$	# It should should start with three hyphens
		(.*?)		# ...have some YAML stuff
		^---\s*$	# then have another three-hyphen line,
		(.*)\Z		# then the rest of the document
/xm
DEFAULT_OPTIONS =

The default page options.

{
	'title'    => '(Untitled)',
	'filters'  => %w[strip textile],
	'tags'     => [],
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(content, catalog = nil, options = {}) ⇒ Page

Create a new Page with the specified content and options.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/strelka/cms/page.rb', line 106

def initialize( content, catalog=nil, options={} )
	# If there's no catalog, the options might be in its place
	if catalog.is_a?( Hash )
		options = catalog
		catalog = nil
	end

	@content  = content
	@catalog  = catalog

	options   = DEFAULT_OPTIONS.merge( options )
	@tags     = options.delete( 'tags' ) || options.delete( 'keywords' )
	@title    = options.delete( 'title' )
	@filters  = options.delete( 'filters' )
	@template = options.delete( 'template' )
	@options  = options
	@created  = Time.now

	@article  = nil

	@path     = nil
end

Instance Attribute Details

#catalogObject

The page’s catalog (if it was loaded via one)



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

def catalog
  @catalog
end

#contentObject

The page’s content



135
136
137
# File 'lib/strelka/cms/page.rb', line 135

def content
  @content
end

#createdObject (readonly)

The Time the page object was instantiated



157
158
159
# File 'lib/strelka/cms/page.rb', line 157

def created
  @created
end

#filtersObject (readonly)

The Array of filter names that will be applied to the rendered output, in the order they will be applied.



145
146
147
# File 'lib/strelka/cms/page.rb', line 145

def filters
  @filters
end

#optionsObject (readonly)

Any additional options in the header



154
155
156
# File 'lib/strelka/cms/page.rb', line 154

def options
  @options
end

#pathObject

The path to the page (if loaded from a file, nil otherwise)



151
152
153
# File 'lib/strelka/cms/page.rb', line 151

def path
  @path
end

#templateObject (readonly)

The path to the Inversion template to wrap the page content in



148
149
150
# File 'lib/strelka/cms/page.rb', line 148

def template
  @template
end

#titleObject

The page title given in the page config



141
142
143
# File 'lib/strelka/cms/page.rb', line 141

def title
  @title
end

Class Method Details

.load(path, catalog = nil) ⇒ Object

Read page source from the file at the given path and return a new Page object.



64
65
66
67
68
69
70
71
72
# File 'lib/strelka/cms/page.rb', line 64

def self::load( path, catalog=nil )
	page = File.open( path, 'r', encoding: 'utf-8' ) do |io|
		self.read( io, catalog )
	end

	page.path = path

	return page
end

.parse(source, catalog = nil) ⇒ Object

Parse the given source and return a new Page object.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/strelka/cms/page.rb', line 84

def self::parse( source, catalog=nil )
	options = nil

	if source =~ PAGE_WITH_YAML_HEADER
		self.log.debug "Parsing page with YAML header..."
		options = YAML.load( $1 )
		source = $2
		self.log.debug "  YAML header options: %p" % [ options ]
	else
		self.log.debug "Parsing page with no header."
		options = {}
	end

	return new( source, catalog, options )
end

.read(io, catalog = nil) ⇒ Object

Read page source from the given io and return a new Page object.



76
77
78
79
80
# File 'lib/strelka/cms/page.rb', line 76

def self::read( io, catalog=nil )
	source = io.read
	self.log.debug "Read %d bytes from %p" % [ source.length, io ]
	page = self.parse( source, catalog )
end

Instance Method Details

#apply_filters(content) ⇒ Object

Apply the filters corresponding to the given filter_names and return the modified content.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/strelka/cms/page.rb', line 184

def apply_filters( content )
	filters = self.filter_objects
	self.log.debug "Applying %d filters to %d bytes of content: %p" %
		[ filters.length, content.length, content[0,100] ]

	return filters.inject( self.content.dup ) do |filtered_content, filter|
		begin
			filter.process( filtered_content, self )
		rescue => err
			self.log.error "%s while applying the %s filter: %s" %
				[ err.class.name, filter.class.factory_type, err.message ]
			self.log.debug "  " + err.backtrace.join("\n  ")
			filtered_content
		end
	end
end

#filter_objectsObject

Return the page’s filters as instances of Strelka::CMS::PageFilter.



203
204
205
206
207
208
# File 'lib/strelka/cms/page.rb', line 203

def filter_objects
	return self.filters.map do |filter_name|
		filter_name.untaint
		Strelka::CMS::PageFilter.create( filter_name )
	end
end

#first_headingObject

Return the contents of the first heading from the rendered page.



212
213
214
215
216
217
218
219
220
221
222
# File 'lib/strelka/cms/page.rb', line 212

def first_heading
	self.log.debug "Fetching page title from rendered page"
	doc = Nokogiri::HTML( self.to_s )
	if heading = doc.css( 'h1,h2,h3' ).first
		self.log.debug "  got first heading: %s" % [ heading ]
		return heading.content
	else
		self.log.debug "  couldn't find a heading."
		return nil
	end
end

#index_fieldsObject

Extract a Hash of fields to be indexed from the page and return it.



253
254
255
256
257
258
259
260
261
262
# File 'lib/strelka/cms/page.rb', line 253

def index_fields
	return {
	    :title         => self.title,
	    :first_heading => self.first_heading,
		:tags          => self.tags.join( ', ' ),
	    :content       => self.stripped_content,
		:modified      => self.modified,
		:created       => self.created,
	}
end

#inspectObject

Return a human-readable representation of the receiving object.



305
306
307
308
309
310
311
312
313
314
# File 'lib/strelka/cms/page.rb', line 305

def inspect
	return %|#<%s:%#0x %p %p [%s] {filters: %s}>| % [
		self.class.name,
		self.object_id / 2,
		self.path,
		self.title,
		self.tags.join(', '),
		self.filters.join('+'),
	]
end

#modifiedObject Also known as: date

Return the Time the page was last modified. This is derived from its ‘date’ header if it has one, or its mtime if it was loaded from a file, or its #created date if neither of those are available.



268
269
270
271
272
273
274
275
276
277
278
# File 'lib/strelka/cms/page.rb', line 268

def modified
	if headerdate = self.options['date']
		headerdate = headerdate.to_time if headerdate.respond_to?( :to_time )
		headerdate = Time.parse( headerdate ) unless headerdate.is_a?( Time )
		return headerdate
	elsif self.path
		return self.path.mtime
	else
		return self.created
	end
end

#relative_html_pathObject

Return the page’s HTML path.



176
177
178
179
# File 'lib/strelka/cms/page.rb', line 176

def relative_html_path
	pagepath = self.relative_path or return nil
	return pagepath.to_s.sub(/\.page$/, '.html')
end

#relative_pathObject

Return the page’s path relative to its catalog.



167
168
169
170
171
172
# File 'lib/strelka/cms/page.rb', line 167

def relative_path
	catalog = self.catalog or return nil
	path = self.path or return nil

	return path.relative_path_from( catalog.basedir )
end

#renderObject

Return the page rendered as HTML after applying filters and wrapping it in its configured template if it has one.



227
228
229
230
231
232
233
234
235
# File 'lib/strelka/cms/page.rb', line 227

def render( * )
	if path = self.template
		tmpl = Inversion::Template.load( path )
		tmpl.page = self
		return tmpl
	else
		return self.to_s
	end
end

#stripped_contentObject

Return the page content with tags stripped.



247
248
249
# File 'lib/strelka/cms/page.rb', line 247

def stripped_content
	return self.content.gsub( /<.*?>/, '' )
end

#summaryObject

Return a summary of the page.



283
284
285
286
# File 'lib/strelka/cms/page.rb', line 283

def summary
	summary = self.article.summarize( sentences: 1 ).first
	return summary[:sentence].strip
end

#summary_topicsObject

Return an Array of topics for the page.



290
291
292
# File 'lib/strelka/cms/page.rb', line 290

def summary_topics
	return self.article.topics
end

#tagsObject Also known as: keywords

Return the Array of tags/keywords set in the header, or derived from the content if not specified explicitly.



297
298
299
300
# File 'lib/strelka/cms/page.rb', line 297

def tags
	@tags ||= self.article.keywords
	return @tags
end

#to_sObject Also known as: to_html

Render the page content, filtering it with its configured filters. Note that this does not wrap it in its template.



240
241
242
# File 'lib/strelka/cms/page.rb', line 240

def to_s
	return self.apply_filters( self.content )
end