HOMEUP

Ruby Hpricot + GNU Source-highlight

GNU Source-highlight

WEBでサンプルコードとかを公開するのは結構厄介です。特にHTML。

'<'と'>'が多すぎる。何行かだと'<'を&lt;と打ち込んだりするけどちょっと行数が多くなるとエディタとかで置換したり他のツールで処理して張り付けたりします。

他にもいろいろやり方があってソースをそのままCGIとかで変換して表示したり、PHPや、eruby、JSPを使ってソース指定してHTML内に直接記述しちゃうとか…

前にRubyのGtk::TreeViewのコードをRuby Gtk::TreeViewを使ってみるで載せたんだけど、あれはGNU highlightを使ってHTMLにしてからソース部分をコピペしたんだよね。

highlight --enclose-pre --wrap-simple\
 --linenumbers --encoding=utf8 tv.rb > x.html

使い方は上のような感じ。説明のために行番号を --linenumbers を指定してつけているのですがこれが曲者で自分でソースをWEBからコピーしようとしたときに行番号もひっついてくるのに気がついた…不便。

そこで行番号とソースを別々にしようと思いました。

まあ探せば結構いいのがいっぱいあるのですが勉強になるしネタ(^^)になるのでRubyでやってみることにしました。

(Text::VimColorという優れものもあるそうですがやり始めた時には知らなかったのでまた今度実験してみます。)

Source-highlight出力の解析

highlight --encoding=utf8 tv.rb で出力されたhtmlは以下のようになっています。

行番号なしで出力してあります。行番号をつけると各行の前に<span class="hl line"> 1 </span>というように行番号が付けられます。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf8">
<title>tv.rb</title>
<link rel="stylesheet" type="text/css" href="highlight.css">
</head>
<body class="hl">
<pre class="hl"><span class="hl slc">#!/usr/bin/env ruby</span>

<span class="hl kwa">require</span> <span class="hl str">'gtk2'</span>

<span class="hl slc"># TreeViewクラス</span>
<span class="hl kwa">class</span> TV <span class="hl sym">&lt;</span> Gtk<span class="hl sym">::</span>TreeView

途中省略

    <span class="hl kwa">end</span>
  <span class="hl kwa">end</span>
<span class="hl kwa">end</span>

<span class="hl slc">#</span>
w <span class="hl sym">=</span> MainWindow<span class="hl sym">.</span>new
w<span class="hl sym">.</span>show_all
Gtk<span class="hl sym">.</span>main
</pre>
</body>
</html>
<!--HTML generated by highlight 2.6.11, http://www.andre-simon.de/-->

で、方針としては

  1. 9行目の(行番号がついてないと説明しづらい^^;)<pre class="hl"> hogehoge </pre>をまるごと<td>の中に放り込む。
  2. 左側にもう一つセルを作って行番号を入れる。

という強引な作戦。(行が折り返されなければ行番号がずれることはないのだけれど次のバージョンでは折り返しても大丈夫にしてみようかな?なんか難しそう:javascriptが必要かも)

Hpricot

とりあえずHTMLを触るのにHpricotというライブラリが良さそうなのでインストール。

# gem install hpricot

↑でインストールできます。gemをインストールしていなければFedora9の場合だと

# yum install rubygems

で、rootになってgemをインストールしてからやってください。

この時にヘッダファイルがない。とか怒られたらruby.hがインストールされていないのでruby-develをインストールします。

Hpricotの簡単な使い方

詳しくはAn Hpricot Showcaseを読めばいろいろとわかりやすく書いてあります。

要素の検索 search

まずは<pre class="hl">を見つけるための要素の検索実験。

require 'rubygems'
require 'hpricot'
require 'open-uri'

doc = Hpricot(open("http://oreshiki.net/"))

(doc/:a).each do |a|
	puts "#{a.inner_html} : #{a[:href]}"
end

コードを見ると大体使い方が解ると思う。

(doc/:a)なんてキモいと言う人はdoc.search('a')ってするといいです。searchのaliasになっています。

実行するとこんな感じ。

$ ruby hp1.rb
WEB関連 : con_web/
Ruby Gtk::TreeViewを使ってみる。 : programming/ruby_gtk_tv.html
旧サイト : http://lowtech.oops.jp
$

