jakewendt-rdoc_rails 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +94 -0
- data/lib/jakewendt-rdoc_rails.rb +1 -0
- data/lib/rdoc_rails.rb +8 -0
- data/lib/rdoc_rails/rake.rb +21 -0
- data/lib/rdoc_rails/rdoc/ar_association.rb +103 -0
- data/lib/rdoc_rails/rdoc/context.rb +19 -0
- data/lib/rdoc_rails/rdoc/generator/railsfish.rb +27 -0
- data/lib/rdoc_rails/rdoc/generator/template/railsfish/classpage.rhtml +308 -0
- data/lib/rdoc_rails/rdoc/parser/rails.rb +387 -0
- data/lib/rdoc_rails/rdoc/token_stream.rb +9 -0
- data/lib/tasks/rdoc_rails.rake +19 -0
- data/test/app/models/blog.rb +4 -0
- data/test/app/models/comment.rb +12 -0
- data/test/app/models/post.rb +6 -0
- data/test/app/models/user.rb +13 -0
- data/test/rdoc_rails_test.rb +15 -0
- data/test/tasks/testing.rb +9 -0
- data/test/test_helper.rb +86 -0
- metadata +118 -0
data/README.rdoc
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
= RDoc::Rails
|
2
|
+
|
3
|
+
This package adds Rails-specific information to RDoc generated docs on Rails
|
4
|
+
projects. It could be particularly useful for people wanting to document Rails
|
5
|
+
applications for internal use within a team of developers. It includes
|
6
|
+
<tt>RDoc::Parser::Rails</tt> based on <tt>RDoc::Parser::Ruby</tt> as well as
|
7
|
+
<tt>RDoc::Generator::Railsfish</tt> based on <tt>RDoc::Generator::Darkfish</tt>
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
Currently, this is written as a Rails plugin, although I will look into
|
11
|
+
packaging it as a gem as well. It works with RDoc version 2.4.3, the most
|
12
|
+
current version as of August, 2009. I have tested it only with Rails 2.0, but I
|
13
|
+
would expect it to work for projects written in earlier and later versions of
|
14
|
+
Rails as well.
|
15
|
+
|
16
|
+
To install as a Rails plugin, try some variation on one of the following:
|
17
|
+
ruby script/plugin install git://github.com/chinasaur/rdoc_rails.git
|
18
|
+
ruby script/plugin install http://github.com/chinasaur/rdoc_rails.git
|
19
|
+
ruby script/plugin install http://github.com/chinasaur/rdoc_rails.git/
|
20
|
+
|
21
|
+
You may then need/want to rename the directory
|
22
|
+
<tt>vendor/plugins/rdoc_rails.git/</tt> to just +rdoc_rails+
|
23
|
+
|
24
|
+
After that, you should be good to go. The standard
|
25
|
+
> rake doc:app
|
26
|
+
or
|
27
|
+
> rake doc:reapp
|
28
|
+
should now run the Rails customized version of RDoc.
|
29
|
+
|
30
|
+
== Features
|
31
|
+
Right now there are just two basic features above and beyond the standard Ruby
|
32
|
+
RDoc:
|
33
|
+
|
34
|
+
1. Documentation for ActiveRecord associations on Models
|
35
|
+
2. Documentation for methods delegated to other models through the +delegate+ method.
|
36
|
+
|
37
|
+
But the infrastructure is all there to make it straightforward to parse
|
38
|
+
additional features in Rails code and generate documentation based on those
|
39
|
+
parsings.
|
40
|
+
|
41
|
+
== Suggested Features
|
42
|
+
|
43
|
+
* named_scope parsing
|
44
|
+
* validate_* parsing
|
45
|
+
* before_* parsing
|
46
|
+
* after_* parsing
|
47
|
+
* attr_protected parsing
|
48
|
+
* attr_accessible parsing
|
49
|
+
* custom user grouping and parsing (probably more core rdoc)
|
50
|
+
|
51
|
+
== Tests
|
52
|
+
|
53
|
+
* Tests are in development
|
54
|
+
* Both tests for Comment model's belongs_to associations fail
|
55
|
+
* one is polymorphic
|
56
|
+
* the other has a redefined class_name and counter_cache => true
|
57
|
+
* tests run, but I don't parse the output yet
|
58
|
+
|
59
|
+
|
60
|
+
== Contributing
|
61
|
+
I will try to document things better to make it easy for others to contribute
|
62
|
+
additional documentation features. For now, get in touch if you have any
|
63
|
+
questions and fork away.
|
64
|
+
|
65
|
+
== License http://i.creativecommons.org/l/by/3.0/us/80x15.png
|
66
|
+
Rdoc::Rails is released under a {Creative Commons Attribution 3.0 United States
|
67
|
+
License}[http://creativecommons.org/licenses/by/3.0/us/]. Please credit me
|
68
|
+
somewhere in your project's documentation if you are using this.
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
== Dev by Jake
|
75
|
+
|
76
|
+
Gemified with Jeweler
|
77
|
+
|
78
|
+
rake version:bump:patch
|
79
|
+
rake version:bump:minor
|
80
|
+
rake version:bump:major
|
81
|
+
|
82
|
+
rake gemspec
|
83
|
+
|
84
|
+
rake install
|
85
|
+
|
86
|
+
rake release
|
87
|
+
|
88
|
+
|
89
|
+
This seems to be incompatible with the latest rdoc 3.4.
|
90
|
+
Attempting to remedy.
|
91
|
+
Still not working.
|
92
|
+
|
93
|
+
|
94
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'rdoc_rails'
|
data/lib/rdoc_rails.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'rdoc_rails/rake'
|
4
|
+
require 'rdoc_rails/rdoc/context'
|
5
|
+
require 'rdoc_rails/rdoc/token_stream'
|
6
|
+
require 'rdoc_rails/rdoc/ar_association'
|
7
|
+
require 'rdoc_rails/rdoc/parser/rails'
|
8
|
+
require 'rdoc_rails/rdoc/generator/railsfish'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Rake
|
2
|
+
def self.remove_task(task_name)
|
3
|
+
Rake.application.instance_variable_get(:@tasks).delete(task_name.to_s) || raise('No such task!')
|
4
|
+
end
|
5
|
+
|
6
|
+
class RDocTask
|
7
|
+
def self.remove_task(task='rdoc', opts={})
|
8
|
+
Rake.remove_task(Rake::Task[task].prerequisites[0])
|
9
|
+
Rake.remove_task(task)
|
10
|
+
|
11
|
+
task = task.to_s.split(':')
|
12
|
+
name = task[-1]
|
13
|
+
path = task[0..-2] * ':'
|
14
|
+
rerdoc = opts[:rerdoc] || "re#{name}"
|
15
|
+
clobber = opts[:clobber_rdoc] || "clobber_#{name}"
|
16
|
+
|
17
|
+
Rake.remove_task("#{path}:#{rerdoc}")
|
18
|
+
Rake.remove_task("#{path}:#{clobber}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
require 'cgi'
|
5
|
+
class CGI
|
6
|
+
def self.escapeHTML_with_nil_check(string)
|
7
|
+
string = '' if string.nil?
|
8
|
+
escapeHTML_without_nil_check(string)
|
9
|
+
end
|
10
|
+
class << self
|
11
|
+
alias_method_chain :escapeHTML, :nil_check
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class RDoc::ArAssociation < RDoc::Context
|
16
|
+
include RDoc::TokenStream
|
17
|
+
attr_accessor :atype
|
18
|
+
attr_accessor :name
|
19
|
+
attr_writer :opts
|
20
|
+
|
21
|
+
def initialize(init={})
|
22
|
+
super()
|
23
|
+
init.each{ |k,v| send("#{k}=", v) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def opts
|
27
|
+
@opts || {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def class_name
|
31
|
+
class_name = opts[:class_name]
|
32
|
+
class_name ||= ActiveSupport::Inflector.classify(name) if ['has_many', 'has_and_belongs_to_many'].include?(atype.to_s)
|
33
|
+
class_name ||= name.camelize
|
34
|
+
class_name
|
35
|
+
end
|
36
|
+
|
37
|
+
def path
|
38
|
+
parent.path
|
39
|
+
end
|
40
|
+
|
41
|
+
# Pulled from RDoc::Generator::Markup
|
42
|
+
# Would be nice if this were moved into a module so it could be includable
|
43
|
+
# without copy/paste.
|
44
|
+
def add_line_numbers(src)
|
45
|
+
if src =~ /\A.*, line (\d+)/ then
|
46
|
+
first = $1.to_i - 1
|
47
|
+
last = first + src.count("\n")
|
48
|
+
size = last.to_s.length
|
49
|
+
|
50
|
+
line = first
|
51
|
+
src.gsub!(/^/) do
|
52
|
+
res = if line == first
|
53
|
+
" " * (size + 2)
|
54
|
+
else
|
55
|
+
"%#{size}d: " % line
|
56
|
+
end
|
57
|
+
|
58
|
+
line += 1
|
59
|
+
res
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Pulled from RDoc::Generator::Markup
|
65
|
+
# Would be nice if this were moved into a module so it could be includable
|
66
|
+
# without copy/paste.
|
67
|
+
def markup_code
|
68
|
+
return '' unless @token_stream
|
69
|
+
|
70
|
+
src = ""
|
71
|
+
|
72
|
+
@token_stream.each do |t|
|
73
|
+
next unless t
|
74
|
+
# style = STYLE_MAP[t.class]
|
75
|
+
style = case t
|
76
|
+
when RDoc::RubyToken::TkCONSTANT then "ruby-constant"
|
77
|
+
when RDoc::RubyToken::TkKW then "ruby-keyword kw"
|
78
|
+
when RDoc::RubyToken::TkIVAR then "ruby-ivar"
|
79
|
+
when RDoc::RubyToken::TkOp then "ruby-operator"
|
80
|
+
when RDoc::RubyToken::TkId then "ruby-identifier"
|
81
|
+
when RDoc::RubyToken::TkNode then "ruby-node"
|
82
|
+
when RDoc::RubyToken::TkCOMMENT then "ruby-comment cmt"
|
83
|
+
when RDoc::RubyToken::TkREGEXP then "ruby-regexp re"
|
84
|
+
when RDoc::RubyToken::TkSTRING then "ruby-value str"
|
85
|
+
when RDoc::RubyToken::TkVal then "ruby-value"
|
86
|
+
else nil
|
87
|
+
end
|
88
|
+
|
89
|
+
text = CGI.escapeHTML(t.text)
|
90
|
+
|
91
|
+
if style
|
92
|
+
src << "<span class=\"#{style}\">#{text}</span>"
|
93
|
+
else
|
94
|
+
src << text
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# add_line_numbers src if RDoc::RDoc.current.options.include_line_numbers
|
99
|
+
# change for rdoc > 2.4.3
|
100
|
+
|
101
|
+
src
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rdoc/context'
|
2
|
+
class RDoc::Context
|
3
|
+
attr_accessor :ar_associations
|
4
|
+
|
5
|
+
# Overriding to initialize ar_associations
|
6
|
+
def initialize_methods_etc
|
7
|
+
@method_list = []
|
8
|
+
@attributes = []
|
9
|
+
@aliases = []
|
10
|
+
@requires = []
|
11
|
+
@includes = []
|
12
|
+
@constants = []
|
13
|
+
@ar_associations = []
|
14
|
+
|
15
|
+
# This Hash maps a method name to a list of unmatched aliases (aliases of
|
16
|
+
# a method not yet encountered).
|
17
|
+
@unmatched_alias_lists = {}
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rdoc/generator/darkfish'
|
2
|
+
class RDoc::Generator::Railsfish < RDoc::Generator::Darkfish
|
3
|
+
RDoc::RDoc.add_generator(self)
|
4
|
+
VERSION = '0.1.0'
|
5
|
+
|
6
|
+
# Override template path to use standard darkfish template for most pages
|
7
|
+
def initialize(opts)
|
8
|
+
opts.instance_variable_set(:@template, 'darkfish') if opts.template == 'railsfish'
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Overriding to allow setting templatefile to my Rails customized version.
|
13
|
+
def generate_class_files
|
14
|
+
debug_msg "Generating class documentation in #@outputdir"
|
15
|
+
templatefile = Pathname.new(File.dirname(__FILE__) + '/template/railsfish/classpage.rhtml')
|
16
|
+
|
17
|
+
@classes.each do |klass|
|
18
|
+
debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ]
|
19
|
+
outfile = @outputdir + klass.path
|
20
|
+
rel_prefix = @outputdir.relative_path_from( outfile.dirname )
|
21
|
+
svninfo = self.get_svninfo( klass )
|
22
|
+
|
23
|
+
debug_msg " rendering #{outfile}"
|
24
|
+
self.render_template( templatefile, binding(), outfile )
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
+
<head>
|
6
|
+
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
|
7
|
+
|
8
|
+
<title><%= klass.type.capitalize %>: <%= klass.full_name %></title>
|
9
|
+
|
10
|
+
<link rel="stylesheet" href="<%= rel_prefix %>/rdoc.css" type="text/css" media="screen" />
|
11
|
+
|
12
|
+
<script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
13
|
+
<script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script>
|
14
|
+
<script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
|
15
|
+
<script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript" charset="utf-8"></script>
|
16
|
+
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body class="<%= klass.type %>">
|
20
|
+
|
21
|
+
<div id="metadata">
|
22
|
+
<div id="file-metadata">
|
23
|
+
<div id="file-list-section" class="section">
|
24
|
+
<h3 class="section-header">In Files</h3>
|
25
|
+
<div class="section-body">
|
26
|
+
<ul>
|
27
|
+
<% klass.in_files.each do |tl| %>
|
28
|
+
<li><a href="<%= rel_prefix %>/<%= h tl.path %>?TB_iframe=true&height=550&width=785"
|
29
|
+
class="thickbox" title="<%= h tl.absolute_name %>"><%= h tl.absolute_name %></a></li>
|
30
|
+
<% end %>
|
31
|
+
</ul>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<% if !svninfo.empty? %>
|
36
|
+
<div id="file-svninfo-section" class="section">
|
37
|
+
<h3 class="section-header">Subversion Info</h3>
|
38
|
+
<div class="section-body">
|
39
|
+
<dl class="svninfo">
|
40
|
+
<dt>Rev</dt>
|
41
|
+
<dd><%= svninfo[:rev] %></dd>
|
42
|
+
|
43
|
+
<dt>Last Checked In</dt>
|
44
|
+
<dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
|
45
|
+
(<%= svninfo[:commitdelta] %> ago)</dd>
|
46
|
+
|
47
|
+
<dt>Checked in by</dt>
|
48
|
+
<dd><%= svninfo[:committer] %></dd>
|
49
|
+
</dl>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
<% end %>
|
53
|
+
</div>
|
54
|
+
|
55
|
+
<div id="class-metadata">
|
56
|
+
|
57
|
+
<!-- Parent Class -->
|
58
|
+
<% if klass.type == 'class' %>
|
59
|
+
<div id="parent-class-section" class="section">
|
60
|
+
<h3 class="section-header">Parent</h3>
|
61
|
+
<% unless String === klass.superclass %>
|
62
|
+
<p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a></p>
|
63
|
+
<% else %>
|
64
|
+
<p class="link"><%= klass.superclass %></p>
|
65
|
+
<% end %>
|
66
|
+
</div>
|
67
|
+
<% end %>
|
68
|
+
|
69
|
+
<!-- Namespace Contents -->
|
70
|
+
<% unless klass.classes_and_modules.empty? %>
|
71
|
+
<div id="namespace-list-section" class="section">
|
72
|
+
<h3 class="section-header">Namespace</h3>
|
73
|
+
<ul class="link-list">
|
74
|
+
<% (klass.modules.sort + klass.classes.sort).each do |mod| %>
|
75
|
+
<li><span class="type"><%= mod.type.upcase %></span> <a href="<%= klass.aref_to mod.path %>"><%= mod.full_name %></a></li>
|
76
|
+
<% end %>
|
77
|
+
</ul>
|
78
|
+
</div>
|
79
|
+
<% end %>
|
80
|
+
|
81
|
+
<!-- Method Quickref -->
|
82
|
+
<% unless klass.method_list.empty? %>
|
83
|
+
<div id="method-list-section" class="section">
|
84
|
+
<h3 class="section-header">Methods</h3>
|
85
|
+
<ul class="link-list">
|
86
|
+
<% klass.each_method do |meth| %>
|
87
|
+
<li><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= meth.name %></a></li>
|
88
|
+
<% end %>
|
89
|
+
</ul>
|
90
|
+
</div>
|
91
|
+
<% end %>
|
92
|
+
|
93
|
+
<!-- Included Modules -->
|
94
|
+
<% unless klass.includes.empty? %>
|
95
|
+
<div id="includes-section" class="section">
|
96
|
+
<h3 class="section-header">Included Modules</h3>
|
97
|
+
<ul class="link-list">
|
98
|
+
<% klass.each_include do |inc| %>
|
99
|
+
<% unless String === inc.module %>
|
100
|
+
<li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a></li>
|
101
|
+
<% else %>
|
102
|
+
<li><span class="include"><%= inc.name %></span></li>
|
103
|
+
<% end %>
|
104
|
+
<% end %>
|
105
|
+
</ul>
|
106
|
+
</div>
|
107
|
+
<% end %>
|
108
|
+
</div>
|
109
|
+
|
110
|
+
<div id="project-metadata">
|
111
|
+
<% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
|
112
|
+
<% unless simple_files.empty? then %>
|
113
|
+
<div id="fileindex-section" class="section project-section">
|
114
|
+
<h3 class="section-header">Files</h3>
|
115
|
+
<ul>
|
116
|
+
<% simple_files.each do |file| %>
|
117
|
+
<li class="file"><a href="<%= rel_prefix %>/<%= file.path %>"><%= h file.base_name %></a></li>
|
118
|
+
<% end %>
|
119
|
+
</ul>
|
120
|
+
</div>
|
121
|
+
<% end %>
|
122
|
+
|
123
|
+
<div id="classindex-section" class="section project-section">
|
124
|
+
<h3 class="section-header">Class Index
|
125
|
+
<span class="search-toggle">
|
126
|
+
<img src="<%= rel_prefix %>/images/find.png"
|
127
|
+
height="16" width="16" alt="[+]"
|
128
|
+
title="show/hide quicksearch" />
|
129
|
+
</span>
|
130
|
+
</h3>
|
131
|
+
<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
|
132
|
+
<fieldset>
|
133
|
+
<legend>Quicksearch</legend>
|
134
|
+
<input type="text" name="quicksearch" value="" class="quicksearch-field" />
|
135
|
+
</fieldset>
|
136
|
+
</form>
|
137
|
+
|
138
|
+
<ul class="link-list">
|
139
|
+
<% @modsort.each do |index_klass| %>
|
140
|
+
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
|
141
|
+
<% end %>
|
142
|
+
</ul>
|
143
|
+
<div id="no-class-search-results" style="display: none;">No matching classes.</div>
|
144
|
+
</div>
|
145
|
+
|
146
|
+
<% if $DEBUG_RDOC %>
|
147
|
+
<div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
|
148
|
+
alt="toggle debugging" height="16" width="16" /></div>
|
149
|
+
<% end %>
|
150
|
+
</div>
|
151
|
+
</div>
|
152
|
+
|
153
|
+
<div id="documentation">
|
154
|
+
<h1 class="<%= klass.type %>"><%= klass.full_name %></h1>
|
155
|
+
|
156
|
+
<div id="description"><%= klass.description %></div>
|
157
|
+
|
158
|
+
<!-- Constants -->
|
159
|
+
<% unless klass.constants.empty? %>
|
160
|
+
<div id="constants-list" class="section">
|
161
|
+
<h3 class="section-header">Constants</h3>
|
162
|
+
<dl>
|
163
|
+
<% klass.each_constant do |const| %>
|
164
|
+
<dt><a name="<%= const.name %>"><%= const.name %></a></dt>
|
165
|
+
<% if const.comment %>
|
166
|
+
<dd class="description"><%= const.description.strip %></dd>
|
167
|
+
<% else %>
|
168
|
+
<dd class="description missing-docs">(Not documented)</dd>
|
169
|
+
<% end %>
|
170
|
+
<% end %>
|
171
|
+
</dl>
|
172
|
+
</div>
|
173
|
+
<% end %>
|
174
|
+
|
175
|
+
<!-- Attributes -->
|
176
|
+
<% unless klass.attributes.empty? %>
|
177
|
+
<div id="attribute-method-details" class="method-section section">
|
178
|
+
<h3 class="section-header">Attributes</h3>
|
179
|
+
|
180
|
+
<% klass.each_attribute do |attrib| %>
|
181
|
+
<div id="<%= attrib.html_name %>-attribute-method" class="method-detail">
|
182
|
+
<a name="<%= h attrib.name %>"></a>
|
183
|
+
<% if attrib.rw =~ /w/i %>
|
184
|
+
<a name="<%= h attrib.name %>="></a>
|
185
|
+
<% end %>
|
186
|
+
<div class="method-heading attribute-method-heading">
|
187
|
+
<span class="method-name"><%= h attrib.name %></span>
|
188
|
+
<span class="attribute-access-type">[<%= attrib.rw %>]</span>
|
189
|
+
</div>
|
190
|
+
|
191
|
+
<div class="method-description">
|
192
|
+
<% if attrib.comment %>
|
193
|
+
<%= attrib.description.strip %>
|
194
|
+
<% else %>
|
195
|
+
<p class="missing-docs">(Not documented)</p>
|
196
|
+
<% end %>
|
197
|
+
</div>
|
198
|
+
</div>
|
199
|
+
<% end %>
|
200
|
+
</div>
|
201
|
+
<% end %>
|
202
|
+
|
203
|
+
<!-- ActiveRecord Associations -->
|
204
|
+
<% unless klass.ar_associations.empty? %>
|
205
|
+
<div id="ara-method-details" class="method-section section">
|
206
|
+
<h3 class="section-header">ActiveRecord Associations</h3>
|
207
|
+
<% klass.ar_associations.each do |ara| %>
|
208
|
+
<div id="<%= ara.name %>-ara-method" class="method-detail">
|
209
|
+
<div class="method-heading ara-method-heading">
|
210
|
+
<span class="method-name">
|
211
|
+
<%= %Q|#{ara.atype} #{h ara.name} (<a href="#{ara.class_name}.html"><tt>#{ara.class_name}</tt></a>)| %>
|
212
|
+
</span>
|
213
|
+
<% if ara.token_stream %>
|
214
|
+
<span class="method-click-advice">click to toggle source</span>
|
215
|
+
<% end %>
|
216
|
+
</div>
|
217
|
+
|
218
|
+
<div class="method-description">
|
219
|
+
<% if ara.comment %>
|
220
|
+
<%= ara.description.strip %>
|
221
|
+
<% end %>
|
222
|
+
|
223
|
+
<% if ara.token_stream %>
|
224
|
+
<div class="method-source-code" id="<%= ara.name %>-source">
|
225
|
+
<pre>
|
226
|
+
<%= ara.markup_code %>
|
227
|
+
</pre>
|
228
|
+
</div>
|
229
|
+
<% end %>
|
230
|
+
</div>
|
231
|
+
</div>
|
232
|
+
<% end %>
|
233
|
+
</div>
|
234
|
+
<% end %>
|
235
|
+
|
236
|
+
<!-- Methods -->
|
237
|
+
<% klass.methods_by_type.each do |type, visibilities|
|
238
|
+
next if visibilities.empty?
|
239
|
+
visibilities.each do |visibility, methods|
|
240
|
+
next if methods.empty? %>
|
241
|
+
<div id="<%= visibility %>-<%= type %>-method-details" class="method-section section">
|
242
|
+
<h3 class="section-header"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
|
243
|
+
|
244
|
+
<% methods.each do |method| %>
|
245
|
+
<div id="<%= method.html_name %>-method" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
|
246
|
+
<a name="<%= h method.aref %>"></a>
|
247
|
+
|
248
|
+
<div class="method-heading">
|
249
|
+
<% if method.call_seq %>
|
250
|
+
<span class="method-callseq"><%= method.call_seq.strip.gsub(/->/, '→').gsub( /^\w.*?\./m, '') %></span>
|
251
|
+
<span class="method-click-advice">click to toggle source</span>
|
252
|
+
<% else %>
|
253
|
+
<span class="method-name"><%= h method.name %></span>
|
254
|
+
<span class="method-args"><%= method.params %></span>
|
255
|
+
<span class="method-click-advice">click to toggle source</span>
|
256
|
+
<% end %>
|
257
|
+
</div>
|
258
|
+
|
259
|
+
<div class="method-description">
|
260
|
+
<% if method.comment %>
|
261
|
+
<%= method.description.strip %>
|
262
|
+
<% else %>
|
263
|
+
<p class="missing-docs">(Not documented)</p>
|
264
|
+
<% end %>
|
265
|
+
|
266
|
+
<% if method.token_stream %>
|
267
|
+
<div class="method-source-code" id="<%= method.html_name %>-source">
|
268
|
+
<pre>
|
269
|
+
<%= method.markup_code %>
|
270
|
+
</pre>
|
271
|
+
</div>
|
272
|
+
<% end %>
|
273
|
+
</div>
|
274
|
+
|
275
|
+
<% unless method.aliases.empty? %>
|
276
|
+
<div class="aliases">
|
277
|
+
Also aliased as: <%= method.aliases.map do |aka|
|
278
|
+
%{<a href="#{ klass.aref_to aka.path}">#{h aka.name}</a>}
|
279
|
+
end.join(", ") %>
|
280
|
+
</div>
|
281
|
+
<% end %>
|
282
|
+
</div>
|
283
|
+
|
284
|
+
<% end %>
|
285
|
+
</div>
|
286
|
+
<% end %>
|
287
|
+
<% end %>
|
288
|
+
|
289
|
+
<div id="rdoc-debugging-section-dump" class="debugging-section">
|
290
|
+
<% if $DEBUG_RDOC
|
291
|
+
require 'pp' %>
|
292
|
+
<pre><%= h PP.pp(klass, _erbout) %></pre>
|
293
|
+
<% else %>
|
294
|
+
<p>Disabled; run with --debug to generate this.</p>
|
295
|
+
<% end %>
|
296
|
+
</div>
|
297
|
+
|
298
|
+
</div>
|
299
|
+
|
300
|
+
<div id="validator-badges">
|
301
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
302
|
+
<p><small>Generated with the Railsfish Rdoc Generator
|
303
|
+
<%= RDoc::Generator::Railsfish::VERSION %></small>.</p>
|
304
|
+
</div>
|
305
|
+
|
306
|
+
</body>
|
307
|
+
</html>
|
308
|
+
|
@@ -0,0 +1,387 @@
|
|
1
|
+
require 'rdoc/parser/ruby'
|
2
|
+
class RDoc::Parser::Rails < RDoc::Parser::Ruby
|
3
|
+
include RDoc::RubyToken
|
4
|
+
parse_files_matching(/\.rbw?$/)
|
5
|
+
|
6
|
+
def parse_rails_meta(container, single, tk, comment)
|
7
|
+
return unless container.document_children
|
8
|
+
restore_init_token(tk)
|
9
|
+
# Start listening to get_tk and saving read tokens into @token_stream, parse
|
10
|
+
# symbol args
|
11
|
+
add_token_listener self
|
12
|
+
args = parse_symbol_arg # This gets any symbol or string args
|
13
|
+
opts = (parse_final_hash if token_stream[-1].is_a?(TkCOMMA)) || {}
|
14
|
+
remove_token_listener self
|
15
|
+
|
16
|
+
send("parse_#{tk.name}", container, single, tk, comment, args, opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_rails_debug(container, single, tk, comment, args, opts)
|
20
|
+
puts tk.name
|
21
|
+
puts args.inspect
|
22
|
+
puts opts.inspect if opts
|
23
|
+
puts ""
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_rails_pending(container, single, tk, comment, args, opts); end
|
27
|
+
alias parse_validates_uniqueness_of parse_rails_pending
|
28
|
+
|
29
|
+
def parse_ar_association(container, single, tk, comment, args, opts)
|
30
|
+
ara = RDoc::ArAssociation.new(
|
31
|
+
:atype => tk.name,
|
32
|
+
:name => args[0],
|
33
|
+
:opts => opts,
|
34
|
+
:comment => comment
|
35
|
+
)
|
36
|
+
|
37
|
+
ara.start_collecting_tokens
|
38
|
+
ara.add_tokens [position_comment(tk), NEWLINE_TOKEN]
|
39
|
+
ara.add_tokens token_stream
|
40
|
+
|
41
|
+
ara.parent = container
|
42
|
+
container.ar_associations << ara
|
43
|
+
end
|
44
|
+
alias parse_belongs_to parse_ar_association
|
45
|
+
alias parse_has_one parse_ar_association
|
46
|
+
alias parse_has_many parse_ar_association
|
47
|
+
alias parse_has_and_belongs_to_many parse_ar_association
|
48
|
+
|
49
|
+
# Take the args, opts, and tokens collected by parse_rails_meta and generate
|
50
|
+
# method documentation for delegated methods.
|
51
|
+
def parse_delegate(container, single, tk, comment, args, opts)
|
52
|
+
add_token_listener self
|
53
|
+
skip_to_eol
|
54
|
+
remove_token_listener self
|
55
|
+
|
56
|
+
args.each do |arg|
|
57
|
+
d_meth = RDoc::AnyMethod.new('', arg)
|
58
|
+
@stats.add_method d_meth
|
59
|
+
container.add_method d_meth
|
60
|
+
|
61
|
+
d_meth.start_collecting_tokens
|
62
|
+
d_meth.add_tokens [position_comment(tk), NEWLINE_TOKEN]
|
63
|
+
d_meth.add_tokens token_stream
|
64
|
+
|
65
|
+
d_meth.params = "(?) - delegated to #{opts[:to].inspect}" if opts[:to]
|
66
|
+
d_meth.params ||= '(?) - delegated method...'
|
67
|
+
|
68
|
+
d_meth.comment = comment
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def skip_to_eol
|
73
|
+
tk = get_tk until tk.is_a?(TkNL)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Parse tokens assumed to represent a final hash argument, thus will parse
|
77
|
+
# either a {} enclosed hash or a naked final hash.
|
78
|
+
#
|
79
|
+
# The purpose of this is mainly to be able to generate documentation for Rails
|
80
|
+
# meta calls, which generally have symbols/strings for keys and values, so
|
81
|
+
# that is what I've prioritized being able to parse. Shouldn't be difficult to
|
82
|
+
# add parsing of numeric keys/values. Parsing array/hash keys/values would be
|
83
|
+
# more difficult and isn't in the scope of what I currently plan to do. If
|
84
|
+
# this hits something it doesn't know how to parse, it rewinds all its tokens
|
85
|
+
# and quits.
|
86
|
+
#
|
87
|
+
# The best way to set up a call to parse_final_hash is as is done in
|
88
|
+
# parse_rails_meta, where we first call parse_symbol_arg. This is good setup
|
89
|
+
# because parse_symbol_arg will rewind to the comma before the final hash if
|
90
|
+
# it detects a hash in parsing other args.
|
91
|
+
def parse_final_hash
|
92
|
+
buffer = TokenStream.new
|
93
|
+
add_token_listener(buffer)
|
94
|
+
skip_tkspace(true)
|
95
|
+
|
96
|
+
case tk = get_tk
|
97
|
+
when TkLBRACE then bracketed = true
|
98
|
+
when TkSYMBOL, TkSTRING then bracketed = false
|
99
|
+
else
|
100
|
+
unget_tk(tk) until buffer.token_stream.empty?
|
101
|
+
remove_token_listener(buffer)
|
102
|
+
return
|
103
|
+
end
|
104
|
+
|
105
|
+
last_tk = tk
|
106
|
+
while tk = get_tk do
|
107
|
+
case tk
|
108
|
+
when TkSEMICOLON then break
|
109
|
+
when TkNL
|
110
|
+
unget_tk(tk) and break unless last_tk and TkCOMMA === last_tk
|
111
|
+
when TkSPACE, TkCOMMENT
|
112
|
+
when TkSYMBOL, TkSTRING, TkCOMMA, TkASSIGN, TkGT, TkASSOC then last_tk = tk # Will probably want to expand this to include numerics, possibly others; let's cross that bridge when we come to it.
|
113
|
+
else
|
114
|
+
break if bracketed and tk.is_a?(TkRBRACE)
|
115
|
+
unget_tk(tk) and break if !bracketed and tk.is_a?(TkDO)
|
116
|
+
|
117
|
+
unget_tk(tk) until buffer.token_stream.empty?
|
118
|
+
remove_token_listener(buffer)
|
119
|
+
return
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
remove_token_listener(buffer)
|
124
|
+
read = buffer.token_stream.collect{|tk|tk.text}.join
|
125
|
+
read = "{#{read}\n}" if !bracketed # We need the \n in case #{read} ends with a comment
|
126
|
+
eval(read) rescue nil
|
127
|
+
end
|
128
|
+
|
129
|
+
# Largely copied from super, but rewinds if it hits a =>, indicating the last
|
130
|
+
# symbol/string read should have been part of the final hash arg. Rewinds to
|
131
|
+
# the comma before the final hash, which provides a good check after we return
|
132
|
+
# of whether there are still more arguments to parse.
|
133
|
+
def parse_symbol_arg(no=nil)
|
134
|
+
buffer = TokenStream.new
|
135
|
+
add_token_listener(buffer)
|
136
|
+
|
137
|
+
args = []
|
138
|
+
skip_tkspace_comment
|
139
|
+
case tk = get_tk
|
140
|
+
when TkLPAREN
|
141
|
+
loop do
|
142
|
+
skip_tkspace_comment
|
143
|
+
if tk = parse_symbol_in_arg
|
144
|
+
args.push tk
|
145
|
+
break if no and args.size >= no
|
146
|
+
end
|
147
|
+
|
148
|
+
skip_tkspace_comment
|
149
|
+
case tk2 = get_tk
|
150
|
+
when TkRPAREN
|
151
|
+
break
|
152
|
+
when TkCOMMA
|
153
|
+
when TkASSOC, TkASSIGN, TkGT
|
154
|
+
# Oops, we started slurping the final Hash!
|
155
|
+
# So rewind back past the symbol or string that came before the =>
|
156
|
+
unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty?
|
157
|
+
args.pop
|
158
|
+
break
|
159
|
+
when TkLBRACE
|
160
|
+
# We hit the beginning of a hash or block, so rewind to the comma
|
161
|
+
unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty?
|
162
|
+
break
|
163
|
+
else
|
164
|
+
warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
|
165
|
+
break
|
166
|
+
end
|
167
|
+
end
|
168
|
+
else
|
169
|
+
unget_tk tk
|
170
|
+
if tk = parse_symbol_in_arg
|
171
|
+
args.push tk
|
172
|
+
return args if no and args.size >= no
|
173
|
+
end
|
174
|
+
|
175
|
+
loop do
|
176
|
+
skip_tkspace(false)
|
177
|
+
|
178
|
+
tk1 = get_tk
|
179
|
+
if TkCOMMA === tk1
|
180
|
+
elsif TkASSOC === tk1 or TkASSIGN === tk1 or TkGT === tk1
|
181
|
+
# Oops, we started slurping the final Hash!
|
182
|
+
# So rewind back past the symbol or string that came before the =>
|
183
|
+
unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty?
|
184
|
+
args.pop
|
185
|
+
break
|
186
|
+
elsif TkLBRACE === tk1
|
187
|
+
# We hit the beginning of a hash or block, so rewind to the comma
|
188
|
+
unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty?
|
189
|
+
break
|
190
|
+
else
|
191
|
+
unget_tk tk1
|
192
|
+
break
|
193
|
+
end
|
194
|
+
|
195
|
+
skip_tkspace_comment
|
196
|
+
if tk = parse_symbol_in_arg
|
197
|
+
args.push tk
|
198
|
+
break if no and args.size >= no
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
remove_token_listener buffer
|
204
|
+
args
|
205
|
+
end
|
206
|
+
|
207
|
+
# Comment line required to help generator put line numbers on included source code.
|
208
|
+
def position_comment(tk)
|
209
|
+
TkCOMMENT.new(tk.line_no, 1, "# File #{@top_level.absolute_name}, line #{tk.line_no}")
|
210
|
+
end
|
211
|
+
|
212
|
+
# Clear @token_stream and then put back the indentation and initial token;
|
213
|
+
# basically assumes tk is the first non-whitespace token on the line.
|
214
|
+
def restore_init_token(tk)
|
215
|
+
start_collecting_tokens
|
216
|
+
# indent = TkSPACE.new(1, 1)
|
217
|
+
# change for rdoc > 2.4.3
|
218
|
+
indent = TkSPACE.new(nil,1, 1)
|
219
|
+
indent.set_text(' ' * tk.char_no)
|
220
|
+
add_tokens([indent, tk])
|
221
|
+
end
|
222
|
+
|
223
|
+
# The identifiers that should be processed as rails meta-calls
|
224
|
+
RAILS_IDENTIFIERS = [
|
225
|
+
'belongs_to',
|
226
|
+
'has_one',
|
227
|
+
'has_many',
|
228
|
+
'has_and_belongs_to_many',
|
229
|
+
'delegate',
|
230
|
+
'validates_uniqueness_of'
|
231
|
+
]
|
232
|
+
|
233
|
+
# Copied from super, with a minor tweak to the TkIDENTIFIER parsing portion.
|
234
|
+
def parse_statements(container, single = NORMAL, current_method = nil, comment = '')
|
235
|
+
nest = 1
|
236
|
+
save_visibility = container.visibility
|
237
|
+
|
238
|
+
non_comment_seen = true
|
239
|
+
|
240
|
+
while tk = get_tk do
|
241
|
+
keep_comment = false
|
242
|
+
|
243
|
+
non_comment_seen = true unless TkCOMMENT === tk
|
244
|
+
|
245
|
+
case tk
|
246
|
+
when TkNL then
|
247
|
+
skip_tkspace true # Skip blanks and newlines
|
248
|
+
tk = get_tk
|
249
|
+
|
250
|
+
if TkCOMMENT === tk then
|
251
|
+
if non_comment_seen then
|
252
|
+
# Look for RDoc in a comment about to be thrown away
|
253
|
+
parse_comment container, tk, comment unless comment.empty?
|
254
|
+
|
255
|
+
comment = ''
|
256
|
+
non_comment_seen = false
|
257
|
+
end
|
258
|
+
|
259
|
+
while TkCOMMENT === tk do
|
260
|
+
comment << tk.text << "\n"
|
261
|
+
tk = get_tk # this is the newline
|
262
|
+
skip_tkspace(false) # leading spaces
|
263
|
+
tk = get_tk
|
264
|
+
end
|
265
|
+
|
266
|
+
unless comment.empty? then
|
267
|
+
look_for_directives_in container, comment
|
268
|
+
|
269
|
+
if container.done_documenting then
|
270
|
+
container.ongoing_visibility = save_visibility
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
keep_comment = true
|
275
|
+
else
|
276
|
+
non_comment_seen = true
|
277
|
+
end
|
278
|
+
|
279
|
+
unget_tk tk
|
280
|
+
keep_comment = true
|
281
|
+
|
282
|
+
when TkCLASS then
|
283
|
+
if container.document_children then
|
284
|
+
parse_class container, single, tk, comment
|
285
|
+
else
|
286
|
+
nest += 1
|
287
|
+
end
|
288
|
+
|
289
|
+
when TkMODULE then
|
290
|
+
if container.document_children then
|
291
|
+
parse_module container, single, tk, comment
|
292
|
+
else
|
293
|
+
nest += 1
|
294
|
+
end
|
295
|
+
|
296
|
+
when TkDEF then
|
297
|
+
if container.document_self then
|
298
|
+
parse_method container, single, tk, comment
|
299
|
+
else
|
300
|
+
nest += 1
|
301
|
+
end
|
302
|
+
|
303
|
+
when TkCONSTANT then
|
304
|
+
if container.document_self then
|
305
|
+
# parse_constant container, single, tk, comment
|
306
|
+
# change for rdoc > 2.4.3
|
307
|
+
parse_constant container, tk, comment
|
308
|
+
end
|
309
|
+
|
310
|
+
when TkALIAS then
|
311
|
+
if container.document_self then
|
312
|
+
parse_alias container, single, tk, comment
|
313
|
+
end
|
314
|
+
|
315
|
+
when TkYIELD then
|
316
|
+
if current_method.nil? then
|
317
|
+
warn "Warning: yield outside of method" if container.document_self
|
318
|
+
else
|
319
|
+
parse_yield container, single, tk, current_method
|
320
|
+
end
|
321
|
+
|
322
|
+
# Until and While can have a 'do', which shouldn't increase the nesting.
|
323
|
+
# We can't solve the general case, but we can handle most occurrences by
|
324
|
+
# ignoring a do at the end of a line.
|
325
|
+
when TkUNTIL, TkWHILE then
|
326
|
+
nest += 1
|
327
|
+
skip_optional_do_after_expression
|
328
|
+
|
329
|
+
# 'for' is trickier
|
330
|
+
when TkFOR then
|
331
|
+
nest += 1
|
332
|
+
skip_for_variable
|
333
|
+
skip_optional_do_after_expression
|
334
|
+
|
335
|
+
when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then
|
336
|
+
nest += 1
|
337
|
+
|
338
|
+
when TkIDENTIFIER then
|
339
|
+
if nest == 1 and current_method.nil? then
|
340
|
+
case tk.name
|
341
|
+
when 'private', 'protected', 'public', 'private_class_method',
|
342
|
+
'public_class_method', 'module_function' then
|
343
|
+
parse_visibility container, single, tk
|
344
|
+
keep_comment = true
|
345
|
+
when 'attr' then
|
346
|
+
parse_attr container, single, tk, comment
|
347
|
+
when /^attr_(reader|writer|accessor)$/ then
|
348
|
+
parse_attr_accessor container, single, tk, comment
|
349
|
+
when 'alias_method' then
|
350
|
+
if container.document_self then
|
351
|
+
parse_alias container, single, tk, comment
|
352
|
+
end
|
353
|
+
when *RAILS_IDENTIFIERS then parse_rails_meta container, single, tk, comment
|
354
|
+
else
|
355
|
+
if container.document_self and comment =~ /\A#\#$/ then
|
356
|
+
parse_meta_method container, single, tk, comment
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
case tk.name
|
362
|
+
when "require" then
|
363
|
+
parse_require container, comment
|
364
|
+
when "include" then
|
365
|
+
parse_include container, comment
|
366
|
+
end
|
367
|
+
|
368
|
+
when TkEND then
|
369
|
+
nest -= 1
|
370
|
+
if nest == 0 then
|
371
|
+
read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
|
372
|
+
container.ongoing_visibility = save_visibility
|
373
|
+
return
|
374
|
+
end
|
375
|
+
|
376
|
+
end
|
377
|
+
|
378
|
+
comment = '' unless keep_comment
|
379
|
+
|
380
|
+
begin
|
381
|
+
get_tkread
|
382
|
+
skip_tkspace(false)
|
383
|
+
end while peek_tk == TkNL
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../rdoc_rails')
|
2
|
+
|
3
|
+
Rake::RDocTask.remove_task('doc:app')
|
4
|
+
|
5
|
+
namespace :doc do
|
6
|
+
desc "Generate documentation for the application. Set custom template with TEMPLATE=/path/to/rdoc/template.rb Set custom format with FORMAT=format_name"
|
7
|
+
Rake::RDocTask.new('app') { |rdoc|
|
8
|
+
ENV['format'] ||= 'railsfish'
|
9
|
+
rdoc.rdoc_dir = 'doc/app'
|
10
|
+
rdoc.template = ENV['template'] if ENV['template']
|
11
|
+
rdoc.title = "Rails Application Documentation"
|
12
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
13
|
+
rdoc.options << '--charset' << 'utf-8'
|
14
|
+
rdoc.options << '--format' << ENV['format']
|
15
|
+
rdoc.rdoc_files.include('doc/README_FOR_APP')
|
16
|
+
rdoc.rdoc_files.include('app/**/*.rb')
|
17
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
18
|
+
}
|
19
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Comment < ActiveRecord::Base
|
2
|
+
# This will parse incorrectly, ignoring the definition
|
3
|
+
# of :class_name => "User"
|
4
|
+
belongs_to :commenter,
|
5
|
+
:class_name => "User",
|
6
|
+
:counter_cache => true
|
7
|
+
|
8
|
+
# This has no idea who or what commentable is.
|
9
|
+
belongs_to :commentable,
|
10
|
+
:polymorphic => true,
|
11
|
+
:counter_cache => true
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class RDocRailsTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
# test "should say hello" do
|
7
|
+
# puts 'hello'
|
8
|
+
# end
|
9
|
+
|
10
|
+
test "should do something" do
|
11
|
+
FileUtils.remove_dir("test/rdoc") if File.exists?("test/rdoc")
|
12
|
+
Rake::Task[:rdoc_test].invoke
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rdoc'
|
2
|
+
require 'rdoc/rdoc'
|
3
|
+
#require 'rake'
|
4
|
+
#require 'rake/testtask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require File.dirname(__FILE__) + '/../../lib/rdoc_rails'
|
7
|
+
|
8
|
+
# Load Rails rakefile extensions
|
9
|
+
Dir["#{File.dirname(__FILE__)}/*.rake"].each { |ext| load ext }
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/test_case'
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
require 'tasks/testing'
|
8
|
+
$: << File.expand_path(File.dirname(__FILE__) + "/../lib/" )
|
9
|
+
require 'rdoc_rails'
|
10
|
+
|
11
|
+
$: << File.expand_path(File.dirname(__FILE__) + "/app/models/" )
|
12
|
+
%w( user blog post comment ).each{|m| require m }
|
13
|
+
|
14
|
+
#ActiveRecord::Base.establish_connection(
|
15
|
+
# :adapter => "sqlite3",
|
16
|
+
# :database => ":memory:")
|
17
|
+
#
|
18
|
+
#def setup_db
|
19
|
+
# ActiveRecord::Schema.define(:version => 1) do
|
20
|
+
# create_table :users do |t|
|
21
|
+
# end
|
22
|
+
# create_table :blogs do |t|
|
23
|
+
# t.references :user
|
24
|
+
# end
|
25
|
+
# create_table :posts do |t|
|
26
|
+
# t.references :blog
|
27
|
+
# t.references :user
|
28
|
+
# end
|
29
|
+
# create_table :comments do |t|
|
30
|
+
# t.references :commenter
|
31
|
+
# t.references :commentable, :polymorphic => true
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#end
|
35
|
+
#
|
36
|
+
#def teardown_db
|
37
|
+
# ActiveRecord::Base.connection.tables.each do |table|
|
38
|
+
# ActiveRecord::Base.connection.drop_table(table)
|
39
|
+
# end
|
40
|
+
#end
|
41
|
+
|
42
|
+
|
43
|
+
class ActiveSupport::TestCase
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
Rake::Task.class_eval do
|
49
|
+
|
50
|
+
# For some reason, a blank prerequisite is added
|
51
|
+
# which causes
|
52
|
+
# RuntimeError: Don't know how to build task ''
|
53
|
+
# so I make sure that they are gone
|
54
|
+
def invoke_prerequisites_with_compressing(
|
55
|
+
task_args, invocation_chain)
|
56
|
+
@prerequisites.delete_if{|a|a.blank?} # || a =~ /\A\s*\z/ }
|
57
|
+
invoke_prerequisites_without_compressing(
|
58
|
+
task_args, invocation_chain
|
59
|
+
)
|
60
|
+
end
|
61
|
+
alias_method_chain :invoke_prerequisites, :compressing
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
RDoc::Generator::Railsfish.class_eval do
|
67
|
+
def generate_class_files
|
68
|
+
debug_msg "Generating class documentation in #@outputdir"
|
69
|
+
|
70
|
+
# The pathname ends up being incorrect by "../."
|
71
|
+
# That's all it takes and since there is not apparent
|
72
|
+
# variable, I just override the method for testing.
|
73
|
+
|
74
|
+
templatefile = Pathname.new("../../lib/rdoc_rails/rdoc/generator/template/railsfish/classpage.rhtml")
|
75
|
+
|
76
|
+
@classes.each do |klass|
|
77
|
+
debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ]
|
78
|
+
outfile = @outputdir + klass.path
|
79
|
+
rel_prefix = @outputdir.relative_path_from( outfile.dirname )
|
80
|
+
svninfo = self.get_svninfo( klass )
|
81
|
+
debug_msg " rendering #{outfile}"
|
82
|
+
self.render_template( templatefile, binding(), outfile )
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jakewendt-rdoc_rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Chinasaur
|
14
|
+
- George 'Jake' Wendt
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-02-08 00:00:00 -08:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: rails
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 7
|
31
|
+
segments:
|
32
|
+
- 2
|
33
|
+
version: "2"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rdoc
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 7
|
45
|
+
segments:
|
46
|
+
- 2
|
47
|
+
version: "2"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
description: longer description of your gem
|
51
|
+
email: github@jakewendt.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files:
|
57
|
+
- README.rdoc
|
58
|
+
files:
|
59
|
+
- lib/jakewendt-rdoc_rails.rb
|
60
|
+
- lib/rdoc_rails.rb
|
61
|
+
- lib/rdoc_rails/rake.rb
|
62
|
+
- lib/rdoc_rails/rdoc/ar_association.rb
|
63
|
+
- lib/rdoc_rails/rdoc/context.rb
|
64
|
+
- lib/rdoc_rails/rdoc/generator/railsfish.rb
|
65
|
+
- lib/rdoc_rails/rdoc/generator/template/railsfish/classpage.rhtml
|
66
|
+
- lib/rdoc_rails/rdoc/parser/rails.rb
|
67
|
+
- lib/rdoc_rails/rdoc/token_stream.rb
|
68
|
+
- lib/tasks/rdoc_rails.rake
|
69
|
+
- README.rdoc
|
70
|
+
- test/app/models/blog.rb
|
71
|
+
- test/app/models/comment.rb
|
72
|
+
- test/app/models/post.rb
|
73
|
+
- test/app/models/user.rb
|
74
|
+
- test/rdoc_rails_test.rb
|
75
|
+
- test/tasks/testing.rb
|
76
|
+
- test/test_helper.rb
|
77
|
+
has_rdoc: true
|
78
|
+
homepage: http://github.com/jakewendt/rdoc_rails
|
79
|
+
licenses: []
|
80
|
+
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
requirements: []
|
105
|
+
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.5.0
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: one-line summary of your gem
|
111
|
+
test_files:
|
112
|
+
- test/app/models/blog.rb
|
113
|
+
- test/app/models/comment.rb
|
114
|
+
- test/app/models/post.rb
|
115
|
+
- test/app/models/user.rb
|
116
|
+
- test/rdoc_rails_test.rb
|
117
|
+
- test/tasks/testing.rb
|
118
|
+
- test/test_helper.rb
|