#!/usr/bin/env ruby
require 'getoptlong'

def show_usage
  $stderr.print <<-EOF
Usage: #{File.basename($0.to_s)} [options] rd-file > hindex-file
global options:
    -b, --base-level=NUM   目次の base level を設定する (デフォールトは 2)
    -d, --max-depth=NUM    目次の max depth を設定する  (デフォールトは 6)
        --with-part=PART   PART 部分を含めて目次を作成する (複数指定可)
  EOF
end

=begin

= RD の HeadLine の目次を作る (改造版)

=end

##################################################
######            更新履歴情報              ######
=begin HTML
<small>
=end HTML
=begin
* ((<森川 靖大|URL:http://www.ep.sci.hokudai.ac.jp/~morikawa>)),
  ((<安宅 正之|URL:http://pop-club.hp.infoseek.co.jp/>))
  * 2005/07/17 (森川 靖大)
    履歴を修正.

  * 2005/07/09 (森川 靖大)
    --with-part オプション追加。usage を標準エラー出力へ出力するようにした。
    usage の形式を rd2 っぽくした。

  * 2005/07/08 (安宅 正之)
    --max-depth オプション追加。

  * 2005/07/07 (安宅 正之)
    --base-level オプション追加。
    エラーに対して、usage を表示するよう改良

  * 2005/07/06 (安宅 正之)
    "=begin", "=end" 外の HeadLineを読みこまないよう改良

  * 2004/10/06 (森川 靖大)
    るびきちさんのオリジナル版 rd-hindex.rb を持ってきて改造

=end
=begin HTML
</small>
<hr></hr>
=end HTML
######            更新履歴情報              ######
##################################################


=begin
<<< rd-hindex2.hindex.rd

== 概要

RD から HeadLine の目次 RD を作成する。
長文 RD を扱うときは便利。

元々は ((<rubikitch さん|URL:http://www.rubyist.net/~rubikitch/>))
が、((<URL:http://www.rubyist.net/~rubikitch/computer/myruby/rd-hindex/>))
で公開していた rd-hindex.rd を勝手に改造したもの。

+ レベル 5 のヘッダ
と
++ レベル 6 のヘッダ
も目次として取り込む仕様になっている。

他にも、目次レベルの最小値と最大値の設定やフィルター機能を利用している
RD のための名前付き PART にも対応している。


== ダウンロード

* ((<URL:http://www.ep.sci.hokudai.ac.jp/~morikawa/ruby/rd/rd-hindex2/rd-hindex2.rb>))

== 使い方

まずこのスクリプトで目次を作成し、もとのRDに「Include」で取り込む。

(1) 目次作成
      $ rd-hindex2.rb input.rd > input.hindex.rd

(2) もとのRDにIncludeで取り込む。((<実行結果>))参照。

=== 例

例えばこの rd-hindex2.rb でやってみると以下のような感じ

(1) 自身を取り込めないので、まずはテスト用にコピー
    その際 「Include」行をコメントアウト。

      $ sed s/^'<<<'/'#<<<'/ < rd-hindex2.rd  > input.rd

(2) 目次ファイル生成。
      $ ruby rd-hindex2.rb input.rd > rd-hindex2.hindex.rd

(3) 取り込んで HTML 作成。
      $ rd2 rd-hindex2.rb > rd-hindex2.html

== オプション

=== -b NUM (--base-level=NUM)

目次レベルの最小値を設定する。
デフォールト値は2。
つまり、h2要素以下に対して目次を作成する。
h1要素も目次に含めるには、-b 1 を指定する。

=== -d NUM (--max-depth=NUM)

目次レベルの最大値を設定する。
デフォールト値は6。

=== --with-part=PART

フィルター機能を利用している RD の「名前付き Part」に対応
している。例えば PART に "JA:rd" を指定すると、
"=begin JA" と "=end JA" でくくられた部分の目次も作成する。
なお "JA:include" と指定した場合は目次を作成しない。
(rd2 の --with-part オプションと書式をあわせたつもり)。

=end

def parse_options
  parser = GetoptLong.new
  parser.set_options(['--base-level', '-b', GetoptLong::REQUIRED_ARGUMENT],
		     ['--max-depth' , '-d', GetoptLong::REQUIRED_ARGUMENT],
		     ['--with-part' , GetoptLong::REQUIRED_ARGUMENT])
  options = Hash.new
  parser.each_option {|name, arg| 
    case name
    when'--with-part'
      options[name.sub(/^--/, "")] = Array.new unless options[name.sub(/^--/, "")].instance_of?(Array)
      options[name.sub(/^--/, "")] << arg
    else
      options[name.sub(/^--/, "")] = arg
    end
  }
  (show_usage; exit(1)) if ARGV.empty?
  return options
end

def main
  options = parse_options
  inbody = false
  if options['base-level']
    base_level = options['base-level'].to_i 
  else
    base_level = 2
  end

  if options['max-depth']
    max_depth =  options['max-depth'].to_i
  else
    max_depth = 6
  end

  if options['with-part']
    with_part = Array.new
    options['with-part'].each{ |part|
      name, filter = part.split(':', 2)
      next if filter == 'include'
      with_part << name
    }
  else
    with_part = Array.new
  end

  puts "=begin"
  puts readlines.collect {|line|
    # start rd documents
    inbody = true  if line =~ /^=begin$/
    with_part.each{ |part|
      inbody = true  if /^=begin\s+#{part}$/ =~ line
    }
    # end rd documents
    inbody = false if line =~ /^=end(\s+\w+)*$/
    # skip "=begin", "=end"
    next if line =~ /^=(begin|end)$/
    next if line =~ /^=(begin\s+|end\s+)\w+$/
    # parse headline
    if inbody && line =~ /^(=+|\++)\s*(.+)$/
      level = $1.length
      content = $2
      if $1 =~ /^\++$/
	level = level + 4
      end
      #pp %w[level content], binding
      next if level < base_level
      next if level > max_depth
      %Q[#{'  ' * (level - base_level)}* ((<"#{content}">))]
    end
  }.compact
  puts "=end"
end

main
