olddoc 1.0.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.gitignore +16 -0
  4. data/.olddoc.yml +9 -0
  5. data/COPYING +674 -0
  6. data/Documentation/.gitignore +4 -0
  7. data/Documentation/GNUmakefile +53 -0
  8. data/Documentation/olddoc.1.txt +21 -0
  9. data/Documentation/olddoc.5.txt +26 -0
  10. data/GNUmakefile +59 -0
  11. data/INSTALL +9 -0
  12. data/README +89 -0
  13. data/Rakefile +31 -0
  14. data/TODO +1 -0
  15. data/bin/olddoc +16 -0
  16. data/lib/olddoc.rb +20 -0
  17. data/lib/olddoc/gemspec.rb +17 -0
  18. data/lib/olddoc/history.rb +57 -0
  19. data/lib/olddoc/merge.rb +26 -0
  20. data/lib/olddoc/news_atom.rb +51 -0
  21. data/lib/olddoc/news_rdoc.rb +36 -0
  22. data/lib/olddoc/prepare.rb +24 -0
  23. data/lib/olddoc/readme.rb +27 -0
  24. data/lib/oldweb.rb +303 -0
  25. data/lib/oldweb/_head.rhtml +7 -0
  26. data/lib/oldweb/_sidebar_classes.rhtml +27 -0
  27. data/lib/oldweb/_sidebar_extends.rhtml +13 -0
  28. data/lib/oldweb/_sidebar_includes.rhtml +12 -0
  29. data/lib/oldweb/_sidebar_installed.rhtml +10 -0
  30. data/lib/oldweb/_sidebar_methods.rhtml +6 -0
  31. data/lib/oldweb/_sidebar_navigation.rhtml +6 -0
  32. data/lib/oldweb/_sidebar_pages.rhtml +17 -0
  33. data/lib/oldweb/_sidebar_parent.rhtml +13 -0
  34. data/lib/oldweb/_sidebar_sections.rhtml +8 -0
  35. data/lib/oldweb/_sidebar_table_of_contents.rhtml +15 -0
  36. data/lib/oldweb/_tail.rhtml +25 -0
  37. data/lib/oldweb/class.rhtml +79 -0
  38. data/lib/oldweb/page.rhtml +5 -0
  39. data/lib/oldweb/servlet_not_found.rhtml +5 -0
  40. data/lib/oldweb/servlet_root.rhtml +39 -0
  41. data/lib/oldweb/table_of_contents.rhtml +52 -0
  42. data/lib/rdoc/discover.rb +5 -0
  43. data/olddoc.gemspec +21 -0
  44. metadata +119 -0
