wpdoc 0.2.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/.gitignore +4 -0
  2. data/LICENSE +21 -0
  3. data/README.rdoc +37 -0
  4. data/Rakefile +51 -0
  5. data/VERSION.yml +5 -0
  6. data/bin/wpdoc +11 -0
  7. data/bin/wpdoc-merge +12 -0
  8. data/lib/rdoc/discover.rb +1 -0
  9. data/lib/wpdoc.rb +23 -0
  10. data/lib/wpdoc/c_parser_fix.rb +31 -0
  11. data/lib/wpdoc/generator/shtml.rb +359 -0
  12. data/lib/wpdoc/generator/template/direct/_context.rhtml +180 -0
  13. data/lib/wpdoc/generator/template/direct/class.rhtml +42 -0
  14. data/lib/wpdoc/generator/template/direct/file.rhtml +30 -0
  15. data/lib/wpdoc/generator/template/direct/index.rhtml +14 -0
  16. data/lib/wpdoc/generator/template/direct/resources/apple-touch-icon.png +0 -0
  17. data/lib/wpdoc/generator/template/direct/resources/css/main.css +286 -0
  18. data/lib/wpdoc/generator/template/direct/resources/css/panel.css +383 -0
  19. data/lib/wpdoc/generator/template/direct/resources/css/reset.css +53 -0
  20. data/lib/wpdoc/generator/template/direct/resources/favicon.ico +0 -0
  21. data/lib/wpdoc/generator/template/direct/resources/i/arrows.png +0 -0
  22. data/lib/wpdoc/generator/template/direct/resources/i/results_bg.png +0 -0
  23. data/lib/wpdoc/generator/template/direct/resources/i/tree_bg.png +0 -0
  24. data/lib/wpdoc/generator/template/direct/resources/js/jquery-1.3.2.min.js +19 -0
  25. data/lib/wpdoc/generator/template/direct/resources/js/jquery-effect.js +593 -0
  26. data/lib/wpdoc/generator/template/direct/resources/js/main.js +22 -0
  27. data/lib/wpdoc/generator/template/direct/resources/js/searchdoc.js +620 -0
  28. data/lib/wpdoc/generator/template/direct/resources/panel/index.html +71 -0
  29. data/lib/wpdoc/generator/template/merge/index.rhtml +14 -0
  30. data/lib/wpdoc/github.rb +64 -0
  31. data/lib/wpdoc/helpers.rb +26 -0
  32. data/lib/wpdoc/merge.rb +219 -0
  33. data/lib/wpdoc/templatable.rb +58 -0
  34. metadata +123 -0
