1#!/usr/bin/env ruby
2# $originalId: ruby2html.rb,v 1.2 2005/09/23 22:53:47 aamine Exp $
3
4TEMPLATE_LINE = __LINE__ + 2
5TEMPLATE = <<-EndTemplate
6<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
7<html>
8<head>
9  <meta http-equiv="Content-Type" content="text/html; charset=<%= encoding %>">
10<% if css %>
11  <link rel="stylesheet" type="text/css" href="<%= css %>">
12<% end %>
13  <title><%= File.basename(f.path) %></title>
14</head>
15<body>
16<pre>
17<%
18    if print_line_number
19      Ruby2HTML.compile(f).each_with_index do |line, idx|
20%><%= sprintf('%4d  %s', idx+1, line) %><%
21      end
22    else
23%><%= Ruby2HTML.compile(f) %><%
24    end
25%>
26</pre>
27</body>
28</html>
29EndTemplate
30
31require 'ripper'
32require 'stringio'
33require 'cgi'
34require 'erb'
35require 'optparse'
36
37def main
38  encoding = 'us-ascii'
39  css = nil
40  print_line_number = false
41  parser = OptionParser.new
42  parser.banner = "Usage: #{File.basename($0)} [-l] [<file>...]"
43  parser.on('--encoding=NAME', 'Character encoding [us-ascii].') {|name|
44    encoding = name
45  }
46  parser.on('--css=URL', 'Set a link to CSS.') {|url|
47    css = url
48  }
49  parser.on('-l', '--line-number', 'Show line number.') {
50    print_line_number = true
51  }
52  parser.on('--help', 'Prints this message and quit.') {
53    puts parser.help
54    exit 0
55  }
56  begin
57    parser.parse!
58  rescue OptionParser::ParseError => err
59    $stderr.puts err
60    $stderr.puts parser.help
61    exit 1
62  end
63  puts ruby2html(ARGF, encoding, css, print_line_number)
64end
65
66class ERB
67  attr_accessor :lineno
68
69  remove_method :result
70  def result(b)
71    eval(@src, b, (@filename || '(erb)'), (@lineno || 1))
72  end
73end
74
75def ruby2html(f, encoding, css, print_line_number)
76  erb = ERB.new(TEMPLATE, nil, '>')
77  erb.filename = __FILE__
78  erb.lineno = TEMPLATE_LINE
79  erb.result(binding())
80end
81
82class Ruby2HTML < Ripper::Filter
83  def Ruby2HTML.compile(f)
84    buf = StringIO.new
85    Ruby2HTML.new(f).parse(buf)
86    buf.string
87  end
88
89  def on_default(event, tok, f)
90    f << CGI.escapeHTML(tok)
91  end
92
93  def on_kw(tok, f)
94    f << %Q[<span class="resword">#{CGI.escapeHTML(tok)}</span>]
95  end
96
97  def on_comment(tok, f)
98    f << %Q[<span class="comment">#{CGI.escapeHTML(tok.rstrip)}</span>\n]
99  end
100
101  def on_tstring_beg(tok, f)
102    f << %Q[<span class="string">#{CGI.escapeHTML(tok)}]
103  end
104
105  def on_tstring_end(tok, f)
106    f << %Q[#{CGI.escapeHTML(tok)}</span>]
107  end
108end
109
110if $0 == __FILE__
111  main
112end
113