rocco 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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