here.rb

hyuki さんが id:hyuki:20060601#here で、公開されている here.pl を ruby に移植してみました。自分の記憶力と迂闊さを考慮して、ちょっと余分に機能を付け足しています。
もしよかったらお使いください。
無保証、無サポート。

使い方

  • 必要なもの: Windows, ruby実行環境
  • 下準備
    1. 下にある here.rb のコードをコピーして "here.rb" と名前を付けて保存する。
    2. "here.bat" という名前で下に示した内容(ディレクトリは自分の here.rb が置いてある場所に適宜変更)のバッチファイルを作り、path の通ったディレクトリに置く。*1
    3. here.rb が生成するバッチファイルを置くためのディレクトリを作り、そこに path を通す。*2 here.bat を置いてあるディレクトリに here という名前のディレクトリを作ると覚えやすいと思われる。
    4. here.rb 内の定数 Batch_dir の値を上で新たに作った生成バッチファイル置き場のディレクトリに書き換える。

here.bat

@echo off
ruby -Ks c:\rb_cmd\here.rb %*
  • here.rb の動作
    • 基本的には here.pl と同じ。コマンドプロンプト上で任意のディレクトリで here hoge と打ち込むと、Batch_dir で指定されたディレクトリに、現在いるディレクトリに戻ってくるためのバッチファイル hoge.bat が生成される。その Batch_dir で指定されたディレクトリに path が通っていれば、以降 hoge と打ち込めばそのディレクトリへ移動する。
    • 同じ名前のファイルが既にあった場合、上書きしてよいか尋ねてくるので、y/n で許可/キャンセルを行なう。
    • here.rb は存在すれば第2引数も取る事ができ "here hoge テスト用" などとすれば、バッチファイルに覚書用のコメントを入れることができる。
    • 引数無しで実行すると、現在あるファイルの一覧を表示する。
    • オプション -p str (str は任意の文字列)で str で始まるファイルの一覧を表示する。同様に -d str で str で始まる名前のディレクトリを指すファイルの一覧を表示する。
    • 表示は我が家用に作ってあるため、改行が乱れて見にくくなる事があるかもしれません。その場合 here.rb 中の Visible, Project_code_width 等の定数の値を適当な大きさに書き換えて下さい。

(「続きを読む」以下に here.rb 本体のコードがあります)
here.rb

#
# here.rb
# here.pl の ruby への移植版
#
require "optparse"

# ↓自分のバッチファイル生成場所に変更して下さい。
# path を通すのを忘れないで下さい。
Batch_dir = "c:/bat/here/"

# command line option 解析部
options = Hash.new

parser = OptionParser.new
parser.banner = "Usage:\there.rb project-code [note]\n\there.rb option [str]"
parser.separator("")

parser.on("-p [str]", "\"str\"で始まる procect-code を持つバッチの一覧を表示"){|arg|
  options[:p] = arg
}
parser.on("-d [str]", "\"str\"で始まるディレクトリを指すバッチの一覧を表示"){|arg|
  options[:d] = arg
}
parser.parse!

# このスクリプトの主目的機能。
# 引数の 0 番目の要素の値を名前とするバッチファイルを作る。
# 引数に 1 番目の要素があれば、バッチファイルにコメントとして書き込む。
def make_bat( args )
  chdir = Dir.pwd

  File.open(Batch_dir + args[0] + ".bat", "w"){|file|
    file.puts("@echo off")
    file.puts("REM here_note: #{args[1]}") if args[1]
    file.puts("pushd #{chdir.gsub!(/\//, "\\")}")
  }
end

def dialogue( args )
  unless File.exist?(filename = Batch_dir + args[0] + ".bat")
    make_bat(args)
  else
    print "同じ project-code が存在します。\n\n"

    puts "#{filename}"

    overlap_pr = Projects.new([Projects.parse_info(filename)])
    overlap_pr.show_self

    begin
      print "上書きしますか? [y/n] "
      ans = $stdin.gets.chomp!
    end until ans == "y" || ans == "n"

    case ans
    when "y"
      make_bat(args)
      puts "上書きしました。"
      overlap_pr = Projects.new([Projects.parse_info(filename)])
      overlap_pr.show_self
      exit
    when "n"
      puts "中止しました。"
      exit
    end
  end
end

# here.rb 用バッチファイルの集まりを表すクラス
class Projects
  def initialize( ary )
    @list = ary.dup
  end

  def collect_project_code( str )
    pr_list = @list.find_all{|project| /^#{str}.*/ =~ project[:project_code]}
    Projects.new(pr_list.sort_by{|project| project[:project_code]})
  end

  def collect_destination_dir( str )
    pr_list = @list.find_all{|project| /^#{str}.*/ =~ File.basename(project[:destination_dir])}
    Projects.new(pr_list.sort_by{|project| project[:destination_dir]})
  end

  # Project_code_width: プロジェクトコードの表示幅。
  Project_code_width = 10
  # Visible: 表示するには長すぎるパス名を切り詰めるための定数。
  # パス名の頭と尻尾がそれぞれこの数字分出力される。
  Visible = 23
              
  def show_self
    #scale_len = 8; scale = ""
    #1.upto(scale_len){|i| scale << (" "*9 + i.to_s)}
    #
    #puts "#{scale}"
    #puts "1234567890" * scale_len

    display_len = 2 * Visible + 5

    @list.each{|pr|
      pr_code = pr[:project_code]

      d_d_name = pr[:destination_dir]

      if d_d_name.length > display_len 
        last = d_d_name.length

        name_head = d_d_name[0...Visible]
        snip_str  = d_d_name[Visible...-(Visible)]
        name_tail = d_d_name[-Visible...last]

        # ディレクトリの深さが分かるように、省略されたパス名の中の"\"数を数える。
        if 0 < b_slash = snip_str.count("\\")
          d_d_name = name_head + "[..#{b_slash.to_s}]" + name_tail
        else
          d_d_name = name_head + "....." + name_tail
        end
      end

      note = pr[:note] ? "# " + pr[:note] : ""

      display_str = pr_code.ljust(Project_code_width) + d_d_name.ljust(display_len + 2) + note

      puts "#{display_str}"
    }
  end

  # 以下 2つのクラスメソッドで here.rb 用バッチファイルから、
  # project-code, そのバッチが指す行き先のディレクトリ, 覚え書き
  # の情報を取り出し、Projects のインスタンスを生成する。
  def Projects.list_from_dir( dir )
    list = []
    Dir.glob(dir + "*.bat"){|file_name|
      list << Projects.parse_info(file_name)
    }
    return Projects.new(list)
  end

  def Projects.parse_info( file_name )
    info = {:project_code => File.basename(file_name, ".bat")}

    File.open(file_name){|file|
      file.readlines.each{|line|
        case line
        when /pushd\s*/
          info[:destination_dir] = $'.chomp!
        when /REM\shere_note:\s*/i
          info[:note] = $'.chomp!
        end
      }
    }
    return info
  end
end

if options.empty?
  if ARGV.empty?
    Projects.list_from_dir(Batch_dir).show_self
    #puts parser.help
  else
    dialogue(ARGV)
  end
else
  pj_list = Projects.list_from_dir(Batch_dir)

  if options.has_key?(:p)
    pj_ini_chr = options[:p] || ""
    pj_list.collect_project_code(pj_ini_chr).show_self
  else
    dest_ini_chr = options[:d] || ""
    pj_list.collect_destination_dir(dest_ini_chr).show_self
  end
end

*1:*.rb ファイルの関連付けがされているなら、単に here.rb を path の通ったディレクトリに置くだけでもいい。ただしこの場合 help メッセージの一部が文字化けする。

*2:here.rb は生成されたバッチファイルから情報を取り出す。生成されたバッチファイルと同じディレクトリに、それ以外のバッチファイルが存在するとそれらのファイルも読み取られて、正しい表示が得られなくなる。