rocco 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,23 @@
1
+
2
+
3
+ ___ ___ ___ ___ ___
4
+ /\ \ /\ \ /\ \ /\ \ /\ \
5
+ /::\ \ /::\ \ /::\ \ /::\ \ /::\ \
6
+ /::\:\__\ /:/\:\__\ /:/\:\__\ /:/\:\__\ /:/\:\__\
7
+ \;:::/ / \:\/:/ / \:\ \/__/ \:\ \/__/ \:\/:/ /
8
+ |:\/__/ \::/ / \:\__\ \:\__\ \::/ /
9
+ \|__| \/__/ \/__/ \/__/ \/__/
10
+
11
+
12
+
13
+ Rocco is a quick-and-dirty, literate-programming-style documentation
14
+ generator for Ruby. See the Rocco generated docs for more information:
15
+
16
+ <http://rtomayko.github.com/rocco/>
17
+
18
+
19
+ Rocco is a port of, and borrows heavily from, Docco -- the original
20
+ quick-and-dirty, hundred-line-long, literate-programming-style
21
+ documentation generator in CoffeeScript:
22
+
23
+ <http://jashkenas.github.com/docco/>
data/Rakefile CHANGED
@@ -1,5 +1,18 @@
1
+ $LOAD_PATH.unshift 'lib'
2
+
1
3
  require 'rake/testtask'
2
- task :default => :test
4
+ require 'rake/clean'
5
+
6
+ task :default => [:sup, :docs]
7
+
8
+ desc 'Holla'
9
+ task :sup do
10
+ verbose do
11
+ lines = File.read('README').split("\n")[0,12]
12
+ lines.map! { |line| line[15..-1] }
13
+ puts lines.join("\n")
14
+ end
15
+ end
3
16
 
4
17
  desc 'Run tests (default)'
5
18
  Rake::TestTask.new(:test) do |t|
@@ -7,6 +20,52 @@ Rake::TestTask.new(:test) do |t|
7
20
  t.ruby_opts = ['-rubygems'] if defined? Gem
8
21
  end
9
22
 
23
+ # Bring in Rocco tasks
24
+ require 'rocco/tasks'
25
+ Rocco::make 'docs/'
26
+
27
+ desc 'Build rocco docs'
28
+ task :docs => :rocco
29
+ directory 'docs/'
30
+
31
+ desc 'Build docs and open in browser for the reading'
32
+ task :read => :docs do
33
+ sh 'open docs/rocco.html'
34
+ end
35
+
36
+ # Make index.html a copy of rocco.html
37
+ file 'docs/index.html' => 'docs/rocco.html' do |f|
38
+ cp 'docs/rocco.html', 'docs/index.html', :preserve => true
39
+ end
40
+ task :docs => 'docs/index.html'
41
+ CLEAN.include 'docs/index.html'
42
+
43
+ # Alias for docs task
44
+ task :doc => :docs
45
+
46
+ # GITHUB PAGES ===============================================================
47
+
48
+ desc 'Update gh-pages branch'
49
+ task :pages => ['docs/.git', :docs] do
50
+ rev = `git rev-parse --short HEAD`.strip
51
+ Dir.chdir 'docs' do
52
+ sh "git add *.html"
53
+ sh "git commit -m 'rebuild pages from #{rev}'" do |ok,res|
54
+ if ok
55
+ verbose { puts "gh-pages updated" }
56
+ sh "git push -q o HEAD:gh-pages"
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ # Update the pages/ directory clone
63
+ file 'docs/.git' => ['docs/', '.git/refs/heads/gh-pages'] do |f|
64
+ sh "cd docs && git init -q && git remote add o ../.git" if !File.exist?(f.name)
65
+ sh "cd docs && git fetch -q o && git reset -q --hard o/gh-pages && touch ."
66
+ end
67
+ CLOBBER.include 'docs/.git'
68
+
10
69
  # PACKAGING =================================================================
11
70
 
12
71
  if defined?(Gem)
@@ -39,21 +98,18 @@ end
39
98
  # GEMSPEC ===================================================================
