rote 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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>
@@ -0,0 +1,4 @@
1
+ # the default
2
+ #layout 'page'
3
+
4
+ @page_title = 'Welcome!'
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