]> Shamusworld >> Repos - ardour-manual-diverged/blob - build.rb
Builds the manual without Jekyll.
[ardour-manual-diverged] / build.rb
1 require 'pathname'
2 require 'fileutils'
3 require 'yaml'
4 require 'liquid'
5
6 def split_frontmatter(txt)
7     re = /\A---[ \t\r]*\n(?<frontmatter>.*?)^---[ \t\r]*\n(?<content>.*)\z/m
8     match = re.match txt 
9     match ? [match['frontmatter'], match['content']] : nil
10 end
11
12 def child_url?(a, b)
13     a.start_with?(b) && b.count('/') + 1 == a.count('/')
14 end
15
16 class Site
17     attr_reader :pages
18
19     def initialize()
20         @pages = []
21         @config = {
22             'pages_dir' => '_manual',
23             'layouts_dir' => '_layouts',
24             'static_dir' => 'source',
25             'output_dir' => '_site'
26         }
27         @layouts = {}
28     end
29     
30     def read_layouts()
31         layouts_dir = Pathname(@config['layouts_dir'])
32         Pathname.glob(layouts_dir + Pathname('*.html')) do |path|
33             next if !path.file?
34             layout = Layout.new(self, path)
35             layout.read
36             @layouts[path.basename('.html').to_s] = layout
37         end
38     end
39     
40     def find_layout(name)
41         @layouts[name]
42     end
43     
44     def read_pages()
45         pages_dir = Pathname.new(@config['pages_dir'])
46         pages_dir.find do |path|
47             if path.file? && path.extname == '.html'
48                 page = Page.new(self, path)
49                 page.read
50                 @pages << page
51             end
52         end
53     end
54
55     def find_children(url)
56         @pages.select{ |p| child_url?(p.url, url) }.sort_by{ |p| p.path.basename }
57     end
58     
59     def process_pages()
60         @pages.each {|page| page.process}
61     end
62     
63     def copy_static()
64         # http://ruby-doc.org/stdlib-2.2.1/libdoc/fileutils/rdoc/index.html
65     end
66     
67     def pages_dir()
68         Pathname(@config['pages_dir'])
69     end
70     
71     def output_dir()
72         Pathname(@config['output_dir'])
73     end
74
75     def run()
76         #read_config()
77         read_layouts()
78         read_pages()
79         copy_static()
80         process_pages()
81     end
82 end
83
84 class Page
85     attr_reader :path, :out_path, :url, :sort_url
86
87     def initialize(site, path)
88         @site = site
89         @path = path
90
91         canon = canonical
92         @out_path = @site.output_dir + canon + Pathname("index.html")
93         @url = '/' + canon + '/'
94         @sort_url = @path.to_s.sub(/\.html$/, '')
95     end
96
97     def canonical()
98         remove_numbers = lambda {|x| x.sub(/^[0-9]*[-_]/, '') }
99         path = @path.relative_path_from(@site.pages_dir)
100         a = path.each_filename.map(&remove_numbers)
101         a[-1] = a[-1].sub(/\.html$/, '')
102         a.join('/')
103     end
104
105     def related_to?(p)
106         # should we show p in the index on selfs page?
107         url.start_with?(p.url) || child_url?(url, p.url)
108     end
109
110     def title()
111         if !@page_context
112             puts 'nil page context: ' + @path.to_s
113         end
114         @page_context['title'] || ""
115     end
116
117     def read()
118         content = @path.read
119         split = split_frontmatter content
120         split || abort("Not a Jekyll-formatted file: #{@path}") 
121         frontmatter, @content = split
122         @page_context = YAML.load(frontmatter)
123         @template = Liquid::Template.parse(@content)
124     end        
125     
126     def find_layout()
127         @site.find_layout(@page_context['layout'] || 'default')
128     end
129
130     def children()
131         @site.find_children(@url)
132     end
133     
134     def render()
135         registers = {page: self, site: @site}
136         context = {'page' => @page_context}
137         content = @template.render!(context, registers: registers)
138         find_layout.render(context.merge({'content' => content}), registers)
139     end
140     
141     def process()
142         path = out_path
143         path.dirname.mkpath
144         path.write(render)
145     end
146 end
147
148 class Layout < Page
149     def render(context, registers)
150         context = context.dup
151         context['page'] = @page_context.merge(context['page'])
152         content = @template.render!(context, registers: registers)
153         if @page_context.has_key?('layout')
154             find_layout.render(context.merge({'content' => content}), registers)
155         else
156             content
157         end
158     end
159 end
160
161 class Tag_tree < Liquid::Tag
162     def join(children_html)
163         children_html.empty? ? "" : "<dl>\n" + children_html.join + "</dl>\n"
164     end
165
166     def render(context)
167         current = context.registers[:page]
168         site = context.registers[:site]
169
170         format_entry = lambda do |page|
171             children = page.children
172             
173             css = (page == current) ? ' class="active"' : ""
174             children_html = current.related_to?(page) ? join(children.map(&format_entry)) : ""
175             
176             %{
177           <dt#{css}>
178             <a href='#{page.url}'>#{page.title}</a>
179           </dt>
180           <dd#{css}>
181             #{children_html}
182           </dd>
183         }
184         end
185
186         join(site.find_children('/').map(&format_entry))
187     end
188 end
189
190 class Tag_children < Liquid::Tag
191     def render(context)
192         children = context.registers[:page].children
193         entries = children.map {|p| "<li><a href='#{p.url}'>#{p.title}</a></li>" }
194         
195         "<div id='subtopics'>
196         <h2>This chapter covers the following topics:</h2>
197         <ul>
198           #{entries.join}
199         </ul>
200         </div>
201       "
202     end
203 end
204
205 class Tag_prevnext < Liquid::Tag
206     def render(context)
207         site = context.registers[:site]
208         current = context.registers[:page]
209         
210         pages = site.pages.sort_by{ |p| p.sort_url }
211         
212         ind = pages.index { |page| page == current }
213         return '' if !ind
214         
215         lnk = lambda do |p, cls, txt| 
216             "<li><a title='#{p.title}' href='#{p.url}' class='#{cls}'>#{txt}</a></li>"
217         end
218         prev_link = ind > 0 ? lnk.call(pages[ind-1], "previous", " &lt; Previous ") : ""
219         next_link = ind < pages.length-1 ? lnk.call(pages[ind+1], "next", " Next &gt; ") : ""
220         
221         "<ul class='pager'>#{prev_link}#{next_link}</ul>"
222     end
223 end
224
225 Liquid::Template.register_tag('tree', Tag_tree)
226 Liquid::Template.register_tag('children', Tag_children)
227 Liquid::Template.register_tag('prevnext', Tag_prevnext)
228
229 Liquid::Template.error_mode = :strict
230
231 Site.new.run