tomdoc 0.1.0

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.
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.
@@ -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
@@ -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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tomdoc'
4
+
5
+ # Process options
6
+ TomDoc::CLI.parse_options(ARGV)
@@ -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
@@ -0,0 +1,14 @@
1
+ module TomDoc
2
+ class Arg
3
+ attr_accessor :name, :description
4
+
5
+ def initialize(name, description = '')
6
+ @name = name.to_s.intern
7
+ @description = description
8
+ end
9
+
10
+ def optional?
11
+ @description.downcase.include? 'optional'
12
+ end
13
+ end
14
+ end
@@ -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