rdoc 2.5.11 → 3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rdoc might be problematic. Click here for more details.
- data.tar.gz.sig +0 -0
- data/.document +1 -0
- data/History.txt +95 -0
- data/Manifest.txt +13 -4
- data/README.txt +9 -3
- data/Rakefile +1 -1
- data/lib/rdoc.rb +15 -298
- data/lib/rdoc/alias.rb +65 -16
- data/lib/rdoc/any_method.rb +27 -150
- data/lib/rdoc/attr.rb +36 -115
- data/lib/rdoc/class_module.rb +236 -22
- data/lib/rdoc/code_object.rb +76 -31
- data/lib/rdoc/constant.rb +32 -4
- data/lib/rdoc/context.rb +494 -222
- data/lib/rdoc/encoding.rb +79 -0
- data/lib/rdoc/erbio.rb +37 -0
- data/lib/rdoc/gauntlet.rb +9 -5
- data/lib/rdoc/generator.rb +33 -1
- data/lib/rdoc/generator/darkfish.rb +284 -375
- data/lib/rdoc/generator/markup.rb +72 -36
- data/lib/rdoc/generator/ri.rb +4 -4
- data/lib/rdoc/generator/template/darkfish/classpage.rhtml +267 -274
- data/lib/rdoc/generator/template/darkfish/filepage.rhtml +91 -91
- data/lib/rdoc/generator/template/darkfish/index.rhtml +45 -45
- data/lib/rdoc/generator/template/darkfish/rdoc.css +298 -298
- data/lib/rdoc/include.rb +40 -1
- data/lib/rdoc/known_classes.rb +1 -0
- data/lib/rdoc/markup.rb +467 -2
- data/lib/rdoc/markup/attribute_manager.rb +24 -6
- data/lib/rdoc/markup/blank_line.rb +11 -3
- data/lib/rdoc/markup/document.rb +6 -0
- data/lib/rdoc/markup/formatter.rb +10 -0
- data/lib/rdoc/markup/formatter_test_case.rb +339 -3
- data/lib/rdoc/markup/heading.rb +3 -0
- data/lib/rdoc/markup/inline.rb +11 -1
- data/lib/rdoc/markup/list.rb +3 -0
- data/lib/rdoc/markup/list_item.rb +3 -0
- data/lib/rdoc/markup/paragraph.rb +3 -0
- data/lib/rdoc/markup/parser.rb +191 -237
- data/lib/rdoc/markup/{preprocess.rb → pre_process.rb} +50 -29
- data/lib/rdoc/markup/raw.rb +4 -0
- data/lib/rdoc/markup/rule.rb +3 -0
- data/lib/rdoc/markup/text_formatter_test_case.rb +116 -0
- data/lib/rdoc/markup/to_ansi.rb +14 -2
- data/lib/rdoc/markup/to_bs.rb +8 -2
- data/lib/rdoc/markup/to_html.rb +84 -91
- data/lib/rdoc/markup/to_html_crossref.rb +77 -26
- data/lib/rdoc/markup/to_rdoc.rb +94 -49
- data/lib/rdoc/markup/to_test.rb +9 -1
- data/lib/rdoc/markup/verbatim.rb +6 -3
- data/lib/rdoc/method_attr.rb +353 -0
- data/lib/rdoc/normal_class.rb +11 -2
- data/lib/rdoc/normal_module.rb +0 -5
- data/lib/rdoc/options.rb +373 -82
- data/lib/rdoc/parser.rb +59 -23
- data/lib/rdoc/parser/c.rb +224 -86
- data/lib/rdoc/parser/ruby.rb +219 -111
- data/lib/rdoc/parser/ruby_tools.rb +4 -1
- data/lib/rdoc/parser/simple.rb +9 -4
- data/lib/rdoc/rdoc.rb +68 -28
- data/lib/rdoc/require.rb +21 -0
- data/lib/rdoc/ri/driver.rb +20 -10
- data/lib/rdoc/ri/paths.rb +2 -2
- data/lib/rdoc/ri/store.rb +22 -5
- data/lib/rdoc/ruby_lex.rb +11 -12
- data/lib/rdoc/ruby_token.rb +2 -2
- data/lib/rdoc/single_class.rb +2 -1
- data/lib/rdoc/stats.rb +202 -162
- data/lib/rdoc/stats/normal.rb +51 -0
- data/lib/rdoc/stats/quiet.rb +59 -0
- data/lib/rdoc/stats/verbose.rb +45 -0
- data/lib/rdoc/text.rb +133 -4
- data/lib/rdoc/{tokenstream.rb → token_stream.rb} +0 -2
- data/lib/rdoc/top_level.rb +230 -39
- data/test/test_attribute_manager.rb +58 -7
- data/test/test_rdoc_alias.rb +13 -0
- data/test/test_rdoc_any_method.rb +43 -2
- data/test/test_rdoc_attr.rb +15 -8
- data/test/test_rdoc_class_module.rb +133 -0
- data/test/test_rdoc_code_object.rb +62 -5
- data/test/test_rdoc_context.rb +72 -26
- data/test/test_rdoc_encoding.rb +145 -0
- data/test/test_rdoc_generator_darkfish.rb +119 -0
- data/test/test_rdoc_generator_ri.rb +22 -2
- data/test/test_rdoc_include.rb +79 -0
- data/test/test_rdoc_markup_attribute_manager.rb +4 -4
- data/test/test_rdoc_markup_parser.rb +134 -95
- data/test/test_rdoc_markup_pre_process.rb +7 -2
- data/test/test_rdoc_markup_to_ansi.rb +43 -153
- data/test/test_rdoc_markup_to_bs.rb +42 -156
- data/test/test_rdoc_markup_to_html.rb +130 -58
- data/test/test_rdoc_markup_to_html_crossref.rb +10 -10
- data/test/test_rdoc_markup_to_rdoc.rb +40 -151
- data/test/test_rdoc_method_attr.rb +122 -0
- data/test/test_rdoc_normal_class.rb +1 -1
- data/test/test_rdoc_normal_module.rb +6 -1
- data/test/test_rdoc_options.rb +237 -12
- data/test/test_rdoc_parser.rb +3 -22
- data/test/test_rdoc_parser_c.rb +203 -2
- data/test/test_rdoc_parser_ruby.rb +403 -89
- data/test/test_rdoc_parser_simple.rb +25 -1
- data/test/test_rdoc_rdoc.rb +44 -32
- data/test/test_rdoc_ri_driver.rb +29 -24
- data/test/test_rdoc_ri_store.rb +46 -3
- data/test/test_rdoc_task.rb +1 -1
- data/test/test_rdoc_text.rb +102 -8
- data/test/test_rdoc_top_level.rb +13 -4
- data/test/xref_data.rb +8 -0
- data/test/xref_test_case.rb +6 -0
- metadata +29 -19
- metadata.gz.sig +0 -0
- data/lib/rdoc/parser/perl.rb +0 -165
- data/test/test_rdoc_parser_perl.rb +0 -73
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rdoc'
|
2
|
+
|
3
|
+
##
|
4
|
+
# This class is a wrapper around File IO and Encoding that helps RDoc load
|
5
|
+
# files and convert them to the correct encoding.
|
6
|
+
|
7
|
+
module RDoc::Encoding
|
8
|
+
|
9
|
+
##
|
10
|
+
# Reads the contents of +filename+ and handles any encoding directives in
|
11
|
+
# the file.
|
12
|
+
#
|
13
|
+
# The content will be converted to the +encoding+. If the file cannot be
|
14
|
+
# converted a warning will be printed and nil will be returned.
|
15
|
+
|
16
|
+
def self.read_file filename, encoding
|
17
|
+
content = open filename, "rb" do |f| f.read end
|
18
|
+
|
19
|
+
utf8 = content.sub!(/\A\xef\xbb\xbf/, '')
|
20
|
+
|
21
|
+
RDoc::Encoding.set_encoding content
|
22
|
+
|
23
|
+
if Object.const_defined? :Encoding then
|
24
|
+
encoding ||= Encoding.default_external
|
25
|
+
orig_encoding = content.encoding
|
26
|
+
|
27
|
+
if utf8 then
|
28
|
+
content.force_encoding Encoding::UTF_8
|
29
|
+
content.encode! encoding
|
30
|
+
else
|
31
|
+
# assume the content is in our output encoding
|
32
|
+
content.force_encoding encoding
|
33
|
+
end
|
34
|
+
|
35
|
+
unless content.valid_encoding? then
|
36
|
+
# revert and try to transcode
|
37
|
+
content.force_encoding orig_encoding
|
38
|
+
content.encode! encoding
|
39
|
+
end
|
40
|
+
|
41
|
+
unless content.valid_encoding? then
|
42
|
+
warn "unable to convert #{filename} to #{encoding}, skipping"
|
43
|
+
content = nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
content
|
48
|
+
rescue ArgumentError => e
|
49
|
+
raise unless e.message =~ /unknown encoding name - (.*)/
|
50
|
+
warn "unknown encoding name \"#{$1}\" for #{filename}, skipping"
|
51
|
+
nil
|
52
|
+
rescue Encoding::UndefinedConversionError => e
|
53
|
+
warn "unable to convert #{e.message} for #{filename}, skipping"
|
54
|
+
nil
|
55
|
+
rescue Errno::EISDIR, Errno::ENOENT
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Sets the encoding of +string+ based on the magic comment
|
61
|
+
|
62
|
+
def self.set_encoding string
|
63
|
+
return unless Object.const_defined? :Encoding
|
64
|
+
|
65
|
+
first_line = string[/\A(?:#!.*\n)?.*\n/]
|
66
|
+
|
67
|
+
name = case first_line
|
68
|
+
when /^<\?xml[^?]*encoding=(["'])(.*?)\1/ then $2
|
69
|
+
when /\b(?:en)?coding[=:]\s*([^\s;]+)/i then $1
|
70
|
+
else return
|
71
|
+
end
|
72
|
+
|
73
|
+
enc = Encoding.find name
|
74
|
+
string.force_encoding enc if enc
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
data/lib/rdoc/erbio.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
##
|
4
|
+
# A subclass of ERB that writes directly to an IO. Credit to Aaron Patterson
|
5
|
+
# and Masatoshi SEKI.
|
6
|
+
#
|
7
|
+
# To use:
|
8
|
+
#
|
9
|
+
# erbio = RDoc::ERBIO.new '<%= "hello world" %>', nil, nil
|
10
|
+
#
|
11
|
+
# open 'hello.txt', 'w' do |io|
|
12
|
+
# erbio.result binding
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# Note that binding must enclose the io you wish to output on.
|
16
|
+
|
17
|
+
class RDoc::ERBIO < ERB
|
18
|
+
|
19
|
+
##
|
20
|
+
# Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize
|
21
|
+
|
22
|
+
def initialize str, safe_level = nil, trim_mode = nil, eoutvar = 'io'
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Instructs +compiler+ how to write to +io_variable+
|
28
|
+
|
29
|
+
def set_eoutvar compiler, io_variable
|
30
|
+
compiler.put_cmd = "#{io_variable}.write"
|
31
|
+
compiler.insert_cmd = "#{io_variable}.write"
|
32
|
+
compiler.pre_cmd = []
|
33
|
+
compiler.post_cmd = []
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
data/lib/rdoc/gauntlet.rb
CHANGED
@@ -7,16 +7,19 @@ require 'fileutils'
|
|
7
7
|
|
8
8
|
class RDoc::Gauntlet < Gauntlet
|
9
9
|
|
10
|
+
##
|
11
|
+
# Runs an RDoc generator for gem +name+
|
12
|
+
|
10
13
|
def run name
|
11
|
-
|
14
|
+
return if self.data.key? name
|
12
15
|
|
13
|
-
|
14
|
-
FileUtils.rm_rf
|
16
|
+
dir = File.expand_path "~/.gauntlet/data/rdoc/#{name}"
|
17
|
+
FileUtils.rm_rf dir if File.exist? dir
|
15
18
|
|
16
19
|
yaml = File.read 'gemspec'
|
17
20
|
spec = Gem::Specification.from_yaml yaml
|
18
21
|
|
19
|
-
args = %W[--ri --op #{
|
22
|
+
args = %W[--ri --op #{dir}]
|
20
23
|
args.push(*spec.rdoc_options)
|
21
24
|
args << spec.require_paths
|
22
25
|
args << spec.extra_rdoc_files
|
@@ -32,7 +35,8 @@ class RDoc::Gauntlet < Gauntlet
|
|
32
35
|
r.document args
|
33
36
|
self.data[name] = true
|
34
37
|
puts 'passed'
|
35
|
-
|
38
|
+
FileUtils.rm_rf dir
|
39
|
+
rescue Interrupt, StandardError, RDoc::Error, SystemStackError => e
|
36
40
|
puts "failed - (#{e.class}) #{e.message}"
|
37
41
|
self.data[name] = false
|
38
42
|
end
|
data/lib/rdoc/generator.rb
CHANGED
@@ -1,7 +1,39 @@
|
|
1
1
|
require 'rdoc'
|
2
2
|
|
3
3
|
##
|
4
|
-
#
|
4
|
+
# RDoc uses generators to turn parsed source code in the form of an
|
5
|
+
# RDoc::CodeObject tree into some form of output. RDoc comes with the HTML
|
6
|
+
# generator RDoc::Generator::Darkfish and an ri data generator
|
7
|
+
# RDoc::Generator::RI.
|
8
|
+
#
|
9
|
+
# = Registering a Generator
|
10
|
+
#
|
11
|
+
# Generators are registered by calling RDoc::RDoc.add_generator with the class
|
12
|
+
# of the generator:
|
13
|
+
#
|
14
|
+
# class My::Awesome::Generator
|
15
|
+
# RDoc::RDoc.add_generator self
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# = Adding Options to +rdoc+
|
19
|
+
#
|
20
|
+
# Before option processing in +rdoc+, RDoc::Options will call ::setup_options
|
21
|
+
# on the generator class with an RDoc::Options instance. The generator can
|
22
|
+
# use RDoc::Options#option_parser to add command-line options to the +rdoc+
|
23
|
+
# tool. See OptionParser for details on how to add options.
|
24
|
+
#
|
25
|
+
# You can extend the RDoc::Options instance with additional accesors for your
|
26
|
+
# generator.
|
27
|
+
#
|
28
|
+
# = Generator Instantiation
|
29
|
+
#
|
30
|
+
# After parsing, RDoc::RDoc will instantiate a generator by calling
|
31
|
+
# #initialize with an RDoc::Options instance.
|
32
|
+
#
|
33
|
+
# RDoc will then call #generate on the generator instance and pass in an Array
|
34
|
+
# of RDoc::TopLevel instances, each representing a parsed file. You can use
|
35
|
+
# the various class methods on RDoc::TopLevel and in the RDoc::CodeObject tree
|
36
|
+
# to create your desired output format.
|
5
37
|
|
6
38
|
module RDoc::Generator
|
7
39
|
end
|
@@ -1,15 +1,12 @@
|
|
1
1
|
# -*- mode: ruby; ruby-indent-level: 2; tab-width: 2 -*-
|
2
|
-
# vim: noet ts=2 sts=8 sw=2
|
3
2
|
|
4
3
|
require 'pathname'
|
5
4
|
require 'fileutils'
|
6
|
-
require '
|
5
|
+
require 'rdoc/erbio'
|
7
6
|
|
8
7
|
require 'rdoc/generator/markup'
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
#
|
9
|
+
##
|
13
10
|
# Darkfish RDoc HTML Generator
|
14
11
|
#
|
15
12
|
# $Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $
|
@@ -52,402 +49,314 @@ $DARKFISH_DRYRUN = false # TODO make me non-global
|
|
52
49
|
#
|
53
50
|
class RDoc::Generator::Darkfish
|
54
51
|
|
55
|
-
|
52
|
+
RDoc::RDoc.add_generator self
|
53
|
+
|
54
|
+
include ERB::Util
|
55
|
+
|
56
|
+
# Path to this file's parent directory. Used to find templates and other
|
57
|
+
# resources.
|
58
|
+
|
59
|
+
GENERATOR_DIR = File.join 'rdoc', 'generator'
|
60
|
+
|
61
|
+
##
|
62
|
+
# Release Version
|
63
|
+
|
64
|
+
VERSION = '2'
|
65
|
+
|
66
|
+
##
|
67
|
+
# Initialize a few instance variables before we start
|
56
68
|
|
57
|
-
|
69
|
+
def initialize options
|
70
|
+
@options = options
|
58
71
|
|
59
|
-
|
60
|
-
|
72
|
+
@template_dir = Pathname.new options.template_dir
|
73
|
+
@template_cache = {}
|
61
74
|
|
62
|
-
|
63
|
-
|
75
|
+
@files = nil
|
76
|
+
@classes = nil
|
64
77
|
|
65
|
-
|
66
|
-
|
67
|
-
GENERATOR_DIR = File.join 'rdoc', 'generator'
|
78
|
+
@basedir = Pathname.pwd.expand_path
|
79
|
+
end
|
68
80
|
|
69
|
-
|
70
|
-
|
81
|
+
##
|
82
|
+
# The output directory
|
71
83
|
|
72
|
-
|
73
|
-
CLASS_DIR = nil
|
84
|
+
attr_reader :outputdir
|
74
85
|
|
75
|
-
|
76
|
-
|
86
|
+
##
|
87
|
+
# Output progress information if debugging is enabled
|
77
88
|
|
89
|
+
def debug_msg *msg
|
90
|
+
return unless $DEBUG_RDOC
|
91
|
+
$stderr.puts(*msg)
|
92
|
+
end
|
78
93
|
|
79
|
-
|
80
|
-
|
81
|
-
|
94
|
+
##
|
95
|
+
# Directory where generated class HTML files live relative to the output
|
96
|
+
# dir.
|
82
97
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
98
|
+
def class_dir
|
99
|
+
nil
|
100
|
+
end
|
87
101
|
|
102
|
+
##
|
103
|
+
# Directory where generated class HTML files live relative to the output
|
104
|
+
# dir.
|
88
105
|
|
89
|
-
|
90
|
-
|
91
|
-
|
106
|
+
def file_dir
|
107
|
+
nil
|
108
|
+
end
|
92
109
|
|
93
|
-
|
94
|
-
|
95
|
-
|
110
|
+
##
|
111
|
+
# Create the directories the generated docs will live in if they don't
|
112
|
+
# already exist.
|
96
113
|
|
97
|
-
|
114
|
+
def gen_sub_directories
|
115
|
+
@outputdir.mkpath
|
116
|
+
end
|
98
117
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
File.directory? dir
|
103
|
-
end
|
118
|
+
##
|
119
|
+
# Copy over the stylesheet into the appropriate place in the output
|
120
|
+
# directory.
|
104
121
|
|
105
|
-
|
106
|
-
|
122
|
+
def write_style_sheet
|
123
|
+
debug_msg "Copying static files"
|
124
|
+
options = { :verbose => $DEBUG_RDOC, :noop => @options.dry_run }
|
107
125
|
|
108
|
-
|
126
|
+
FileUtils.cp @template_dir + 'rdoc.css', '.', options
|
109
127
|
|
110
|
-
|
111
|
-
|
128
|
+
Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
|
129
|
+
next if File.directory? path
|
130
|
+
next if File.basename(path) =~ /^\./
|
112
131
|
|
113
|
-
|
114
|
-
end
|
132
|
+
dst = Pathname.new(path).relative_path_from @template_dir
|
115
133
|
|
116
|
-
|
117
|
-
|
118
|
-
|
134
|
+
# I suck at glob
|
135
|
+
dst_dir = dst.dirname
|
136
|
+
FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir
|
119
137
|
|
120
|
-
|
121
|
-
|
138
|
+
FileUtils.cp @template_dir + path, dst, options
|
139
|
+
end
|
140
|
+
end
|
122
141
|
|
142
|
+
##
|
143
|
+
# Build the initial indices and output objects based on an array of TopLevel
|
144
|
+
# objects containing the extracted information.
|
123
145
|
|
124
|
-
|
125
|
-
|
126
|
-
return unless $DEBUG_RDOC
|
127
|
-
$stderr.puts( *msg )
|
128
|
-
end
|
146
|
+
def generate top_levels
|
147
|
+
@outputdir = Pathname.new(@options.op_dir).expand_path(@basedir)
|
129
148
|
|
130
|
-
|
131
|
-
|
132
|
-
|
149
|
+
@files = top_levels.sort
|
150
|
+
@classes = RDoc::TopLevel.all_classes_and_modules.sort
|
151
|
+
@methods = @classes.map { |m| m.method_list }.flatten.sort
|
152
|
+
@modsort = get_sorted_module_list(@classes)
|
133
153
|
|
134
|
-
|
135
|
-
|
136
|
-
|
154
|
+
# Now actually write the output
|
155
|
+
write_style_sheet
|
156
|
+
generate_index
|
157
|
+
generate_class_files
|
158
|
+
generate_file_files
|
137
159
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
160
|
+
rescue StandardError => err
|
161
|
+
debug_msg "%s: %s\n %s" % [
|
162
|
+
err.class.name, err.message, err.backtrace.join("\n ")
|
163
|
+
]
|
164
|
+
|
165
|
+
raise
|
166
|
+
end
|
167
|
+
|
168
|
+
protected
|
169
|
+
|
170
|
+
##
|
171
|
+
# Return a list of the documented modules sorted by salience first, then
|
172
|
+
# by name.
|
173
|
+
|
174
|
+
def get_sorted_module_list(classes)
|
175
|
+
nscounts = classes.inject({}) do |counthash, klass|
|
176
|
+
top_level = klass.full_name.gsub(/::.*/, '')
|
177
|
+
counthash[top_level] ||= 0
|
178
|
+
counthash[top_level] += 1
|
179
|
+
|
180
|
+
counthash
|
181
|
+
end
|
182
|
+
|
183
|
+
# Sort based on how often the top level namespace occurs, and then on the
|
184
|
+
# name of the module -- this works for projects that put their stuff into
|
185
|
+
# a namespace, of course, but doesn't hurt if they don't.
|
186
|
+
classes.sort_by do |klass|
|
187
|
+
top_level = klass.full_name.gsub( /::.*/, '' )
|
188
|
+
[nscounts[top_level] * -1, klass.full_name]
|
189
|
+
end.select do |klass|
|
190
|
+
klass.document_self
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Generate an index page which lists all the classes which are documented.
|
196
|
+
|
197
|
+
def generate_index
|
198
|
+
template_file = @template_dir + 'index.rhtml'
|
199
|
+
return unless template_file.exist?
|
200
|
+
|
201
|
+
debug_msg "Rendering the index page..."
|
202
|
+
|
203
|
+
out_file = @basedir + @options.op_dir + 'index.html'
|
204
|
+
|
205
|
+
render_template template_file, out_file do |io| binding end
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Generate a documentation file for each class
|
210
|
+
|
211
|
+
def generate_class_files
|
212
|
+
template_file = @template_dir + 'classpage.rhtml'
|
213
|
+
return unless template_file.exist?
|
214
|
+
debug_msg "Generating class documentation in #@outputdir"
|
215
|
+
|
216
|
+
@classes.each do |klass|
|
217
|
+
debug_msg " working on %s (%s)" % [klass.full_name, klass.path]
|
218
|
+
out_file = @outputdir + klass.path
|
219
|
+
# suppress 1.9.3 warning
|
220
|
+
rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
|
221
|
+
svninfo = svninfo = self.get_svninfo(klass)
|
222
|
+
|
223
|
+
debug_msg " rendering #{out_file}"
|
224
|
+
render_template template_file, out_file do |io| binding end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
##
|
229
|
+
# Generate a documentation file for each file
|
230
|
+
|
231
|
+
def generate_file_files
|
232
|
+
template_file = @template_dir + 'filepage.rhtml'
|
233
|
+
return unless template_file.exist?
|
234
|
+
debug_msg "Generating file documentation in #@outputdir"
|
235
|
+
|
236
|
+
@files.each do |file|
|
237
|
+
out_file = @outputdir + file.path
|
238
|
+
debug_msg " working on %s (%s)" % [ file.full_name, out_file ]
|
239
|
+
# suppress 1.9.3 warning
|
240
|
+
rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
|
241
|
+
|
242
|
+
debug_msg " rendering #{out_file}"
|
243
|
+
render_template template_file, out_file do |io| binding end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
##
|
248
|
+
# Return a string describing the amount of time in the given number of
|
249
|
+
# seconds in terms a human can understand easily.
|
250
|
+
|
251
|
+
def time_delta_string seconds
|
252
|
+
return 'less than a minute' if seconds < 60
|
253
|
+
return "#{seconds / 60} minute#{seconds / 60 == 1 ? '' : 's'}" if
|
254
|
+
seconds < 3000 # 50 minutes
|
255
|
+
return 'about one hour' if seconds < 5400 # 90 minutes
|
256
|
+
return "#{seconds / 3600} hours" if seconds < 64800 # 18 hours
|
257
|
+
return 'one day' if seconds < 86400 # 1 day
|
258
|
+
return 'about one day' if seconds < 172800 # 2 days
|
259
|
+
return "#{seconds / 86400} days" if seconds < 604800 # 1 week
|
260
|
+
return 'about one week' if seconds < 1209600 # 2 week
|
261
|
+
return "#{seconds / 604800} weeks" if seconds < 7257600 # 3 months
|
262
|
+
return "#{seconds / 2419200} months" if seconds < 31536000 # 1 year
|
263
|
+
return "#{seconds / 31536000} years"
|
264
|
+
end
|
265
|
+
|
266
|
+
# %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $"
|
267
|
+
SVNID_PATTERN = /
|
268
|
+
\$Id:\s
|
269
|
+
(\S+)\s # filename
|
270
|
+
(\d+)\s # rev
|
271
|
+
(\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD)
|
272
|
+
(\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ)
|
273
|
+
(\w+)\s # committer
|
274
|
+
\$$
|
275
|
+
/x
|
276
|
+
|
277
|
+
##
|
278
|
+
# Try to extract Subversion information out of the first constant whose
|
279
|
+
# value looks like a subversion Id tag. If no matching constant is found,
|
280
|
+
# and empty hash is returned.
|
281
|
+
|
282
|
+
def get_svninfo klass
|
283
|
+
constants = klass.constants or return {}
|
284
|
+
|
285
|
+
constants.find { |c| c.value =~ SVNID_PATTERN } or return {}
|
286
|
+
|
287
|
+
filename, rev, date, time, committer = $~.captures
|
288
|
+
commitdate = Time.parse "#{date} #{time}"
|
289
|
+
|
290
|
+
return {
|
291
|
+
:filename => filename,
|
292
|
+
:rev => Integer(rev),
|
293
|
+
:commitdate => commitdate,
|
294
|
+
:commitdelta => time_delta_string(Time.now - commitdate),
|
295
|
+
:committer => committer,
|
296
|
+
}
|
297
|
+
end
|
298
|
+
|
299
|
+
##
|
300
|
+
# Load and render the erb template in the given +template_file+ and write
|
301
|
+
# it out to +out_file+.
|
302
|
+
#
|
303
|
+
# Both +template_file+ and +out_file+ should be Pathname-like objects.
|
304
|
+
#
|
305
|
+
# An io will be yielded which must be captured by binding in the caller.
|
306
|
+
|
307
|
+
def render_template template_file, out_file # :yield: io
|
308
|
+
template = template_for template_file
|
309
|
+
|
310
|
+
unless @options.dry_run then
|
311
|
+
debug_msg "Outputting to %s" % [out_file.expand_path]
|
312
|
+
|
313
|
+
out_file.dirname.mkpath
|
314
|
+
out_file.open 'w', 0644 do |io|
|
315
|
+
io.set_encoding @options.encoding if Object.const_defined? :Encoding
|
316
|
+
|
317
|
+
context = yield io
|
318
|
+
|
319
|
+
template_result template, context, template_file
|
320
|
+
end
|
321
|
+
else
|
322
|
+
context = yield nil
|
323
|
+
|
324
|
+
output = template_result template, context, template_file
|
325
|
+
|
326
|
+
debug_msg " would have written %d characters to %s" % [
|
327
|
+
output.length, out_file.expand_path
|
328
|
+
]
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
##
|
333
|
+
# Creates the result for +template+ with +context+. If an error is raised a
|
334
|
+
# Pathname +template_file+ will indicate the file where the error occurred.
|
335
|
+
|
336
|
+
def template_result template, context, template_file
|
337
|
+
template.filename = template_file.to_s
|
338
|
+
template.result context
|
339
|
+
rescue NoMethodError => e
|
340
|
+
raise RDoc::Error, "Error while evaluating %s: %s" % [
|
341
|
+
template_file.expand_path,
|
342
|
+
e.message,
|
343
|
+
], e.backtrace
|
344
|
+
end
|
345
|
+
|
346
|
+
##
|
347
|
+
# Retrieves a cache template for +file+, if present, or fills the cache.
|
348
|
+
|
349
|
+
def template_for file
|
350
|
+
template = @template_cache[file]
|
351
|
+
|
352
|
+
return template if template
|
353
|
+
|
354
|
+
klass = @options.dry_run ? ERB : RDoc::ERBIO
|
355
|
+
|
356
|
+
template = klass.new file.read, nil, '<>'
|
357
|
+
@template_cache[file] = template
|
358
|
+
template
|
359
|
+
end
|
143
360
|
|
144
|
-
### Copy over the stylesheet into the appropriate place in the output
|
145
|
-
### directory.
|
146
|
-
def write_style_sheet
|
147
|
-
debug_msg "Copying static files"
|
148
|
-
options = { :verbose => $DEBUG_RDOC, :noop => $DARKFISH_DRYRUN }
|
149
|
-
|
150
|
-
FileUtils.cp @template_dir + 'rdoc.css', '.', options
|
151
|
-
|
152
|
-
Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
|
153
|
-
next if File.directory? path
|
154
|
-
next if File.basename(path) =~ /^\./
|
155
|
-
|
156
|
-
dst = Pathname.new(path).relative_path_from @template_dir
|
157
|
-
|
158
|
-
# I suck at glob
|
159
|
-
dst_dir = dst.dirname
|
160
|
-
FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir
|
161
|
-
|
162
|
-
FileUtils.cp @template_dir + path, dst, options
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
### Build the initial indices and output objects
|
167
|
-
### based on an array of TopLevel objects containing
|
168
|
-
### the extracted information.
|
169
|
-
def generate( top_levels )
|
170
|
-
@outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir )
|
171
|
-
|
172
|
-
@files = top_levels.sort
|
173
|
-
@classes = RDoc::TopLevel.all_classes_and_modules.sort
|
174
|
-
@methods = @classes.map { |m| m.method_list }.flatten.sort
|
175
|
-
@modsort = get_sorted_module_list( @classes )
|
176
|
-
|
177
|
-
# Now actually write the output
|
178
|
-
write_style_sheet
|
179
|
-
generate_index
|
180
|
-
generate_class_files
|
181
|
-
generate_file_files
|
182
|
-
|
183
|
-
rescue StandardError => err
|
184
|
-
debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ]
|
185
|
-
raise
|
186
|
-
end
|
187
|
-
|
188
|
-
#########
|
189
|
-
protected
|
190
|
-
#########
|
191
|
-
|
192
|
-
### Return a list of the documented modules sorted by salience first, then
|
193
|
-
### by name.
|
194
|
-
def get_sorted_module_list( classes )
|
195
|
-
nscounts = classes.inject({}) do |counthash, klass|
|
196
|
-
top_level = klass.full_name.gsub( /::.*/, '' )
|
197
|
-
counthash[top_level] ||= 0
|
198
|
-
counthash[top_level] += 1
|
199
|
-
|
200
|
-
counthash
|
201
|
-
end
|
202
|
-
|
203
|
-
# Sort based on how often the top level namespace occurs, and then on the
|
204
|
-
# name of the module -- this works for projects that put their stuff into
|
205
|
-
# a namespace, of course, but doesn't hurt if they don't.
|
206
|
-
classes.sort_by do |klass|
|
207
|
-
top_level = klass.full_name.gsub( /::.*/, '' )
|
208
|
-
[
|
209
|
-
nscounts[ top_level ] * -1,
|
210
|
-
klass.full_name
|
211
|
-
]
|
212
|
-
end.select do |klass|
|
213
|
-
klass.document_self
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
### Generate an index page which lists all the classes which
|
218
|
-
### are documented.
|
219
|
-
def generate_index
|
220
|
-
template_file = @template_dir + 'index.rhtml'
|
221
|
-
return unless template_file.exist?
|
222
|
-
|
223
|
-
debug_msg "Rendering the index page..."
|
224
|
-
|
225
|
-
template_src = template_file.read
|
226
|
-
template = ERB.new( template_src, nil, '<>' )
|
227
|
-
template.filename = template_file.to_s
|
228
|
-
context = binding()
|
229
|
-
|
230
|
-
output = nil
|
231
|
-
|
232
|
-
begin
|
233
|
-
output = template.result( context )
|
234
|
-
rescue NoMethodError => err
|
235
|
-
raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
|
236
|
-
template_file,
|
237
|
-
err.message,
|
238
|
-
eval( "_erbout[-50,50]", context )
|
239
|
-
], err.backtrace
|
240
|
-
end
|
241
|
-
|
242
|
-
outfile = @basedir + @options.op_dir + 'index.html'
|
243
|
-
unless $DARKFISH_DRYRUN
|
244
|
-
debug_msg "Outputting to %s" % [outfile.expand_path]
|
245
|
-
outfile.open( 'w', 0644 ) do |fh|
|
246
|
-
fh.print( output )
|
247
|
-
end
|
248
|
-
else
|
249
|
-
debug_msg "Would have output to %s" % [outfile.expand_path]
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
### Generate a documentation file for each class
|
254
|
-
def generate_class_files
|
255
|
-
template_file = @template_dir + 'classpage.rhtml'
|
256
|
-
return unless template_file.exist?
|
257
|
-
debug_msg "Generating class documentation in #@outputdir"
|
258
|
-
|
259
|
-
@classes.each do |klass|
|
260
|
-
debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ]
|
261
|
-
outfile = @outputdir + klass.path
|
262
|
-
rel_prefix = @outputdir.relative_path_from( outfile.dirname )
|
263
|
-
svninfo = self.get_svninfo( klass )
|
264
|
-
|
265
|
-
debug_msg " rendering #{outfile}"
|
266
|
-
self.render_template( template_file, binding(), outfile )
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
### Generate a documentation file for each file
|
271
|
-
def generate_file_files
|
272
|
-
template_file = @template_dir + 'filepage.rhtml'
|
273
|
-
return unless template_file.exist?
|
274
|
-
debug_msg "Generating file documentation in #@outputdir"
|
275
|
-
|
276
|
-
@files.each do |file|
|
277
|
-
outfile = @outputdir + file.path
|
278
|
-
debug_msg " working on %s (%s)" % [ file.full_name, outfile ]
|
279
|
-
rel_prefix = @outputdir.relative_path_from( outfile.dirname )
|
280
|
-
context = binding()
|
281
|
-
|
282
|
-
debug_msg " rendering #{outfile}"
|
283
|
-
self.render_template( template_file, binding(), outfile )
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
|
288
|
-
### Return a string describing the amount of time in the given number of
|
289
|
-
### seconds in terms a human can understand easily.
|
290
|
-
def time_delta_string( seconds )
|
291
|
-
return 'less than a minute' if seconds < 1.minute
|
292
|
-
return (seconds / 1.minute).to_s + ' minute' + (seconds/60 == 1 ? '' : 's') if seconds < 50.minutes
|
293
|
-
return 'about one hour' if seconds < 90.minutes
|
294
|
-
return (seconds / 1.hour).to_s + ' hours' if seconds < 18.hours
|
295
|
-
return 'one day' if seconds < 1.day
|
296
|
-
return 'about one day' if seconds < 2.days
|
297
|
-
return (seconds / 1.day).to_s + ' days' if seconds < 1.week
|
298
|
-
return 'about one week' if seconds < 2.week
|
299
|
-
return (seconds / 1.week).to_s + ' weeks' if seconds < 3.months
|
300
|
-
return (seconds / 1.month).to_s + ' months' if seconds < 1.year
|
301
|
-
return (seconds / 1.year).to_s + ' years'
|
302
|
-
end
|
303
|
-
|
304
|
-
|
305
|
-
# %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $"
|
306
|
-
SVNID_PATTERN = /
|
307
|
-
\$Id:\s
|
308
|
-
(\S+)\s # filename
|
309
|
-
(\d+)\s # rev
|
310
|
-
(\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD)
|
311
|
-
(\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ)
|
312
|
-
(\w+)\s # committer
|
313
|
-
\$$
|
314
|
-
/x
|
315
|
-
|
316
|
-
### Try to extract Subversion information out of the first constant whose value looks like
|
317
|
-
### a subversion Id tag. If no matching constant is found, and empty hash is returned.
|
318
|
-
def get_svninfo( klass )
|
319
|
-
constants = klass.constants or return {}
|
320
|
-
|
321
|
-
constants.find {|c| c.value =~ SVNID_PATTERN } or return {}
|
322
|
-
|
323
|
-
filename, rev, date, time, committer = $~.captures
|
324
|
-
commitdate = Time.parse( date + ' ' + time )
|
325
|
-
|
326
|
-
return {
|
327
|
-
:filename => filename,
|
328
|
-
:rev => Integer( rev ),
|
329
|
-
:commitdate => commitdate,
|
330
|
-
:commitdelta => time_delta_string( Time.now.to_i - commitdate.to_i ),
|
331
|
-
:committer => committer,
|
332
|
-
}
|
333
|
-
end
|
334
|
-
|
335
|
-
|
336
|
-
### Load and render the erb template in the given +template_file+ within the
|
337
|
-
### specified +context+ (a Binding object) and write it out to +outfile+.
|
338
|
-
### Both +template_file+ and +outfile+ should be Pathname-like objects.
|
339
|
-
|
340
|
-
def render_template( template_file, context, outfile )
|
341
|
-
template_src = template_file.read
|
342
|
-
template = ERB.new( template_src, nil, '<>' )
|
343
|
-
template.filename = template_file.to_s
|
344
|
-
|
345
|
-
output = begin
|
346
|
-
template.result( context )
|
347
|
-
rescue NoMethodError => err
|
348
|
-
raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
|
349
|
-
template_file.to_s,
|
350
|
-
err.message,
|
351
|
-
eval( "_erbout[-50,50]", context )
|
352
|
-
], err.backtrace
|
353
|
-
end
|
354
|
-
|
355
|
-
unless $DARKFISH_DRYRUN
|
356
|
-
outfile.dirname.mkpath
|
357
|
-
outfile.open( 'w', 0644 ) do |ofh|
|
358
|
-
ofh.print( output )
|
359
|
-
end
|
360
|
-
else
|
361
|
-
debug_msg " would have written %d bytes to %s" %
|
362
|
-
[ output.length, outfile ]
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
end # Roc::Generator::Darkfish
|
367
|
-
|
368
|
-
# :stopdoc:
|
369
|
-
|
370
|
-
### Time constants
|
371
|
-
module TimeConstantMethods # :nodoc:
|
372
|
-
|
373
|
-
### Number of seconds (returns receiver unmodified)
|
374
|
-
def seconds
|
375
|
-
return self
|
376
|
-
end
|
377
|
-
alias_method :second, :seconds
|
378
|
-
|
379
|
-
### Returns number of seconds in <receiver> minutes
|
380
|
-
def minutes
|
381
|
-
return self * 60
|
382
|
-
end
|
383
|
-
alias_method :minute, :minutes
|
384
|
-
|
385
|
-
### Returns the number of seconds in <receiver> hours
|
386
|
-
def hours
|
387
|
-
return self * 60.minutes
|
388
|
-
end
|
389
|
-
alias_method :hour, :hours
|
390
|
-
|
391
|
-
### Returns the number of seconds in <receiver> days
|
392
|
-
def days
|
393
|
-
return self * 24.hours
|
394
|
-
end
|
395
|
-
alias_method :day, :days
|
396
|
-
|
397
|
-
### Return the number of seconds in <receiver> weeks
|
398
|
-
def weeks
|
399
|
-
return self * 7.days
|
400
|
-
end
|
401
|
-
alias_method :week, :weeks
|
402
|
-
|
403
|
-
### Returns the number of seconds in <receiver> fortnights
|
404
|
-
def fortnights
|
405
|
-
return self * 2.weeks
|
406
|
-
end
|
407
|
-
alias_method :fortnight, :fortnights
|
408
|
-
|
409
|
-
### Returns the number of seconds in <receiver> months (approximate)
|
410
|
-
def months
|
411
|
-
return self * 30.days
|
412
|
-
end
|
413
|
-
alias_method :month, :months
|
414
|
-
|
415
|
-
### Returns the number of seconds in <receiver> years (approximate)
|
416
|
-
def years
|
417
|
-
return (self * 365.25.days).to_i
|
418
|
-
end
|
419
|
-
alias_method :year, :years
|
420
|
-
|
421
|
-
|
422
|
-
### Returns the Time <receiver> number of seconds before the
|
423
|
-
### specified +time+. E.g., 2.hours.before( header.expiration )
|
424
|
-
def before( time )
|
425
|
-
return time - self
|
426
|
-
end
|
427
|
-
|
428
|
-
|
429
|
-
### Returns the Time <receiver> number of seconds ago. (e.g.,
|
430
|
-
### expiration > 2.hours.ago )
|
431
|
-
def ago
|
432
|
-
return self.before( ::Time.now )
|
433
|
-
end
|
434
|
-
|
435
|
-
|
436
|
-
### Returns the Time <receiver> number of seconds after the given +time+.
|
437
|
-
### E.g., 10.minutes.after( header.expiration )
|
438
|
-
def after( time )
|
439
|
-
return time + self
|
440
|
-
end
|
441
|
-
|
442
|
-
# Reads best without arguments: 10.minutes.from_now
|
443
|
-
def from_now
|
444
|
-
return self.after( ::Time.now )
|
445
|
-
end
|
446
|
-
end # module TimeConstantMethods
|
447
|
-
|
448
|
-
|
449
|
-
# Extend Numeric with time constants
|
450
|
-
class Numeric # :nodoc:
|
451
|
-
include TimeConstantMethods
|
452
361
|
end
|
453
362
|
|