rote 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|