rocco 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ end
22
22
 
23
23
  # Bring in Rocco tasks
24
24
  require 'rocco/tasks'
25
- Rocco::make 'docs/', FileList['lib/**/*.rb', 'bin/rocco']
25
+ Rocco::make 'docs/'
26
26
 
27
27
  desc 'Build rocco docs'
28
28
  task :docs => :rocco
data/bin/rocco CHANGED
@@ -1,15 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
- # The `rocco(1)` executable.
3
- #
4
- # This isn't documented yet.
5
- #
6
- #/ Usage: rocco [-o <dir>] <file>...
2
+ #/ Usage: rocco [-l <lang>] [-c <chars>] [-o <dir>] <file>...
7
3
  #/ Generate literate-programming-style documentation for Ruby source <file>s.
8
4
  #/
9
5
  #/ Options:
10
- #/ -o, --output=<dir> Directory where generated HTML files are written
6
+ #/ -l, --language=<lang> The Pygments lexer to use to highlight code
7
+ #/ -c, --comment-chars=<chars>
8
+ #/ The string to recognize as a comment marker
9
+ #/ -o, --output=<dir> Directory where generated HTML files are written
11
10
  #/
12
- #/ --help Show this help message
11
+ #/ --help Show this help message
13
12
 
14
13
  require 'optparse'
15
14
 
@@ -32,9 +31,12 @@ end
32
31
  # Parse command line options, aborting if anything goes wrong.
33
32
  output_dir = '.'
34
33
  sources = []
34
+ 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
40
  o.on_tail("-h", "--help") { usage($stdout, 0) }
39
41
  o.parse!
40
42
  } or abort_with_note
@@ -80,8 +82,8 @@ Dir.mkdir output_dir if !File.directory?(output_dir)
80
82
 
81
83
  # Run each file through Rocco and write output.
82
84
  sources.each do |filename|
83
- rocco = Rocco.new(filename, sources)
84
- dest = File.join(output_dir, File.basename(filename, '.rb') + '.html')
85
+ rocco = Rocco.new(filename, sources, options)
86
+ dest = filename.split('.')[0..-2].join('.') + '.html'
85
87
  puts "rocco: #{filename} -> #{dest}"
86
88
  File.open(dest, 'wb') { |fd| fd.write(rocco.to_html) }
87
89
  end
@@ -57,13 +57,18 @@ end
57
57
  #### Public Interface
58
58
 
59
59
  # `Rocco.new` takes a source `filename`, an optional list of source filenames
60
- # for other documentation sources, and an optional `block`. When `block` is
61
- # given, it must read the contents of the file using whatever means necessary
62
- # and return it as a string. With no `block`, the file is read to retrieve data.
60
+ # for other documentation sources, an `options` hash, and an optional `block`.
61
+ # The `options` hash respects two members: `:language`, which specifies which
62
+ # Pygments lexer to use; and `:comment_chars`, which specifies the comment
63
+ # characters of the target language. The options default to `'ruby'` and `'#'`,
64
+ # respectively.
65
+ # When `block` is given, it must read the contents of the file using whatever
66
+ # means necessary and return it as a string. With no `block`, the file is read
67
+ # to retrieve data.
63
68
  class Rocco
64
- VERSION = '0.3'
69
+ VERSION = '0.4'
65
70
 
66
- def initialize(filename, sources=[], &block)
71
+ def initialize(filename, sources=[], options={}, &block)
67
72
  @file = filename
68
73
  @data =
69
74
  if block_given?
@@ -71,7 +76,10 @@ class Rocco
71
76
  else
72
77
  File.read(filename)
73
78
  end
79
+ defaults = { :language => 'ruby', :comment_chars => '#' }
80
+ @options = defaults.merge(options)
74
81
  @sources = sources
82
+ @comment_pattern = Regexp.new("^\\s*#{@options[:comment_chars]}")
75
83
  @sections = highlight(split(parse(@data)))
76
84
  end
77
85
 
@@ -98,13 +106,16 @@ class Rocco
98
106
 
99
107
  # Parse the raw file data into a list of two-tuples. Each tuple has the
100
108
  # form `[docs, code]` where both elements are arrays containing the
101
- # raw lines parsed from the input file.
109
+ # raw lines parsed from the input file. The first line is ignored if it
110
+ # is a shebang line.
102
111
  def parse(data)
103
112
  sections = []
104
113
  docs, code = [], []
105
- data.split("\n").each do |line|
114
+ lines = data.split("\n")
115
+ lines.shift if lines[0] =~ /^\#\!/
116
+ lines.each do |line|
106
117
  case line
107
- when /^\s*#(?:\s+|$)/
118
+ when @comment_pattern
108
119
  if code.any?
109
120
  sections << [docs, code]
110
121
  docs, code = [], []
@@ -124,8 +135,11 @@ class Rocco
124
135
  def split(sections)