要素の生成(ラップ) wrap

require 'rubygems'
require 'hpricot'

doc = Hpricot "<span>hoge<b>fuga</b>piyo</span>"
(doc/:b).wrap "<a><u></u></a>"

print doc.to_html

対象となる要素をタグで挟み込みます。

実行結果は↓

<span>hoge<a><u><b>fuga</b></u></a>piyo</span>

これで<pre class="hl">を<td>の中に入れることができます。

要素の挿入 append/prepend

タイトルが日本語になってないみたい(^^;)。下のコードを見てください。

require 'rubygems'
require 'hpricot'

a = <<'EOT'
<table>
	<tr>
		<td>
			test
		</td>
	</tr>
</table>
EOT

doc = Hpricot a
(doc/:tr).prepend "<td>prepend</td>"
(doc/:tr).append "<td>append</td>"

print doc.to_html

実行すると↓

<table>
	<tr><td>prepend</td>
		<td>
			test
		</td>
	<td>append</td></tr>
</table>

完成した

一応バージョン0完成。

Source-highlightのhighlightがタバコを連想させるでmarlboro(マルボロ)と名づけました。^^;

注意事項

Source-highlightはHTMLの作成と同時にhighlight.cssというスタイルシートを作成するのだけれどその中のpre.hlのfont-familyを指定している所を固定幅フォントにしないとブラウザによって行番号がずれます。

コーディングはすぐにできたのだけれど行番号がずれている原因を見つけるのに苦労しました。

試しにKonquerorで見てみると綺麗に揃っています。以下にhighlight.cssを触っていないときの画像を掲載します。左がFirefox3、右がKonqueror。

Left:Firefox3 Right:Konqueror

使い方は highlight --encoding=utf8 hogehoge.fuga | marlboro > xx.html のようにします。生成された xx.html の中の<table>と</table>までをHTMLへコピペするだけ。

highlight.cssの修正とリンクは忘れずに!

ソースと実行結果は↓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require 'rubygems'
require 'hpricot'

#
doc = Hpricot $stdin
elm = doc.search "pre.hl"

lines = '<td valign="top" align="right"><pre class="hl">'
1.upto(elm.inner_html.count("\n")) do |line|
  lines += '<span class="hl line">' + line.to_s + "</span>\n"
end
lines += "</pre></td>"

elm.wrap "<table><tr><td></td></tr></table>"

doc.search("tr").prepend(lines)

print doc.to_html

なかなか良いですね〜

Ruby Gtk::TreeViewコードの再アップ

これを使ってRuby Gtk::TreeView 表形式での表示を再アップしておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env ruby

require 'gtk2'

# TreeViewクラス
class TV < Gtk::TreeView
  # カラム
  COLUMNS = ["行", "データ"]

  # コンストラクタ
  def initialize()
    # モデルの作成
    @model = Gtk::ListStore.new(Integer,String)
    # TreeViewの作成
    super @model
    # カラムの設定 リサイズ可能にする
    crText = Gtk::CellRendererText.new
    COLUMNS.each_with_index do |name, idx|
      col = Gtk::TreeViewColumn.new name, crText, :text => idx
      col.resizable = true
      append_column col
    end
    # データの設定
    0.upto(100) do |row|
      iter = @model.append
      iter[0] = row
      iter[1] = "データ#{row}"
    end
  end
end

# MainWindow
class MainWindow < Gtk::Window
  # コンストラクタ
  def initialize()
    super
    set_title "TreeViewのテスト"
    set_default_size 100, 100
    # ScrolledWindow
    sw = Gtk::ScrolledWindow.new
    sw.set_policy Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC
    # TreeView(TV)を作成して追加
    tv = TV.new
    add(sw.add(tv))
    # シグナル
    signal_connect "destroy" do
      Gtk.main_quit
    end
  end
end

#
w = MainWindow.new
w.show_all
Gtk.main

IE7にて行番号がずれる;;

IE7にて見てみると行番号がずれることが判明。対処方法を検討中。(2008-08-20)

自分で確認した結果は

ブラウザ表示
Konqueror
Firefox3
Safari 3.1.2 (WinXP)
Opera 9.5 (WinXP)
IE7 (WinXP)×
HOMEUP