#!/usr/bin/ruby

##
## yamlgrep - YAML ファイルから YPath にマッチしたデータを抜き出す
##

def usage()
  command = File.basename($0)
  s = <<END
使い方:  #{command} [-h] [-q] [-u[N]] [-z ypath] ypath-pattern [yamlfile ...]
  -h        : ヘルプ
  -q        : 余分な出力を抑える (quietモード)
  -u[N]     : 親をたどる数 (省略時 N=1)
  -z ypath  : 末尾に追加する YPath パターン
END
  return s
end


require 'yaml'

## コマンドラインオプションを解析
options = {}
while ARGV[0] =~ /^-/
  opt = ARGV.shift
  case opt
  when '-h', '--help'     # ヘルプ
    options[:help]   = true
  when '-q'               # 余分な出力を抑える
    options[:quiet]  = true
  when /^-u(\d*)/         # 親をたどる数
    options[:parent] = $1.empty? ? 1 : $1.to_i
  when /^-z(.*)/          # 末尾に追加する YPath
    ypath = $1.empty? ? ARGV.shift : $1
    unless ypath
      $stderr.puts "#{opt}: YPath パターンが指定されていません。"
      exit(1)
    end
    options[:tail] = ypath
  else
    $stderr.puts "#{opt}: 不正なオプションです。"
    exit(1)
  end
end

## ヘルプを表示
if options[:help]
  puts usage()
  exit(0)
end

## YPath パターンを読み取る
ypath = ARGV.shift
unless ypath
  $stderr.puts "YPath パターンが指定されていません。"
  exit(1)
end

## YAML ファイルを読み込み、ツリーに変換
str = ARGF.read()
tree = YAML.parse(str)

## YPath にマッチするパスをすべて取得
paths = {{*tree.search(ypath)*}}

## パスごとにノードを取得し、データを表示
paths.each do |path|

  ## -u オプションがあれば親をたどる
  options[:parent].times { path = File.dirname(path) } if options[:parent]

  ## -z オプションがあれば YPath パターンを末尾に追加する
  path << options[:tail] if options[:tail]

  ## ノードを取得してオブジェクトに変換する
  objs = []
  nodes = {{*tree.select(path)*}}
  nodes.each do |node|
    obj = {{*node.transform*}}         # ノードをオブジェクトに変換
    objs << obj
  end

  ## 表示する
  puts "## #{path}" unless options[:quiet]
  s = {{*objs.to_yaml*}}               # YAML 形式の文字列に変換
  puts s.sub(/^---\s*\n?/, '')   # ドキュメントの区切り「---」を取り除く
  puts unless options[:quiet]

end