125
136
  docs_blocks, code_blocks = [], []
126
137
  sections.each do |docs,code|
127
- docs_blocks << docs.map { |line| line.sub(/^\s*#\s?/, '') }.join("\n")
128
- code_blocks << code.join("\n")
138
+ docs_blocks << docs.map { |line| line.sub(@comment_pattern, '') }.join("\n")
139
+ code_blocks << code.map do |line|
140
+ tabs = line.match(/^(\t+)/)
141
+ tabs ? line.sub(/^\t+/, ' ' * tabs.captures[0].length) : line
142
+ end.join("\n")
129
143
  end
130
144
  [docs_blocks, code_blocks]
131
145
  end
@@ -147,7 +161,7 @@ class Rocco
147
161
  # Pygments. We `popen` a read/write pygmentize process in the parent and
148
162
  # then fork off a child process to write the input.
149
163
  code_html = nil
150
- open("|pygmentize -l ruby -f html", 'r+') do |fd|
164
+ open("|pygmentize -l #{@options[:language]} -f html", 'r+') do |fd|
151
165
  pid =
152
166
  fork {
153
167
  fd.close_read
@@ -31,7 +31,7 @@ class Rocco::Layout < Mustache
31
31
  {
32
32
  :path => source,
33
33
  :basename => File.basename(source),
34
- :url => File.basename(source, '.rb') + '.html'
34
+ :url => File.basename(source).split('.')[0..-2].join('.') + '.html'
35
35
  }
36
36
  end
37
37
  end
@@ -33,6 +33,15 @@
33
33
  #
34
34
  # Rocco::make 'html/', ['lib/thing.rb', 'lib/thing/*.rb']
35
35
  #
36
+ # Finally, it is also possible to specify which Pygments language you would
37
+ # like to use to highlight the code, as well as the comment characters for the
38
+ # language in the `options` hash:
39
+ #
40
+ # Rocco::make 'html/', 'lib/thing/**/*.rb', {
41
+ # :language => 'io',
42
+ # :comment_chars => '#'
43
+ # }
44
+ #
36
45
 
37
46
  # Might be nice to defer this until we actually need to build docs but this
38
47
  # will have to do for now.
@@ -42,17 +51,18 @@ require 'rocco'
42
51
  # of sugar over `Rocco::Task.new`. If you want your Rake task to be named
43
52
  # something other than `:rocco`, you can use `Rocco::Task` directly.
44
53
  class Rocco
45
- def self.make(dest='docs/', source_files='lib/**/*.rb')
46
- Task.new(:rocco, dest, source_files)
54
+ def self.make(dest='docs/', source_files='lib/**/*.rb', options={})
55
+ Task.new(:rocco, dest, source_files, options)
47
56
  end
48
57
 
49
58
  # `Rocco::Task.new` takes a task name, the destination directory docs
50
59
  # should be built under, and a source file pattern or file list.
51
60
  class Task
52
- def initialize(task_name, dest='docs/', sources='lib/**/*.rb')
61
+ def initialize(task_name, dest='docs/', sources='lib/**/*.rb', options={})
53
62
  @name = task_name
54
63
  @dest = dest[-1] == ?/ ? dest : "#{dest}/"
55
64
  @sources = FileList[sources]
65
+ @options = options
56
66
 
57
67
  # Make sure there's a `directory` task defined for our destination.
58
68
  define_directory_task @dest
@@ -60,7 +70,7 @@ class Rocco
60
70
  # Run over the source file list, constructing destination filenames
61
71
  # and defining file tasks.
62
72
  @sources.each do |source_file|
63
- dest_file = File.basename(source_file, '.rb') + '.html'
73
+ dest_file = File.basename(source_file).split('.')[0..-2].join('.') + '.html'
64
74
  define_file_task source_file, "#{@dest}#{dest_file}"
65
75
 
66
76
  # If `rake/clean` was required, add the generated files to the list.
@@ -92,7 +102,7 @@ class Rocco
92
102
  prerequisites = [@dest, source_file] + rocco_source_files
93
103
  file dest_file => prerequisites do |f|
94
104
  verbose { puts "rocco: #{source_file} -> #{dest_file}" }
95
- rocco = Rocco.new(source_file, @sources.to_a)
105
+ rocco = Rocco.new(source_file, @sources.to_a, @options)
96
106
  File.open(dest_file, 'wb') { |fd| fd.write(rocco.to_html) }
97
107
  end
98
108
  task @name => dest_file
@@ -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.3'
7
- s.date = '2010-03-16'
6
+ s.version = '0.4'
7
+ s.date = '2010-03-19'
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
- - 3
8
- version: "0.3"
7
+ - 4
8
+ version: "0.4"
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-16 00:00:00 -07:00
16
+ date: 2010-03-19 00:00:00 -07:00
17
17
  default_executable:
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency