yard 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- data/LICENSE.txt +22 -0
- data/README.pdf +0 -0
- data/bin/yardoc +73 -0
- data/bin/yri +4 -0
- data/lib/code_object.rb +340 -0
- data/lib/formatter.rb +78 -0
- data/lib/handlers/all_handlers.rb +2 -0
- data/lib/handlers/attribute_handler.rb +46 -0
- data/lib/handlers/class_handler.rb +29 -0
- data/lib/handlers/class_variable_handler.rb +9 -0
- data/lib/handlers/code_object_handler.rb +104 -0
- data/lib/handlers/constant_handler.rb +11 -0
- data/lib/handlers/exception_handler.rb +20 -0
- data/lib/handlers/method_handler.rb +27 -0
- data/lib/handlers/mixin_handler.rb +9 -0
- data/lib/handlers/module_handler.rb +9 -0
- data/lib/handlers/visibility_handler.rb +7 -0
- data/lib/handlers/yield_handler.rb +31 -0
- data/lib/namespace.rb +98 -0
- data/lib/quick_doc.rb +104 -0
- data/lib/ruby_lex.rb +1318 -0
- data/lib/source_parser.rb +246 -0
- data/lib/tag_library.rb +162 -0
- data/lib/tag_type.rb +155 -0
- data/lib/yard.rb +3 -0
- data/templates/html_formatter.erb +455 -0
- data/test/fixtures/docstring.txt +23 -0
- data/test/fixtures/docstring2.txt +4 -0
- data/test/test_code_object.rb +66 -0
- data/test/test_namespace.rb +10 -0
- metadata +78 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2007 Loren Segal
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.pdf
ADDED
Binary file
|
data/bin/yardoc
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require File.dirname(__FILE__) + '/../lib/yard'
|
3
|
+
include YARD
|
4
|
+
|
5
|
+
if ARGV[0] == "-h"
|
6
|
+
puts "yardoc 0.2.0"
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
Dir.mkdir("doc") unless FileTest.directory?("doc")
|
11
|
+
Namespace.load(Namespace::DEFAULT_YARDOC_FILE, true)
|
12
|
+
ac = File.open("doc/all-classes.html", "w")
|
13
|
+
ac.puts <<-eof
|
14
|
+
<html>
|
15
|
+
<head>
|
16
|
+
<base target="main" />
|
17
|
+
</head>
|
18
|
+
<body>
|
19
|
+
<h3>All Classes</h3>
|
20
|
+
eof
|
21
|
+
meths = []
|
22
|
+
Namespace.all.sort.each do |path|
|
23
|
+
object = Namespace.at(path)
|
24
|
+
if object.is_a?(MethodObject) && object.visibility == :public
|
25
|
+
meths << [object.name, object]
|
26
|
+
end
|
27
|
+
|
28
|
+
next unless object.is_a? ClassObject
|
29
|
+
ac.puts "<a href='" + path.gsub("::","_") + ".html'>" + path + "</a><br />"
|
30
|
+
File.open("doc/#{path.gsub('::','_')}.html", "w") {|f| f.write(object.format) }
|
31
|
+
end
|
32
|
+
ac.puts "</body></html>"
|
33
|
+
ac.close
|
34
|
+
|
35
|
+
File.open("doc/all-methods.html", "w") do |f|
|
36
|
+
f.puts <<-eof
|
37
|
+
<html>
|
38
|
+
<head>
|
39
|
+
<base target="main" />
|
40
|
+
</head>
|
41
|
+
<body>
|
42
|
+
<h3>All Methods</h3>
|
43
|
+
eof
|
44
|
+
meths.sort {|a,b| a.first <=> b.first }.each do |name, object|
|
45
|
+
f.puts "<a href='" + object.parent.path.gsub("::", "_") + ".html##{object.scope}_method-#{name}'>#{name}</a><br />"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if ARGV[0]
|
50
|
+
main_page = ARGV[0]
|
51
|
+
else
|
52
|
+
main_page = Namespace.all.sort.find {|name| Namespace.at(name).is_a? YARD::ClassObject }
|
53
|
+
end
|
54
|
+
main_page = main_page.gsub("::", "_") + ".html"
|
55
|
+
File.open("doc/index.html", "w") do |f|
|
56
|
+
f.puts <<-eof
|
57
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
58
|
+
"http://www.w3.org/TR/html4/loose.dtd">
|
59
|
+
<html>
|
60
|
+
<head>
|
61
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
62
|
+
<title>Ruby Classes</title>
|
63
|
+
</head>
|
64
|
+
<frameset cols="250,*">
|
65
|
+
<frameset rows="*,40%">
|
66
|
+
<frame src="all-classes.html">
|
67
|
+
<frame src="all-methods.html">
|
68
|
+
</frameset>
|
69
|
+
<frame name="main" src="#{main_page}">
|
70
|
+
</frameset>
|
71
|
+
</html>
|
72
|
+
eof
|
73
|
+
end
|
data/bin/yri
ADDED
data/lib/code_object.rb
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/tag_library'
|
2
|
+
require File.dirname(__FILE__) + '/formatter'
|
3
|
+
|
4
|
+
module YARD #:nodoc:
|
5
|
+
##
|
6
|
+
# The documentation parser is responsible for parsing the docstring into
|
7
|
+
# text and saving the meta tags attached to it
|
8
|
+
#
|
9
|
+
# @author Loren Segal
|
10
|
+
class CodeObject
|
11
|
+
attr_reader :source, :full_source, :file, :line, :docstring, :attributes
|
12
|
+
|
13
|
+
attr_reader :name, :type
|
14
|
+
attr_accessor :visibility, :scope
|
15
|
+
attr_accessor :parent, :children
|
16
|
+
|
17
|
+
##
|
18
|
+
# Creates a new code object with necessary information such as the object's name (not full path),
|
19
|
+
# it's type (:class, :module, :method, etc.), visibility (:public, :private, :protected) and scope
|
20
|
+
# (:instance or :class level). Optionally you can specify a parent object and comments too, but these
|
21
|
+
# can also be assigned later through the {#parent=} and {#attach_docstring} methods.
|
22
|
+
#
|
23
|
+
# @param [String] name the name of the object, not including its namespace ('initialize' for this method)
|
24
|
+
# @param [Symbol] type the type of object this is, including (but not limited to):
|
25
|
+
# :module, :class, :method, :constant
|
26
|
+
# @param [Symbol] visibility :public, :protected or :private depending on the visibility of the object
|
27
|
+
# @param [Symbol] scope :instance or :class depending on if the object is instance level or class level.
|
28
|
+
# Instance level objects use the '#' character to separate from their parent instead of '::'
|
29
|
+
# @param [CodeObject] parent The parent of this object. Without a parent this object will not be registered
|
30
|
+
# in the {Namespace}
|
31
|
+
# @param [String] comments Comments to be parsed as a docstring for the object.
|
32
|
+
# @return [CodeObject] the created code object
|
33
|
+
# @yieldparam [CodeObject] _self the object is yielded during initialization to perform any initialization operations
|
34
|
+
# on it more conveniently.
|
35
|
+
# @see #attach_docstring
|
36
|
+
# @see #parent=
|
37
|
+
def initialize(name, type, visibility = :public, scope = :instance, parent = nil, comments = nil)
|
38
|
+
@name, @type, @visibility, @scope = name, type, visibility.to_sym, scope.to_sym
|
39
|
+
@tags, @attributes, @children = [], {}, []
|
40
|
+
self.parent = parent
|
41
|
+
attach_docstring(comments)
|
42
|
+
yield(self) if block_given?
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"#{visibility} #{type} #{path}"
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Attaches source code to a code object with an optional file location
|
51
|
+
#
|
52
|
+
# @param [Statement, String] statement the +Statement+ holding the source code
|
53
|
+
# or the raw source as a +String+ for the
|
54
|
+
# definition of the code object only (not the block)
|
55
|
+
# @param [String] file the filename the source resides in
|
56
|
+
def attach_source(statement, file = nil)
|
57
|
+
if statement.is_a? String
|
58
|
+
@source = statement
|
59
|
+
else
|
60
|
+
@source = statement.tokens.to_s
|
61
|
+
@line = statement.tokens.first.line_no
|
62
|
+
attach_full_source statement.tokens.to_s + (statement.block.to_s rescue "")
|
63
|
+
end
|
64
|
+
@file = file
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Manually attaches full source code for an object given the source
|
69
|
+
# as a +String+
|
70
|
+
#
|
71
|
+
# @param [String] source the source code for the object
|
72
|
+
def attach_full_source(source)
|
73
|
+
@full_source = source
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Attaches a docstring to a code oject by parsing the comments attached to the statement
|
78
|
+
# and filling the {#tags} and {#docstring} methods with the parsed information.
|
79
|
+
#
|
80
|
+
# @param [String, Array<String>] comments the comments attached to the code object to be
|
81
|
+
# parsed into a docstring and meta tags.
|
82
|
+
def attach_docstring(comments)
|
83
|
+
parse_comments(comments) if comments
|
84
|
+
end
|
85
|
+
|
86
|
+
def [](key)
|
87
|
+
@attributes[key.to_sym]
|
88
|
+
end
|
89
|
+
|
90
|
+
def []=(key, value)
|
91
|
+
@attributes[key.to_sym] = value
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Sets the parent object and registers the object path with
|
96
|
+
# the {Namespace}. If the object was already registered
|
97
|
+
# to an old path, it will be removed from the namespace.
|
98
|
+
#
|
99
|
+
# @param [CodeObject] value the new parent object
|
100
|
+
# @see Namespace
|
101
|
+
def parent=(value)
|
102
|
+
# Delete old object path if there was one
|
103
|
+
Namespace.instance.namespace.delete(path) if parent
|
104
|
+
|
105
|
+
@parent = value
|
106
|
+
|
107
|
+
# Register new path with namespace
|
108
|
+
Namespace.add_object(self) if value
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# See if the method call exists in the attributes hash, and return
|
113
|
+
# it. Otherwise send the missing method call up the stack.
|
114
|
+
#
|
115
|
+
# @param meth the method name called. This method is checked in the
|
116
|
+
# attributes hash
|
117
|
+
# @param args the arguments to the call
|
118
|
+
# @param block an optional block for the call
|
119
|
+
def method_missing(meth, *args, &block)
|
120
|
+
return self[meth] if self[meth]
|
121
|
+
super
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Returns the unique path for this code object. The resulting path will be
|
126
|
+
# a Ruby style path name of the namespace the object resides in plus the
|
127
|
+
# object name delimited by a "::" or "#" depending on if the object is an
|
128
|
+
# instance level object or a class level object.
|
129
|
+
#
|
130
|
+
# Example:
|
131
|
+
#
|
132
|
+
#
|
133
|
+
#
|
134
|
+
def path
|
135
|
+
[(parent.path if parent && parent.type != :root), name].join(scope == :instance ? "#" : "::").gsub(/^::/, '')
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Convenience method to return the first tag
|
140
|
+
# object in the list of tag objects of that name
|
141
|
+
#
|
142
|
+
# Example:
|
143
|
+
# doc = YARD::Documentation.new("@return zero when nil")
|
144
|
+
# doc.tag("return").text # => "zero when nil"
|
145
|
+
#
|
146
|
+
# @param [#to_s] name the tag name to return data for
|
147
|
+
# @return [BaseTag] the first tag in the list of {#tags}
|
148
|
+
def tag(name)
|
149
|
+
name = name.to_s
|
150
|
+
@tags.find {|tag| tag.tag_name == name }
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Returns a list of tags specified by +name+ or all tags if +name+ is not specified.
|
155
|
+
#
|
156
|
+
# @param name the tag name to return data for, or nil for all tags
|
157
|
+
# @return [Array<BaseTag>] the list of tags by the specified tag name
|
158
|
+
def tags(name = nil)
|
159
|
+
return @tags if name.nil?
|
160
|
+
name = name.to_s
|
161
|
+
@tags.select {|tag| tag.tag_name == name }
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Returns true if at least one tag by the name +name+ was declared
|
166
|
+
#
|
167
|
+
# @param [String] name the tag name to search for
|
168
|
+
# @return [Boolean] whether or not the tag +name+ was declared
|
169
|
+
def has_tag?(name)
|
170
|
+
name = name.to_s
|
171
|
+
@tags.any? {|tag| tag.tag_name == name }
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# Returns a code object formatted as a given type, defaults to html.
|
176
|
+
#
|
177
|
+
# @param [Symbol] format the output format to generate
|
178
|
+
# @return [String] the code object formatted by the specified +format+
|
179
|
+
def format(type = :html)
|
180
|
+
Formatter.new.format(self, type)
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
##
|
185
|
+
# Parses out comments split by newlines into a new code object
|
186
|
+
#
|
187
|
+
# @param [Array<String>, String] comments the newline delimited
|
188
|
+
# array of comments. If the comments
|
189
|
+
# are passed as a String, they will
|
190
|
+
# be split by newlines.
|
191
|
+
def parse_comments(comments)
|
192
|
+
return if comments.empty?
|
193
|
+
meta_match = /^\s*@(\S+)\s*(.*)/
|
194
|
+
comments = comments.split(/\r?\n/) if comments.is_a? String
|
195
|
+
@tags, @docstring = [], ""
|
196
|
+
|
197
|
+
indent, last_indent = comments.first[/^\s*/].length, 0
|
198
|
+
tag_name, tag_klass, tag_buf = nil, nil, ""
|
199
|
+
|
200
|
+
# Add an extra line to catch a meta directive on the last line
|
201
|
+
(comments+['']).each do |line|
|
202
|
+
indent = line[/^\s*/].length
|
203
|
+
|
204
|
+
if (indent < last_indent && tag_name) || line == '' || line =~ meta_match
|
205
|
+
tag_method = "#{tag_name}_tag"
|
206
|
+
if tag_name && TagLibrary.respond_to?(tag_method)
|
207
|
+
@tags << TagLibrary.send(tag_method, tag_buf.squeeze(" "))
|
208
|
+
end
|
209
|
+
tag_name, tag_buf = nil, ''
|
210
|
+
end
|
211
|
+
|
212
|
+
# Found a meta tag
|
213
|
+
if line =~ meta_match
|
214
|
+
tag_name, tag_buf = $1, $2
|
215
|
+
elsif indent >= last_indent && tag_name
|
216
|
+
# Extra data added to the tag on the next line
|
217
|
+
tag_buf << line
|
218
|
+
else
|
219
|
+
# Regular docstring text
|
220
|
+
@docstring << line << "\n"
|
221
|
+
end
|
222
|
+
|
223
|
+
last_indent = indent
|
224
|
+
end
|
225
|
+
|
226
|
+
# Remove trailing/leading whitespace / newlines
|
227
|
+
@docstring.gsub!(/\A[\r\n\s]+|[\r\n\s]+\Z/, '')
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
class CodeObjectWithMethods < CodeObject
|
232
|
+
def initialize(name, type, parent = nil, comments = nil)
|
233
|
+
super(name, type, :public, :class, parent, comments) do |obj|
|
234
|
+
obj[:instance_methods] = {}
|
235
|
+
obj[:class_methods] = {}
|
236
|
+
obj[:constants] = {}
|
237
|
+
obj[:class_variables] = {}
|
238
|
+
obj[:mixins] = []
|
239
|
+
yield(obj) if block_given?
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def inherited_class_methods
|
244
|
+
inherited_methods(:class)
|
245
|
+
end
|
246
|
+
|
247
|
+
def inherited_instance_methods
|
248
|
+
inherited_methods(:instance)
|
249
|
+
end
|
250
|
+
|
251
|
+
def inherited_methods(scopes = [:class, :instance])
|
252
|
+
[scopes].flatten.each do |scope|
|
253
|
+
full_mixins.inject({}) {|hash, mixin| hash.update(mixin.send(scope + "_methods")) }
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def full_mixins
|
258
|
+
mixins.collect {|mixin| Namespace.find_from_path(self, mixin).path rescue mixin }
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
class ModuleObject < CodeObjectWithMethods
|
263
|
+
def initialize(name, *args)
|
264
|
+
super(name, :module, *args) do |obj|
|
265
|
+
yield(obj) if block_given?
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
class ClassObject < CodeObjectWithMethods
|
271
|
+
BASE_OBJECT = "Object"
|
272
|
+
|
273
|
+
def initialize(name, superclass = BASE_OBJECT, *args)
|
274
|
+
super(name, :class, *args) do |obj|
|
275
|
+
obj[:attributes] = {}
|
276
|
+
obj[:superclass] = superclass
|
277
|
+
yield(obj) if block_given?
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def inherited_methods(scopes = [:class, :instance])
|
282
|
+
inherited_methods = super
|
283
|
+
superobject = Namespace.find_from_path(path, superclass)
|
284
|
+
if superobject && superobject.path != path # avoid infinite loop
|
285
|
+
[scopes].flatten.each do |scope|
|
286
|
+
inherited_methods.update(superobject.send(scope + "_methods"))
|
287
|
+
inherited_methods.update(superobject.send("inherited_#{scope}_methods"))
|
288
|
+
end
|
289
|
+
end
|
290
|
+
inherited_methods
|
291
|
+
end
|
292
|
+
|
293
|
+
def superclasses
|
294
|
+
superobject = Namespace.find_from_path(path, superclass)
|
295
|
+
return [superclass] if superobject.nil?
|
296
|
+
[superobject.path] + superobject.superclasses
|
297
|
+
end
|
298
|
+
|
299
|
+
def inheritance_tree
|
300
|
+
full_mixins.reverse + superclasses
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
class MethodObject < CodeObject
|
305
|
+
# @param [String] name the name of the method
|
306
|
+
# @param visibility the object visibility (:public, :private, :protected)
|
307
|
+
# @param [String] scope the object scope (:instance, :class)
|
308
|
+
# @param [CodeObjectWithMethods] parent the object that holds this method
|
309
|
+
def initialize(name, visibility, scope, parent, comments = nil)
|
310
|
+
super(name, :method, visibility, scope, parent, comments) do |obj|
|
311
|
+
parent["#{scope}_methods".to_sym].update(name.to_s => obj)
|
312
|
+
yield(obj) if block_given?
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
class ConstantObject < CodeObject
|
318
|
+
def initialize(name, parent = nil, statement = nil)
|
319
|
+
super(name, :constant, :public, :class, parent) do |obj|
|
320
|
+
if statement
|
321
|
+
obj.attach_docstring(statement.comments)
|
322
|
+
obj.attach_source(statement)
|
323
|
+
parent[:constants].update(name.to_s => obj)
|
324
|
+
yield(obj) if block_given?
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
class ClassVariableObject < CodeObject
|
331
|
+
def initialize(statement, parent)
|
332
|
+
name, value = *statement.tokens.to_s.gsub(/\r?\n/, '').split(/\s*=\s*/, 2)
|
333
|
+
super(name, :class_variable, :public, :class, parent) do |obj|
|
334
|
+
obj.parent[:class_variables].update(name => obj)
|
335
|
+
obj.attach_docstring(statement.comments)
|
336
|
+
obj.attach_source("#{name} = #{value}")
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
data/lib/formatter.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'rdoc/markup/simple_markup'
|
3
|
+
require 'rdoc/markup/simple_markup/to_html'
|
4
|
+
|
5
|
+
SMP = SM::SimpleMarkup.new
|
6
|
+
SMH = SM::ToHtml.new
|
7
|
+
|
8
|
+
module YARD
|
9
|
+
##
|
10
|
+
# Formats the code objects in the {Namespace} in a variety of formats
|
11
|
+
#
|
12
|
+
# @author Loren Segal
|
13
|
+
# @version 1.0
|
14
|
+
class Formatter
|
15
|
+
OUTPUT_FORMATS = [ :html, :xhtml, :xml ]
|
16
|
+
|
17
|
+
##
|
18
|
+
# Formats an object as a specified output format. Default is +:html+.
|
19
|
+
#
|
20
|
+
# @param [String, CodeObject] object the code object to format or the path to the code object
|
21
|
+
# @param [Symbol] format the output format to generate documentation in.
|
22
|
+
# Defaults to +:html+, which is a synonym for +:xhtml+.
|
23
|
+
# @see OUTPUT_FORMATS
|
24
|
+
def format(object, format = :html)
|
25
|
+
object = Namespace.at(object) if object.is_a? String
|
26
|
+
erb = File.join(template_directory, "#{format}_formatter.erb")
|
27
|
+
|
28
|
+
@object = object
|
29
|
+
ERB.new(IO.read(erb), nil, ">").result(binding)
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Directory for templates. Override this to load your own templates
|
34
|
+
def template_directory
|
35
|
+
File.join(File.dirname(__FILE__), '..', 'templates')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def link_to_path(name, from_path = nil, label = nil)
|
41
|
+
return "<a href='#instance_method-#{name[1..-1]}'>#{label || name}</a>" if name =~ /^\#/ && from_path.nil?
|
42
|
+
|
43
|
+
if from_path
|
44
|
+
obj = Namespace.find_from_path(from_path, name)
|
45
|
+
else
|
46
|
+
obj = Namespace.at(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
label = name if label.nil?
|
50
|
+
if obj
|
51
|
+
file = obj.parent.path.gsub("::","_") + ".html"
|
52
|
+
case obj
|
53
|
+
when ConstantObject
|
54
|
+
"<a href='#{file}#const-#{obj.name}'>#{label}</a>"
|
55
|
+
when ClassVariableObject
|
56
|
+
"<a href='#{file}#cvar-#{obj.name}'>#{label}</a>"
|
57
|
+
when MethodObject
|
58
|
+
"<a href='#{file}##{obj.scope}_method-#{obj.name}'>#{label}</a>"
|
59
|
+
else
|
60
|
+
"<a href='#{obj.path.gsub("::","_")}.html'>#{label}</a>"
|
61
|
+
end
|
62
|
+
else
|
63
|
+
name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_html(text, path = @object)
|
68
|
+
resolve_links(SMP.convert(text || "", SMH).gsub(/\A<p>|<\/p>\Z/,''), path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def resolve_links(text, path)
|
72
|
+
t, re = text, /\{(.+?)\}/
|
73
|
+
while t =~ re
|
74
|
+
t.sub!(re, "<tt>" + link_to_path($1, path) + "</tt>")
|
75
|
+
end
|
76
|
+
t
|
77
|
+
end
|
78
|
+
end
|