wpdoc 0.2.17

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.
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