tomdoc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +104 -0
- data/Rakefile +80 -0
- data/bin/tomdoc +6 -0
- data/lib/tomdoc.rb +25 -0
- data/lib/tomdoc/arg.rb +14 -0
- data/lib/tomdoc/cli.rb +150 -0
- data/lib/tomdoc/generator.rb +138 -0
- data/lib/tomdoc/generators/console.rb +68 -0
- data/lib/tomdoc/generators/html.rb +42 -0
- data/lib/tomdoc/method.rb +21 -0
- data/lib/tomdoc/scope.rb +46 -0
- data/lib/tomdoc/source_parser.rb +145 -0
- data/lib/tomdoc/tomdoc.rb +133 -0
- data/lib/tomdoc/version.rb +3 -0
- data/man/tomdoc.5 +320 -0
- data/man/tomdoc.5.html +285 -0
- data/man/tomdoc.5.ronn +203 -0
- data/test/console_generator_test.rb +20 -0
- data/test/fixtures/chimney.rb +711 -0
- data/test/fixtures/multiplex.rb +47 -0
- data/test/fixtures/simple.rb +10 -0
- data/test/generator_test.rb +47 -0
- data/test/helper.rb +21 -0
- data/test/html_generator_test.rb +18 -0
- data/test/source_parser_test.rb +66 -0
- data/test/tomdoc_parser_test.rb +127 -0
- metadata +143 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Tom Preston-Werner, Chris Wanstrath
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
TomDoc
|
2
|
+
======
|
3
|
+
|
4
|
+
TomDoc is documentation for humans. Using a few simple rules and zero
|
5
|
+
special syntax you can produce great looking documentation for both humans
|
6
|
+
and machines.
|
7
|
+
|
8
|
+
Just follow these four easy steps:
|
9
|
+
|
10
|
+
1. Describe your method
|
11
|
+
2. Optionally list and describe its arguments
|
12
|
+
3. Optionally list some examples
|
13
|
+
4. Explain what your method returns
|
14
|
+
|
15
|
+
Like this:
|
16
|
+
|
17
|
+
# Duplicate some text an abitrary number of times.
|
18
|
+
#
|
19
|
+
# text - The String to be duplicated.
|
20
|
+
# count - The Integer number of times to duplicate the text.
|
21
|
+
#
|
22
|
+
# Examples
|
23
|
+
# multiplex('Tom', 4)
|
24
|
+
# # => 'TomTomTomTom'
|
25
|
+
#
|
26
|
+
# Returns the duplicated String.
|
27
|
+
def multiplex(text, count)
|
28
|
+
text * count
|
29
|
+
end
|
30
|
+
|
31
|
+
See [the manual][man] or [the spec][spec] for a more in-depth
|
32
|
+
analysis.
|
33
|
+
|
34
|
+
|
35
|
+
tomdoc.rb
|
36
|
+
---------
|
37
|
+
|
38
|
+
This repository contains tomdoc.rb, a Ruby library for parsing
|
39
|
+
TomDoc and generating pretty documentation from it.
|
40
|
+
|
41
|
+
|
42
|
+
Installation
|
43
|
+
------------
|
44
|
+
|
45
|
+
easy_install Pygments
|
46
|
+
gem install tomdoc
|
47
|
+
|
48
|
+
tomdoc.rb has been tested with Ruby 1.8.7.
|
49
|
+
|
50
|
+
|
51
|
+
Usage
|
52
|
+
-----
|
53
|
+
|
54
|
+
$ tomdoc file.rb
|
55
|
+
# Prints colored documentation of file.rb.
|
56
|
+
|
57
|
+
$ tomdoc file.rb -n STRING
|
58
|
+
# Prints methods or classes in file.rb matching STRING.
|
59
|
+
|
60
|
+
$ tomdoc fileA.rb fileB.rb ...
|
61
|
+
# Prints colored documentation of multiple files.
|
62
|
+
|
63
|
+
$ tomdoc -f html file.rb
|
64
|
+
# Prints HTML documentation of file.rb.
|
65
|
+
|
66
|
+
$ tomdoc -i file.rb
|
67
|
+
# Ignore TomDoc validation, print any methods we find.
|
68
|
+
|
69
|
+
$ tomdoc -h
|
70
|
+
# Displays more options.
|
71
|
+
|
72
|
+
|
73
|
+
Ruby API
|
74
|
+
--------
|
75
|
+
|
76
|
+
Fully TomDoc'd. Well, it will be.
|
77
|
+
|
78
|
+
For now:
|
79
|
+
|
80
|
+
$ tomdoc lib/tomdoc/source_parser.rb
|
81
|
+
|
82
|
+
|
83
|
+
Formats
|
84
|
+
-------
|
85
|
+
|
86
|
+
### Console
|
87
|
+
|
88
|
+
tomdoc lib/tomdoc/source_parser.rb -n token
|
89
|
+
|
90
|
+
![pattern](http://img.skitch.com/20100408-mnyxuxb4xrrg5x4pnpsmuth4mu.png)
|
91
|
+
|
92
|
+
### HTML
|
93
|
+
|
94
|
+
tomdoc -f html lib/tomdoc/source_parser.rb | browser
|
95
|
+
|
96
|
+
or
|
97
|
+
|
98
|
+
tomdoc -f html lib/tomdoc/source_parser.rb > doc.html
|
99
|
+
open doc.html
|
100
|
+
|
101
|
+
![html](http://img.skitch.com/20100408-dbhtc4mef2q3ygmn63csxgh14w.png)
|
102
|
+
|
103
|
+
[man]: https://github.com/defunkt/tomdoc/blob/tomdoc.rb/man/tomdoc.5.ronn
|
104
|
+
[spec]: https://github.com/defunkt/tomdoc/blob/tomdoc.rb/tomdoc.md
|
data/Rakefile
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
def command?(command)
|
4
|
+
system("type #{command} > /dev/null 2>&1")
|
5
|
+
end
|
6
|
+
|
7
|
+
#
|
8
|
+
# Manual
|
9
|
+
#
|
10
|
+
|
11
|
+
if command? :ronn
|
12
|
+
desc "Build and display the manual."
|
13
|
+
task :man => "man:build" do
|
14
|
+
exec "man man/tomdoc.5"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Build and display the manual in your browser."
|
18
|
+
task "man:html" => "man:build" do
|
19
|
+
sh "open man/tomdoc.5.html"
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Build the manual"
|
23
|
+
task "man:build" do
|
24
|
+
sh "ronn -br5 --organization=MOJOMBO --manual='TomDoc Manual' man/*.ronn"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
#
|
30
|
+
# Tests
|
31
|
+
#
|
32
|
+
|
33
|
+
task :default => :test
|
34
|
+
|
35
|
+
if command? :turn
|
36
|
+
desc "Run tests"
|
37
|
+
task :test do
|
38
|
+
suffix = "-n #{ENV['TEST']}" if ENV['TEST']
|
39
|
+
sh "turn test/*.rb #{suffix}"
|
40
|
+
end
|
41
|
+
else
|
42
|
+
Rake::TestTask.new do |t|
|
43
|
+
t.libs << 'lib'
|
44
|
+
t.pattern = 'test/**/*_test.rb'
|
45
|
+
t.verbose = false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
#
|
51
|
+
# Development
|
52
|
+
#
|
53
|
+
|
54
|
+
desc "Drop to irb."
|
55
|
+
task :console do
|
56
|
+
exec "irb -I lib -rtomdoc"
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
#
|
61
|
+
# Gems
|
62
|
+
#
|
63
|
+
|
64
|
+
begin
|
65
|
+
require 'tomdoc/version'
|
66
|
+
require 'mg'
|
67
|
+
MG.new("tomdoc.gemspec")
|
68
|
+
|
69
|
+
desc "Push a new version to Gemcutter and publish docs."
|
70
|
+
task :publish => "gem:publish" do
|
71
|
+
require File.dirname(__FILE__) + '/lib/tomdoc/version'
|
72
|
+
|
73
|
+
sh "git tag v#{TomDoc::VERSION}"
|
74
|
+
sh "git push origin master --tags"
|
75
|
+
sh "git clean -fd"
|
76
|
+
end
|
77
|
+
rescue LoadError
|
78
|
+
warn "mg not available."
|
79
|
+
warn "Install it with: gem i mg"
|
80
|
+
end
|
data/bin/tomdoc
ADDED
data/lib/tomdoc.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
require 'ruby_parser'
|
4
|
+
require 'colored'
|
5
|
+
|
6
|
+
module TomDoc
|
7
|
+
autoload :Open3, 'open3'
|
8
|
+
|
9
|
+
autoload :CLI, 'tomdoc/cli'
|
10
|
+
|
11
|
+
autoload :Scope, 'tomdoc/scope'
|
12
|
+
autoload :Method, 'tomdoc/method'
|
13
|
+
autoload :Arg, 'tomdoc/arg'
|
14
|
+
autoload :TomDoc, 'tomdoc/tomdoc'
|
15
|
+
|
16
|
+
autoload :SourceParser, 'tomdoc/source_parser'
|
17
|
+
autoload :Generator, 'tomdoc/generator'
|
18
|
+
|
19
|
+
autoload :VERSION, 'tomdoc/version'
|
20
|
+
|
21
|
+
module Generators
|
22
|
+
autoload :Console, 'tomdoc/generators/console'
|
23
|
+
autoload :HTML, 'tomdoc/generators/html'
|
24
|
+
end
|
25
|
+
end
|
data/lib/tomdoc/arg.rb
ADDED
data/lib/tomdoc/cli.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module TomDoc
|
4
|
+
class CLI
|
5
|
+
#
|
6
|
+
# DSL Magics
|
7
|
+
#
|
8
|
+
|
9
|
+
def self.options(&block)
|
10
|
+
block ? (@options = block) : @options
|
11
|
+
end
|
12
|
+
|
13
|
+
def options
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.instance_eval(&self.class.options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def pp(*args)
|
20
|
+
require 'pp'
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
#
|
26
|
+
# Define Options
|
27
|
+
#
|
28
|
+
|
29
|
+
options do
|
30
|
+
@options = {}
|
31
|
+
|
32
|
+
self.banner = "Usage: tomdoc [options] FILE1 FILE2 ..."
|
33
|
+
|
34
|
+
separator " "
|
35
|
+
separator "Examples:"
|
36
|
+
separator <<example
|
37
|
+
$ tomdoc file.rb
|
38
|
+
# Prints colored documentation of file.rb.
|
39
|
+
|
40
|
+
$ tomdoc file.rb -n STRING
|
41
|
+
# Prints methods or classes in file.rb matching STRING.
|
42
|
+
|
43
|
+
$ tomdoc -f html file.rb
|
44
|
+
# Prints HTML documentation of file.rb.
|
45
|
+
example
|
46
|
+
|
47
|
+
separator " "
|
48
|
+
separator "Options:"
|
49
|
+
|
50
|
+
on "-c", "--colored", "Pass -p, -s, or -t output to Pygments." do
|
51
|
+
ARGV.delete('-c') || ARGV.delete('--colored')
|
52
|
+
exec "#{$0} #{ARGV * ' '} | pygmentize -l ruby"
|
53
|
+
end
|
54
|
+
|
55
|
+
on "-t", "--tokens", "Parse FILE and print the tokenized form." do
|
56
|
+
sexp = SourceParser.new.sexp(argf.read)
|
57
|
+
pp SourceParser.new.tokenize(sexp)
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
|
61
|
+
on "-s", "--sexp", "Parse FILE and print the AST's sexps." do
|
62
|
+
pp RubyParser.new.parse(argf.read).to_a
|
63
|
+
exit
|
64
|
+
end
|
65
|
+
|
66
|
+
on "-n", "--pattern=PATTERN",
|
67
|
+
"Limit results to strings matching PATTERN." do |pattern|
|
68
|
+
|
69
|
+
@options[:pattern] = pattern
|
70
|
+
end
|
71
|
+
|
72
|
+
on "-f", "--format=FORMAT",
|
73
|
+
"Parse FILE and print the TomDoc as FORMAT." do |format|
|
74
|
+
|
75
|
+
if format.to_s.downcase == "html"
|
76
|
+
puts Generators::HTML.new(@options).generate(argf.read)
|
77
|
+
exit
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
on "-i", "--ignore",
|
82
|
+
"Ignore validation, print all methods we find with comments.." do
|
83
|
+
|
84
|
+
@options[:validate] = false
|
85
|
+
end
|
86
|
+
|
87
|
+
separator " "
|
88
|
+
separator "Common Options:"
|
89
|
+
|
90
|
+
on "-v", "--version", "Print the version" do
|
91
|
+
puts "TomDoc v#{VERSION}"
|
92
|
+
exit
|
93
|
+
end
|
94
|
+
|
95
|
+
on "-h", "--help", "Show this message" do
|
96
|
+
puts self
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
|
100
|
+
on_tail do
|
101
|
+
puts Generators::Console.new(@options).generate(argf.read)
|
102
|
+
exit
|
103
|
+
end
|
104
|
+
|
105
|
+
separator ""
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
#
|
110
|
+
# Actions
|
111
|
+
#
|
112
|
+
|
113
|
+
def self.parse_options(args)
|
114
|
+
new.parse_options(args)
|
115
|
+
end
|
116
|
+
|
117
|
+
def parse_options(args)
|
118
|
+
options.parse(args)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class OptionParser
|
124
|
+
# ARGF faker.
|
125
|
+
def argf
|
126
|
+
buffer = ''
|
127
|
+
|
128
|
+
ARGV.select { |arg| File.exists?(arg) }.each do |file|
|
129
|
+
buffer << File.read(file)
|
130
|
+
end
|
131
|
+
|
132
|
+
require 'stringio'
|
133
|
+
StringIO.new(buffer)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
#
|
139
|
+
# Main
|
140
|
+
#
|
141
|
+
|
142
|
+
# Help is the default.
|
143
|
+
ARGV << '-h' if ARGV.empty? && $stdin.tty?
|
144
|
+
|
145
|
+
# Process options
|
146
|
+
TomDoc::CLI.parse_options(ARGV) if $stdin.tty?
|
147
|
+
|
148
|
+
# Still here - process ARGF
|
149
|
+
TomDoc::CLI.process_files(ARGF)
|
150
|
+
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module TomDoc
|
2
|
+
class Generator
|
3
|
+
attr_reader :options, :scopes
|
4
|
+
|
5
|
+
# Creates a Generator.
|
6
|
+
#
|
7
|
+
# options - Optional Symbol-keyed Hash:
|
8
|
+
# :validate - Whether or not to validate TomDoc.
|
9
|
+
#
|
10
|
+
# scopes - Optional Symbol-keyed Hash.
|
11
|
+
#
|
12
|
+
# Returns an instance of TomDoc::Generator
|
13
|
+
def initialize(options = {}, scopes = {})
|
14
|
+
@options = {
|
15
|
+
:validate => true
|
16
|
+
}
|
17
|
+
@options.update(options)
|
18
|
+
|
19
|
+
@scopes = {}
|
20
|
+
@buffer = ''
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.generate(text_or_sexp)
|
24
|
+
new.generate(text_or_sexp)
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate(text_or_sexp)
|
28
|
+
if text_or_sexp.is_a?(String)
|
29
|
+
sexp = SourceParser.parse(text_or_sexp)
|
30
|
+
else
|
31
|
+
sexp = text_or_sexp
|
32
|
+
end
|
33
|
+
|
34
|
+
process(sexp)
|
35
|
+
end
|
36
|
+
|
37
|
+
def process(scopes = {}, prefix = nil)
|
38
|
+
old_scopes = @scopes
|
39
|
+
@scopes = scopes
|
40
|
+
scopes.each do |name, scope|
|
41
|
+
write_scope(scope, prefix)
|
42
|
+
process(scope, "#{name}::")
|
43
|
+
end
|
44
|
+
|
45
|
+
@buffer
|
46
|
+
ensure
|
47
|
+
@scopes = old_scopes || {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def write_scope(scope, prefix)
|
51
|
+
write_scope_header(scope, prefix)
|
52
|
+
write_class_methods(scope, prefix)
|
53
|
+
write_instance_methods(scope, prefix)
|
54
|
+
write_scope_footer(scope, prefix)
|
55
|
+
end
|
56
|
+
|
57
|
+
def write_scope_header(scope, prefix)
|
58
|
+
end
|
59
|
+
|
60
|
+
def write_scope_footer(scope, prefix)
|
61
|
+
end
|
62
|
+
|
63
|
+
def write_class_methods(scope, prefix = nil)
|
64
|
+
prefix ="#{prefix}#{scope.name}."
|
65
|
+
|
66
|
+
scope.class_methods.map do |method|
|
67
|
+
next if !valid?(method, prefix)
|
68
|
+
write_method(method, prefix)
|
69
|
+
end.compact
|
70
|
+
end
|
71
|
+
|
72
|
+
def write_instance_methods(scope, prefix = nil)
|
73
|
+
prefix = "#{prefix}#{scope.name}#"
|
74
|
+
|
75
|
+
scope.instance_methods.map do |method|
|
76
|
+
next if !valid?(method, prefix)
|
77
|
+
write_method(method, prefix)
|
78
|
+
end.compact
|
79
|
+
end
|
80
|
+
|
81
|
+
def write_method(method, prefix = '')
|
82
|
+
end
|
83
|
+
|
84
|
+
def write(*things)
|
85
|
+
things.each do |thing|
|
86
|
+
@buffer << "#{thing}\n"
|
87
|
+
end
|
88
|
+
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def pygments(text, *args)
|
93
|
+
out = ''
|
94
|
+
|
95
|
+
Open3.popen3("pygmentize", *args) do |stdin, stdout, stderr|
|
96
|
+
stdin.puts text
|
97
|
+
stdin.close
|
98
|
+
out = stdout.read.chomp
|
99
|
+
end
|
100
|
+
|
101
|
+
out
|
102
|
+
end
|
103
|
+
|
104
|
+
def constant?(const)
|
105
|
+
const = const.split('::').first if const.include?('::')
|
106
|
+
constant_names.include?(const.intern) || Object.const_defined?(const)
|
107
|
+
end
|
108
|
+
|
109
|
+
def constant_names
|
110
|
+
name = @scopes.name if @scopes.respond_to?(:name)
|
111
|
+
[ :Boolean, :Test, name ].compact + @scopes.keys
|
112
|
+
end
|
113
|
+
|
114
|
+
def valid?(object, prefix)
|
115
|
+
matches_pattern?(prefix, object.name) && valid_tomdoc?(object.tomdoc)
|
116
|
+
end
|
117
|
+
|
118
|
+
def matches_pattern?(prefix, name)
|
119
|
+
if pattern = options[:pattern]
|
120
|
+
# "-n hey" vs "-n /he.+y/"
|
121
|
+
if pattern =~ /^\/.+\/$/
|
122
|
+
pattern = pattern.sub(/^\//, '').sub(/\/$/, '')
|
123
|
+
regexp = Regexp.new(pattern)
|
124
|
+
else
|
125
|
+
regexp = Regexp.new(Regexp.escape(pattern))
|
126
|
+
end
|
127
|
+
|
128
|
+
regexp =~ name.to_s || regexp =~ prefix.to_s
|
129
|
+
else
|
130
|
+
true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def valid_tomdoc?(comment)
|
135
|
+
options[:validate] ? TomDoc.valid?(comment) : true
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|