@@ -0,0 +1,51 @@
1
+ # Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ require 'builder'
4
+
5
+ module Olddoc::NewsAtom
6
+ include Olddoc::History
7
+ include Olddoc::Readme
8
+
9
+ # generates an Atom feed based on git tags in the document directory
10
+ def news_atom_xml
11
+ project_name, short_desc, _ = readme_metadata
12
+ new_tags = tags[0,10]
13
+ atom_uri = @rdoc_uri.dup
14
+ atom_uri.path += "NEWS.atom.xml"
15
+ news_uri = @rdoc_uri.dup
16
+ news_uri.path += "NEWS.html"
17
+ x = Builder::XmlMarkup.new
18
+ x.feed(xmlns: "http://www.w3.org/2005/Atom") do
19
+ x.id(atom_uri.to_s)
20
+ x.title("#{project_name} news")
21
+ x.subtitle(short_desc)
22
+ x.link(rel: 'alternate', type: 'text/html', href: news_uri.to_s)
23
+ x.updated(new_tags.empty? ? '1970-01-01:00:00:00Z' : new_tags[0][:time])
24
+ new_tags.each do |tag|
25
+ x.entry do
26
+ x.title(tag[:subject])
27
+ x.updated(tag[:time])
28
+ x.published(tag[:time])
29
+ x.author do
30
+ x.name(tag[:tagger_name])
31
+ x.email(tag[:tagger_email])
32
+ end
33
+ uri = tag_uri(tag[:tag]).to_s
34
+ x.link(rel: "alternate", type: 'text/html', href: uri)
35
+ x.id(uri)
36
+ x.content(type: :xhtml) { x.pre(tag[:body]) }
37
+ end # entry
38
+ end # new_tags
39
+ end # feed
40
+ [ x.target!, new_tags ]
41
+ end
42
+
43
+ def news_atom(dest = "NEWS.atom.xml")
44
+ xml, new_tags = news_atom_xml
45
+ File.open(dest, "w") { |fp| fp.write(xml) }
46
+ unless new_tags.empty?
47
+ time = new_tags[0][:ruby_time]
48
+ File.utime(time, time, dest)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
3
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
4
+
5
+ require 'tempfile'
6
+
7
+ module Olddoc::NewsRdoc
8
+ include Olddoc::History
9
+
10
+ def puts_tag(fp, tag)
11
+ time = tag[:time].tr('T', ' ').gsub!(/:\d\dZ/, ' UTC')
12
+ fp.puts "=== #{tag[:subject]} / #{time}"
13
+ fp.puts ""
14
+
15
+ body = tag[:body]
16
+ fp.puts tag[:body].gsub(/^/smu, " ").gsub(/[ \t]+$/smu, "")
17
+ fp.puts ""
18
+ end
19
+
20
+ # generates a NEWS file in the top-level directory based on git tags
21
+ def news_rdoc
22
+ news = Tempfile.new('NEWS', '.')
23
+ tags.each { |tag| puts_tag(news, tag) }
24
+ File.open("LATEST", "wb") { |latest|
25
+ if tags.empty?
26
+ latest.puts "Currently unreleased"
27
+ news.puts "No news yet."
28
+ else
29
+ puts_tag(latest, tags[0])
30
+ end
31
+ }
32
+ news.chmod(0666 & ~File.umask)
33
+ File.rename(news.path, 'NEWS')
34
+ news.close!
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ # Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+
4
+ require 'uri'
5
+ class Olddoc::Prepare
6
+ include Olddoc::NewsRdoc
7
+ include Olddoc::NewsAtom
8
+ include Olddoc::Readme
9
+
10
+ def initialize(opts)
11
+ rdoc_url = opts['rdoc_url']
12
+ cgit_url = opts['cgit_url']
13
+ rdoc_url && cgit_url or
14
+ abort "rdoc_url and cgit_url required in .olddoc.yml for `prepare'"
15
+ @rdoc_uri = URI.parse(rdoc_url)
16
+ @cgit_uri = URI.parse(cgit_url)
17
+ @name, @short_desc = readme_metadata
18
+ end
19
+
20
+ def run
21
+ news_rdoc
22
+ news_atom
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+
4
+ # helpers for parsing the top-level README file
5
+ module Olddoc::Readme
6
+
7
+ def readme_path
8
+ 'README'
9
+ end
10
+
11
+ # returns a one-paragraph summary from the README
12
+ def readme_description
13
+ File.read(readme_path).split(/\n\n/)[1]
14
+ end
15
+
16
+ # parses the README file in the top-level directory for project metadata
17
+ def readme_metadata
18
+ l = File.readlines(readme_path)[0].strip!
19
+ l.gsub!(/^=\s+/, '') or abort "#{l.inspect} doesn't start with '='"
20
+ title = l.dup
21
+ if l.gsub!(/^(\w+\!)\s+/, '') # Rainbows!
22
+ return $1, l, title
23
+ else
24
+ return (l.split(/\s*[:-]\s*/, 2)).push(title)
25
+ end
26
+ end
27
+ end
data/lib/oldweb.rb ADDED
@@ -0,0 +1,303 @@
1
+ # Copyright (C) 2015, all contributors <olddoc-public@80x24.org>
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ # Loosely derived from Darkfish in the main rdoc distribution
4
+ require 'rdoc'
5
+ require 'erb'
6
+ require 'pathname'
7
+ require 'yaml'
8
+ require 'cgi'
9
+ require 'uri'
10
+
11
+ class Oldweb
12
+ RDoc::RDoc.add_generator(self)
13
+ include ERB::Util
14
+ attr_reader :class_dir
15
+ attr_reader :file_dir
16
+
17
+ # description of the generator
18
+ DESCRIPTION = 'minimal HTML generator'
19
+
20
+ # version of this generator
21
+ VERSION = '1'
22
+
23
+ def initialize(store, options)
24
+ # just because we're capable of generating UTF-8 to get human names
25
+ # right does not mean we should overuse it for quotation marks and such,
26
+ # our clients may not have the necessary fonts.
27
+ RDoc::Text::TO_HTML_CHARACTERS[Encoding::UTF_8] =
28
+ RDoc::Text::TO_HTML_CHARACTERS[Encoding::ASCII]
29
+
30
+ @store = store
31
+ @options = options
32
+ @base_dir = Pathname.pwd.expand_path
33
+ @dry_run = options.dry_run
34
+ @file_output = true
35
+ @template_dir = Pathname.new(File.join(File.dirname(__FILE__), 'oldweb'))
36
+ @template_cache = {}
37
+ @classes = nil
38
+ @context = nil
39
+ @files = nil
40
+ @methods = nil
41
+ @modsort = nil
42
+ @class_dir = nil
43
+ @file_dir = nil
44
+ @outputdir = nil
45
+ @old_vcs_url = nil
46
+ @git_tag = nil
47
+
48
+ # olddoc-specific stuff
49
+ # infer title from README
50
+ if options.title == 'RDoc Documentation' && File.readable?('README')
51
+ line = File.open('README') { |fp| fp.gets.strip }
52
+ line.sub!(/\A=+\s*/, '')
53
+ options.title = line
54
+ end
55
+
56
+ # load olddoc config
57
+ cfg = '.olddoc.yml'
58
+ if File.readable?(cfg)
59
+ @old_cfg = YAML.load(File.read(cfg))
60
+ else
61
+ @old_cfg = {}
62
+ warn "#{cfg} not readable"
63
+ end
64
+ %w(toc_max).each { |k| v = @old_cfg[k] and @old_cfg[k] = v.to_i }
65
+ @old_cfg['toc_max'] ||= 6
66
+
67
+ ni = {}
68
+ noindex = @old_cfg['noindex'] and noindex.each { |k| ni[k] = true }
69
+ @old_cfg['noindex'] = ni
70
+
71
+ if cgit_url = @old_cfg['cgit_url']
72
+ cgit_url += '/tree/%s' # path name
73
+ tag = @git_tag and cgit_url << "id=#{URI.escape(tag)}"
74
+ cgit_url << '#n%d' # lineno
75
+ @old_vcs_url = cgit_url
76
+ end
77
+ end
78
+
79
+ def generate
80
+ setup
81
+ generate_class_files
82
+ generate_file_files
83
+ generate_table_of_contents
84
+ src = Dir["#@outputdir/README*.html"].first
85
+ begin
86
+ dst = "#@outputdir/index.html"
87
+ File.link(src, dst)
88
+ rescue SystemCallError
89
+ IO.copy_stream(src, dst)
90
+ end if src
91
+ end
92
+
93
+ def rel_path(out_file)
94
+ rel_prefix = @outputdir.relative_path_from(out_file.dirname)
95
+ rel_prefix == '.' ? '' : "#{rel_prefix}/"
96
+ end
97
+
98
+ # called standalone by servelet
99
+ def generate_class(klass, template_file = nil)
100
+ setup
101
+ current = klass
102
+ template_file ||= @template_dir + 'class.rhtml'
103
+ out_file = @outputdir + klass.path
104
+ rel_prefix = rel_path(out_file)
105
+ @title = "#{klass.type} #{klass.full_name}"
106
+ @suppress_warning = [ rel_prefix, current ]
107
+ render_template(template_file, out_file) { |io| binding }
108
+ end
109
+
110
+ # Generate a documentation file for each class and module
111
+ def generate_class_files
112
+ setup
113
+ template_file = @template_dir + 'class.rhtml'
114
+ current = nil
115
+
116
+ @classes.each do |klass|
117
+ current = klass
118
+ generate_class(klass, template_file)
119
+ end
120
+ rescue => e
121
+ e!(e, "error generating #{current.path}: #{e.message} (#{e.class})")
122
+ end
123
+
124
+ # Generate a documentation file for each file
125
+ def generate_file_files
126
+ setup
127
+ @files.each do |file|
128
+ generate_page(file) if file.text?
129
+ end
130
+ end
131
+
132
+ # Generate a page file for +file+
133
+ def generate_page(file, out_file = @outputdir + file.path)
134
+ setup
135
+ template_file = @template_dir + 'page.rhtml'
136
+ rel_prefix = rel_path(out_file)
137
+ current = file
138
+
139
+ @title = "#{file.page_name} - #{@options.title}"
140
+
141
+ # use the first header as title instead of page_name if there is one
142
+ File.open("#{@options.root}/#{file.absolute_name}") do |f|
143
+ line = f.gets.strip
144
+ line.sub!(/^=+\s*/, '') and @title = line
145
+ end
146
+
147
+ @suppress_warning = [ current, rel_prefix ]
148
+
149
+ render_template(template_file, out_file) { |io| binding }
150
+ rescue => e
151
+ e!(e, "error generating #{out_file}: #{e.message} (#{e.class})")
152
+ end
153
+
154
+ # Generates the 404 page for the RDoc servlet
155
+ def generate_servlet_not_found(message)
156
+ setup
157
+ template_file = @template_dir + 'servlet_not_found.rhtml'
158
+ rel_prefix = ''
159
+ @suppress_warning = rel_prefix
160
+ @title = 'Not Found'
161
+ render_template(template_file) { |io| binding }
162
+ rescue => e
163
+ e!(e, "error generating servlet_not_found: #{e.message} (#{e.class})")
164
+ end
165
+
166
+ # Generates the servlet root page for the RDoc servlet
167
+ def generate_servlet_root(installed)
168
+ setup
169
+
170
+ template_file = @template_dir + 'servlet_root.rhtml'
171
+
172
+ rel_prefix = ''
173
+ @suppress_warning = rel_prefix
174
+
175
+ @title = 'Local RDoc Documentation'
176
+ render_template(template_file) { |io| binding }
177
+ rescue => e
178
+ e!(e, "error generating servlet_root: #{e.message} (#{e.class})")
179
+ end
180
+
181
+ def generate_table_of_contents
182
+ setup
183
+ template_file = @template_dir + 'table_of_contents.rhtml'
184
+ out_file = @outputdir + 'table_of_contents.html'
185
+ rel_prefix = rel_path(out_file)
186
+ @suppress_warning = rel_prefix
187
+ @title = "Table of Contents - #{@options.title}"
188
+ render_template(template_file, out_file) { |io| binding }
189
+ rescue => e
190
+ e!(e, "error generating table_of_contents.html: #{e.message} (#{e.class})")
191
+ end
192
+
193
+ def setup
194
+ return if @outputdir
195
+ @outputdir = Pathname.new(@options.op_dir).expand_path(@base_dir)
196
+ return unless @store
197
+ @classes = @store.all_classes_and_modules.sort
198
+ @files = @store.all_files.sort
199
+ @methods = @classes.map(&:method_list).flatten.sort
200
+ @modsort = @classes.select(&:display?).sort
201
+ end
202
+
203
+ # Creates a template from its components and the +body_file+.
204
+ def assemble_template(body_file)
205
+ body = body_file.read
206
+ head = @template_dir + '_head.rhtml'
207
+ tail = @template_dir + '_tail.rhtml'
208
+ "<html><head>#{head.read.strip}</head><body\n" \
209
+ "id=\"top\">#{body.strip}#{tail.read.strip}</body></html>"
210
+ end
211
+
212
+ # Renders the ERb contained in +file_name+ relative to the template
213
+ # directory and returns the result based on the current context.
214
+ def render(file_name)
215
+ template_file = @template_dir + file_name
216
+ template = template_for(template_file, false, RDoc::ERBPartial)
217
+ template.filename = template_file.to_s
218
+ template.result(@context)
219
+ end
220
+
221
+ # Load and render the erb template in the given +template_file+ and write
222
+ # it out to +out_file+.
223
+ # Both +template_file+ and +out_file+ should be Pathname-like objects.
224
+ # An io will be yielded which must be captured by binding in the caller.
225
+ def render_template(template_file, out_file = nil) # :yield: io
226
+ io_output = out_file && !@dry_run && @file_output
227
+ erb_klass = io_output ? RDoc::ERBIO : ERB
228
+ template = template_for(template_file, true, erb_klass)
229
+
230
+ if io_output
231
+ out_file.dirname.mkpath
232
+ out_file.open('w', 0644) do |io|
233
+ io.set_encoding(@options.encoding)
234
+ @context = yield io
235
+ template_result(template, @context, template_file)
236
+ end
237
+ else
238
+ @context = yield nil
239
+ template_result(template, @context, template_file)
240
+ end
241
+ end
242
+
243
+ # Creates the result for +template+ with +context+. If an error is raised a
244
+ # Pathname +template_file+ will indicate the file where the error occurred.
245
+ def template_result(template, context, template_file)
246
+ template.filename = template_file.to_s
247
+ template.result(context)
248
+ rescue NoMethodError => e
249
+ e!(e, "Error while evaluating #{template_file.expand_path}: #{e.message}")
250
+ end
251
+
252
+ def template_for(file, page = true, klass = ERB)
253
+ template = @template_cache[file]
254
+
255
+ return template if template
256
+
257
+ if page
258
+ template = assemble_template(file)
259
+ erbout = 'io'
260
+ else
261
+ template = file.read
262
+ template = template.encode(@options.encoding)
263
+ file_var = File.basename(file).sub(/\..*/, '')
264
+ erbout = "_erbout_#{file_var}"
265
+ end
266
+
267
+ template = klass.new(template, nil, '<>', erbout)
268
+ @template_cache[file] = template
269
+ end
270
+
271
+ def e!(e, msg)
272
+ raise RDoc::Error, msg, e.backtrace
273
+ end
274
+
275
+ def method_srclink(m)
276
+ url = @old_vcs_url or return ""
277
+ line = m.line or return ""
278
+ path = URI.escape(m.file_name)
279
+ %Q(<a href="#{url % [ path, line ]}">source</a>)
280
+ end
281
+
282
+ # reach into RDoc internals to generate less HTML
283
+ module LessHtml
284
+ def accept_verbatim(verbatim)
285
+ @res << "\n<pre>#{CGI.escapeHTML(verbatim.text.rstrip)}</pre>\n"
286
+ end
287
+
288
+ def accept_heading(heading)
289
+ level = [6, heading.level].min
290
+ label = heading.label(@code_object)
291
+ @res << "<h#{level}"
292
+ @res << (@options.output_decoration ? "\nid=\"#{label}\">" : ">")
293
+ @res << to_html(heading.text)
294
+ @res << "</h#{level}>"
295
+ end
296
+ end
297
+ end
298
+
299
+ class RDoc::Markup::ToHtml # :nodoc:
300
+ remove_method :accept_heading
301
+ remove_method :accept_verbatim
302
+ include Oldweb::LessHtml
303
+ end
@@ -0,0 +1,7 @@
1
+ <meta charset="<%= @options.charset %>"><title><%= h @title %></title><%
2
+ if rdoc_url = @old_cfg['rdoc_url'] %><link
3
+ rel="alternate"
4
+ title="Atom feed"
5
+ href="<%= rdoc_url %>NEWS.atom.xml"
6
+ type="application/atom+xml" /><%
7
+ end %>