sqlpostgres 1.2.4
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.
- data/Gemfile +8 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.md +23 -0
- data/README.rdoc +59 -0
- data/Rakefile +32 -0
- data/VERSION +1 -0
- data/doc/BUGS +2 -0
- data/doc/examples/README +6 -0
- data/doc/examples/connection.rb +16 -0
- data/doc/examples/connection_auto.rb +22 -0
- data/doc/examples/connection_ctor.rb +18 -0
- data/doc/examples/connection_default.rb +15 -0
- data/doc/examples/connection_exec.rb +18 -0
- data/doc/examples/connection_manual.rb +12 -0
- data/doc/examples/connection_wrapped_new.rb +13 -0
- data/doc/examples/connection_wrapped_open.rb +13 -0
- data/doc/examples/cursor.rb +38 -0
- data/doc/examples/include_module.rb +9 -0
- data/doc/examples/include_module2.rb +12 -0
- data/doc/examples/insert.rb +30 -0
- data/doc/examples/insert2.rb +36 -0
- data/doc/examples/insert_bytea.rb +16 -0
- data/doc/examples/insert_bytea_array.rb +17 -0
- data/doc/examples/insert_default_values.rb +16 -0
- data/doc/examples/insert_insert.rb +16 -0
- data/doc/examples/insert_insert_default.rb +16 -0
- data/doc/examples/insert_insert_select.rb +20 -0
- data/doc/examples/insert_select.rb +20 -0
- data/doc/examples/interval.rb +17 -0
- data/doc/examples/savepoint.rb +38 -0
- data/doc/examples/select.rb +33 -0
- data/doc/examples/select2.rb +36 -0
- data/doc/examples/select_cross_join.rb +18 -0
- data/doc/examples/select_distinct.rb +18 -0
- data/doc/examples/select_distinct_on +19 -0
- data/doc/examples/select_for_update.rb +18 -0
- data/doc/examples/select_from.rb +17 -0
- data/doc/examples/select_from_subselect.rb +20 -0
- data/doc/examples/select_group_by.rb +19 -0
- data/doc/examples/select_having.rb +20 -0
- data/doc/examples/select_join_on.rb +18 -0
- data/doc/examples/select_join_using.rb +18 -0
- data/doc/examples/select_limit.rb +19 -0
- data/doc/examples/select_natural_join.rb +18 -0
- data/doc/examples/select_offset.rb +19 -0
- data/doc/examples/select_order_by.rb +20 -0
- data/doc/examples/select_select.rb +30 -0
- data/doc/examples/select_select_alias.rb +30 -0
- data/doc/examples/select_select_expression.rb +31 -0
- data/doc/examples/select_select_literal.rb +24 -0
- data/doc/examples/select_union.rb +21 -0
- data/doc/examples/select_where_array.rb +18 -0
- data/doc/examples/select_where_in.rb +18 -0
- data/doc/examples/select_where_string.rb +18 -0
- data/doc/examples/simple.rb +34 -0
- data/doc/examples/transaction.rb +30 -0
- data/doc/examples/transaction_abort.rb +30 -0
- data/doc/examples/transaction_commit.rb +34 -0
- data/doc/examples/translate_substitute_values.rb +17 -0
- data/doc/examples/update.rb +32 -0
- data/doc/examples/update2.rb +44 -0
- data/doc/examples/update_only.rb +17 -0
- data/doc/examples/update_set.rb +17 -0
- data/doc/examples/update_set_array.rb +16 -0
- data/doc/examples/update_set_bytea.rb +16 -0
- data/doc/examples/update_set_expression.rb +16 -0
- data/doc/examples/update_set_subselect.rb +20 -0
- data/doc/examples/update_where.rb +17 -0
- data/doc/examples/use_prefix.rb +8 -0
- data/doc/examples/use_prefix2.rb +11 -0
- data/doc/index.html +31 -0
- data/doc/insertexamples.rb +9 -0
- data/doc/makemanual +4 -0
- data/doc/makerdoc +5 -0
- data/doc/manual.dbk +622 -0
- data/lib/sqlpostgres/Connection.rb +198 -0
- data/lib/sqlpostgres/Cursor.rb +157 -0
- data/lib/sqlpostgres/Delete.rb +67 -0
- data/lib/sqlpostgres/Exceptions.rb +15 -0
- data/lib/sqlpostgres/Insert.rb +279 -0
- data/lib/sqlpostgres/NullConnection.rb +22 -0
- data/lib/sqlpostgres/PgBit.rb +73 -0
- data/lib/sqlpostgres/PgBox.rb +37 -0
- data/lib/sqlpostgres/PgCidr.rb +21 -0
- data/lib/sqlpostgres/PgCircle.rb +75 -0
- data/lib/sqlpostgres/PgInet.rb +21 -0
- data/lib/sqlpostgres/PgInterval.rb +208 -0
- data/lib/sqlpostgres/PgLineSegment.rb +37 -0
- data/lib/sqlpostgres/PgMacAddr.rb +21 -0
- data/lib/sqlpostgres/PgPath.rb +64 -0
- data/lib/sqlpostgres/PgPoint.rb +65 -0
- data/lib/sqlpostgres/PgPolygon.rb +56 -0
- data/lib/sqlpostgres/PgTime.rb +77 -0
- data/lib/sqlpostgres/PgTimeWithTimeZone.rb +98 -0
- data/lib/sqlpostgres/PgTimestamp.rb +93 -0
- data/lib/sqlpostgres/PgTwoPoints.rb +54 -0
- data/lib/sqlpostgres/PgType.rb +34 -0
- data/lib/sqlpostgres/PgWrapper.rb +41 -0
- data/lib/sqlpostgres/Savepoint.rb +98 -0
- data/lib/sqlpostgres/Select.rb +855 -0
- data/lib/sqlpostgres/Transaction.rb +120 -0
- data/lib/sqlpostgres/Translate.rb +436 -0
- data/lib/sqlpostgres/Update.rb +188 -0
- data/lib/sqlpostgres.rb +67 -0
- data/test/Assert.rb +72 -0
- data/test/Connection.test.rb +246 -0
- data/test/Cursor.test.rb +190 -0
- data/test/Delete.test.rb +68 -0
- data/test/Insert.test.rb +123 -0
- data/test/MockPGconn.rb +62 -0
- data/test/NullConnection.test.rb +32 -0
- data/test/PgBit.test.rb +98 -0
- data/test/PgBox.test.rb +108 -0
- data/test/PgCidr.test.rb +61 -0
- data/test/PgCircle.test.rb +107 -0
- data/test/PgInet.test.rb +61 -0
- data/test/PgInterval.test.rb +180 -0
- data/test/PgLineSegment.test.rb +108 -0
- data/test/PgMacAddr.test.rb +61 -0
- data/test/PgPath.test.rb +106 -0
- data/test/PgPoint.test.rb +100 -0
- data/test/PgPolygon.test.rb +95 -0
- data/test/PgTime.test.rb +120 -0
- data/test/PgTimeWithTimeZone.test.rb +117 -0
- data/test/PgTimestamp.test.rb +134 -0
- data/test/RandomThings.rb +25 -0
- data/test/Savepoint.test.rb +286 -0
- data/test/Select.test.rb +930 -0
- data/test/Test.rb +62 -0
- data/test/TestConfig.rb +21 -0
- data/test/TestSetup.rb +13 -0
- data/test/TestUtil.rb +92 -0
- data/test/Transaction.test.rb +275 -0
- data/test/Translate.test.rb +354 -0
- data/test/Update.test.rb +227 -0
- data/test/roundtrip.test.rb +565 -0
- data/test/test +34 -0
- data/tools/exampleinserter/ExampleInserter.rb +177 -0
- data/tools/rdoc/ChangeLog +796 -0
- data/tools/rdoc/EXAMPLE.rb +48 -0
- data/tools/rdoc/MANIFEST +58 -0
- data/tools/rdoc/Makefile +27 -0
- data/tools/rdoc/NEW_FEATURES +226 -0
- data/tools/rdoc/README +390 -0
- data/tools/rdoc/ToDo +6 -0
- data/tools/rdoc/contrib/Index +6 -0
- data/tools/rdoc/contrib/xslfo/ChangeLog +181 -0
- data/tools/rdoc/contrib/xslfo/README +106 -0
- data/tools/rdoc/contrib/xslfo/TODO +10 -0
- data/tools/rdoc/contrib/xslfo/convert.xsl +151 -0
- data/tools/rdoc/contrib/xslfo/demo/README +21 -0
- data/tools/rdoc/contrib/xslfo/demo/rdocfo +99 -0
- data/tools/rdoc/contrib/xslfo/fcm.xsl +54 -0
- data/tools/rdoc/contrib/xslfo/files.xsl +62 -0
- data/tools/rdoc/contrib/xslfo/labeled-lists.xsl +66 -0
- data/tools/rdoc/contrib/xslfo/lists.xsl +44 -0
- data/tools/rdoc/contrib/xslfo/modules.xsl +152 -0
- data/tools/rdoc/contrib/xslfo/rdoc.xsl +75 -0
- data/tools/rdoc/contrib/xslfo/source.xsl +66 -0
- data/tools/rdoc/contrib/xslfo/styles.xsl +69 -0
- data/tools/rdoc/contrib/xslfo/tables.xsl +67 -0
- data/tools/rdoc/contrib/xslfo/utils.xsl +21 -0
- data/tools/rdoc/debian/changelog +33 -0
- data/tools/rdoc/debian/compat +1 -0
- data/tools/rdoc/debian/control +20 -0
- data/tools/rdoc/debian/copyright +10 -0
- data/tools/rdoc/debian/dirs +2 -0
- data/tools/rdoc/debian/docs +2 -0
- data/tools/rdoc/debian/rdoc.1 +252 -0
- data/tools/rdoc/debian/rdoc.manpages +1 -0
- data/tools/rdoc/debian/rdoc.pod +149 -0
- data/tools/rdoc/debian/rules +9 -0
- data/tools/rdoc/dot/dot.rb +255 -0
- data/tools/rdoc/etc/rdoc.dtd +203 -0
- data/tools/rdoc/install.rb +137 -0
- data/tools/rdoc/markup/install.rb +43 -0
- data/tools/rdoc/markup/sample/sample.rb +42 -0
- data/tools/rdoc/markup/simple_markup/fragments.rb +323 -0
- data/tools/rdoc/markup/simple_markup/inline.rb +348 -0
- data/tools/rdoc/markup/simple_markup/lines.rb +147 -0
- data/tools/rdoc/markup/simple_markup/preprocess.rb +68 -0
- data/tools/rdoc/markup/simple_markup/to_html.rb +281 -0
- data/tools/rdoc/markup/simple_markup.rb +474 -0
- data/tools/rdoc/markup/test/AllTests.rb +2 -0
- data/tools/rdoc/markup/test/TestInline.rb +151 -0
- data/tools/rdoc/markup/test/TestParse.rb +411 -0
- data/tools/rdoc/rdoc/code_objects.rb +536 -0
- data/tools/rdoc/rdoc/diagram.rb +331 -0
- data/tools/rdoc/rdoc/generators/chm_generator.rb +112 -0
- data/tools/rdoc/rdoc/generators/html_generator.rb +1268 -0
- data/tools/rdoc/rdoc/generators/template/chm/chm.rb +86 -0
- data/tools/rdoc/rdoc/generators/template/html/html.rb +705 -0
- data/tools/rdoc/rdoc/generators/template/html/kilmer.rb +377 -0
- data/tools/rdoc/rdoc/generators/template/xml/rdf.rb +110 -0
- data/tools/rdoc/rdoc/generators/template/xml/xml.rb +110 -0
- data/tools/rdoc/rdoc/generators/xml_generator.rb +130 -0
- data/tools/rdoc/rdoc/options.rb +451 -0
- data/tools/rdoc/rdoc/parsers/parse_c.rb +287 -0
- data/tools/rdoc/rdoc/parsers/parse_f95.rb +118 -0
- data/tools/rdoc/rdoc/parsers/parse_rb.rb +2311 -0
- data/tools/rdoc/rdoc/parsers/parse_simple.rb +37 -0
- data/tools/rdoc/rdoc/parsers/parserfactory.rb +75 -0
- data/tools/rdoc/rdoc/rdoc.rb +219 -0
- data/tools/rdoc/rdoc/template.rb +234 -0
- data/tools/rdoc/rdoc/tokenstream.rb +25 -0
- data/tools/rdoc/rdoc.rb +9 -0
- metadata +291 -0
|
@@ -0,0 +1,1268 @@
|
|
|
1
|
+
# We're responsible for generating all the HTML files
|
|
2
|
+
# from the object tree defined in code_objects.rb. We
|
|
3
|
+
# generate:
|
|
4
|
+
#
|
|
5
|
+
# [files] an html file for each input file given. These
|
|
6
|
+
# input files appear as objects of class
|
|
7
|
+
# TopLevel
|
|
8
|
+
#
|
|
9
|
+
# [classes] an html file for each class or module encountered.
|
|
10
|
+
# These classes are not grouped by file: if a file
|
|
11
|
+
# contains four classes, we'll generate an html
|
|
12
|
+
# file for the file itself, and four html files
|
|
13
|
+
# for the individual classes.
|
|
14
|
+
#
|
|
15
|
+
# [indices] we generate three indices for files, classes,
|
|
16
|
+
# and methods. These are displayed in a browser
|
|
17
|
+
# like window with three index panes across the
|
|
18
|
+
# top and the selected description below
|
|
19
|
+
#
|
|
20
|
+
# Method descriptions appear in whatever entity (file, class,
|
|
21
|
+
# or module) that contains them.
|
|
22
|
+
#
|
|
23
|
+
# We generate files in a structure below a specified subdirectory,
|
|
24
|
+
# normally +doc+.
|
|
25
|
+
#
|
|
26
|
+
# opdir
|
|
27
|
+
# |
|
|
28
|
+
# |___ files
|
|
29
|
+
# | |__ per file summaries
|
|
30
|
+
# |
|
|
31
|
+
# |___ classes
|
|
32
|
+
# |__ per class/module descriptions
|
|
33
|
+
#
|
|
34
|
+
# HTML is generated using the Template class.
|
|
35
|
+
#
|
|
36
|
+
|
|
37
|
+
require 'ftools'
|
|
38
|
+
|
|
39
|
+
require 'rdoc/options'
|
|
40
|
+
require 'rdoc/template'
|
|
41
|
+
require 'markup/simple_markup'
|
|
42
|
+
require 'markup/simple_markup/to_html'
|
|
43
|
+
require 'cgi'
|
|
44
|
+
|
|
45
|
+
module Generators
|
|
46
|
+
|
|
47
|
+
# Name of sub-direcories that hold file and class/module descriptions
|
|
48
|
+
|
|
49
|
+
FILE_DIR = "files"
|
|
50
|
+
CLASS_DIR = "classes"
|
|
51
|
+
CSS_NAME = "rdoc-style.css"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Build a hash of all items that can be cross-referenced.
|
|
56
|
+
# This is used when we output required and included names:
|
|
57
|
+
# if the names appear in this hash, we can generate
|
|
58
|
+
# an html cross reference to the appropriate description.
|
|
59
|
+
# We also use this when parsing comment blocks: any decorated
|
|
60
|
+
# words matching an entry in this list are hyperlinked.
|
|
61
|
+
|
|
62
|
+
class AllReferences
|
|
63
|
+
@@refs = {}
|
|
64
|
+
|
|
65
|
+
def AllReferences::reset
|
|
66
|
+
@@refs = {}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def AllReferences.add(name, html_class)
|
|
70
|
+
@@refs[name] = html_class
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def AllReferences.[](name)
|
|
74
|
+
@@refs[name]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# Subclass of the SM::ToHtml class that supports looking
|
|
81
|
+
# up words in the AllReferences list. Those that are
|
|
82
|
+
# found (like AllReferences in this comment) will
|
|
83
|
+
# be hyperlinked
|
|
84
|
+
|
|
85
|
+
class HyperlinkHtml < SM::ToHtml
|
|
86
|
+
# We need to record the html path of our caller so we can generate
|
|
87
|
+
# correct relative paths for any hyperlinks that we find
|
|
88
|
+
def initialize(from_path, context)
|
|
89
|
+
super()
|
|
90
|
+
@from_path = from_path
|
|
91
|
+
|
|
92
|
+
@parent_name = context.parent_name
|
|
93
|
+
@parent_name += "::" if @parent_name
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# We're invoked when any text matches the CROSSREF pattern
|
|
97
|
+
# (defined in MarkUp). If we fine the corresponding reference,
|
|
98
|
+
# generate a hyperlink. If the name we're looking for contains
|
|
99
|
+
# no punctuation, we look for it up the module/class chain. For
|
|
100
|
+
# example, HyperlinkHtml is found, even without the Generators::
|
|
101
|
+
# prefix, because we look for it in module Generators first.
|
|
102
|
+
|
|
103
|
+
def handle_special_CROSSREF(special)
|
|
104
|
+
name = special.text
|
|
105
|
+
if name[0,1] == '#'
|
|
106
|
+
lookup = name[1..-1]
|
|
107
|
+
name = lookup unless Options.instance.show_hash
|
|
108
|
+
else
|
|
109
|
+
lookup = name
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
ref = nil
|
|
113
|
+
|
|
114
|
+
if @parent_name and lookup !~ /\.:/
|
|
115
|
+
ref = AllReferences[@parent_name + lookup]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
if !ref
|
|
119
|
+
ref = AllReferences[lookup]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
if ref and ref.document_self
|
|
123
|
+
"<a href=\"#{ref.as_href(@from_path)}\">#{name}</a>"
|
|
124
|
+
else
|
|
125
|
+
name
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# And we're invoked with a potential external hyperlink mailto:
|
|
130
|
+
# just gets inserted. http: links are checked to see if they
|
|
131
|
+
# reference an image. If so, that image gets inserted using an
|
|
132
|
+
# <img> tag. Otherwise a conventional <a href> is used. We also
|
|
133
|
+
# support a special type of hyperlink, link:, which is a reference
|
|
134
|
+
# to a local file whose path is relative to the --op directory.
|
|
135
|
+
|
|
136
|
+
def handle_special_HYPERLINK(special)
|
|
137
|
+
url = special.text
|
|
138
|
+
if url =~ /([A-Za-z]+):(.*)/
|
|
139
|
+
type = $1
|
|
140
|
+
path = $2
|
|
141
|
+
else
|
|
142
|
+
type = "http"
|
|
143
|
+
path = url
|
|
144
|
+
url = "http://#{url}"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
if type == "link"
|
|
148
|
+
if path[0,1] == '#' # is this meaningful?
|
|
149
|
+
url = path
|
|
150
|
+
else
|
|
151
|
+
url = HTMLGenerator.gen_url(@from_path, path)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if (type == "http" || type == "link") &&
|
|
156
|
+
url =~ /\.(gif|png|jpg|jpeg|bmp)$/
|
|
157
|
+
|
|
158
|
+
"<img src=\"#{url}\">"
|
|
159
|
+
else
|
|
160
|
+
"<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# HEre's a hypedlink where the label is different to the URL
|
|
165
|
+
# <label>[url]
|
|
166
|
+
#
|
|
167
|
+
|
|
168
|
+
def handle_special_TIDYLINK(special)
|
|
169
|
+
text = special.text
|
|
170
|
+
unless text =~ /(\S+)\[(.*?)\]/
|
|
171
|
+
return text
|
|
172
|
+
end
|
|
173
|
+
label = $1
|
|
174
|
+
url = $2
|
|
175
|
+
|
|
176
|
+
unless url =~ /\w+?:/
|
|
177
|
+
url = "http://#{url}"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
"<a href=\"#{url}\">#{label}</a>"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
#####################################################################
|
|
188
|
+
#
|
|
189
|
+
# Handle common markup tasks for the various Html classes
|
|
190
|
+
#
|
|
191
|
+
|
|
192
|
+
module MarkUp
|
|
193
|
+
|
|
194
|
+
# Convert a string in markup format into HTML. We keep a cached
|
|
195
|
+
# SimpleMarkup object lying around after the first time we're
|
|
196
|
+
# called per object.
|
|
197
|
+
|
|
198
|
+
def markup(str)
|
|
199
|
+
return '' unless str
|
|
200
|
+
unless defined? @markup
|
|
201
|
+
@markup = SM::SimpleMarkup.new
|
|
202
|
+
|
|
203
|
+
# class names, variable names, file names, or instance variables
|
|
204
|
+
@markup.add_special(/(
|
|
205
|
+
\b([A-Z]\w+(::\w+)*)
|
|
206
|
+
| \#\w+[!?=]?
|
|
207
|
+
| \b\w+([_\/\.]+\w+)+[!?=]?
|
|
208
|
+
)/x,
|
|
209
|
+
:CROSSREF)
|
|
210
|
+
|
|
211
|
+
# external hyperlinks
|
|
212
|
+
@markup.add_special(/((link:|http:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
|
|
213
|
+
|
|
214
|
+
# and links of the form <text>[<url>]
|
|
215
|
+
@markup.add_special(/\b(\S+?\[\S+?\.\S+?\])/, :TIDYLINK)
|
|
216
|
+
|
|
217
|
+
end
|
|
218
|
+
unless defined? @html_formatter
|
|
219
|
+
@html_formatter = HyperlinkHtml.new(self.path, self)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Convert leading comment markers to spaces, but only
|
|
223
|
+
# if all non-blank lines have them
|
|
224
|
+
|
|
225
|
+
if str =~ /^(?>\s*)[^\#]/
|
|
226
|
+
content = str
|
|
227
|
+
else
|
|
228
|
+
content = str.gsub(/^\s*(#+)/) { $1.tr('#',' ') }
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
@markup.convert(content, @html_formatter)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
#####################################################################
|
|
237
|
+
#
|
|
238
|
+
# A Context is built by the parser to represent a container: contexts
|
|
239
|
+
# hold classes, modules, methods, require lists and include lists.
|
|
240
|
+
# ClassModule and TopLevel are the context objects we process here
|
|
241
|
+
#
|
|
242
|
+
class ContextUser
|
|
243
|
+
|
|
244
|
+
include MarkUp
|
|
245
|
+
|
|
246
|
+
attr_reader :context
|
|
247
|
+
|
|
248
|
+
def initialize(context, options)
|
|
249
|
+
@context = context
|
|
250
|
+
@options = options
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# convenience method to build a hyperlink
|
|
254
|
+
def href(link, cls, name)
|
|
255
|
+
%{<a href="#{link}" class="#{cls}">#{name}</a>} #"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# return a reference to outselves to be used as an href=
|
|
259
|
+
# the form depends on whether we're all in one file
|
|
260
|
+
# or in multiple files
|
|
261
|
+
|
|
262
|
+
def as_href(from_path)
|
|
263
|
+
if @options.all_one_file
|
|
264
|
+
"#" + path
|
|
265
|
+
else
|
|
266
|
+
HTMLGenerator.gen_url(from_path, path)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Create a list of HtmlMethod objects for each method
|
|
271
|
+
# in the corresponding context object. If the @options.show_all
|
|
272
|
+
# variable is set (corresponding to the <tt>--all</tt> option,
|
|
273
|
+
# we include all methods, otherwise just the public ones.
|
|
274
|
+
|
|
275
|
+
def collect_methods
|
|
276
|
+
list = @context.method_list
|
|
277
|
+
unless @options.show_all
|
|
278
|
+
list = list.find_all {|m| m.visibility == :public || m.force_documentation }
|
|
279
|
+
end
|
|
280
|
+
@methods = list.collect {|m| HtmlMethod.new(m, self, @options) }
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Build a summary list of all the methods in this context
|
|
284
|
+
def build_method_summary_list(path_prefix="")
|
|
285
|
+
collect_methods unless @methods
|
|
286
|
+
meths = @methods.sort
|
|
287
|
+
res = []
|
|
288
|
+
meths.each do |meth|
|
|
289
|
+
res << {
|
|
290
|
+
"name" => CGI.escapeHTML(meth.name),
|
|
291
|
+
"aref" => "#{path_prefix}\##{meth.aref}"
|
|
292
|
+
}
|
|
293
|
+
end
|
|
294
|
+
res
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# Build a list of aliases fo which we couldn't find a corresponding method
|
|
299
|
+
def build_alias_summary_list
|
|
300
|
+
@context.aliases.map do |al|
|
|
301
|
+
{
|
|
302
|
+
'old_name' => al.old_name,
|
|
303
|
+
'new_name' => al.new_name,
|
|
304
|
+
}
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def build_requires_list(context)
|
|
309
|
+
potentially_referenced_list(context.requires) {|fn| [fn + ".rb"] }
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def build_include_list(context)
|
|
313
|
+
potentially_referenced_list(context.includes)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Build a list from an array of <i>Htmlxxx</i> items. Look up each
|
|
317
|
+
# in the AllReferences hash: if we find a corresponding entry,
|
|
318
|
+
# we generate a hyperlink to it, otherwise just output the name.
|
|
319
|
+
# However, some names potentially need massaging. For example,
|
|
320
|
+
# you may require a Ruby file without the .rb extension,
|
|
321
|
+
# but the file names we know about may have it. To deal with
|
|
322
|
+
# this, we pass in a block which performs the massaging,
|
|
323
|
+
# returning an array of alternative names to match
|
|
324
|
+
|
|
325
|
+
def potentially_referenced_list(array)
|
|
326
|
+
res = []
|
|
327
|
+
array.each do |i|
|
|
328
|
+
ref = AllReferences[i.name]
|
|
329
|
+
if !ref && block_given?
|
|
330
|
+
possibles = yield(i.name)
|
|
331
|
+
while !ref and !possibles.empty?
|
|
332
|
+
ref = AllReferences[possibles.shift]
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
h_name = CGI.escapeHTML(i.name)
|
|
336
|
+
if ref and ref.document_self
|
|
337
|
+
path = url(ref.path)
|
|
338
|
+
res << { "name" => h_name, "aref" => path }
|
|
339
|
+
else
|
|
340
|
+
res << { "name" => h_name }
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
res
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# Build an array of arrays of method details. The outer array has up
|
|
347
|
+
# to six entries, public, private, and protected for both class
|
|
348
|
+
# methods, the other for instance methods. The inner arrays contain
|
|
349
|
+
# a hash for each method
|
|
350
|
+
|
|
351
|
+
def build_method_detail_list
|
|
352
|
+
outer = []
|
|
353
|
+
|
|
354
|
+
for singleton in [true, false]
|
|
355
|
+
for vis in [ :public, :protected, :private ]
|
|
356
|
+
res = []
|
|
357
|
+
@methods.each do |m|
|
|
358
|
+
if m.document_self and m.visibility == vis and m.singleton == singleton
|
|
359
|
+
row = {}
|
|
360
|
+
row["name"] = CGI.escapeHTML(m.name)
|
|
361
|
+
desc = m.description.strip
|
|
362
|
+
row["m_desc"] = desc unless desc.empty?
|
|
363
|
+
row["params"] = m.params
|
|
364
|
+
row["aref"] = m.aref
|
|
365
|
+
row["visibility"] = m.visibility.to_s
|
|
366
|
+
|
|
367
|
+
unless m.aliases.empty?
|
|
368
|
+
row["aka"] = m.aliases.map do |other|
|
|
369
|
+
{
|
|
370
|
+
'name' => other.name,
|
|
371
|
+
'aref' => other.viewer.as_href(path)
|
|
372
|
+
}
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
if @options.inline_source
|
|
377
|
+
code = m.source_code
|
|
378
|
+
row["sourcecode"] = code if code
|
|
379
|
+
else
|
|
380
|
+
code = m.src_url
|
|
381
|
+
if code
|
|
382
|
+
row["codeurl"] = code
|
|
383
|
+
row["imgurl"] = m.img_url
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
res << row
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
if res.size > 0
|
|
390
|
+
outer << {
|
|
391
|
+
"type" => vis.to_s.capitalize,
|
|
392
|
+
"category" => singleton ? "Class" : "Instance",
|
|
393
|
+
"methods" => res
|
|
394
|
+
}
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
outer
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# Build the structured list of classes and modules contained
|
|
402
|
+
# in this context.
|
|
403
|
+
|
|
404
|
+
def build_class_list(level, from)
|
|
405
|
+
res = ""
|
|
406
|
+
prefix = " ::" * level;
|
|
407
|
+
|
|
408
|
+
from.modules.sort.each do |mod|
|
|
409
|
+
if mod.document_self
|
|
410
|
+
res <<
|
|
411
|
+
prefix <<
|
|
412
|
+
"Module " <<
|
|
413
|
+
href(url(mod.viewer.path), "link", mod.full_name) <<
|
|
414
|
+
"<br />\n" <<
|
|
415
|
+
build_class_list(level + 1, mod)
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
from.classes.sort.each do |cls|
|
|
420
|
+
if cls.document_self
|
|
421
|
+
res <<
|
|
422
|
+
prefix <<
|
|
423
|
+
"Class " <<
|
|
424
|
+
href(url(cls.viewer.path), "link", cls.full_name) <<
|
|
425
|
+
"<br />\n" <<
|
|
426
|
+
build_class_list(level + 1, cls)
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
res
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def url(target)
|
|
434
|
+
HTMLGenerator.gen_url(path, target)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def aref_to(target)
|
|
438
|
+
if @options.all_one_file
|
|
439
|
+
"#" + target
|
|
440
|
+
else
|
|
441
|
+
url(target)
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def document_self
|
|
446
|
+
@context.document_self
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def diagram_reference(diagram)
|
|
450
|
+
res = diagram.gsub(/((?:src|href)=")(.*?)"/) {
|
|
451
|
+
$1 + url($2) + '"'
|
|
452
|
+
}
|
|
453
|
+
res
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
#####################################################################
|
|
459
|
+
#
|
|
460
|
+
# Wrap a ClassModule context
|
|
461
|
+
|
|
462
|
+
class HtmlClass < ContextUser
|
|
463
|
+
|
|
464
|
+
attr_reader :path
|
|
465
|
+
|
|
466
|
+
def initialize(context, html_file, prefix, options)
|
|
467
|
+
super(context, options)
|
|
468
|
+
|
|
469
|
+
@html_file = html_file
|
|
470
|
+
@is_module = context.is_module?
|
|
471
|
+
@values = {}
|
|
472
|
+
|
|
473
|
+
context.viewer = self
|
|
474
|
+
|
|
475
|
+
if options.all_one_file
|
|
476
|
+
@path = context.full_name
|
|
477
|
+
else
|
|
478
|
+
@path = http_url(context.full_name, prefix)
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
collect_methods
|
|
482
|
+
|
|
483
|
+
AllReferences.add(name, self)
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
# return the relative file name to store this class in,
|
|
487
|
+
# which is also its url
|
|
488
|
+
def http_url(full_name, prefix)
|
|
489
|
+
path = full_name.dup
|
|
490
|
+
if path['<<']
|
|
491
|
+
path.gsub!(/<<\s*(\w*)/) { "from-#$1" }
|
|
492
|
+
end
|
|
493
|
+
File.join(prefix, path.split("::")) + ".html"
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def name
|
|
498
|
+
@context.full_name
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def parent_name
|
|
502
|
+
@context.parent.full_name
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def index_name
|
|
506
|
+
name
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def write_on(f)
|
|
510
|
+
value_hash
|
|
511
|
+
template = TemplatePage.new(RDoc::Page::BODY,
|
|
512
|
+
RDoc::Page::CLASS_PAGE,
|
|
513
|
+
RDoc::Page::METHOD_LIST)
|
|
514
|
+
template.write_html_on(f, @values)
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
def value_hash
|
|
518
|
+
class_attribute_values
|
|
519
|
+
|
|
520
|
+
@values["charset"] = @options.charset
|
|
521
|
+
@values["style_url"] = url(CSS_NAME)
|
|
522
|
+
|
|
523
|
+
d = markup(@context.comment)
|
|
524
|
+
@values["description"] = d unless d.empty?
|
|
525
|
+
|
|
526
|
+
ml = build_method_summary_list
|
|
527
|
+
@values["methods"] = ml unless ml.empty?
|
|
528
|
+
|
|
529
|
+
al = build_alias_summary_list
|
|
530
|
+
@values["aliases"] = al unless al.empty?
|
|
531
|
+
|
|
532
|
+
il = build_include_list(@context)
|
|
533
|
+
@values["includes"] = il unless il.empty?
|
|
534
|
+
|
|
535
|
+
al = build_attribute_list
|
|
536
|
+
@values["attributes"] = al unless al.empty?
|
|
537
|
+
|
|
538
|
+
cl = build_class_list(0, @context)
|
|
539
|
+
@values["classlist"] = cl unless cl.empty?
|
|
540
|
+
|
|
541
|
+
mdl = build_method_detail_list
|
|
542
|
+
@values["method_list"] = mdl unless mdl.empty?
|
|
543
|
+
@values
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
def build_attribute_list
|
|
547
|
+
atts = @context.attributes.sort
|
|
548
|
+
res = []
|
|
549
|
+
atts.each do |att|
|
|
550
|
+
res << {
|
|
551
|
+
"name" => CGI.escapeHTML(att.name),
|
|
552
|
+
"rw" => att.rw,
|
|
553
|
+
"a_desc" => markup(att.comment)
|
|
554
|
+
}
|
|
555
|
+
end
|
|
556
|
+
res
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def class_attribute_values
|
|
560
|
+
h_name = CGI.escapeHTML(name)
|
|
561
|
+
|
|
562
|
+
@values["classmod"] = @is_module ? "Module" : "Class"
|
|
563
|
+
@values["title"] = "#{@values['classmod']}: #{h_name}"
|
|
564
|
+
|
|
565
|
+
c = @context
|
|
566
|
+
c = c.parent while c and !c.diagram
|
|
567
|
+
if c && c.diagram
|
|
568
|
+
@values["diagram"] = diagram_reference(c.diagram)
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
@values["full_name"] = h_name
|
|
572
|
+
|
|
573
|
+
parent_class = @context.superclass
|
|
574
|
+
|
|
575
|
+
if parent_class
|
|
576
|
+
@values["parent"] = CGI.escapeHTML(parent_class)
|
|
577
|
+
|
|
578
|
+
if parent_name
|
|
579
|
+
lookup = parent_name + "::" + parent_class
|
|
580
|
+
else
|
|
581
|
+
lookup = parent_class
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
parent_url = AllReferences[lookup] || AllReferences[parent_class]
|
|
585
|
+
|
|
586
|
+
if parent_url and parent_url.document_self
|
|
587
|
+
@values["par_url"] = aref_to(parent_url.path)
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
files = []
|
|
592
|
+
@context.in_files.each do |f|
|
|
593
|
+
res = {}
|
|
594
|
+
res["full_path"] = CGI.escapeHTML(f.file_absolute_name)
|
|
595
|
+
res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
|
|
596
|
+
files << res
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
@values['infiles'] = files
|
|
600
|
+
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
def <=>(other)
|
|
604
|
+
self.name <=> other.name
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
#####################################################################
|
|
610
|
+
#
|
|
611
|
+
# Handles the mapping of a file's information to HTML. In reality,
|
|
612
|
+
# a file corresponds to a +TopLevel+ object, containing modules,
|
|
613
|
+
# classes, and top-level methods. In theory it _could_ contain
|
|
614
|
+
# attributes and aliases, but we ignore these for now.
|
|
615
|
+
|
|
616
|
+
class HtmlFile < ContextUser
|
|
617
|
+
|
|
618
|
+
attr_reader :path
|
|
619
|
+
attr_reader :name
|
|
620
|
+
|
|
621
|
+
def initialize(context, options, file_dir)
|
|
622
|
+
super(context, options)
|
|
623
|
+
|
|
624
|
+
@values = {}
|
|
625
|
+
|
|
626
|
+
if options.all_one_file
|
|
627
|
+
@path = filename_to_label
|
|
628
|
+
else
|
|
629
|
+
@path = http_url(file_dir)
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
@name = @context.file_relative_name
|
|
633
|
+
|
|
634
|
+
collect_methods
|
|
635
|
+
AllReferences.add(name, self)
|
|
636
|
+
context.viewer = self
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def http_url(file_dir)
|
|
640
|
+
File.join(file_dir, @context.file_relative_name.tr('.', '_')) +
|
|
641
|
+
".html"
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
def filename_to_label
|
|
645
|
+
@context.file_relative_name.gsub(/%|\/|\?|\#/) {|s| '%' + ("%x" % s[0]) }
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
def index_name
|
|
649
|
+
name
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def parent_name
|
|
653
|
+
nil
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
def value_hash
|
|
657
|
+
file_attribute_values
|
|
658
|
+
|
|
659
|
+
@values["charset"] = @options.charset
|
|
660
|
+
@values["href"] = path
|
|
661
|
+
@values["style_url"] = url(CSS_NAME)
|
|
662
|
+
|
|
663
|
+
if @context.comment
|
|
664
|
+
d = markup(@context.comment)
|
|
665
|
+
@values["description"] = d if d.size > 0
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
ml = build_method_summary_list
|
|
669
|
+
@values["methods"] = ml unless ml.empty?
|
|
670
|
+
|
|
671
|
+
il = build_include_list(@context)
|
|
672
|
+
@values["includes"] = il unless il.empty?
|
|
673
|
+
|
|
674
|
+
rl = build_requires_list(@context)
|
|
675
|
+
@values["requires"] = rl unless rl.empty?
|
|
676
|
+
|
|
677
|
+
cl = build_class_list(0, @context)
|
|
678
|
+
@values["classlist"] = cl unless cl.empty?
|
|
679
|
+
|
|
680
|
+
mdl = build_method_detail_list
|
|
681
|
+
@values["method_list"] = mdl unless mdl.empty?
|
|
682
|
+
@values
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
def write_on(f)
|
|
686
|
+
value_hash
|
|
687
|
+
template = TemplatePage.new(RDoc::Page::BODY,
|
|
688
|
+
RDoc::Page::FILE_PAGE,
|
|
689
|
+
RDoc::Page::METHOD_LIST)
|
|
690
|
+
template.write_html_on(f, @values)
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def file_attribute_values
|
|
694
|
+
full_path = @context.file_absolute_name
|
|
695
|
+
short_name = File.basename(full_path)
|
|
696
|
+
|
|
697
|
+
@values["title"] = CGI.escapeHTML("File: #{short_name}")
|
|
698
|
+
|
|
699
|
+
if @context.diagram
|
|
700
|
+
@values["diagram"] = diagram_reference(@context.diagram)
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
@values["short_name"] = CGI.escapeHTML(short_name)
|
|
704
|
+
@values["full_path"] = CGI.escapeHTML(full_path)
|
|
705
|
+
@values["dtm_modified"] = @context.file_stat.mtime.to_s
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
def <=>(other)
|
|
709
|
+
self.name <=> other.name
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
#####################################################################
|
|
714
|
+
|
|
715
|
+
class HtmlMethod
|
|
716
|
+
include MarkUp
|
|
717
|
+
|
|
718
|
+
attr_reader :context
|
|
719
|
+
attr_reader :src_url
|
|
720
|
+
attr_reader :img_url
|
|
721
|
+
attr_reader :source_code
|
|
722
|
+
|
|
723
|
+
@@seq = "M000000"
|
|
724
|
+
|
|
725
|
+
@@all_methods = []
|
|
726
|
+
|
|
727
|
+
def HtmlMethod::reset
|
|
728
|
+
@@all_methods = []
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
def initialize(context, html_class, options)
|
|
732
|
+
@context = context
|
|
733
|
+
@html_class = html_class
|
|
734
|
+
@options = options
|
|
735
|
+
@@seq = @@seq.succ
|
|
736
|
+
@seq = @@seq
|
|
737
|
+
@@all_methods << self
|
|
738
|
+
|
|
739
|
+
context.viewer = self
|
|
740
|
+
|
|
741
|
+
if (ts = @context.token_stream)
|
|
742
|
+
@source_code = markup_code(ts)
|
|
743
|
+
unless @options.inline_source
|
|
744
|
+
@src_url = create_source_code_file(@source_code)
|
|
745
|
+
@img_url = HTMLGenerator.gen_url(path, 'source.png')
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
AllReferences.add(name, self)
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
# return a reference to outselves to be used as an href=
|
|
753
|
+
# the form depends on whether we're all in one file
|
|
754
|
+
# or in multiple files
|
|
755
|
+
|
|
756
|
+
def as_href(from_path)
|
|
757
|
+
if @options.all_one_file
|
|
758
|
+
"#" + path
|
|
759
|
+
else
|
|
760
|
+
HTMLGenerator.gen_url(from_path, path)
|
|
761
|
+
end
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
def name
|
|
765
|
+
@context.name
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
def index_name
|
|
769
|
+
"#{@context.name} (#{@html_class.name})"
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
def parent_name
|
|
773
|
+
if @context.parent.parent
|
|
774
|
+
@context.parent.parent.full_name
|
|
775
|
+
else
|
|
776
|
+
nil
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def aref
|
|
781
|
+
@seq
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
def path
|
|
785
|
+
if @options.all_one_file
|
|
786
|
+
aref
|
|
787
|
+
else
|
|
788
|
+
@html_class.path + "#" + aref
|
|
789
|
+
end
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
def description
|
|
793
|
+
markup(@context.comment)
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
def visibility
|
|
797
|
+
@context.visibility
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
def singleton
|
|
801
|
+
@context.singleton
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
def params
|
|
805
|
+
p = @context.params.gsub(/\s*\#.*/, '')
|
|
806
|
+
p = p.tr("\n", " ").squeeze(" ")
|
|
807
|
+
p = "(" + p + ")" unless p[0] == ?(
|
|
808
|
+
|
|
809
|
+
if (block = @context.block_params)
|
|
810
|
+
block.gsub!(/\s*\#.*/, '')
|
|
811
|
+
block = block.tr("\n", " ").squeeze(" ")
|
|
812
|
+
if block[0] == ?(
|
|
813
|
+
block.sub!(/^\(/, '').sub!(/\)/, '')
|
|
814
|
+
end
|
|
815
|
+
p << " {|#{block}| ...}"
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
CGI.escapeHTML(p)
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
def create_source_code_file(code_body)
|
|
822
|
+
meth_path = @html_class.path.sub(/\.html$/, '.src')
|
|
823
|
+
File.makedirs(meth_path)
|
|
824
|
+
file_path = File.join(meth_path, @seq) + ".html"
|
|
825
|
+
|
|
826
|
+
template = TemplatePage.new(RDoc::Page::SRC_PAGE)
|
|
827
|
+
File.open(file_path, "w") do |f|
|
|
828
|
+
values = {
|
|
829
|
+
'title' => CGI.escapeHTML(index_name),
|
|
830
|
+
'code' => code_body,
|
|
831
|
+
'style_url' => HTMLGenerator.gen_url(file_path, CSS_NAME),
|
|
832
|
+
'charset' => @options.charset
|
|
833
|
+
}
|
|
834
|
+
template.write_html_on(f, values)
|
|
835
|
+
end
|
|
836
|
+
HTMLGenerator.gen_url(path, file_path)
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
def HtmlMethod.all_methods
|
|
840
|
+
@@all_methods
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
def <=>(other)
|
|
844
|
+
@context <=> other.context
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
##
|
|
848
|
+
# Given a sequence of source tokens, mark up the source code
|
|
849
|
+
# to make it look purty.
|
|
850
|
+
|
|
851
|
+
def markup_code(tokens)
|
|
852
|
+
src = ""
|
|
853
|
+
tokens.each do |t|
|
|
854
|
+
next unless t
|
|
855
|
+
# p t.class
|
|
856
|
+
style = nil
|
|
857
|
+
text = CGI.escapeHTML(t.text)
|
|
858
|
+
case t
|
|
859
|
+
when RubyToken::TkKW
|
|
860
|
+
style = "kw"
|
|
861
|
+
when RubyToken::TkCOMMENT
|
|
862
|
+
style = "cmt"
|
|
863
|
+
when RubyToken::TkSTRING
|
|
864
|
+
style = "str"
|
|
865
|
+
when RubyToken::TkREGEXP
|
|
866
|
+
style = "re"
|
|
867
|
+
end
|
|
868
|
+
if style
|
|
869
|
+
src << "<span class=\"#{style}\">#{text}</span>"
|
|
870
|
+
else
|
|
871
|
+
src << text
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
add_line_numbers(src) if Options.instance.include_line_numbers
|
|
876
|
+
src
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
# we rely on the fact that the first line of a source code
|
|
880
|
+
# listing has
|
|
881
|
+
# # File xxxxx, line dddd
|
|
882
|
+
|
|
883
|
+
def add_line_numbers(src)
|
|
884
|
+
if src =~ /\A.*, line (\d+)/
|
|
885
|
+
first = $1.to_i - 1
|
|
886
|
+
last = first + src.count("\n")
|
|
887
|
+
size = last.to_s.length
|
|
888
|
+
real_fmt = "%#{size}d: "
|
|
889
|
+
fmt = " " * (size+2)
|
|
890
|
+
src.gsub!(/^/) do
|
|
891
|
+
res = sprintf(fmt, first)
|
|
892
|
+
first += 1
|
|
893
|
+
fmt = real_fmt
|
|
894
|
+
res
|
|
895
|
+
end
|
|
896
|
+
end
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
def document_self
|
|
900
|
+
@context.document_self
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
def aliases
|
|
904
|
+
@context.aliases
|
|
905
|
+
end
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
#####################################################################
|
|
909
|
+
|
|
910
|
+
class HTMLGenerator
|
|
911
|
+
|
|
912
|
+
include MarkUp
|
|
913
|
+
|
|
914
|
+
##
|
|
915
|
+
# convert a target url to one that is relative to a given
|
|
916
|
+
# path
|
|
917
|
+
|
|
918
|
+
def HTMLGenerator.gen_url(path, target)
|
|
919
|
+
from = File.dirname(path)
|
|
920
|
+
to, to_file = File.split(target)
|
|
921
|
+
|
|
922
|
+
from = from.split("/")
|
|
923
|
+
to = to.split("/")
|
|
924
|
+
|
|
925
|
+
while from.size > 0 and to.size > 0 and from[0] == to[0]
|
|
926
|
+
from.shift
|
|
927
|
+
to.shift
|
|
928
|
+
end
|
|
929
|
+
|
|
930
|
+
from.fill("..")
|
|
931
|
+
from.concat(to)
|
|
932
|
+
from << to_file
|
|
933
|
+
File.join(*from)
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
# Generators may need to return specific subclasses depending
|
|
937
|
+
# on the options they are passed. Because of this
|
|
938
|
+
# we create them using a factory
|
|
939
|
+
|
|
940
|
+
def HTMLGenerator.for(options)
|
|
941
|
+
AllReferences::reset
|
|
942
|
+
HtmlMethod::reset
|
|
943
|
+
|
|
944
|
+
if options.all_one_file
|
|
945
|
+
HTMLGeneratorInOne.new(options)
|
|
946
|
+
else
|
|
947
|
+
HTMLGenerator.new(options)
|
|
948
|
+
end
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
class <<self
|
|
952
|
+
protected :new
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
# Set up a new HTML generator. Basically all we do here is load
|
|
956
|
+
# up the correct output temlate
|
|
957
|
+
|
|
958
|
+
def initialize(options) #:not-new:
|
|
959
|
+
@options = options
|
|
960
|
+
load_html_template
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
##
|
|
965
|
+
# Build the initial indices and output objects
|
|
966
|
+
# based on an array of TopLevel objects containing
|
|
967
|
+
# the extracted information.
|
|
968
|
+
|
|
969
|
+
def generate(info)
|
|
970
|
+
@info = info
|
|
971
|
+
@files = []
|
|
972
|
+
@classes = []
|
|
973
|
+
@hyperlinks = {}
|
|
974
|
+
|
|
975
|
+
# write_source_icon
|
|
976
|
+
write_style_sheet
|
|
977
|
+
gen_sub_directories()
|
|
978
|
+
build_indices
|
|
979
|
+
generate_html
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
private
|
|
983
|
+
|
|
984
|
+
##
|
|
985
|
+
# Load up the HTML template specified in the options
|
|
986
|
+
#
|
|
987
|
+
def load_html_template
|
|
988
|
+
template = File.join("rdoc/generators/template",
|
|
989
|
+
@options.generator.key, @options.template)
|
|
990
|
+
require template
|
|
991
|
+
extend RDoc::Page
|
|
992
|
+
rescue LoadError
|
|
993
|
+
$stderr.puts "Could not find HTML template '#{template}'"
|
|
994
|
+
exit 99
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
##
|
|
998
|
+
# Write out the style sheet used by the main frames
|
|
999
|
+
#
|
|
1000
|
+
|
|
1001
|
+
def write_style_sheet
|
|
1002
|
+
template = TemplatePage.new(RDoc::Page::STYLE)
|
|
1003
|
+
File.open(CSS_NAME, "w") do |f|
|
|
1004
|
+
values = { "fonts" => RDoc::Page::FONTS }
|
|
1005
|
+
template.write_html_on(f, values)
|
|
1006
|
+
end
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
##
|
|
1010
|
+
# See the comments at the top for a description of the
|
|
1011
|
+
# directory structure
|
|
1012
|
+
|
|
1013
|
+
def gen_sub_directories
|
|
1014
|
+
File.makedirs(FILE_DIR, CLASS_DIR)
|
|
1015
|
+
rescue
|
|
1016
|
+
$stderr.puts $!.message
|
|
1017
|
+
exit 1
|
|
1018
|
+
end
|
|
1019
|
+
|
|
1020
|
+
##
|
|
1021
|
+
# Generate:
|
|
1022
|
+
#
|
|
1023
|
+
# * a list of HtmlFile objects for each TopLevel object.
|
|
1024
|
+
# * a list of HtmlClass objects for each first level
|
|
1025
|
+
# class or module in the TopLevel objects
|
|
1026
|
+
# * a complete list of all hyperlinkable terms (file,
|
|
1027
|
+
# class, module, and method names)
|
|
1028
|
+
|
|
1029
|
+
def build_indices
|
|
1030
|
+
|
|
1031
|
+
@info.each do |toplevel|
|
|
1032
|
+
@files << HtmlFile.new(toplevel, @options, FILE_DIR)
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
RDoc::TopLevel.all_classes_and_modules.each do |cls|
|
|
1036
|
+
build_class_list(cls, @files[0], CLASS_DIR)
|
|
1037
|
+
end
|
|
1038
|
+
end
|
|
1039
|
+
|
|
1040
|
+
def build_class_list(from, html_file, class_dir)
|
|
1041
|
+
@classes << HtmlClass.new(from, html_file, class_dir, @options)
|
|
1042
|
+
from.each_classmodule do |mod|
|
|
1043
|
+
build_class_list(mod, html_file, class_dir)
|
|
1044
|
+
end
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1047
|
+
##
|
|
1048
|
+
# Generate all the HTML
|
|
1049
|
+
#
|
|
1050
|
+
def generate_html
|
|
1051
|
+
# the individual descriptions for files and classes
|
|
1052
|
+
gen_into(@files)
|
|
1053
|
+
gen_into(@classes)
|
|
1054
|
+
# and the index files
|
|
1055
|
+
gen_file_index
|
|
1056
|
+
gen_class_index
|
|
1057
|
+
gen_method_index
|
|
1058
|
+
gen_main_index
|
|
1059
|
+
|
|
1060
|
+
# this method is defined in the template file
|
|
1061
|
+
write_extra_pages if defined? write_extra_pages
|
|
1062
|
+
end
|
|
1063
|
+
|
|
1064
|
+
def gen_into(list)
|
|
1065
|
+
list.each do |item|
|
|
1066
|
+
if item.document_self
|
|
1067
|
+
op_file = item.path
|
|
1068
|
+
File.makedirs(File.dirname(op_file))
|
|
1069
|
+
File.open(op_file, "w") { |file| item.write_on(file) }
|
|
1070
|
+
end
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
def gen_file_index
|
|
1076
|
+
gen_an_index(@files, 'Files',
|
|
1077
|
+
RDoc::Page::FILE_INDEX,
|
|
1078
|
+
"fr_file_index.html")
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
def gen_class_index
|
|
1082
|
+
gen_an_index(@classes, 'Classes',
|
|
1083
|
+
RDoc::Page::CLASS_INDEX,
|
|
1084
|
+
"fr_class_index.html")
|
|
1085
|
+
end
|
|
1086
|
+
|
|
1087
|
+
def gen_method_index
|
|
1088
|
+
gen_an_index(HtmlMethod.all_methods, 'Methods',
|
|
1089
|
+
RDoc::Page::METHOD_INDEX,
|
|
1090
|
+
"fr_method_index.html")
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
def gen_an_index(collection, title, template, filename)
|
|
1095
|
+
template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
|
|
1096
|
+
res = []
|
|
1097
|
+
collection.sort.each do |f|
|
|
1098
|
+
if f.document_self
|
|
1099
|
+
res << { "href" => f.path, "name" => f.index_name }
|
|
1100
|
+
end
|
|
1101
|
+
end
|
|
1102
|
+
|
|
1103
|
+
values = {
|
|
1104
|
+
"entries" => res,
|
|
1105
|
+
'list_title' => CGI.escapeHTML(title),
|
|
1106
|
+
'index_url' => main_url,
|
|
1107
|
+
'charset' => @options.charset
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
File.open(filename, "w") do |f|
|
|
1111
|
+
template.write_html_on(f, values)
|
|
1112
|
+
end
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1115
|
+
# The main index page is mostly a template frameset, but includes
|
|
1116
|
+
# the initial page. If the <tt>--main</tt> option was given,
|
|
1117
|
+
# we use this as our main page, otherwise we use the
|
|
1118
|
+
# first file specified on the command line.
|
|
1119
|
+
|
|
1120
|
+
def gen_main_index
|
|
1121
|
+
template = TemplatePage.new(RDoc::Page::INDEX)
|
|
1122
|
+
File.open("index.html", "w") do |f|
|
|
1123
|
+
values = {
|
|
1124
|
+
"initial_page" => main_url,
|
|
1125
|
+
'title' => CGI.escapeHTML(@options.title),
|
|
1126
|
+
'charset' => @options.charset
|
|
1127
|
+
}
|
|
1128
|
+
template.write_html_on(f, values)
|
|
1129
|
+
end
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
# return the url of the main page
|
|
1133
|
+
def main_url
|
|
1134
|
+
main_page = @options.main_page
|
|
1135
|
+
ref = nil
|
|
1136
|
+
if main_page
|
|
1137
|
+
ref = AllReferences[main_page]
|
|
1138
|
+
if ref
|
|
1139
|
+
ref = ref.path
|
|
1140
|
+
else
|
|
1141
|
+
$stderr.puts "Could not find main page #{main_page}"
|
|
1142
|
+
end
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
ref = @files[0].path unless ref
|
|
1146
|
+
|
|
1147
|
+
ref
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
|
|
1154
|
+
######################################################################
|
|
1155
|
+
|
|
1156
|
+
|
|
1157
|
+
class HTMLGeneratorInOne < HTMLGenerator
|
|
1158
|
+
|
|
1159
|
+
def initialize(*args)
|
|
1160
|
+
super
|
|
1161
|
+
end
|
|
1162
|
+
|
|
1163
|
+
##
|
|
1164
|
+
# Build the initial indices and output objects
|
|
1165
|
+
# based on an array of TopLevel objects containing
|
|
1166
|
+
# the extracted information.
|
|
1167
|
+
|
|
1168
|
+
def generate(info)
|
|
1169
|
+
@info = info
|
|
1170
|
+
@files = []
|
|
1171
|
+
@classes = []
|
|
1172
|
+
@hyperlinks = {}
|
|
1173
|
+
|
|
1174
|
+
build_indices
|
|
1175
|
+
generate_xml
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
##
|
|
1180
|
+
# Generate:
|
|
1181
|
+
#
|
|
1182
|
+
# * a list of HtmlFile objects for each TopLevel object.
|
|
1183
|
+
# * a list of HtmlClass objects for each first level
|
|
1184
|
+
# class or module in the TopLevel objects
|
|
1185
|
+
# * a complete list of all hyperlinkable terms (file,
|
|
1186
|
+
# class, module, and method names)
|
|
1187
|
+
|
|
1188
|
+
def build_indices
|
|
1189
|
+
|
|
1190
|
+
@info.each do |toplevel|
|
|
1191
|
+
@files << HtmlFile.new(toplevel, @options, FILE_DIR)
|
|
1192
|
+
end
|
|
1193
|
+
|
|
1194
|
+
RDoc::TopLevel.all_classes_and_modules.each do |cls|
|
|
1195
|
+
build_class_list(cls, @files[0], CLASS_DIR)
|
|
1196
|
+
end
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1199
|
+
def build_class_list(from, html_file, class_dir)
|
|
1200
|
+
@classes << HtmlClass.new(from, html_file, class_dir, @options)
|
|
1201
|
+
from.each_classmodule do |mod|
|
|
1202
|
+
build_class_list(mod, html_file, class_dir)
|
|
1203
|
+
end
|
|
1204
|
+
end
|
|
1205
|
+
|
|
1206
|
+
##
|
|
1207
|
+
# Generate all the HTML. For the one-file case, we generate
|
|
1208
|
+
# all the information in to one big hash
|
|
1209
|
+
#
|
|
1210
|
+
def generate_xml
|
|
1211
|
+
values = {
|
|
1212
|
+
'charset' => @options.charset,
|
|
1213
|
+
'files' => gen_into(@files),
|
|
1214
|
+
'classes' => gen_into(@classes),
|
|
1215
|
+
'title' => CGI.escapeHTML(@options.title),
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
# this method is defined in the template file
|
|
1219
|
+
write_extra_pages if defined? write_extra_pages
|
|
1220
|
+
|
|
1221
|
+
template = TemplatePage.new(RDoc::Page::ONE_PAGE)
|
|
1222
|
+
|
|
1223
|
+
if @options.op_name
|
|
1224
|
+
opfile = File.open(@options.op_name, "w")
|
|
1225
|
+
else
|
|
1226
|
+
opfile = $stdout
|
|
1227
|
+
end
|
|
1228
|
+
template.write_html_on(opfile, values)
|
|
1229
|
+
end
|
|
1230
|
+
|
|
1231
|
+
def gen_into(list)
|
|
1232
|
+
res = []
|
|
1233
|
+
list.each do |item|
|
|
1234
|
+
res << item.value_hash
|
|
1235
|
+
end
|
|
1236
|
+
res
|
|
1237
|
+
end
|
|
1238
|
+
|
|
1239
|
+
def gen_file_index
|
|
1240
|
+
gen_an_index(@files, 'Files')
|
|
1241
|
+
end
|
|
1242
|
+
|
|
1243
|
+
def gen_class_index
|
|
1244
|
+
gen_an_index(@classes, 'Classes')
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
def gen_method_index
|
|
1248
|
+
gen_an_index(HtmlMethod.all_methods, 'Methods')
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
def gen_an_index(collection, title)
|
|
1253
|
+
res = []
|
|
1254
|
+
collection.sort.each do |f|
|
|
1255
|
+
if f.document_self
|
|
1256
|
+
res << { "href" => f.path, "name" => f.index_name }
|
|
1257
|
+
end
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
return {
|
|
1261
|
+
"entries" => res,
|
|
1262
|
+
'list_title' => title,
|
|
1263
|
+
'index_url' => main_url,
|
|
1264
|
+
}
|
|
1265
|
+
end
|
|
1266
|
+
|
|
1267
|
+
end
|
|
1268
|
+
end
|