rocco 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2010 Ryan Tomayko <http://tomayko.com/about>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # rocco
2
+
3
+ This is a Ruby port of [Docco](http://jashkenas.github.com/docco/), a
4
+ _quick-and-dirty, hundred-line-long, literate-programming-style
5
+ documentation generator_.
6
+
7
+ See the [Rocco generated documentation](http://rtomayko.github.com/rocco/)
8
+ for more information.
data/Rakefile ADDED
@@ -0,0 +1,59 @@
1
+ require 'rake/testtask'
2
+ task :default => :test
3
+
4
+ desc 'Run tests (default)'
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.test_files = FileList['test/*_test.rb']
7
+ t.ruby_opts = ['-rubygems'] if defined? Gem
8
+ end
9
+
10
+ # PACKAGING =================================================================
11
+
12
+ if defined?(Gem)
13
+ SPEC = eval(File.read('rocco.gemspec'))
14
+
15
+ def package(ext='')
16
+ "pkg/rocco-#{SPEC.version}" + ext
17
+ end
18
+
19
+ desc 'Build packages'
20
+ task :package => %w[.gem .tar.gz].map {|e| package(e)}
21
+
22
+ desc 'Build and install as local gem'
23
+ task :install => package('.gem') do
24
+ sh "gem install #{package('.gem')}"
25
+ end
26
+
27
+ directory 'pkg/'
28
+
29
+ file package('.gem') => %w[pkg/ rocco.gemspec] + SPEC.files do |f|
30
+ sh "gem build rocco.gemspec"
31
+ mv File.basename(f.name), f.name
32
+ end
33
+
34
+ file package('.tar.gz') => %w[pkg/] + SPEC.files do |f|
35
+ sh "git archive --format=tar HEAD | gzip > #{f.name}"
36
+ end
37
+ end
38
+
39
+ # GEMSPEC ===================================================================
40
+
41
+ file 'rocco.gemspec' => FileList['{lib,test,bin}/**','Rakefile'] do |f|
42
+ # read version from tilt.rb
43
+ version = File.read('lib/rocco.rb')[/VERSION = '(.*)'/] && $1
44
+ # read spec file and split out manifest section
45
+ spec = File.
46
+ read(f.name).
47
+ sub(/s\.version\s*=\s*'.*'/, "s.version = '#{version}'")
48
+ parts = spec.split(" # = MANIFEST =\n")
49
+ # determine file list from git ls-files
50
+ files = `git ls-files`.
51
+ split("\n").sort.reject{ |file| file =~ /^\./ }.
52
+ map{ |file| " #{file}" }.join("\n")
53
+ # piece file back together and write...
54
+ parts[1] = " s.files = %w[\n#{files}\n ]\n"
55
+ spec = parts.join(" # = MANIFEST =\n")
56
+ spec.sub!(/s.date = '.*'/, "s.date = '#{Time.now.strftime("%Y-%m-%d")}'")
57
+ File.open(f.name, 'w') { |io| io.write(spec) }
58
+ puts "updated #{f.name}"
59
+ end
data/bin/rocco ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ libdir = File.expand_path('../../lib', __FILE__).sub(/^#{Dir.pwd}\//, '')
3
+
4
+ begin
5
+ require 'rdiscount'
6
+ require 'rocco'
7
+ rescue LoadError
8
+ case $!.to_s
9
+ when /rdiscount/
10
+ if !defined?(Gem)
11
+ warn "warn: #$!. trying again with rubygems"
12
+ require 'rubygems'
13
+ retry
14
+ end
15
+ when /rocco/
16
+ if !$:.include?(libdir)
17
+ warn "warn: #$!. trying again with #{libdir} on load path"
18
+ $:.unshift(libdir)
19
+ retry
20
+ end
21
+ end
22
+ raise
23
+ end
24
+
25
+ ARGV.each do |filename|
26
+ rocco = Rocco.new(filename)
27
+ dest = File.basename(filename, '.rb') + '.html'
28
+ warn "rocco: #{filename} -> #{dest}"
29
+ File.open(dest, 'wb') { |fd| fd.write(rocco.to_html) }
30
+ end
data/lib/rocco.rb ADDED
@@ -0,0 +1,153 @@
1
+ # **Rocco** is a Ruby port of [Docco][do], the quick-and-dirty,
2
+ # hundred-line-long, literate-programming-style documentation generator.
3
+ #
4
+ # Rocco reads Ruby source files and produces annotated source documentation
5
+ # in HTML format. Comments are formatted with [Markdown][md] and presented
6
+ # alongside syntax highlighted code so as to give an annotation effect.
7
+ # This page is the result of running Rocco against its own source file.
8
+ #
9
+ # Most of this was written while waiting for [node.js][no] to build (so I
10
+ # could use Docco!). Docco's gorgeous HTML and CSS are taken verbatim.
11
+ # The main difference is that Rocco is written in Ruby instead of
12
+ # [CoffeeScript][co] and may be a bit easier to obtain and install in
13
+ # existing Ruby environments or where node doesn't run yet.
14
+ #
15
+ # Rocco can be installed with rubygems:
16
+ #
17
+ # gem install rocco
18
+ #
19
+ # Once installed, the `rocco` command can be used to generate documentation
20
+ # for a set of Ruby source files:
21
+ #
22
+ # rocco lib/*.rb
23
+ #
24
+ # The HTML files are written to the current working directory.
25
+ #
26
+ # [no]: http://nodejs.org/
27
+ # [do]: http://jashkenas.github.com/docco/
28
+ # [co]: http://coffeescript.org/
29
+ # [md]: http://daringfireball.net/projects/markdown/
30
+
31
+ #### Prerequisites
32
+
33
+ # The [rdiscount](http://github.com/rtomayko/rdiscount) library is
34
+ # required for Markdown processing.
35
+ require 'rdiscount'
36
+
37
+ # We use [{{ mustache }}](http://defunkt.github.com/mustache/) for
38
+ # templating.
39
+ require 'mustache'
40
+
41
+ # Code is run through [Pygments](http://pygments.org/) for syntax
42
+ # highlighting. Fail fast if we can't find the `pygmentize` program.
43
+ if ! ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
44
+ fail "Pygments is required for syntax highlighting"
45
+ end
46
+
47
+ #### Public Interface
48
+
49
+ # `Rocco.new` takes a source `filename` and an optional `block`.
50
+ # When `block` is given, it must read the contents of the file using
51
+ # whatever means necessary and return it as a string. With no `block`, the
52
+ # file is read to retrieve data.
53
+ class Rocco
54
+ VERSION = '0.1'
55
+
56
+ def initialize(filename, &block)
57
+ @file = filename
58
+ @data =
59
+ if block_given?
60
+ yield
61
+ else
62
+ File.read(filename)
63
+ end
64
+ # Parsing and highlighting
65
+ @sections = highlight(parse(@data))
66
+ end
67
+
68
+ # The filename as given to `Rocco.new`.
69
+ attr_reader :file
70
+
71
+ # A list of two-tuples representing each *section* of the source file. Each
72
+ # item in the list has the form: `[docs_html, code_html]`, where both
73
+ # elements are strings containing the documentation and source code HTML,
74
+ # respectively.
75
+ attr_reader :sections
76
+
77
+ # Generate HTML output for the entire document.
78
+ require 'rocco/layout'
79
+ def to_html
80
+ Rocco::Layout.new(self).render
81
+ end
82
+
83
+ #### Internal Parsing and Highlighting
84
+
85
+ # Parse the raw file data into a list of two-tuples.
86
+ def parse(data)
87
+ sections = []
88
+ docs, code = [], []
89
+ data.split("\n").each do |line|
90
+ case line
91
+ when /^\s*#/
92
+ if code.any?
93
+ sections << [docs, code]
94
+ docs, code = [], []
95
+ end
96
+ docs << line
97
+ when /^\s*$/
98
+ code << line
99
+ else
100
+ code << line
101
+ end
102
+ end
103
+ sections << [docs, code] if docs.any? || code.any?
104
+ sections
105
+ end
106
+
107
+ # Take the raw section data and apply markdown formatting and syntax
108
+ # highlighting.
109
+ def highlight(sections)
110
+ # Start by splitting the docs and codes blocks into two separate lists.
111
+ docs_blocks, code_blocks = [], []
112
+ sections.each do |docs,code|
113
+ docs_blocks << docs.map { |line| line.sub(/^\s*#\s?/, '') }.join("\n")
114
+ code_blocks << code.join("\n")
115
+ end
116
+
117
+ # Combine all docs blocks into a single big markdown document and run
118
+ # through RDiscount. Then split it back out into separate sections.
119
+ markdown = docs_blocks.join("\n##### DIVIDER\n")
120
+ docs_html = Markdown.new(markdown, :smart).
121
+ to_html.
122
+ split("\n<h5>DIVIDER</h5>\n")
123
+
124
+ # Combine all code blocks into a single big stream and run through
125
+ # pygments. We `popen` a pygmentize process and then fork off a
126
+ # writer process.
127
+ code_html = nil
128
+ open("|pygmentize -l ruby -f html", 'r+') do |fd|
129
+ fork {
130
+ fd.close_read
131
+ fd.write code_blocks.join("\n# DIVIDER\n")
132
+ fd.close_write
133
+ exit!
134
+ }
135
+
136
+ fd.close_write
137
+ code_html = fd.read
138
+ fd.close_read
139
+ end
140
+
141
+ # Do some post-processing on the pygments output to remove
142
+ # partial `<pre>` blocks. We'll add these back when we build to main
143
+ # document.
144
+ code_html = code_html.
145
+ split(/\n?<span class="c1"># DIVIDER<\/span>\n?/m).
146
+ map { |code| code.sub(/\n?<div class="highlight"><pre>/m, '') }.
147
+ map { |code| code.sub(/\n?<\/pre><\/div>\n/m, '') }
148
+
149
+ # Combine the docs and code lists into the same sections style list we
150
+ # started with.
151
+ docs_html.zip(code_html)
152
+ end
153
+ end
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>{{ title }}</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <table cellspacing=0 cellpadding=0>
11
+ <thead>
12
+ <tr>
13
+ <th class=docs><h1>{{ title }}</h1></th>
14
+ <th class=code></th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ {{#sections}}
19
+ <tr id='section-{{ num }}'>
20
+ <td class=docs>{{{ docs }}}</td>
21
+ <td class=code>
22
+ <div class='highlight'><pre>{{{ code }}}</pre></div>
23
+ </td>
24
+ </tr>
25
+ {{/sections}}
26
+ </table>
27
+ </div>
28
+ </body>
@@ -0,0 +1,24 @@
1
+ require 'mustache'
2
+
3
+ class Rocco::Layout < Mustache
4
+ self.template_path = File.dirname(__FILE__)
5
+
6
+ def initialize(doc)
7
+ @doc = doc
8
+ end
9
+
10
+ def title
11
+ File.basename(@doc.file)
12
+ end
13
+
14
+ def sections
15
+ num = 0
16
+ @doc.sections.map do |docs,code|
17
+ {
18
+ :docs => docs,
19
+ :code => code,
20
+ :num => (num += 1)
21
+ }
22
+ end
23
+ end
24
+ end
data/rocco.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+
5
+ s.name = 'rocco'
6
+ s.version = '0.1'
7
+ s.date = '2010-03-08'
8
+
9
+ s.description = "Docco in Ruby"
10
+ s.summary = s.description
11
+
12
+ s.authors = ["Ryan Tomayko"]
13
+ s.email = "r@tomayko.com"
14
+
15
+ # = MANIFEST =
16
+ s.files = %w[
17
+ COPYING
18
+ README.md
19
+ Rakefile
20
+ bin/rocco
21
+ lib/rocco.rb
22
+ lib/rocco/layout.mustache
23
+ lib/rocco/layout.rb
24
+ rocco.gemspec
25
+ ]
26
+ # = MANIFEST =
27
+
28
+ s.executables = ["rocco"]
29
+
30
+ s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
31
+ s.add_dependency 'rdiscount'
32
+ s.add_dependency 'mustache'
33
+
34
+ s.has_rdoc = false
35
+ s.homepage = "http://rtomayko.github.com/rocco/"
36
+ s.require_paths = %w[lib]
37
+ s.rubygems_version = '1.1.1'
38
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rocco
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Ryan Tomayko
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-03-08 00:00:00 -08:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: rdiscount
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
28
+ version: "0"
29
+ type: :runtime
30
+ version_requirements: *id001
31
+ - !ruby/object:Gem::Dependency
32
+ name: mustache
33
+ prerelease: false
34
+ requirement: &id002 !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ segments:
39
+ - 0
40
+ version: "0"
41
+ type: :runtime
42
+ version_requirements: *id002
43
+ description: Docco in Ruby
44
+ email: r@tomayko.com
45
+ executables:
46
+ - rocco
47
+ extensions: []
48
+
49
+ extra_rdoc_files: []
50
+
51
+ files:
52
+ - COPYING
53
+ - README.md
54
+ - Rakefile
55
+ - bin/rocco
56
+ - lib/rocco.rb
57
+ - lib/rocco/layout.mustache
58
+ - lib/rocco/layout.rb
59
+ - rocco.gemspec
60
+ has_rdoc: true
61
+ homepage: http://rtomayko.github.com/rocco/
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options: []
66
+
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.3.6
87
+ signing_key:
88
+ specification_version: 2
89
+ summary: Docco in Ruby
90
+ test_files: []
91
+