40
99
 
41
100
  file 'rocco.gemspec' => FileList['{lib,test,bin}/**','Rakefile'] do |f|
42
- # read version from tilt.rb
43
101
  version = File.read('lib/rocco.rb')[/VERSION = '(.*)'/] && $1
44
- # read spec file and split out manifest section
102
+ date = Time.now.strftime("%Y-%m-%d")
45
103
  spec = File.
46
104
  read(f.name).
47
105
  sub(/s\.version\s*=\s*'.*'/, "s.version = '#{version}'")
48
106
  parts = spec.split(" # = MANIFEST =\n")
49
- # determine file list from git ls-files
50
107
  files = `git ls-files`.
51
108
  split("\n").sort.reject{ |file| file =~ /^\./ }.
52
109
  map{ |file| " #{file}" }.join("\n")
53
- # piece file back together and write...
54
110
  parts[1] = " s.files = %w[\n#{files}\n ]\n"
55
111
  spec = parts.join(" # = MANIFEST =\n")
56
- spec.sub!(/s.date = '.*'/, "s.date = '#{Time.now.strftime("%Y-%m-%d")}'")
112
+ spec.sub!(/s.date = '.*'/, "s.date = '#{date}'")
57
113
  File.open(f.name, 'w') { |io| io.write(spec) }
58
- puts "updated #{f.name}"
114
+ puts "#{f.name} #{version} (#{date})"
59
115
  end
data/bin/rocco CHANGED
@@ -11,6 +11,11 @@ rescue LoadError
11
11
  warn "warn: #$!. trying again with rubygems"
12
12
  require 'rubygems'
13
13
  retry
14
+ else
15
+ require 'bluecloth'
16
+ Markdown = BlueCloth
17
+ $LOADED_FEATURES << 'rdiscount.rb'
18
+ retry
14
19
  end
15
20
  when /rocco/
16
21
  if !$:.include?(libdir)
data/lib/rocco.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  # Rocco reads Ruby source files and produces annotated source documentation
5
5
  # in HTML format. Comments are formatted with [Markdown][md] and presented
6
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.
7
+ # This page is the result of running Rocco against [its own source file][so].
8
8
  #
9
9
  # Most of this was written while waiting for [node.js][no] to build (so I
10
10
  # could use Docco!). Docco's gorgeous HTML and CSS are taken verbatim.
@@ -12,7 +12,7 @@
12
12
  # [CoffeeScript][co] and may be a bit easier to obtain and install in
13
13
  # existing Ruby environments or where node doesn't run yet.
14
14
  #
15
- # Rocco can be installed with rubygems:
15
+ # Install Rocco with Rubygems:
16
16
  #
17
17
  # gem install rocco
18
18
  #
@@ -27,19 +27,29 @@
27
27
  # [do]: http://jashkenas.github.com/docco/
28
28
  # [co]: http://coffeescript.org/
29
29
  # [md]: http://daringfireball.net/projects/markdown/
30
+ # [so]: http://github.com/rtomayko/rocco/blob/master/lib/rocco.rb#commit
30
31
 
31
32
  #### Prerequisites
32
33
 
33
- # The [rdiscount](http://github.com/rtomayko/rdiscount) library is
34
- # required for Markdown processing.
35
- require 'rdiscount'
34
+ # We'll need a Markdown library. [RDiscount][rd], if we're lucky. Otherwise,
35
+ # issue a warning and fall back on using BlueCloth.
36
+ #
37
+ # [rd]: http://github.com/rtomayko/rdiscount
38
+ begin
39
+ require 'rdiscount'
40
+ rescue LoadError => boom
41
+ warn "warn: #{boom}. trying bluecloth"
42
+ require 'bluecloth'
43
+ Markdown = BlueCloth
44
+ end
36
45
 
37
46
  # We use [{{ mustache }}](http://defunkt.github.com/mustache/) for
38
- # templating.
47
+ # HTML templating.
39
48
  require 'mustache'
40
49
 
