rocco 0.4 → 0.5

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 (4) hide show
  1. data/bin/rocco +14 -8
  2. data/lib/rocco.rb +48 -20
  3. data/rocco.gemspec +2 -2
  4. metadata +8 -4
data/bin/rocco CHANGED
@@ -7,14 +7,14 @@
7
7
  #/ -c, --comment-chars=<chars>
8
8
  #/ The string to recognize as a comment marker
9
9
  #/ -o, --output=<dir> Directory where generated HTML files are written
10
- #/
11
10
  #/ --help Show this help message
12
11
 
13
12
  require 'optparse'
13
+ require 'fileutils'
14
14
 
15
15
  # Write usage message to stdout and exit.
16
16
  def usage(stream=$stderr, status=1)
17
- stream.puts File.read(__FILE__).
17
+ stream.puts File.readlines(__FILE__).
18
18
  grep(/^#\//).
19
19
  map { |line| line.sub(/^#. ?/, '') }.
20
20
  join
@@ -35,12 +35,20 @@ options = {}
35
35
  ARGV.options { |o|
36
36
  o.program_name = File.basename($0)
37
37
  o.on("-o", "--output=DIR") { |dir| output_dir = dir }
38
- o.on("-l", "--language=LANG") { |lang| options[:language] = lang }
39
- o.on("-c", "--comment-chars=CHARS") { |chars| options[:comment_chars] = Regexp.escape(chars) }
38
+ o.on("-l", "--language=LANG") { |lang| options[:language] = lang }
39
+ o.on("-c", "--comment-chars=CHARS") { |chars| options[:comment_chars] = Regexp.escape(chars) }
40
40
  o.on_tail("-h", "--help") { usage($stdout, 0) }
41
41
  o.parse!
42
42
  } or abort_with_note
43
43
 
44
+ # Use http://pygments.appspot.com in case `pygmentize(1)` isn't available.
45
+ if ! ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
46
+ unless options[:webservice]
47
+ $stderr.puts "pygmentize not in PATH; using pygments.appspot.com instead"
48
+ options[:webservice] = true
49
+ end
50
+ end
51
+
44
52
  # Eat sources from ARGV.
45
53
  sources << ARGV.shift while ARGV.any?
46
54
 
@@ -77,13 +85,11 @@ rescue LoadError
77
85
  raise
78
86
  end
79
87
 
80
- # Create the output directory if it doesn't already exist.
81
- Dir.mkdir output_dir if !File.directory?(output_dir)
82
-
83
88
  # Run each file through Rocco and write output.
84
89
  sources.each do |filename|
85
90
  rocco = Rocco.new(filename, sources, options)
86
- dest = filename.split('.')[0..-2].join('.') + '.html'
91
+ dest = File.join(output_dir, (filename.split('.')[0..-2].empty? ? filename : filename.split('.')[0..-2].join('.')) + '.html')
87
92
  puts "rocco: #{filename} -> #{dest}"
93
+ FileUtils.mkdir_p File.dirname(dest)
88
94
  File.open(dest, 'wb') { |fd| fd.write(rocco.to_html) }
89
95
  end
data/lib/rocco.rb CHANGED
@@ -38,7 +38,7 @@
38
38
  begin
39
39
  require 'rdiscount'
40
40
  rescue LoadError => boom
41
- warn "warn: #{boom}. trying bluecloth"
41
+ warn "WARNING: #{boom}. Trying bluecloth."
42
42
  require 'bluecloth'
43
43
  Markdown = BlueCloth
44
44
  end
@@ -47,11 +47,14 @@ end
47
47
  # HTML templating.
48
48
  require 'mustache'
49
49
 
50
+ # We use `Net::HTTP` to highlight code via <http://pygments.appspot.com>
51
+ require 'net/http'
52
+
50
53
  # Code is run through [Pygments](http://pygments.org/) for syntax
51
- # highlighting. Fail fast right here if we can't find the `pygmentize`
52
- # program on PATH.
53
- if ! ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
54
- fail "Pygments is required for syntax highlighting"
54
+ # highlighting. If it's not installed, locally, use a webservice.
55
+ include FileTest
56
+ if !ENV['PATH'].split(':').any? { |dir| executable?("#{dir}/pygmentize") }
57
+ warn "WARNING: Pygments not found. Using webservice."
55
58
  end
56
59
 
57
60
  #### Public Interface
@@ -66,7 +69,7 @@ end
66
69
  # means necessary and return it as a string. With no `block`, the file is read
67
70
  # to retrieve data.
68
71
  class Rocco
69
- VERSION = '0.4'
72
+ VERSION = '0.5'
70
73
 
71
74
  def initialize(filename, sources=[], options={}, &block)
72
75
  @file = filename
@@ -76,7 +79,10 @@ class Rocco
76
79
  else
77
80
  File.read(filename)
78
81
  end
79
- defaults = { :language => 'ruby', :comment_chars => '#' }
82
+ defaults = {
83
+ :language => 'ruby',
84
+ :comment_chars => '#',
85
+ }
80
86
  @options = defaults.merge(options)
81
87
  @sources = sources
82
88
  @comment_pattern = Regexp.new("^\\s*#{@options[:comment_chars]}")
@@ -157,15 +163,36 @@ class Rocco
157
163
  to_html.
158
164
  split(/\n*<h5>DIVIDER<\/h5>\n*/m)
159
165
 
160
- # Combine all code blocks into a single big stream and run through
161
- # Pygments. We `popen` a read/write pygmentize process in the parent and
162
- # then fork off a child process to write the input.
166
+ # Combine all code blocks into a single big stream and run through either
167
+ # `pygmentize(1)` or <http://pygments.appspot.com>
168
+ code_stream = code_blocks.join("\n\n#{@options[:comment_chars]} DIVIDER\n\n")
169
+
170
+ if ENV['PATH'].split(':').any? { |dir| executable?("#{dir}/pygmentize") }
171
+ code_html = highlight_pygmentize(code_stream)
172
+ else
173
+ code_html = highlight_webservice(code_stream)
174
+ end
175
+
176
+ # Do some post-processing on the pygments output to split things back
177
+ # into sections and remove partial `<pre>` blocks.
178
+ code_html = code_html.
179
+ split(/\n*<span class="c.">#{@options[:comment_chars]} DIVIDER<\/span>\n*/m).
180
+ map { |code| code.sub(/\n?<div class="highlight"><pre>/m, '') }.
181
+ map { |code| code.sub(/\n?<\/pre><\/div>\n/m, '') }
182
+
183
+ # Lastly, combine the docs and code lists back into a list of two-tuples.
184
+ docs_html.zip(code_html)
185
+ end
186
+
187
+ # We `popen` a read/write pygmentize process in the parent and
188
+ # then fork off a child process to write the input.
189
+ def highlight_pygmentize(code)
163
190
  code_html = nil
164
191
  open("|pygmentize -l #{@options[:language]} -f html", 'r+') do |fd|
165
192
  pid =
166
193
  fork {
167
194
  fd.close_read
168
- fd.write code_blocks.join("\n\n# DIVIDER\n\n")
195
+ fd.write code
169
196
  fd.close_write
170
197
  exit!
171
198
  }
@@ -175,15 +202,16 @@ class Rocco
175
202
  Process.wait(pid)
176
203
  end
177
204
 
178
- # Do some post-processing on the pygments output to split things back
179
- # into sections and remove partial `<pre>` blocks.
180
- code_html = code_html.
181
- split(/\n*<span class="c1"># DIVIDER<\/span>\n*/m).
182
- map { |code| code.sub(/\n?<div class="highlight"><pre>/m, '') }.
183
- map { |code| code.sub(/\n?<\/pre><\/div>\n/m, '') }
184
-
185
- # Lastly, combine the docs and code lists back into a list of two-tuples.
186
- docs_html.zip(code_html)
205
+ code_html
206
+ end
207
+
208
+ # Pygments is not one of those things that's trivial for a ruby user to install,
209
+ # so we'll fall back on a webservice to highlight the code if it isn't available.
210
+ def highlight_webservice(code)
211
+ Net::HTTP.post_form(
212
+ URI.parse('http://pygments.appspot.com/'),
213
+ {'lang' => @options['language'], 'code' => code}
214
+ ).body
187
215
  end
188
216
  end
189
217
 
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.4'
7
- s.date = '2010-03-19'
6
+ s.version = '0.5'
7
+ s.date = '2010-09-10'
8
8
 
9
9
  s.description = "Docco in Ruby"
10
10
  s.summary = s.description
metadata CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 4
8
- version: "0.4"
7
+ - 5
8
+ version: "0.5"
9
9
  platform: ruby
10
10
  authors:
11
11
  - Ryan Tomayko
@@ -13,13 +13,14 @@ autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
15
 
16
- date: 2010-03-19 00:00:00 -07:00
16
+ date: 2010-09-10 00:00:00 -07:00
17
17
  default_executable:
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: rdiscount
21
21
  prerelease: false
22
22
  requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
23
24
  requirements:
24
25
  - - ">="
25
26
  - !ruby/object:Gem::Version
@@ -32,6 +33,7 @@ dependencies:
32
33
  name: mustache
33
34
  prerelease: false
34
35
  requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
35
37
  requirements:
36
38
  - - ">="
37
39
  - !ruby/object:Gem::Version
@@ -68,6 +70,7 @@ rdoc_options: []
68
70
  require_paths:
69
71
  - lib
70
72
  required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
71
74
  requirements:
72
75
  - - ">="
73
76
  - !ruby/object:Gem::Version
@@ -75,6 +78,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
75
78
  - 0
76
79
  version: "0"
77
80
  required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
78
82
  requirements:
79
83
  - - ">="
80
84
  - !ruby/object:Gem::Version
@@ -84,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
88
  requirements: []
85
89
 
86
90
  rubyforge_project:
87
- rubygems_version: 1.3.6
91
+ rubygems_version: 1.3.7
88
92
  signing_key:
89
93
  specification_version: 2
90
94
  summary: Docco in Ruby