rote 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README +293 -0
- data/Rakefile +369 -0
- data/TODO +12 -0
- data/bin/rote +14 -0
- data/doc/jamis.rb +591 -0
- data/doc/layouts/page.html +44 -0
- data/doc/pages/COMMON.rb +18 -0
- data/doc/pages/index.html +66 -0
- data/doc/pages/index.rb +4 -0
- data/doc/res/images/computer-med.png +0 -0
- data/doc/res/images/dialog-information-med.png +0 -0
- data/doc/res/images/document-new-med.png +0 -0
- data/doc/res/images/go-home-med.png +0 -0
- data/doc/res/images/rote-big.png +0 -0
- data/doc/res/images/rote-logo.xcf +0 -0
- data/doc/res/images/rote-med.png +0 -0
- data/doc/res/images/rote-small.png +0 -0
- data/doc/res/images/rpot-big.png +0 -0
- data/doc/res/images/rpot-large-x.xcf +0 -0
- data/doc/res/images/rpot-large.xcf +0 -0
- data/doc/res/images/rpot-sml.png +0 -0
- data/doc/res/images/rpot-tiny.png +0 -0
- data/doc/res/images/user-id-med.png +0 -0
- data/doc/res/stylesheets/normal.css +141 -0
- data/install.rb +96 -0
- data/lib/rote/app.rb +112 -0
- data/lib/rote/dirfilelist.rb +42 -0
- data/lib/rote/page.rb +184 -0
- data/lib/rote/rotetasks.rb +122 -0
- data/lib/rote.rb +86 -0
- data/test/pages/COMMON.rb +1 -0
- data/test/pages/badlayout.rb +1 -0
- data/test/pages/samedir.rb +1 -0
- data/test/pages/textile.rb +1 -0
- data/test/pages/withcode.rb +5 -0
- data/test/test_page.rb +137 -0
- metadata +94 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
h2. Rote - A static website build tool for Ruby
|
2
|
+
|
3
|
+
*Rote is a simple page-based template system for your static website that was
|
4
|
+
written to make it easier to author and maintain non-dynamic websites and
|
5
|
+
offline documentation.* Rote provides a simple commandline or
|
6
|
+
"Rake":http://rake.rubyforge.org based build for your pages, with page
|
7
|
+
rendering (optionally supporting Textile and Markdown with
|
8
|
+
"RedCloth":http://redcloth.rubyforge.org/ and ruby code with
|
9
|
+
"ERB":http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html), layout,
|
10
|
+
and general documentation / website build tasks.
|
11
|
+
|
12
|
+
h3. Features
|
13
|
+
|
14
|
+
Rote offers the following major features:
|
15
|
+
|
16
|
+
* Simple set-up based on page templates and sections.
|
17
|
+
* ERB, Textile, and Markdown supported out of the box.
|
18
|
+
* Multiple configurable layouts apply boilerplate to your pages.
|
19
|
+
* 'Scoped' Ruby code support allows fine-grained control of data available across
|
20
|
+
all documentation, a subset, or individual pages.
|
21
|
+
* Can be used standalone (from the command-line) or from within "Rake":http://rake.rubyforge.org
|
22
|
+
as a custom task library.
|
23
|
+
* Supports any (text-based) format, while providing utilities and helpers for
|
24
|
+
common formats (HTML at present).
|
25
|
+
|
26
|
+
h3. So where is it?
|
27
|
+
|
28
|
+
The first release of Rote can be downloaded from "Our FRS on RubyForge":http://rubyforge.org/frs/?group_id=1120 .
|
29
|
+
It should be also available as a RubyGem (rote-0.1.0) in the usual way.
|
30
|
+
The "README":rdoc/files/README.html has the most comprehensive user guide at the moment. Obviously, this
|
31
|
+
site is still under construction too.
|
32
|
+
|
33
|
+
You can also grab the latest code from "CVS":http://rubyforge.org/cgi-bin/viewcvs.cgi/?cvsroot=rote.
|
34
|
+
|
35
|
+
Please note that Rote is still pretty new, and while this first release is fairly functional, it's
|
36
|
+
also still shiny and new, and liable to break down, destroy data, and run away with your spouse if
|
37
|
+
given half a chance. Check out the "Project page on Rubyforge":http://rubyforge.org/projects/rote
|
38
|
+
for everything you need to get going with the CVS version.
|
39
|
+
|
40
|
+
h3. Licence
|
41
|
+
|
42
|
+
<ul>
|
43
|
+
<pre>
|
44
|
+
<code>
|
45
|
+
Copyright (c) 2005 Ross Bamford (and contributors)
|
46
|
+
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
48
|
+
this software and associated documentation files (the "Software"), to deal in
|
49
|
+
the Software without restriction, including without limitation the rights to
|
50
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
51
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
52
|
+
so, subject to the following conditions:
|
53
|
+
|
54
|
+
The above copyright notice and this permission notice shall be included in all
|
55
|
+
copies or substantial portions of the Software.
|
56
|
+
|
57
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
58
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
59
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
60
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
61
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
62
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
63
|
+
SOFTWARE.
|
64
|
+
</code>
|
65
|
+
</pre>
|
66
|
+
</ul>
|
data/doc/pages/index.rb
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,141 @@
|
|
1
|
+
/*
|
2
|
+
* (c)2005 Ross Bamford.
|
3
|
+
*
|
4
|
+
* rosco at roscopeco dot co dot uk
|
5
|
+
*/
|
6
|
+
body {
|
7
|
+
background: #ffffff;
|
8
|
+
color: #000000;
|
9
|
+
font-family: arial, helvetica, sans-serif;
|
10
|
+
font-size: 10pt;
|
11
|
+
padding: 0px;
|
12
|
+
margin: 0px 0px 0px 0px;
|
13
|
+
}
|
14
|
+
|
15
|
+
a:link {
|
16
|
+
color: #cc3030;
|
17
|
+
text-decoration: none;
|
18
|
+
}
|
19
|
+
|
20
|
+
a:hover {
|
21
|
+
color: #df3b3b;
|
22
|
+
text-decoration: underline;
|
23
|
+
}
|
24
|
+
|
25
|
+
a:active {
|
26
|
+
color: #df3b3b;
|
27
|
+
text-decoration: underline;
|
28
|
+
}
|
29
|
+
|
30
|
+
a:visited {
|
31
|
+
color: #b02424;
|
32
|
+
text-decoration: none;
|
33
|
+
}
|
34
|
+
|
35
|
+
a#nav:link {
|
36
|
+
color: #cc3030;
|
37
|
+
text-decoration: none;
|
38
|
+
font-weight: bold;
|
39
|
+
background: auto;
|
40
|
+
}
|
41
|
+
|
42
|
+
a#nav:hover {
|
43
|
+
color: #df3b3b;
|
44
|
+
text-decoration: underline;
|
45
|
+
font-weight: bold;
|
46
|
+
background: #c3c3c3;
|
47
|
+
}
|
48
|
+
|
49
|
+
a#nav:active {
|
50
|
+
color: #df3b3b;
|
51
|
+
text-decoration: underline;
|
52
|
+
font-weight: bold;
|
53
|
+
background: #c3c3c3;
|
54
|
+
}
|
55
|
+
|
56
|
+
a#nav:visited {
|
57
|
+
color: #b02424;
|
58
|
+
text-decoration: none;
|
59
|
+
font-weight: bold;
|
60
|
+
background: auto;
|
61
|
+
}
|
62
|
+
|
63
|
+
/* outer div top bar on pages */
|
64
|
+
table.topbar {
|
65
|
+
background: #f5f5f5;
|
66
|
+
color: #000000;
|
67
|
+
width: 100%;
|
68
|
+
border: white thin none;
|
69
|
+
}
|
70
|
+
|
71
|
+
tr.topnav {
|
72
|
+
background: #ebebeb;
|
73
|
+
text-align: center;
|
74
|
+
padding: 5px;
|
75
|
+
}
|
76
|
+
|
77
|
+
td.toplogo {
|
78
|
+
text-align: left;
|
79
|
+
}
|
80
|
+
|
81
|
+
td.toprpotlogo {
|
82
|
+
text-align: right;
|
83
|
+
}
|
84
|
+
|
85
|
+
td.navicon {
|
86
|
+
width: 22px;
|
87
|
+
}
|
88
|
+
|
89
|
+
img.navicon {
|
90
|
+
border: white thin none;
|
91
|
+
width: 22px;
|
92
|
+
height: 22px;
|
93
|
+
}
|
94
|
+
|
95
|
+
/* ***************** */
|
96
|
+
|
97
|
+
div.frontcopyright {
|
98
|
+
/* Copyright bit on front page */
|
99
|
+
color: #909090;
|
100
|
+
position: absolute;
|
101
|
+
bottom: 2%;
|
102
|
+
right: 2%;
|
103
|
+
text-align: right;
|
104
|
+
font-size: 8pt;
|
105
|
+
}
|
106
|
+
|
107
|
+
div.copyright {
|
108
|
+
/* Copyright bit on pages */
|
109
|
+
color: #909090;
|
110
|
+
position: relative;
|
111
|
+
top: 5em;
|
112
|
+
right: 2%;
|
113
|
+
text-align: right;
|
114
|
+
font-size: 8pt;
|
115
|
+
}
|
116
|
+
|
117
|
+
div.main {
|
118
|
+
/* main div on front page */
|
119
|
+
width: 90%;
|
120
|
+
margin: 2% 2% 2% 2%;
|
121
|
+
}
|
122
|
+
|
123
|
+
img.smallrpotlogo {
|
124
|
+
width: 210px;
|
125
|
+
height: 47px;
|
126
|
+
}
|
127
|
+
|
128
|
+
img.biglogo {
|
129
|
+
width: 294px;
|
130
|
+
height: 135px;
|
131
|
+
}
|
132
|
+
|
133
|
+
img.medlogo {
|
134
|
+
width: 221px;
|
135
|
+
height: 101px;
|
136
|
+
}
|
137
|
+
|
138
|
+
img.smalllogo {
|
139
|
+
width: 147px;
|
140
|
+
height: 68px;
|
141
|
+
}
|
data/install.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
puts <<-EOM
|
2
|
+
NOT YET SUPPORTED
|
3
|
+
|
4
|
+
Please copy 'bin' and 'lib' to a new directory, and set ROTE_HOME to
|
5
|
+
point there. Standard installation is not yet supported.
|
6
|
+
EOM
|
7
|
+
|
8
|
+
__END__
|
9
|
+
require 'rbconfig'
|
10
|
+
require 'find'
|
11
|
+
require 'ftools'
|
12
|
+
|
13
|
+
include Config
|
14
|
+
|
15
|
+
$ruby = CONFIG['ruby_install_name']
|
16
|
+
|
17
|
+
##
|
18
|
+
# Install a binary file. We patch in on the way through to
|
19
|
+
# insert a #! line. If this is a Unix install, we name
|
20
|
+
# the command (for example) 'rake' and let the shebang line
|
21
|
+
# handle running it. Under windows, we add a '.rb' extension
|
22
|
+
# and let file associations to their stuff
|
23
|
+
#
|
24
|
+
|
25
|
+
def installBIN(from, opfile)
|
26
|
+
|
27
|
+
tmp_dir = nil
|
28
|
+
for t in [".", "/tmp", "c:/temp", $bindir]
|
29
|
+
stat = File.stat(t) rescue next
|
30
|
+
if stat.directory? and stat.writable?
|
31
|
+
tmp_dir = t
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
fail "Cannot find a temporary directory" unless tmp_dir
|
37
|
+
tmp_file = File.join(tmp_dir, "_tmp")
|
38
|
+
|
39
|
+
File.open(from) do |ip|
|
40
|
+
File.open(tmp_file, "w") do |op|
|
41
|
+
ruby = File.join($realbindir, $ruby)
|
42
|
+
op.puts "#!#{ruby} -w"
|
43
|
+
op.write ip.read
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
opfile += ".rb" if CONFIG["target_os"] =~ /mswin/i
|
48
|
+
File::install(tmp_file, File.join($bindir, opfile), 0755, true)
|
49
|
+
File::unlink(tmp_file)
|
50
|
+
end
|
51
|
+
|
52
|
+
$sitedir = CONFIG["sitelibdir"]
|
53
|
+
unless $sitedir
|
54
|
+
version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
55
|
+
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
56
|
+
$sitedir = $:.find {|x| x =~ /site_ruby/}
|
57
|
+
if !$sitedir
|
58
|
+
$sitedir = File.join($libdir, "site_ruby")
|
59
|
+
elsif $sitedir !~ Regexp.quote(version)
|
60
|
+
$sitedir = File.join($sitedir, version)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
$bindir = CONFIG["bindir"]
|
65
|
+
|
66
|
+
$realbindir = $bindir
|
67
|
+
|
68
|
+
bindir = CONFIG["bindir"]
|
69
|
+
if (destdir = ENV['DESTDIR'])
|
70
|
+
$bindir = destdir + $bindir
|
71
|
+
$sitedir = destdir + $sitedir
|
72
|
+
|
73
|
+
File::makedirs($bindir)
|
74
|
+
File::makedirs($sitedir)
|
75
|
+
end
|
76
|
+
|
77
|
+
rote_dest = File.join($sitedir, "rote")
|
78
|
+
File::makedirs(rote_dest, true)
|
79
|
+
File::chmod(0755, rote_dest)
|
80
|
+
|
81
|
+
# The library files
|
82
|
+
|
83
|
+
files = Dir.chdir('lib') { Dir['**/*.rb'] }
|
84
|
+
|
85
|
+
for fn in files
|
86
|
+
fn_dir = File.dirname(fn)
|
87
|
+
target_dir = File.join($sitedir, fn_dir)
|
88
|
+
if ! File.exist?(target_dir)
|
89
|
+
File.makedirs(target_dir)
|
90
|
+
end
|
91
|
+
File::install(File.join('lib', fn), File.join($sitedir, fn), 0644, true)
|
92
|
+
end
|
93
|
+
|
94
|
+
# and the executable
|
95
|
+
|
96
|
+
installBIN("bin/rote", "rote")
|
data/lib/rote/app.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'getoptlong'
|
2
|
+
|
3
|
+
module Rote
|
4
|
+
|
5
|
+
# Command-line launcher for Rote.
|
6
|
+
class Application
|
7
|
+
attr_accessor :rote_bin
|
8
|
+
attr_accessor :rote_lib
|
9
|
+
attr_accessor :debug
|
10
|
+
attr_accessor :tasks
|
11
|
+
attr_accessor :trace
|
12
|
+
attr_accessor :usage
|
13
|
+
attr_accessor :version
|
14
|
+
attr_accessor :rake
|
15
|
+
attr_accessor :rakefile
|
16
|
+
attr_accessor :rakeopts
|
17
|
+
|
18
|
+
# Create a new Application instance, processing command-line arguments,
|
19
|
+
# optionally passing +self+ to the supplied block for further
|
20
|
+
# configuration.
|
21
|
+
def initialize(rote_bin, rote_lib) # :yield: self if block_given?
|
22
|
+
# init vars
|
23
|
+
@rote_bin = rote_bin
|
24
|
+
@rote_lib = rote_lib || rote_bin
|
25
|
+
@debug = false
|
26
|
+
@tasks = false
|
27
|
+
@trace = false
|
28
|
+
@usage = false
|
29
|
+
@version = false
|
30
|
+
|
31
|
+
@rakefile = File.exists?('Rakefile') ? 'Rakefile' : "#{rote_lib}/builtin.rf"
|
32
|
+
@rakeopts = ENV['RAKE_OPTS'] || ''
|
33
|
+
@rake = ENV['RAKE_CMD'] || 'rake'
|
34
|
+
|
35
|
+
process_args
|
36
|
+
|
37
|
+
yield self if block_given?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Run the application with the current options.
|
41
|
+
def run
|
42
|
+
if @version
|
43
|
+
print "rote, version #{ROTEVERSION}\n"
|
44
|
+
|
45
|
+
elsif @tasks
|
46
|
+
print `#{rake} --rakefile=#{rakefile} --libdir=#{rote_lib} --tasks`.gsub(/^rake /,'rote ')
|
47
|
+
|
48
|
+
elsif @usage
|
49
|
+
show_usage()
|
50
|
+
|
51
|
+
else
|
52
|
+
if @trace
|
53
|
+
rakeopts << ' --trace'
|
54
|
+
elsif @debug
|
55
|
+
rakeopts << '--verbose'
|
56
|
+
end
|
57
|
+
|
58
|
+
exec("#{rake} --rakefile=#{rakefile} --libdir=#{rote_lib} #{rakeopts} #{$*.join(' ')}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Display help text
|
65
|
+
def show_usage
|
66
|
+
print <<-EOM
|
67
|
+
Usage: rote [options] [task1] .. [taskN]
|
68
|
+
|
69
|
+
Where [taskN] is a valid task or target name for the current project.
|
70
|
+
Rite generates targets for each page source, and also defines a number
|
71
|
+
of top-level tasks for various things. Use the '--tasks' option to get
|
72
|
+
a list of valid tasks.
|
73
|
+
|
74
|
+
Recognised options are:
|
75
|
+
|
76
|
+
--tasks -T Display a list of tasks in this project.
|
77
|
+
--debug -d Enable debugging information.
|
78
|
+
--trace -t Enables verbose debugging information.
|
79
|
+
--usage -u Display this help message and quit
|
80
|
+
--help -h Synonym for --usage
|
81
|
+
--version -v Display Rote's version and quit
|
82
|
+
|
83
|
+
The 'rote' command is implemented as a wrapper around Rake, and
|
84
|
+
requires the 'rake' command be in your path. You can circumvent this
|
85
|
+
by setting the RAKE_CMD environment variable appropriately.
|
86
|
+
Additional options can be passed to Rake via the RAKE_OPTS variable.
|
87
|
+
|
88
|
+
Depending on your environment, you may need to set ROTE_HOME to point
|
89
|
+
to the installation directory.
|
90
|
+
EOM
|
91
|
+
end
|
92
|
+
|
93
|
+
# Process commandline
|
94
|
+
def process_args
|
95
|
+
GetoptLong.new(
|
96
|
+
[ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
|
97
|
+
[ "--tasks", "-T", GetoptLong::NO_ARGUMENT ],
|
98
|
+
[ "--trace", "-x", GetoptLong::NO_ARGUMENT ],
|
99
|
+
[ "--usage", "-u", GetoptLong::NO_ARGUMENT ],
|
100
|
+
[ "--help", "-h", GetoptLong::NO_ARGUMENT ],
|
101
|
+
[ "--version", "-v", GetoptLong::NO_ARGUMENT ]
|
102
|
+
).each { |opt,arg|
|
103
|
+
@debug = true if opt == '--debug'
|
104
|
+
@trace = true if opt == '--trace'
|
105
|
+
@tasks = true if opt == '--tasks'
|
106
|
+
@usage = true if opt == '--usage' || opt == '--help'
|
107
|
+
@version = true if opt == '--version'
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
end # Application
|
112
|
+
end # Rote
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rote
|
2
|
+
|
3
|
+
# An extension to the Rake +FileList+ class that allows a root
|
4
|
+
# directory to be specified.
|
5
|
+
class DirectoryFileList < FileList
|
6
|
+
|
7
|
+
# Create a +DirectoryFileList+ with optional root directory and
|
8
|
+
# patterns. You may also pass a block to perform additional
|
9
|
+
# configuration (e.g. if you have a lot of includes/excludes
|
10
|
+
# or just don't like arguments for whatever reason).
|
11
|
+
def initialize(basedir = '.', *patterns)
|
12
|
+
dir=(basedir)
|
13
|
+
super(*patterns)
|
14
|
+
end
|
15
|
+
|
16
|
+
# The root directory from which this filelist matches. All patterns
|
17
|
+
# are considered relative to this directory.
|
18
|
+
attr_accessor :dir
|
19
|
+
def dir=(newdir)
|
20
|
+
newdir = newdir.sub(/\/$/,'')
|
21
|
+
sub!(/^#{@dir}/,newdir)
|
22
|
+
@dir = newdir
|
23
|
+
end
|
24
|
+
|
25
|
+
# Adds the specified *shell glob* pattern(s) to the list of includes
|
26
|
+
# for this file list. The base directory is implied.
|
27
|
+
def include(*patterns)
|
28
|
+
super(*patterns.map { |it| "#{dir}/#{it}"})
|
29
|
+
end
|
30
|
+
|
31
|
+
# Adds the specified *regexp or shell glob* pattern(s) to the list of
|
32
|
+
# excludes for this file list. The base directory is implied on
|
33
|
+
# non-+Regexp+.arguments.
|
34
|
+
def exclude(*patterns)
|
35
|
+
# exclude takes regexps too, which we should leave alone.
|
36
|
+
super(*patterns.map { |it|
|
37
|
+
it.is_a?(String) ? "#{dir}/#{it}" : it
|
38
|
+
})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/rote/page.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
require_gem('RedCloth')
|
5
|
+
|
6
|
+
module Rote
|
7
|
+
|
8
|
+
#####
|
9
|
+
## A +Page+ object represents an individual page, taking input from a
|
10
|
+
## template and (optionally) some ruby code, and producing rendered
|
11
|
+
## ('merged') output as a +String+.
|
12
|
+
## When a page is created, ruby source will be found alongside the
|
13
|
+
## file, with same basename and an '.rb' extension. If found it will
|
14
|
+
## run through +instance_eval+. That source can call methods
|
15
|
+
## and set any instance variables, for use later in the template.
|
16
|
+
##
|
17
|
+
## Rendering happens only once for a given page object, when the
|
18
|
+
## to_html method is first called. Once a page has been rendered
|
19
|
+
## it is frozen.
|
20
|
+
class Page
|
21
|
+
# The text of the template to use for this page.
|
22
|
+
attr_reader :template_text
|
23
|
+
|
24
|
+
# The text of the layout to use for this page. This is read in
|
25
|
+
# when (if) the page source calls layout(basename).
|
26
|
+
attr_reader :layout_text
|
27
|
+
|
28
|
+
# Formatting options passed to RedCloth. This is an array of the
|
29
|
+
# option symbols defined by RedCloth.
|
30
|
+
# The most common are :textile and :markdown. See RedCloth
|
31
|
+
# documentation for full details of supported options.
|
32
|
+
#
|
33
|
+
# The default is [], which means 'No formatting'. This setting
|
34
|
+
# does not affect ERB rendering (which is always performed, before
|
35
|
+
# any formatting).
|
36
|
+
attr_accessor :format_opts
|
37
|
+
def format_opts=(opts)
|
38
|
+
if !opts.nil? && opts.respond_to?(:to_ary)
|
39
|
+
@format_opts = opts
|
40
|
+
else
|
41
|
+
@format_opts = [opts]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Reads the template, and evaluates the global and page scripts, if
|
46
|
+
# available, using the current binding. You may define any instance
|
47
|
+
# variables or methods you like in that code for use in the template,
|
48
|
+
# as well as accessing the predefined @template and @template_text
|
49
|
+
# variables.
|
50
|
+
#
|
51
|
+
# If specified, the layout path will be used to find layouts referenced
|
52
|
+
# from templates.
|
53
|
+
#
|
54
|
+
# If a block is supplied, it is executed _after_ the global / page
|
55
|
+
# code, so you can locally override variables and so on.
|
56
|
+
def initialize(template_fn,
|
57
|
+
layout_path = File.dirname(template_fn),
|
58
|
+
default_layout_ext = File.extname(template_fn)) # :yield: self if block_given?
|
59
|
+
@template_text = nil
|
60
|
+
@layout_text = nil
|
61
|
+
@content_for_layout = nil
|
62
|
+
@result = nil
|
63
|
+
@format_opts = []
|
64
|
+
@layout_defext = default_layout_ext
|
65
|
+
@layout_path = layout_path
|
66
|
+
@fixme_dir = File.dirname(template_fn)
|
67
|
+
|
68
|
+
# read in the template. Layout _may_ get configured later in page code
|
69
|
+
read_template(template_fn)
|
70
|
+
|
71
|
+
# get script filenames, and eval them if found
|
72
|
+
src_rb = template_fn.sub(/\..*$/,'') + '.rb'
|
73
|
+
section_rb = @fixme_dir + '/COMMON.rb'
|
74
|
+
instance_eval(File.read(section_rb)) if File.exists?(section_rb)
|
75
|
+
instance_eval(File.read(src_rb)) if File.exists?(src_rb)
|
76
|
+
|
77
|
+
# Allow block to have the final say
|
78
|
+
yield self if block_given?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Sets the layout from the specified file, or disables layout if
|
82
|
+
# +nil+ is passed in. The specified basename should be the name
|
83
|
+
# of the layout file relative to the +layout_dir+, with no extension.
|
84
|
+
#
|
85
|
+
# The layout is read by this method. An exception is
|
86
|
+
# thrown if the layout doesn't exist.
|
87
|
+
#
|
88
|
+
# This can only be called before the first call to +render+. After
|
89
|
+
# that the instance is frozen.
|
90
|
+
def layout(basename)
|
91
|
+
if basename
|
92
|
+
fn = layout_fn(basename)
|
93
|
+
raise "Layout #{fn} not found" unless File.exists?(fn)
|
94
|
+
@layout_text = File.read(fn)
|
95
|
+
else
|
96
|
+
@layout_text = nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Render this page's textile and ERB, and apply layout.
|
101
|
+
# This is only done once - after that, it's cached for next time. You can
|
102
|
+
# also circumvent rendering by setting @result yourself in your page's ruby.
|
103
|
+
def render
|
104
|
+
@result or do_render! # sets up result for next time...
|
105
|
+
end
|
106
|
+
|
107
|
+
alias to_s render
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# Sets the template from the specified file, or clears the template if
|
112
|
+
# +nil+ is passed in. The specified basename should be the name
|
113
|
+
# of the layout file relative to the +layout_dir+, with no extension.
|
114
|
+
def read_template(fn)
|
115
|
+
if fn
|
116
|
+
raise "Template #{fn} not found" unless File.exists?(fn)
|
117
|
+
@template_text = File.read(fn)
|
118
|
+
else
|
119
|
+
@template_text = nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# render, set up @result for next time. Return result too.
|
124
|
+
def do_render!
|
125
|
+
# Render the page content into the @content_for_layout
|
126
|
+
if !@template_text.nil?
|
127
|
+
ctl = ERB.new(@template_text).result(binding)
|
128
|
+
|
129
|
+
@content_for_layout =
|
130
|
+
if @format_opts && ((@format_opts.respond_to?(:to_ary) && (!@format_opts.empty?)) || @format_opts.is_a?(Symbol))
|
131
|
+
opts = @format_opts.respond_to?(:to_ary) ? @format_opts : [@format_opts]
|
132
|
+
RedCloth.new(ctl).to_html(*opts)
|
133
|
+
else
|
134
|
+
ctl
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# render into the layout if supplied.
|
139
|
+
@result = if !@layout_text.nil?
|
140
|
+
ERB.new(@layout_text).result(binding)
|
141
|
+
else
|
142
|
+
@content_for_layout
|
143
|
+
end
|
144
|
+
|
145
|
+
freeze
|
146
|
+
@result
|
147
|
+
end
|
148
|
+
|
149
|
+
# Get a full layout filename from a basename. If the basename has no extension,
|
150
|
+
# the default extension is added.
|
151
|
+
def layout_fn(basename)
|
152
|
+
ext = File.extname(basename)
|
153
|
+
"#{@layout_path}/#{basename}#{@layout_defext if ext.empty?}"
|
154
|
+
end
|
155
|
+
|
156
|
+
# FIXME NASTY HACK: Allow templates to inherit COMMON.rb. This should be replaced
|
157
|
+
# with a proper search for inherited in Page.new. Call from your COMMON.rb to
|
158
|
+
# inherit the COMMON.rb immediately above this. If none exists there, this doesn't go
|
159
|
+
# looking beyond that - it just returns false
|
160
|
+
def inherit_common
|
161
|
+
inh = "#{@fixme_dir}/../COMMON.rb"
|
162
|
+
if File.exists?(inh)
|
163
|
+
instance_eval(File.read(inh))
|
164
|
+
true
|
165
|
+
else
|
166
|
+
false
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# FIXME NASTY HACK II: relative links (doesn't work)
|
171
|
+
def link_rel(href)
|
172
|
+
thr = href
|
173
|
+
if thr.is_a?(String) && href[0,1] == '/'
|
174
|
+
thr = href[1..href.length]
|
175
|
+
count = @fixme_dir.split('/').length - 2
|
176
|
+
if count > 0 then count.times {
|
177
|
+
thr = '../' + thr
|
178
|
+
} end
|
179
|
+
end
|
180
|
+
thr
|
181
|
+
end
|
182
|
+
|
183
|
+
end #class
|
184
|
+
end #module
|