41
50
  # Code is run through [Pygments](http://pygments.org/) for syntax
42
- # highlighting. Fail fast if we can't find the `pygmentize` program.
51
+ # highlighting. Fail fast right here if we can't find the `pygmentize`
52
+ # program on PATH.
43
53
  if ! ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
44
54
  fail "Pygments is required for syntax highlighting"
45
55
  end
@@ -51,7 +61,7 @@ end
51
61
  # whatever means necessary and return it as a string. With no `block`, the
52
62
  # file is read to retrieve data.
53
63
  class Rocco
54
- VERSION = '0.1'
64
+ VERSION = '0.2'
55
65
 
56
66
  def initialize(filename, &block)
57
67
  @file = filename
@@ -61,8 +71,7 @@ class Rocco
61
71
  else
62
72
  File.read(filename)
63
73
  end
64
- # Parsing and highlighting
65
- @sections = highlight(parse(@data))
74
+ @sections = highlight(split(parse(@data)))
66
75
  end
67
76
 
68
77
  # The filename as given to `Rocco.new`.
@@ -82,7 +91,9 @@ class Rocco
82
91
 
83
92
  #### Internal Parsing and Highlighting
84
93
 
85
- # Parse the raw file data into a list of two-tuples.
94
+ # Parse the raw file data into a list of two-tuples. Each tuple has the
95
+ # form `[docs, code]` where both elements are arrays containing the
96
+ # raw lines parsed from the input file.
86
97
  def parse(data)
87
98
  sections = []
88
99
  docs, code = [], []
@@ -94,8 +105,6 @@ class Rocco
94
105
  docs, code = [], []
95
106
  end
96
107
  docs << line
97
- when /^\s*$/
98
- code << line
99
108
  else
100
109
  code << line
101
110
  end
@@ -104,50 +113,59 @@ class Rocco
104
113
  sections
105
114
  end
106
115
 
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.
116
+ # Take the list of paired *sections* two-tuples and split into two
117
+ # separate lists: one holding the comments with leaders removed and
118
+ # one with the code blocks.
119
+ def split(sections)
111
120
  docs_blocks, code_blocks = [], []
112
121
  sections.each do |docs,code|