@@ -0,0 +1,4 @@
1
+ pkg
2
+ doc
3
+ /test.rb
4
+ wpdoc.gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2009 Vladimir Kolesnikov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,37 @@
1
+ = SDoc
2
+ == What's in?
3
+ - shtml - RDoc's generator to build searchable documentation
4
+ - <tt>sdoc-merge</tt> - comand line tool to build merge multiple sdoc documentations
5
+ packages into a single one
6
+ - <tt>sdoc</tt> - command line tool to run rdoc with generator=shtml
7
+
8
+ == Getting Started
9
+ sudo gem install sdoc
10
+ sdoc -N projectdir
11
+
12
+ == Command line sdoc
13
+ sdoc is simply a wrapper to rdoc command line tool. see <tt>sdoc --help </tt>
14
+ for more details. <tt>--fmt</tt> is set to shtml by default.
15
+ Default template <tt>-T</tt> is shtml. You can also use 'direct' template.
16
+ Example:
17
+ <tt>sdoc -o doc/rails -T direct rails</tt>
18
+
19
+ == Rake
20
+ # Rakefile
21
+ require 'sdoc' # and use your RDoc task the same way you used it before
22
+
23
+ Rake::RDocTask.new do |rdoc|
24
+ rdoc.rdoc_dir = 'doc/rdoc'
25
+ rdoc.options << '--fmt' << 'shtml' # explictly set shtml generator
26
+ rdoc.template = 'direct' # lighter template used on railsapi.com
27
+ ...
28
+ end
29
+
30
+ == sdoc-merge
31
+ Usage: sdoc-merge [options] directories
32
+ -n, --names [NAMES] Names of merged repositories. Comma separated
33
+ -o, --op [DIRECTORY] Set the output directory
34
+ -t, --title [TITLE] Set the title of merged file
35
+
36
+ Example:
37
+ <tt>sdoc-merge --title "Ruby v1.9, Rails v2.3.2.1" --op merged --names "Ruby,Rails" ruby-v1.9 rails-v2.3.2.1</tt>
@@ -0,0 +1,51 @@
1
+ require 'rake/testtask'
2
+ require 'rake/gempackagetask'
3
+
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new("test") do |t|
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.warning = true
10
+ t.verbose = true
11
+ end
12
+
13
+ desc "Generate file list for .gemspec"
14
+ task :gem_file_list do
15
+ f = FileList.new
16
+ f.include('lib/**/**')
17
+ f.include('rdoc/**/**')
18
+ f.exclude('rdoc/test/**/**')
19
+ print "%w(" + f.to_a.select{|file| !File.directory? file }.join(' ') + ")\n"
20
+ end
21
+
22
+ begin
23
+ require 'jeweler'
24
+
25
+ spec = Gem::Specification.new do |gem|
26
+ gem.name = "wpdoc"
27
+ gem.summary = "rdoc html with javascript search index."
28
+ gem.email = "voloko@gmail.com"
29
+ gem.homepage = "http://github.com/dxw/wpdoc"
30
+ gem.authors = ["Volodya Kolesnikov"]
31
+ gem.add_dependency("rdoc", ">= 2.4.2")
32
+
33
+ if defined?(JRUBY_VERSION)
34
+ gem.platform = Gem::Platform.new(['universal', 'java', nil])
35
+ gem.add_dependency("json_pure", ">= 1.1.3")
36
+ else
37
+ gem.add_dependency("json", ">= 1.1.3")
38
+ end
39
+ end
40
+
41
+ jewler = Jeweler::Tasks.new(spec)
42
+
43
+ desc "Replace system gem with symlink to this folder"
44
+ task 'ghost' do
45
+ path = Gem.searcher.find(jewler.gemspec.name).full_gem_path
46
+ system 'sudo', 'rm', '-r', path
47
+ symlink File.expand_path('.'), path
48
+ end
49
+ rescue LoadError
50
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
51
+ end
@@ -0,0 +1,5 @@
1
+ ---
2
+ :patch: 17
3
+ :major: 0
4
+ :build:
5
+ :minor: 2
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby -KU
2
+
3
+ require File.dirname(__FILE__) + '/../lib/wpdoc' # add extensions
4
+
5
+ begin
6
+ r = RDoc::RDoc.new
7
+ r.document(ARGV)
8
+ rescue RDoc::RDocError => e
9
+ $stderr.puts e.message
10
+ exit(1)
11
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby -KU
2
+
3
+ require File.dirname(__FILE__) + '/../lib/wpdoc' # add extensions
4
+ require 'wpdoc/merge'
5
+
6
+ begin
7
+ m = SDoc::Merge.new
8
+ m.merge(ARGV)
9
+ rescue RDoc::RDocError => e
10
+ $stderr.puts e.message
11
+ exit(1)
12
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), '/../wpdoc')
@@ -0,0 +1,23 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require "rubygems"
3
+ gem "rdoc", ">= 2.4.2"
4
+
5
+ require "rdoc/rdoc"
6
+
7
+ module SDoc
8
+ end
9
+
10
+ require "wpdoc/generator/shtml"
11
+ require "wpdoc/c_parser_fix"
12
+
13
+ unless defined? SDOC_FIXED_RDOC_OPTIONS
14
+ SDOC_FIXED_RDOC_OPTIONS = 1
15
+ class RDoc::Options
16
+ alias_method :rdoc_initialize, :initialize
17
+
18
+ def initialize
19
+ rdoc_initialize
20
+ @generator = RDoc::Generator::SHtml
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ require "rdoc/parser/c"
2
+
3
+ # New RDoc somehow misses class comments.
4
+ # copied this function from "2.2.2"
5
+ if ['2.4.2', '2.4.3'].include? RDoc::VERSION
6
+
7
+ class RDoc::Parser::C
8
+ def find_class_comment(class_name, class_meth)
9
+ comment = nil
10
+ if @content =~ %r{((?>/\*.*?\*/\s+))
11
+ (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then
12
+ comment = $1
13
+ elsif @content =~ %r{Document-(?:class|module):\s#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m
14
+ comment = $1
15
+ else
16
+ if @content =~ /rb_define_(class|module)/m then
17
+ class_name = class_name.split("::").last
18
+ comments = []
19
+ @content.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
20
+ comments[index] = chunk
21
+ if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
22
+ comment = comments[index-1]
23
+ break
24
+ end
25
+ end
26
+ end
27
+ end
28
+ class_meth.comment = mangle_comment(comment) if comment
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,359 @@
1
+ require 'rubygems'
2
+ gem "rdoc", ">= 2.4.2"
3
+ if Gem.available? "json"
4
+ gem "json", ">= 1.1.3"
5
+ else
6
+ gem "json_pure", ">= 1.1.3"
7
+ end
8
+
9
+ require 'iconv'
10
+ require 'json'
11
+ require 'pathname'
12
+ require 'fileutils'
13
+ require 'erb'
14
+
15
+ require 'rdoc/rdoc'
16
+ require 'rdoc/generator'
17
+ require 'rdoc/generator/markup'
18
+
19
+ require 'wpdoc/github'
20
+ require 'wpdoc/templatable'
21
+ require 'wpdoc/helpers'
22
+
23
+ class RDoc::ClassModule
24
+ def document_self_or_methods
25
+ document_self || method_list.any?{ |m| m.document_self }
26
+ end
27
+
28
+ def with_documentation?
29
+ document_self_or_methods || classes_and_modules.any?{ |c| c.with_documentation? }
30
+ end
31
+ end
32
+
33
+ class RDoc::Generator::SHtml
34
+ RDoc::RDoc.add_generator( self )
35
+ include ERB::Util
36
+ include SDoc::GitHub
37
+ include SDoc::Templatable
38
+ include SDoc::Helpers
39
+
40
+ GENERATOR_DIRS = [File.join('wpdoc', 'generator'), File.join('rdoc', 'generator')]
41
+
42
+ # Used in js to reduce index sizes
43
+ TYPE_CLASS = 1
44
+ TYPE_METHOD = 2
45
+ TYPE_FILE = 3
46
+
47
+ TREE_FILE = File.join 'panel', 'tree.js'
48
+ SEARCH_INDEX_FILE = File.join 'panel', 'search_index.js'
49
+
50
+ FILE_DIR = 'files'
51
+ CLASS_DIR = 'classes'
52
+
53
+ RESOURCES_DIR = File.join('resources', '.')
54
+
55
+ attr_reader :basedir
56
+
57
+ def self.for(options)
58
+ self.new(options)
59
+ end
60
+
61
+ def self.template_dir template
62
+ $LOAD_PATH.map do |path|
63
+ GENERATOR_DIRS.map do |dir|
64
+ File.join path, dir, 'template', template
65
+ end
66
+ end.flatten.find do |dir|
67
+ File.directory? dir
68
+ end
69
+ end
70
+
71
+ def initialize(options)
72
+ @options = options
73
+ if @options.respond_to?('diagram=')
74
+ @options.diagram = false
75
+ end
76
+ @github_url_cache = {}
77
+
78
+ template = @options.template || 'direct'
79
+
80
+ templ_dir = self.class.template_dir template
81
+
82
+ raise RDoc::Error, "could not find template #{template.inspect}" unless
83
+ templ_dir
84
+
85
+ @template_dir = Pathname.new File.expand_path(templ_dir)
86
+ @basedir = Pathname.pwd.expand_path
87
+ end
88
+
89
+ def generate( top_levels )
90
+ @outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir )
91
+ @files = top_levels.sort
92
+ @classes = RDoc::TopLevel.all_classes_and_modules.sort
93
+
94
+ # Now actually write the output
95
+ copy_resources
96
+ generate_class_tree
97
+ generate_search_index
98
+ generate_file_files
99
+ generate_class_files
100
+ generate_index_file
101
+ end
102
+
103
+ def class_dir
104
+ CLASS_DIR
105
+ end
106
+
107
+ def file_dir
108
+ FILE_DIR
109
+ end
110
+
111
+
112
+ protected
113
+ ### Output progress information if debugging is enabled
114
+ def debug_msg( *msg )
115
+ return unless $DEBUG_RDOC
116
+ $stderr.puts( *msg )
117
+ end
118
+
119
+ ### Create class tree structure and write it as json
120
+ def generate_class_tree
121
+ debug_msg "Generating class tree"
122
+ topclasses = @classes.select {|klass| !(RDoc::ClassModule === klass.parent) }
123
+ tree = generate_file_tree + generate_class_tree_level(topclasses)
124
+ debug_msg " writing class tree to %s" % TREE_FILE
125
+ File.open(TREE_FILE, "w", 0644) do |f|
126
+ f.write('var tree = '); f.write(tree.to_json)
127
+ end unless $dryrun
128
+ end
129
+
130
+ ### Recursivly build class tree structure
131
+ def generate_class_tree_level(classes)
132
+ tree = []
133
+ classes.select{|c| c.with_documentation? }.sort.each do |klass|
134
+ item = [
135
+ klass.name,
136
+ klass.document_self_or_methods ? klass.path : '',
137
+ klass.module? ? '' : (klass.superclass ? " < #{String === klass.superclass ? klass.superclass : klass.superclass.full_name}" : ''),
138
+ generate_class_tree_level(klass.classes_and_modules)
139
+ ]
140
+ tree << item
141
+ end
142
+ tree
143
+ end
144
+
145
+ ### Create search index for all classes, methods and files
146
+ ### Wite it as json
147
+ def generate_search_index
148
+ debug_msg "Generating search index"
149
+
150
+ index = {
151
+ :searchIndex => [],
152
+ :longSearchIndex => [],
153
+ :info => []
154
+ }
155
+
156
+ add_class_search_index(index)
157
+ add_method_search_index(index)
158
+ add_file_search_index(index)
159
+
160
+ debug_msg " writing search index to %s" % SEARCH_INDEX_FILE
161
+ data = {
162
+ :index => index
163
+ }
164
+ File.open(SEARCH_INDEX_FILE, "w", 0644) do |f|
165
+ f.write('var search_data = '); f.write(data.to_json)
166
+ end unless $dryrun
167
+ end
168
+
169
+ ### Add files to search +index+ array
170
+ def add_file_search_index(index)
171
+ debug_msg " generating file search index"
172
+
173
+ @files.select { |file|
174
+ file.document_self
175
+ }.sort.each do |file|
176
+ index[:searchIndex].push( search_string(file.name) )
177
+ index[:longSearchIndex].push( search_string(file.path) )
178
+ index[:info].push([
179
+ file.name,
180
+ file.path,
181
+ file.path,
182
+ '',
183
+ snippet(file.comment),
184
+ TYPE_FILE
185
+ ])
186
+ end
187
+ end
188
+
189
+ ### Add classes to search +index+ array
190
+ def add_class_search_index(index)
191
+ debug_msg " generating class search index"
192
+
193
+ @classes.select { |klass|
194
+ klass.document_self_or_methods
195
+ }.sort.each do |klass|
196
+ modulename = klass.module? ? '' : (klass.superclass ? (String === klass.superclass ? klass.superclass : klass.superclass.full_name) : '')
197
+ index[:searchIndex].push( search_string(klass.name) )
198
+ index[:longSearchIndex].push( search_string(klass.parent.full_name) )
199
+ files = klass.in_files.map{ |file| file.absolute_name }
200
+ index[:info].push([
201
+ klass.name,
202
+ files.include?(klass.parent.full_name) ? files.first : klass.parent.full_name,
203
+ klass.path,
204
+ modulename ? " < #{modulename}" : '',
205
+ snippet(klass.comment),
206
+ TYPE_CLASS
207
+ ])
208
+ end
209
+ end
210
+
211
+ ### Add methods to search +index+ array
212
+ def add_method_search_index(index)
213
+ debug_msg " generating method search index"
214
+
215
+ list = @classes.map { |klass|
216
+ klass.method_list
217
+ }.flatten.sort{ |a, b| a.name == b.name ? a.parent.full_name <=> b.parent.full_name : a.name <=> b.name }.select { |method|
218
+ method.document_self
219
+ }
220
+ unless @options.show_all
221
+ list = list.find_all {|m| m.visibility == :public || m.visibility == :protected || m.force_documentation }
222
+ end
223
+
224
+ list.each do |method|
225
+ index[:searchIndex].push( search_string(method.name) + '()' )
226
+ index[:longSearchIndex].push( search_string(method.parent.full_name) )
227
+ index[:info].push([
228
+ method.name,
229
+ method.parent.full_name,
230
+ method.path,
231
+ method.params,
232
+ snippet(method.comment),
233
+ TYPE_METHOD
234
+ ])
235
+ end
236
+ end
237
+
238
+ ### Generate a documentation file for each class
239
+ def generate_class_files
240
+ debug_msg "Generating class documentation in #@outputdir"
241
+ templatefile = @template_dir + 'class.rhtml'
242
+
243
+ @classes.each do |klass|
244
+ debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ]
245
+ outfile = @outputdir + klass.path
246
+ rel_prefix = @outputdir.relative_path_from( outfile.dirname )
247
+
248
+ debug_msg " rendering #{outfile}"
249
+ self.render_template( templatefile, binding(), outfile )
250
+ end
251
+ end
252
+
253
+ ### Generate a documentation file for each file
254
+ def generate_file_files
255
+ debug_msg "Generating file documentation in #@outputdir"
256
+ templatefile = @template_dir + 'file.rhtml'
257
+
258
+ @files.each do |file|
259
+ outfile = @outputdir + file.path
260
+ debug_msg " working on %s (%s)" % [ file.full_name, outfile ]
261
+ rel_prefix = @outputdir.relative_path_from( outfile.dirname )
262
+
263
+ debug_msg " rendering #{outfile}"
264
+ self.render_template( templatefile, binding(), outfile )
265
+ end
266
+ end
267
+
268
+ def index_file
269
+ if @options.main_page && file = @files.find { |f| f.full_name == @options.main_page }
270
+ file
271
+ else
272
+ @files.first
273
+ end
274
+ end
275
+
276
+ ### Create index.html with frameset
277
+ def generate_index_file
278
+ debug_msg "Generating index file in #@outputdir"
279
+ templatefile = @template_dir + 'index.rhtml'
280
+ outfile = @outputdir + 'index.html'
281
+ index_path = index_file.path
282
+
283
+ self.render_template( templatefile, binding(), outfile )
284
+ end
285
+
286
+ ### Strip comments on a space after 100 chars
287
+ def snippet(str)
288
+ str ||= ''
289
+ if str =~ /^(?>\s*)[^\#]/
290
+ content = str
291
+ else
292
+ content = str.gsub(/^\s*(#+)\s*/, '')
293
+ end
294
+
295
+ content = content.sub(/^(.{100,}?)\s.*/m, "\\1").gsub(/\r?\n/m, ' ')
296
+
297
+ begin
298
+ content.to_json
299
+ rescue # might fail on non-unicode string
300
+ begin
301
+ content = Iconv.conv('latin1//ignore', "UTF8", content) # remove all non-unicode chars
302
+ content.to_json
303
+ rescue
304
+ content = '' # something hugely wrong happend
305
+ end
306
+ end
307
+ content
308
+ end
309
+
310
+ ### Build search index key
311
+ def search_string(string)
312
+ string ||= ''
313
+ string.downcase.gsub(/\s/,'')
314
+ end
315
+
316
+ ### Copy all the resource files to output dir
317
+ def copy_resources
318
+ resoureces_path = @template_dir + RESOURCES_DIR
319
+ debug_msg "Copying #{resoureces_path}/** to #{@outputdir}/**"
320
+ FileUtils.cp_r resoureces_path.to_s, @outputdir.to_s, :preserve => true unless $dryrun
321
+ end
322
+
323
+ class FilesTree
324
+ attr_reader :children
325
+ def add(path, url)
326
+ path = path.split(File::SEPARATOR) unless Array === path
327
+ @children ||= {}
328
+ if path.length == 1
329
+ @children[path.first] = url
330
+ else
331
+ @children[path.first] ||= FilesTree.new
332
+ @children[path.first].add(path[1, path.length], url)
333
+ end
334
+ end
335
+ end
336
+
337
+ def generate_file_tree
338
+ if @files.length > 1
339
+ @files_tree = FilesTree.new
340
+ @files.each do |file|
341
+ @files_tree.add(file.relative_name, file.path)
342
+ end
343
+ [['', '', 'files', generate_file_tree_level(@files_tree)]]
344
+ else
345
+ []
346
+ end
347
+ end
348
+
349
+ def generate_file_tree_level(tree)
350
+ tree.children.keys.sort.map do |name|
351
+ child = tree.children[name]
352
+ if String === child
353
+ [name, child, '', []]
354
+ else
355
+ ['', '', name, generate_file_tree_level(child)]
356
+ end
357
+ end
358
+ end
359
+ end