113
122
  docs_blocks << docs.map { |line| line.sub(/^\s*#\s?/, '') }.join("\n")
114
123
  code_blocks << code.join("\n")
115
124
  end
125
+ [docs_blocks, code_blocks]
126
+ end
116
127
 
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")
128
+ # Take the result of `split` and apply Markdown formatting to comments and
129
+ # syntax highlighting to source code.
130
+ def highlight(blocks)
131
+ docs_blocks, code_blocks = blocks
132
+
133
+ # Combine all docs blocks into a single big markdown document with section
134
+ # dividers and run through the Markdown processor. Then split it back out
135
+ # into separate sections.
136
+ markdown = docs_blocks.join("\n\n##### DIVIDER\n\n")
120
137
  docs_html = Markdown.new(markdown, :smart).
121
138
  to_html.
122
- split("\n<h5>DIVIDER</h5>\n")
139
+ split(/\n*<h5>DIVIDER<\/h5>\n*/m)
123
140
 
124
141
  # 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.
142
+ # Pygments. We `popen` a read/write pygmentize process in the parent and
143
+ # then fork off a child process to write the input.
127
144
  code_html = nil
128
145
  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
-
146
+ pid =
147
+ fork {
148
+ fd.close_read
149
+ fd.write code_blocks.join("\n\n# DIVIDER\n\n")
150
+ fd.close_write
151
+ exit!
152
+ }
136
153
  fd.close_write
137
154
  code_html = fd.read
138
155
  fd.close_read
156
+ Process.wait(pid)
139
157
  end
140
158
 
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.
159
+ # Do some post-processing on the pygments output to split things back
160
+ # into sections and remove partial `<pre>` blocks.
144
161
  code_html = code_html.
145
- split(/\n?<span class="c1"># DIVIDER<\/span>\n?/m).
162
+ split(/\n*<span class="c1"># DIVIDER<\/span>\n*/m).
146
163
  map { |code| code.sub(/\n?<div class="highlight"><pre>/m, '') }.
147
164
  map { |code| code.sub(/\n?<\/pre><\/div>\n/m, '') }
148
165
 
149
- # Combine the docs and code lists into the same sections style list we
150
- # started with.
166
+ # Lastly, combine the docs and code lists back into a list of two-tuples.
151
167
  docs_html.zip(code_html)
152
168
  end
153
169
  end
170
+
171
+ # And that's it.
@@ -7,6 +7,7 @@
7
7
  </head>
8
8
  <body>
9
9
  <div id='container'>
10
+ <div id="background"></div>
10
11
  <table cellspacing=0 cellpadding=0>
11
12
  <thead>
12
13
  <tr>
@@ -17,7 +18,12 @@
17
18
  <tbody>
18
19
  {{#sections}}
19
20
  <tr id='section-{{ num }}'>
20
- <td class=docs>{{{ docs }}}</td>
21
+ <td class=docs>
22
+ <div class="octowrap">
23
+ <a class="octothorpe" href="#section-{{ num }}">#</a>
24
+ </div>
25
+ {{{ docs }}}
26
+ </td>
21
27
  <td class=code>
22
28
  <div class='highlight'><pre>{{{ code }}}</pre></div>
23
29
  </td>
@@ -0,0 +1,110 @@
1
+ #### Rocco Rake Tasks
2
+ #
3
+ # To use the Rocco Rake tasks, require `rocco/tasks` in your `Rakefile`
4
+ # and define a Rake task with `rocco_task`. In its simplest form, `rocco_task`
5
+ # takes the path to a destination directory where HTML docs should be built:
6
+ #
7
+ # require 'rocco/tasks'
8
+ #
9
+ # desc "Build Rocco Docs"
10
+ # Rocco::make 'docs/'
11
+ #
12
+ # This creates a `:rocco` rake task, which can then be run with:
13
+ #
14
+ # rake rocco
15
+ #
16
+ # It's a good idea to guard against Rocco not being available, since your
17
+ # Rakefile will fail to load otherwise. Consider doing something like this,
18
+ # so that your Rakefile will still work
19
+ #
20
+ # begin
21
+ # require 'rocco/tasks'
22
+ # Rocco::make 'docs/'
23
+ # rescue LoadError
24
+ # warn "#$! -- rocco tasks not loaded."
25
+ # task :rocco
26
+ # end
27
+ #
28
+ # It's also possible to pass a glob pattern:
29
+ #
30
+ # Rocco::make 'html/', 'lib/thing/**/*.rb'
31
+ #
32
+ # Or a list of glob patterns:
33
+ #
34
+ # Rocco::make 'html/', ['lib/thing.rb', 'lib/thing/*.rb']
35
+ #
36
+
37
+ # Might be nice to defer this until we actually need to build docs but this
38
+ # will have to do for now.
39
+ require 'rocco'
40
+
41
+ # Reopen the Rocco class and add a `make` class method. This is a simple bit
42
+ # of sugar over `Rocco::Task.new`. If you want your Rake task to be named
43
+ # something other than `:rocco`, you can use `Rocco::Task` directly.
44
+ class Rocco
45
+ def self.make(dest='docs/', source_files='lib/**/*.rb')
46
+ Task.new(:rocco, dest, source_files)
47
+ end
48
+
49
+ # `Rocco::Task.new` takes a task name, the destination directory docs
50
+ # should be built under, and a source file pattern or file list.
51
+ class Task
52
+ def initialize(task_name, dest='docs/', sources='lib/**/*.rb')
53
+ @name = task_name
54
+ @dest = dest[-1] == ?/ ? dest : "#{dest}/"
55
+ @sources = FileList[sources]
56
+
57
+ # Make sure there's a `directory` task defined for our destination.
58
+ define_directory_task @dest
59
+
60
+ # Run over the source file list, constructing destination filenames
61
+ # and defining file tasks.
62
+ @sources.each do |source_file|
63
+ dest_file = File.basename(source_file, '.rb') + '.html'
64
+ define_file_task source_file, "#{@dest}#{dest_file}"
65
+
66
+ # If `rake/clean` was required, add the generated files to the list.
67
+ # That way all Rocco generated are removed when running `rake clean`.
68
+ CLEAN.include "#{@dest}#{dest_file}" if defined? CLEAN
69
+ end
70
+ end
71
+
72
+ # Define the destination directory task and make the `:rocco` task depend
73
+ # on it. This causes the destination directory to be created if it doesn't
74
+ # already exist.
75
+ def define_directory_task(path)
76
+ directory path
77
+ task @name => path
78
+ end
79
+
80
+ # Setup a `file` task for a single Rocco output file (`dest_file`). It
81
+ # depends on the source file, the destination directory, and all of Rocco's
82
+ # internal source code, so that the destination file is rebuilt when any of
83
+ # those changes.
84
+ #
85
+ # You can run these tasks directly with Rake:
86
+ #
87
+ # rake docs/foo.html docs/bar.html
88
+ #
89
+ # ... would generate the `foo.html` and `bar.html` files but only if they
90
+ # don't already exist or one of their dependencies was changed.
91
+ def define_file_task(source_file, dest_file)
92
+ prerequisites = [@dest, source_file] + rocco_source_files
93
+ file dest_file => prerequisites do |f|
94
+ verbose { puts "rocco: #{source_file} -> #{dest_file}" }
95
+ rocco = Rocco.new(source_file)
96
+ File.open(dest_file, 'wb') { |fd| fd.write(rocco.to_html) }
97
+ end
98
+ task @name => dest_file
99
+ end
100
+
101
+ # Return a `FileList` that includes all of Roccos source files. This causes
102
+ # output files to be regenerated properly when someone upgrades the Rocco
103
+ # library.
104
+ def rocco_source_files
105
+ libdir = File.expand_path('../..', __FILE__)
106
+ FileList["#{libdir}/rocco.rb", "#{libdir}/rocco/**"]
107
+ end
108
+
109
+ end
110
+ end
data/rocco.gemspec CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
3
3
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
4
 
5
5
  s.name = 'rocco'
6
- s.version = '0.1'
7
- s.date = '2010-03-08'
6
+ s.version = '0.2'
7
+ s.date = '2010-03-11'
8
8
 
9
9
  s.description = "Docco in Ruby"
10
10
  s.summary = s.description
@@ -15,12 +15,13 @@ Gem::Specification.new do |s|
15
15
  # = MANIFEST =
16
16
  s.files = %w[
17
17
  COPYING
18
- README.md
18
+ README
19
19
  Rakefile
20
20
  bin/rocco
21
21
  lib/rocco.rb
22
22
  lib/rocco/layout.mustache
23
23
  lib/rocco/layout.rb
24
+ lib/rocco/tasks.rb
24
25
  rocco.gemspec
25
26
  ]
26
27
  # = MANIFEST =
metadata CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- version: "0.1"
7
+ - 2
8
+ version: "0.2"
9
9
  platform: ruby
10
10
  authors:
11
11
  - Ryan Tomayko
@@ -13,7 +13,7 @@ autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
15
 
16
- date: 2010-03-08 00:00:00 -08:00
16
+ date: 2010-03-11 00:00:00 -08:00
17
17
  default_executable:
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
@@ -50,12 +50,13 @@ extra_rdoc_files: []
50
50
 
51
51
  files:
52
52
  - COPYING
53
- - README.md
53
+ - README
54
54
  - Rakefile
55
55
  - bin/rocco
56
56
  - lib/rocco.rb
57
57
  - lib/rocco/layout.mustache
58
58
  - lib/rocco/layout.rb
59
+ - lib/rocco/tasks.rb
59
60
  - rocco.gemspec
60
61
  has_rdoc: true
61
62
  homepage: http://rtomayko.github.com/rocco/
data/README.md DELETED
@@ -1,8 +0,0 @@
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.