Module RecursiveUtils::FrontEnd
In: recursiveutils.rb

Summary

RecursiveUtils::FullPathList, RecursiveUtils::Rename, RecursiveUtils::Sed, RecursiveUtils#chmod, RecursiveUtils#chown のフロントエンド

How to Use

  1) recursiveutils.rb を実効権限を付加して
     Ruby のライブラリパスに置く.

  2) パスの通った場所にシンボリックリンクを作成する.
     名前と実行されるメソッドの関係は以下の通り.

     /find/i   => FrontEnd#find
     /rename/i => FrontEnd#rename
     /sed/i    => FrontEnd#sed
     /chmod/i  => FrontEnd#chmod
     /chown/i  => FrontEnd#chown

  3) シンボリックリンクを実行すると名前に対応したメソッドが実行される.
     (実際は FrontEnd#wrapper を経由して実行される)

  4) recursiveutils.rb に実行権限を付けたくない場合は
     以下のようなラッパースクリプトを作成すると良い.

     rsed.rb
     #! /usr/bin/env ruby
     require 'recursiveutils'
     exit RecursiveUtils::FrontEnd.sed(ARGV)

Methods

Public Methods

フロントエンド:find, rename, sed, chmod, chown
ラッパー:wrapper

Private Methods

メッセージ処理:usage, help, version, error
オプション設定:make_parser
引数チェック:check_code, check_number
その他:make_base_data, compare_version, sort_help

Methods

Included Modules

LocaleFilter::PrintWrapper

Public Instance methods

Summary

RecursiveUtils#chmod のフロントエンド.

Synopsis

   rchmod.rb [OPTIONS] mode file [file...]

Options

  -d, --dir              ディレクトリを対象に含める。
  -D, --debug            デバッグ用メッセージを表示する。(開発者用)
  -F, --file-code CODE   ファイル名の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -h, --usage            Usage とオプションを出力する。
  -H, --help             詳細なヘルプを出力する。
  -i, --ignore-case      正規表現の大文字小文字を区別しない。
  -I, --input-code CODE  入力文字列の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -n, --no-exec          実行結果のみ出力し、実行はしない。
  -o, --owner            所有権を持たないファイルを処理対象から除く。
  -p, --prune PATTERN    正規表現でマッチするファイルを処理対象から除く。
  -R, --readable         読み込み権を持たないファイルを除く。
  -S, --symlink          シンボリックリンクを処理対象から除く。
  -t, --target PATTERN   処理対象ファイル名を正規表現で限定する。
  -v, --version          バージョン情報を出力する。
  -V, --verbose          冗長なメッセージを出力する。
  -W, --writable         書き込み権を持たないファイルを除く。
  -x, --executable       実行権を持たないファイルを除く。

[Source]

# File recursiveutils.rb, line 1668
    def chmod(argv = ARGV)
      extend FrontEnd

      make_base_data()
      @name    = 'rchmod.rb'
      @version = '0.7'
      @update  = '2008/07/20'

      if @japanese
        @summary = '再帰処理機能付きの Ruby 版 chmod'
        @description = %Q(
      #{@name} は 再帰処理を追加した Ruby 版 chmod です。
      File#chmod を RecursiveUtils::FullPathList を介して
      再帰的に処理しています。
      FullPathList 独自のオプションが追加されている事を除けば
      FileUtils#chmod_R とほぼ同じです。
      UNIX コマンドの chmod とは mode の指定の仕方が違うので
      注意して下さい。)

      else
        @summary = 'recursive chmod with Ruby'
        @description = %Q(
      #{@name} is the chmod with Ruby that mounts the reflexive processing function.
      File#chmod is recurrently processed through RecursiveUtils::FullPathList.
      If the thing that the option of original FullPathList is added is excluded,
      it is almost the same as FileUtils#chmod_R.
      Please note that a method specified of mode is different from
      the chmod of UNIX command.)
      end

      @usage = "
      #{@name} [OPTIONS] mode file [file...]"

      if @japanese
        @todo = '
      8進数を使った指定もできるようにする。'
      end

      @author = '
      Koichi MICHIMASA <michi[at]ep.sci.hokudai.ac.jp>'

      @history = '
      2008/07/20  Ver. 0.7  (by Michimasa)
      2007/12/13  Ver. 0.6  (by Michimasa)
      2007/12/05  Ver. 0.5  (by Michimasa)
      2007/11/25  Ver. 0.4  (by Michimasa)
      2007/11/10  Ver. 0.3  (by Michimasa)
      2007/10/29  Ver. 0.2  (by Michimasa)
      2007/10/05  Ver. 0.1  (created by Michimasa)'

      op, opts = make_parser()
      op.parse!(argv)  rescue error()
      error('No argument.')  if argv.size < 2
      puts "set locale: #{LOCALE_NAME}"  if opts[:debug]

      begin
        return RecursiveUtils.chmod(argv[0], argv[1..-1], opts)
      rescue
        error()
      end
    end

Summary

RecursiveUtils#chown のフロントエンド.

Synopsis

   rchown.rb [OPTIONS] mode file [file...]

Options

  -d, --dir              ディレクトリを対象に含める。
  -D, --debug            デバッグ用メッセージを表示する。(開発者用)
  -F, --file-code CODE   ファイル名の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -h, --usage            Usage とオプションを出力する。
  -H, --help             詳細なヘルプを出力する。
  -i, --ignore-case      正規表現の大文字小文字を区別しない。
  -I, --input-code CODE  入力文字列の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -n, --no-exec          実行結果のみ出力し、実行はしない。
  -o, --owner            所有権を持たないファイルを処理対象から除く。
  -p, --prune PATTERN    正規表現でマッチするファイルを処理対象から除く。
  -R, --readable         読み込み権を持たないファイルを除く。
  -S, --symlink          シンボリックリンクを処理対象から除く。
  -t, --target PATTERN   処理対象ファイル名を正規表現で限定する。
  -v, --version          バージョン情報を出力する。
  -V, --verbose          冗長なメッセージを出力する。
  -W, --writable         書き込み権を持たないファイルを除く。
  -x, --executable       実行権を持たないファイルを除く。

[Source]

# File recursiveutils.rb, line 1757
    def chown(argv = ARGV)
      extend FrontEnd

      make_base_data()
      @name    = 'rchown.rb'
      @version = '0.7'
      @update  = '2008/07/20'

      if @japanese
        @summary = '再帰処理機能付きの Ruby 版 chown'
        @description = %Q(
      #{@name} は 再帰処理を追加した Ruby 版 chown です。
      File#chown を RecursiveUtils::FullPathList を介して
      再帰的に処理しています。
      FullPathList 独自のオプションが追加されている事を除けば
      FileUtils#chown_R とほぼ同じです。
      UNIX コマンドの chown とは owner, group の指定の仕方が
      違うので注意して下さい。)

      else
        @summary = 'recursive chown with Ruby'
        @description = %Q(
      #{@name} is the chown with Ruby that mounts the reflexive processing function.
      File#chown is recurrently processed through RecursiveUtils::FullPathList.
      If the thing that the option of original FullPathList is added is excluded,
      it is almost the same as FileUtils#chown_R.
      Please note that a method specified of mode is different from
      the chown of UNIX command.)
      end

      @usage = "
      #{@name} [OPTIONS] owner group file [file...]"

      @author = '
      Koichi MICHIMASA <michi[at]ep.sci.hokudai.ac.jp>'

      @history = '
      2008/07/20  Ver. 0.7  (by Michimasa)
      2007/12/13  Ver. 0.6  (by Michimasa)
      2007/12/05  Ver. 0.5  (by Michimasa)
      2007/11/25  Ver. 0.4  (by Michimasa)
      2007/11/10  Ver. 0.3  (by Michimasa)
      2007/10/29  Ver. 0.2  (by Michimasa)
      2007/10/05  Ver. 0.1  (created  by Michimasa)'

      op, opts = make_parser()
      op.parse!(argv)  rescue error()
      error('No argument.')  if argv.size < 3
      puts "set locale: #{LOCALE_NAME}"  if opts[:debug]

      begin
        return RecursiveUtils.chown(argv[0], argv[1], argv[2..-1], opts)
      rescue
        error()
      end
    end

Summary

RecursiveUtils::FullPathList#get のフロントエンド.

Synopsis

   rfind.rb [OPTIONS] dir [dir...]

Options

  -0, --null             出力時のファイル名の区切りにNULL文字を使用する。
  -D, --debug            デバッグ用メッセージを表示する。(開発者用)
  -F, --file-code CODE   ファイル名の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -h, --usage            Usage とオプションを出力する。
  -H, --help             詳細なヘルプを出力する。
  -i, --ignore-case      正規表現の大文字小文字を区別しない。
  -I, --input-code CODE  入力文字列の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -n, --no-convert       文字コードを変換せずに出力する。
  -o, --owner            所有権を持たないファイルを処理対象から除く。
  -p, --prune PATTERN    正規表現でマッチするファイルを処理対象から除く。
  -R, --readable         読み込み権を持たないファイルを除く。
  -S, --symlink          シンボリックリンクを処理対象から除く。
  -t, --target PATTERN   処理対象ファイル名を正規表現で限定する。
  -T, --type TYPE        ファイルの種類を指定する。
                         (f: regular file, d: directory, s: symbolic link)
  -v, --version          バージョン情報を出力する。
  -V, --verbose          冗長なメッセージを出力する。
  -W, --writable         書き込み権を持たないファイルを除く。
  -x, --executable       実行権を持たないファイルを除く。

[Source]

# File recursiveutils.rb, line 1843
    def find(argv = ARGV)
      extend FrontEnd

      make_base_data()
      @name    = 'rfind.rb'
      @version = '0.4'
      @update  = '2008/07/20'

      if @japanese
        @summary = 'Ruby 版 find'
        @description = %Q(
      Ruby 版 find。)

        @exit = %Q(
      一つでも表示するファイルがあれば 0 を, 無ければ 1 を返します。
      文法エラーやシステムエラーが発生した場合は 2 を返します。)

      else
        @summary = 'find with Ruby'
        @description = %Q(
      #{@name} is the find with Ruby.)

        @exit = %Q(
      Normally, exit status is 0 if there is a file that
      display and 1 otherwise.
      But the exit status is 2 if an error occurred.)
      end

      @usage = "
      #{@name} [OPTIONS] directory [directory...]"

      @author = '
      Koichi MICHIMASA <michi[at]ep.sci.hokudai.ac.jp>'

      @history = '
      2008/07/20  Ver. 0.4  (by Michimasa)
      2007/12/13  Ver. 0.3  (by Michimasa)
      2007/12/06  Ver. 0.2  (by Michimasa)
      2007/11/20  Ver. 0.1  (created by Michimasa)'

      op, opts = make_parser()

      op.on('-0', '--null',
            @japanese ?
            '出力時のファイル名の区切りにNULL文字を使用する。' : \
            'use null character instead of newline when display result'
            ) { opts[:output_opt] = 'null' }

      op.on('-n', '--no-convert',
            @japanese ?
            '文字コードを変換せずに出力する。' : \
            'do not convert encode when display result'
            ) { opts[:output_opt] = 'noconv' }

      op.on('-T', '--type TYPE', String,
            @japanese ?
            'ファイルの種類を指定する。' : \
            'specify the file type for find',
            '(f: regular file, d: directory, s: symbolic link)'
            ) { |i| opts[:file_type] = i }

      op.parse!(argv)  rescue error()

      error('No argument.')  if argv.size < 1
      puts "set locale: #{LOCALE_NAME}"  if opts[:debug]
      opts[:recursive] = true

      begin
        pathlist = RecursiveUtils::FullPathList.get(opts, argv)
        return false  if pathlist.empty?
        case opts[:output_opt]
        when 'noconv'
          STDOUT.puts pathlist

        when 'null'
          STDOUT.print pathlist.join("\0")

        else
          puts pathlist
        end

      rescue
        error()
      end
      return true
    end

Summary

RecursiveUtils::Rename のフロントエンド.

Synopsis

   rename.rb [OPTIONS] from to file [file...]
   rename.rb [-du] file [file...]
   rename.rb --code CODE file [file...]

Options

  -b, --base             拡張子以外を変換する。
  -c, --code CODE        ファイル名の文字コードを変換する。
                         (sjis, euc, jis, utf8, utf16)
  -d, --down             大文字を小文字に変換する。
  -D, --debug            デバッグ用メッセージを表示する。(開発者用)
  -e, --ext              拡張子のみを変換する。
  -E, --escape           正規表現のメタ文字を保護する。
  -f, --force            確認せずに変換を行う。
  -F, --file-code CODE   ファイル名の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -h, --usage            Usage とオプションを出力する。
  -H, --help             詳細なヘルプを出力する。
  -i, --ignore-case      正規表現の大文字小文字を区別しない。
  -I, --input-code CODE  入力文字列の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -n, --no-exec          実行結果のみ出力し、実行はしない。
  -N, --number NUM       パターン中の "/" を指定した桁数の連番に変換する。
  -o, --owner            所有権を持たないファイルを処理対象から除く。
  -p, --prune PATTERN    正規表現でマッチするファイルを処理対象から除く。
  -q, --quiet            メッセージの出力を抑制する。
  -r, --recursive        再帰的に実行する。
  -R, --readable         読み込み権を持たないファイルを除く。
  -s, --start NUM        連番の初期値を指定する。 (-N 参照)
  -S, --symlink          シンボリックリンクを処理対象から除く。
  -t, --target PATTERN   処理対象ファイル名を正規表現で限定する。
  -u, --up               小文字を大文字に変換する。
  -v, --version          バージョン情報を出力する。
  -V, --verbose          冗長なメッセージを出力する。
  -W, --writable         書き込み権を持たないファイルを除く。
  -x, --executable       実行権を持たないファイルを除く。

[Source]

# File recursiveutils.rb, line 1221
    def rename(argv = ARGV)
      extend FrontEnd

      make_base_data()
      @name    = 'rename.rb'
      @version = '3.10'
      @update  = '2008/07/20'

      if @japanese
        @summary = '再帰処理機能付きの Ruby 版 rename'
        @description = '
      再帰処理機能を実装した Ruby 版 rename です。
      指定したファイル名を Ruby の正規表現を用いて置換します。
      [-c] オプションでファイル名の文字コードを変換する事もできます。'

      else
        @summary = 'rename multiple files'
        @description = '
      Rename multiple files at a time by regular expression.
      Convert character code of multiple filenames at a time.'
      end

      @usage = "
      #{@name} [OPTIONS] from to file [file...]
      #{@name} [OPTIONS] [-du] file [file...]
      #{@name} [OPTIONS] --code CODE file [file...]"

      if @japanese
        @example = %Q(
      $ #{@name} -de ./*
      => 該当するファイル中の拡張子を小文字に変換します。

      $ #{@name} -N 2 '\\.' '_/.' a.txt b.jpg c.log
      => a_01.txt b_02.jpg c_03.log
         -N オプションが指定された場合は変換パターンの "/" を
         指定した桁数の連番に置換します。

      $ #{@name} -N 4 -b '..*' '/' foo/b foo/a.txt bar/c.log
      => bar/0001.log foo/0001.txt foo/0002
         番号はディレクトリ毎にリセットされ、
         引数順ではなく、ファイル名順に振られます。

      $ #{@name} -I euc 'あ' 'a' あいうえお.txt
      => 変換文字列に日本語があって、文字化けなどで上手く変換
         出来ない場合は -I オプションで文字コードを指定して下さい。)
      end

      if @japanese
        @bug = '
      ・文字列が短すぎて文字コードの自動判定に失敗する
         => -F オプションで文字コードを指定できます。
           ただし、個別指定は出来ないので複数の文字コードが
           混在している場合は注意が必要です。

      ・連番変換時、ディレクトリ内に同じ番号があるか
        確認をしていない'
      end

      @author = '
      Yasuhiro MORIKAWA  <morikawa[at]ep.sci.hokudai.ac.jp>
      Koichi   MICHIMASA <michi[at]ep.sci.hokudai.ac.jp>
      Daisuke  TSUKAHARA <daktu32[at]ep.sci.hokudai.ac.jp>'

      @history = '
      2008/07/20  Ver. 3.10   (by Michimasa)
      2008/03/05  Ver. 3.9    (by Michimasa)
      2007/12/13  Ver. 3.8    (by Michimasa)
      2007/12/07  Ver. 3.7    (by Michimasa)
      2007/11/25  Ver. 3.6    (by Michimasa)
      2007/11/10  Ver. 3.5    (by Michimasa)
      2007/10/29  Ver. 3.4    (by Michimasa)
      2007/10/05  Ver. 3.3    (by Michimasa)
      2007/05/27  Ver. 3.2    (by Michimasa)
      2007/05/23  Ver. 3.1    (by Michimasa)
      2007/05/19  Ver. 3.0.1  (by Michimasa)
      2007/05/09  Ver. 3.0    (by Michimasa)
      2007/01/19  Ver. 2.3.1  (by Michimasa)
      2007/01/08  Ver. 2.3    (by Michimasa)
      2006/11/17  Ver. 2.2    (by Michimasa)
      2006/11/13  Ver. 2.1    (by Michimasa)
      2006/11/04  Ver. 2.0    (by Michimasa)
      2006/10/30  Ver. 1.3    (by Michimasa)
      2006/10/25  Ver. 1.2    (by Michimasa)
      2006/10/24  Ver. 1.1    (by Morikawa)
      2006/10/24  Ver. 1.0    (by Michimasa)
      2003/12/20  Ver. 0.2    (by Tsukahara)
      2003/11/18  Ver. 0.1.1  (by Tsukahara)
      2003/09/??  Ver. 0.1    (created by Tsukahara)'

      op, opts = make_parser()

      op.on('-e', '--ext',
            @japanese ?
            '拡張子のみを変換する。' : \
            'convert only extension'
            ) { opts[:name_type] = 'e' }

      op.on('-b', '--base',
            @japanese ?
            '拡張子以外を変換する。' : \
            'convert except for extension'
            ) { opts[:name_type] = 'b' }

      op.on('-c', '--code CODE', String,
            @japanese ?
            'ファイル名の文字コードを変換する。' : \
            'convert character code of filename',
            "(#{LocaleFilter::LOCALE_LIST.join(',')})"
            ) { |i| opts[:code] = check_code(i) }

      op.on('-N', '--number NUM', Integer,
            @japanese ?
            'パターン中の "/" を指定した桁数の連番に変換する。' : \
            'convert "/" in the pattern to sequential numbers'
            ) { |i| opts[:figure] = check_number(i) }

      op.on('-s', '--start NUM', Integer,
            @japanese ?
            '連番の初期値を指定する。 (-N 参照)' : \
            'specify starting number. (for -N)'
            ) { |i| opts[:number] = check_number(i) }

      op.on('-f', '--force',
            @japanese ?
            '確認せずに変換を行う。' : \
            'rename without confirmations'
            ) { opts[:force] = true }

      op.parse!(argv)  rescue error()

      if (opts[:code] || opts[:changecase]) ? argv.empty? : argv.size < 3
        error('No argument.')
      end

      begin
        rr = RecursiveUtils::Rename.new(opts)
        puts "set locale: #{LOCALE_NAME}"  if opts[:debug]

        case
        when opts[:code]
          return rr.convert(opts[:code], argv)

        when opts[:changecase]
          return rr.__send__(opts[:changecase], argv)

        else
          return rr.gsub(argv[0], argv[1], argv[2..-1])
        end

      rescue
        error()
      end
      return true
    end

Summary

RecursiveUtils::Sed のフロントエンド.

Synopsis

   rsed.rb [OPTIONS] from to files [file...]
   rsed.rb [OPTIONS] [-du] file [file...]

Options

  -b, --backup           元ファイルを "*.bak" という名前で保存し、
                         オリジナルのファイルを上書きする。
  -c, --code CODE        ファイルの文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -d, --down             大文字を小文字に変換する。
  -D, --debug            デバッグ用メッセージを表示する。(開発者用)
  -e, --ext EXTENSION    バックアップファイルの拡張子を指定する。
  -E, --escape           正規表現のメタ文字を保護する。
  -F, --file-code CODE   ファイル名の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -f, --force            オリジナルのファイルを上書きする。
  -h, --usage            Usage とオプションを出力する。
  -H, --help             詳細なヘルプを出力する。
  -i, --ignore-case      正規表現の大文字小文字を区別しない。
  -I, --input-code CODE  入力文字の文字コードを指定する。
                         (sjis, euc, jis, utf8, utf16)
  -l, --files-list       変更されるファイルのリストのみを表示する。
  -m, --multi            複数行の置換を有効にする。
  -M, --expand-multi     複数行の置換を有効にする。("." が改行にもマッチする)
  -n, --no-exec          実行結果のみ出力し、実行はしない。
  -o, --owner            所有権を持たないファイルを処理対象から除く。
  -p, --prune PATTERN    正規表現でマッチするファイルを処理対象から除く。
  -P, --protect          一時ファイルやバックアップファイルの作成時に
                         既存のファイルを上書きしない。
  -q, --quiet            メッセージの出力を抑制する。
  -r, --recursive        再帰的に実行する。
  -s, --size BYTES       ファイルの文字コード判定時に読み込む
                         ファイルサイズを指定する。
                         (default : 1024 byte, max: 1048576 byte)
  -S, --symlink          シンボリックリンクを処理対象から除く。
  -t, --target PATTERN   処理対象ファイル名を正規表現で限定する。
  -u, --up               小文字を大文字に変換する。
  -v, --version          バージョン情報を出力する。
  -V, --verbose          冗長なメッセージを出力する。
  -x, --executable       実行権を持たないファイルを除く。

[Source]

# File recursiveutils.rb, line 1420
    def sed(argv = ARGV)
      extend FrontEnd

      make_base_data()
      @name    = 'rsed.rb'
      @version = '6.6'
      @update  = '2008/10/07'

      if @japanese
        @summary = '再帰処理機能付きの Ruby 版 sed'
        @description = %Q(
      #{@name} は 再帰処理機能を実装した Ruby 版 sed です。
      default では、「file」で指定したパスのファイルに対して
      「from」で指定した正規表現パターンを検索し、「to」に
      置換した後、 "file_" のようにオリジナルのファイル名の
      最後にアンダーバーを付加したファイルへ出力します。)

      else
        @summary = 'recursive sed with Ruby'
        @description = %Q(
      #{@name} is the sed with Ruby that mounts the reflexive processing function.
      In default, after the regular expression pattern specified by "from"
      for the file of passing of the specification by "file" is retrieved,
      and it substitutes it for "to", it outputs it to the file that added
      under a bar like "File _" at the end of an original file name.)
      end

      @usage = "
      #{@name} [OPTIONS] from to file [file...]
      #{@name} [OPTIONS] [-du] file [file...]"

      if @japanese
        @example = %Q[
      $ #{@name} -f '2002' '2004' ./html/200?.html
      => ./html/200?.html に該当するファイル中の "2002" を
         "2004" に変換します。

      $ #{@name} -m 'foo\\nbar' 'baz\\n' text2002.html
      => -m オプションで複数行の置換が出来ます。
         ファイルの中身を一度に全て読み込んでから処理をするので
         メモリに充分な余裕がある場合は改行コードを含まなくても
         このオプションを加えると通常よりも高速に動作します。

      $ #{@name} '.*(hoge)' '\\1' hoge.txt
      => Ruby の正規表現が一通り使えます。
         (この場合は /hoge/ の前の文字列が消える)

      $ #{@name} -s 2048 'from' 'to' file
      => ファイルの文字コードの自動判定が上手くいかない場合は
         -s オプションで読み込むサイズを大きくするか、
         -c オプションでファイルの文字コードを指定して下さい。

      $ #{@name} -I euc '日本語' 'Japanese' a.txt
      => 変換文字列に日本語があって、文字化けなどで上手く変換
         出来ない場合は -I オプションで文字コードを指定して下さい。]
      end

      if @japanese
        @bug = '
      ・複数の文字コードが混在したファイルを与えると
        高確率で文字化けを起こす。
        => 行毎に自動判定させるオプションの実装を検討中

      ・ASCII と誤判定された日本語は EUC に変換されてしまう
        (内部で処理をする時に EUC に変換している為)。
        => -s や -c オプションで対応して下さい

      ・ファイルのサイズが非常に大きい場合にスクリプトが
        落ちる可能性がある (特に複数行の置換を行う時)'
      end

      if @japanese
        @todo = '
      EXAMPLE の英語化。'
      end

      @author = '
      Koichi   MICHIMASA <michi[at]ep.sci.hokudai.ac.jp>
      Yasuhiro MORIKAWA  <morikawa[at]ep.sci.hokudai.ac.jp>
      Daisuke  TSUKAHARA <daktu32[at]ep.sci.hokudai.ac.jp>'

      @history = '
      2008/10/07  Ver. 6.6  (by Michimasa)
      2008/07/20  Ver. 6.5  (by Michimasa)
      2007/12/13  Ver. 6.4  (by Michimasa)
      2007/12/06  Ver. 6.3  (by Michimasa)
      2007/11/25  Ver. 6.2  (by Michimasa)
      2007/11/10  Ver. 6.1  (by Michimasa)
      2007/10/29  Ver. 6.0  (by Michimasa)
      2007/10/05  Ver. 5.4  (by Michimasa)
      2007/05/27  Ver. 5.3  (by Michimasa)
      2007/05/26  Ver. 5.2  (by Michimasa)
      2007/05/23  Ver. 5.1  (by Michimasa)
      2007/05/09  Ver. 5.0  (by Michimasa)
      2007/01/19  Ver. 4.3  (by Michimasa)
      2006/11/21  Ver. 4.2  (by Michimasa)
      2006/11/17  Ver. 4.1  (by Michimasa)
      2006/11/13  Ver. 4.0  (by Michimasa)
      2006/11/09  Ver. 3.7  (by Tsukahara)
      2006/10/30  Ver. 3.6  (by Michimasa)
      2006/10/20  Ver. 3.5  (by Michimasa)
      2006/10/14  Ver. 3.4  (by Michimasa)
      2006/10/13  Ver. 3.3  (by Michimasa)
      2006/10/02  Ver. 3.2  (by Morikawa)
      2006/10/02  Ver. 3.1  (by Morikawa)
      2006/10/01  Ver. 3.0  (by Michimasa)
      2006/04/15  Ver. 2.5  (by Morikawa)
      2004/12/23  Ver. 2.4  (by Morikawa)
      2004/10/26  Ver. 2.3  (by Morikawa)
      2004/08/06  Ver. 2.2  (by Morikawa)
      2004/02/12  Ver. 2.1  (by Morikawa)
      2004/02/10  Ver. 2.0  (by Morikawa)
      2004/01/11  Ver. 1.0  (created by Tsukahara)'

      op, opts = make_parser()

      op.on('-c', '--code CODE', String,
            @japanese ?
            'ファイルの文字コードを指定する。' : \
            'specify the character code of file',
            "(#{LocaleFilter::LOCALE_LIST.join(', ')})"
            ) { |i| opts[:code] = check_code(i) }

      op.on('-m', '--multi',
            @japanese ?
            '複数行の置換を有効にする。' : \
            'effect the multi-line replacement'
            ) { opts[:multi] = true }

      op.on('-M', '--expand-multi',
            @japanese ?
            '複数行の置換を有効にする。("." が改行にもマッチする)' : \
            'effect the expanded multi-line replacement',
            unless @japanese
              '("." match line break characters)'
            end
            ) { opts[:multi] = true; opts[:expand] = true }

      op.on('-b', '--backup',
            @japanese ?
            '元ファイルを "*.bak" という名前で保存し、' : \
            'save the original file by the name of "*.bak"',
            @japanese ?
            'オリジナルのファイルを上書きする。' : \
            'and overwrite the original file'
            ) { opts[:backup] = true }

      op.on('-e', '--ext EXTENSION', String,
            @japanese ?
            'バックアップファイルの拡張子を指定する。' : \
            'spacify the extension of backup file'
            ) { |i| opts[:extension] = i; opts[:backup] = true }

      op.on('-f', '--force',
            @japanese ?
            'オリジナルのファイルを上書きする。' : \
            'overwrite the original file'
            ) { opts[:force] = true }

      op.on('-P', '--protect',
            @japanese ?
            '一時ファイルやバックアップファイルの作成時に' : \
            'not overwrite existing files',
            @japanese ?
            '既存のファイルを上書きしない。' : \
            'when making temporary or backup files'
            ) { opts[:protect] = true }

      op.on('-s', '--size BYTES', Integer,
            @japanese ?
            'ファイルの文字コード判定時に読み込む' : \
            'specify the size of file read when guessing',
            @japanese ?
            'ファイルサイズを指定する。' : \
            'the chracter code of the file',
            "(default : #{Sed::DEF_SIZE} byte, max: #{Sed::MAX_SIZE} byte)"
            ) { |i| opts[:size] = check_number(i) }

      op.on('-l', '--files-list',
            @japanese ?
            '変更されるファイルのリストのみを表示する。' : \
            'display the files list which will be replaced only'
            ) { opts[:file_list] = true }

      op.parse!(argv)  rescue error()

      if opts[:casechange] ? argv.empty? : argv.size < 3
        error('No argument.')
      end

      begin
        rs = RecursiveUtils::Sed.new(opts)
        if opts[:changecase]
          return rs.__send__(opts[:changecase], argv)
        else
          return rs.gsub(argv[0], argv[1], argv[2..-1])
        end

      rescue => message
        if message.to_s =~ /Invalid size|Too big/
          lf = LocaleFilter.new
          lf.input = 'euc'
          @usage = "\n"
          flag = false
          sort_help(op).each do |i|
            case i
            when /^\s*\-s/
              flag = true

            when /^\s*\-S/
              break
            end
            @usage << lf.tolocale(i).chop << "\n"  if flag
          end
          @backtrace = false
        end
        error(message)
      end
      return true
    end

ファイル名 path に応じてフロントエンドメソッドを実行する.

[Source]

# File recursiveutils.rb, line 1165
    def wrapper(path = $0, argv = ARGV)
      case File.basename(path).downcase
      when /rename/
        method = :rename
      when /sed/
        method = :sed
      when /chmod/
        method = :chmod
      when /chown/
        method = :chown
      when /find/
        method = :find
      end
      exit __send__(method, argv)
    end

Private Instance methods

引数チェック用メソッド. 日本語以外の文字コードだった場合は例外 ArgumentError を返す.

[Source]

# File recursiveutils.rb, line 2204
    def check_code(txt)
      unless code = LocaleFilter.japanese_code?(txt)
        if @japanese
          message = '不正な文字コードです。'
        else
          message = 'Invalide character code.'
        end
        raise ArgumentError, "#{txt}: #{message}"
      end
      return code
    end

引数チェック用メソッド. 自然数以外だった場合は例外 ArgumentError を返す.

[Source]

# File recursiveutils.rb, line 2218
    def check_number(num)
      unless num > 0
        if @japanese
          message = '正の整数を指定して下さい。'
        else
          message = 'Invalide number (required natural number).'
        end
        raise ArgumentError, "#{num}: #{message}"
      end
      return num
    end

ライブラリのバージョンチェック用メソッド. now よりも req が低いと false を返す.

[Source]

# File recursiveutils.rb, line 2232
    def compare_version(now, req)
      a = now.split(/[\.| ]/).map { |i| i.to_i }
      b = req.split(/[\.| ]/).map { |i| i.to_i }

      (a[0] <=> b[0]) * 8 + (a[1] <=> b[1]) * 4 + \
      (a[2] <=> b[2]) * 2 + (a[3] ? -1 : 1) > 0
    end

エラーメッセージ表示用メソッド.

[Source]

# File recursiveutils.rb, line 2192
    def error(message = $!)
      if @backtrace
        putserr "#{@name}: ", message.backtrace
      else
        putserr "#{@name}: #{message}"
      end
      putserr "  #{@usage}", %Q(\nType "#{@name} --help" for advanced help.)
      exit 2
    end

ヘルプ表示用メソッド.

[Source]

# File recursiveutils.rb, line 2149
    def help(option)
      message = "  NAME:
      #{@name} - #{@summary}

  SYNOPSIS:#{@usage}

  DESCRIPTION:#{@description}

  #{option}"

      message << "\n  ENVIRONMENT:#{@env}\n"   if @env
      message << "\n  EXIT STATUS:#{@exit}\n"  if @exit
      message << "\n  EXAMPLE:#{@example}\n"   if @example
      message << "\n  BUGS:#{@bug}\n"          if @bug
      message << "\n  TODO:#{@todo}\n"         if @todo

      message << "
  VERSION:
      #{@name} Version #{@version}, Last Update: #{@update}

  LIBRARY VERSION:
      RecursiveUtils Version #{RecursiveUtils::VERSION}, Last Update: #{RecursiveUtils::UPDATE}
      LocaleFilter   Version #{LocaleFilter::VERSION}, Last Update: #{LocaleFilter::UPDATE}

  AUTHOR:#{@author}
        All Rights Reserved.

  URL:
      #{RecursiveUtils::URL}

  HISTORY:#{@history}"

      puts message
      exit true
    end

共通データを設定する.

[Source]

# File recursiveutils.rb, line 1934
    def make_base_data
      lf = '4.5.1'
      unless compare_version(LocaleFilter::VERSION, lf)
        warn %Q(error: "#{@name}" required "LocaleFilter" Version #{lf} or later.)
        exit 2
      end

      @japanese = LocaleFilter.japanese_code?(LOCALE_NAME)

      if @japanese
        @env = %Q[
      #{LocaleFilter::LOCALE_ENV.join(', ')}
      メッセージに使用する言語を指定します。]

        @exit = %Q(
      一つでも変換に成功したファイルがあれば 0 を, 無ければ
      1 を返します。文法エラーやシステムエラーが発生した場合は
      2 を返します。)

      else
        @env = %Q[
      #{LocaleFilter::LOCALE_ENV.join(', ')}
      Specify the locale for display messages.]

        @exit = %Q(
      Normally, exit status is 0 if there is a file that
      succeeds in conversion and 1 otherwise.
      But the exit status is 2 if an error occurred.)
      end
    end

共通オプションを設定した OptionParser オブジェクトを返す.

[Source]

# File recursiveutils.rb, line 1966
    def make_parser(width = 22)
      # オプション解析 (banner, width, indent)
      op   = OptionParser.new('OPTIONS:', width, ' ' * 6)
      opts = Hash.new

      op.on('-D', '--debug',
            @japanese ?
            'デバッグ用メッセージを表示する。(開発者用)' : \
            'execute with debug mode (for developer)'
            ) { |i| opts[:debug] = true }

      op.on('---backtrace') { @backtrace = true }
      # op.on('-T',     'for OptionParser test (do nothing)')
      # op.on('--test', 'for OptionParser test (do nothing)')

      op.on('-h', '--usage',
            @japanese ?
            'Usage とオプションを出力する。' : \
            'display usage'
            ) { usage(sort_help(op)) }

      op.on('-H', '--help',
            @japanese ?
            '詳細なヘルプを出力する。' : \
            'display detailed help'
            ) { help(sort_help(op)) }

      op.on('-v', '--version',
            @japanese ?
            'バージョン情報を出力する。' : \
            'display version information'
            ) { version() }

      op.on('-x', '--executable',
            @japanese ?
            '実行権を持たないファイルを除く。' : \
            'execute  executable files only'
            ) { opts[:executable] = true }

      op.on('-o', '--owner',
            @japanese ?
            '所有権を持たないファイルを処理対象から除く。' : \
            'execute owned files only'
            ) { opts[:owner] = true }

      op.on('-S', '--symlink',
            @japanese ?
            'シンボリックリンクを処理対象から除く。' : \
            'remove symbolic link from target'
            ) { opts[:symlink] = true }

      op.on('-t', '--target PATTERN', String,
            @japanese ?
            '処理対象ファイル名を正規表現で限定する。' : \
            'limit target files by regular expression'
            ) { |i| opts[:target] = i }

      op.on('-p', '--prune PATTERN', String,
            @japanese ?
            '正規表現でマッチするファイルを処理対象から除く。' : \
            'remove target files by regular expression'
            ) { |i| opts[:prune] = i }

      op.on('-i', '--ignore-case',
            @japanese ?
            '正規表現の大文字小文字を区別しない。' : \
            'ignore case distinctions'
            ) { opts[:casefold] = true }

      op.on('-I', '--input-code CODE', String,
            @japanese ?
            '入力文字列の文字コードを指定する。' : \
            'specify the character code of pattern',
            "(#{LocaleFilter::LOCALE_LIST.join(', ')})"
            ) { |i| opts[:input_code] = check_code(i) }

      op.on('-F', '--file-code CODE', String,
            @japanese ?
            'ファイル名の文字コードを指定する。' : \
            'specify the character code of file name',
            "(#{LocaleFilter::LOCALE_LIST.join(', ')})"
            ) { |i| opts[:file_code] = check_code(i) }

      op.on('-V', '--verbose',
            @japanese ?
            '冗長なメッセージを出力する。' : \
            'display verbose messages'
            ) { opts[:verbose] = true; opts[:warning] = true }

      case @name
      when /rename/, /sed/
        op.on('-r', '--recursive',
              @japanese ?
              '再帰的に実行する。' : \
              'execute recurrently'
              ) { opts[:recursive] = true }

        op.on('-u', '--up',
              @japanese ?
              '小文字を大文字に変換する。' : \
              'convert to the capital letter'
              ) { opts[:changecase] = :upcase }

        op.on('-d', '--down',
              @japanese ?
              '大文字を小文字に変換する。' : \
              'convert to the small letter'
              ) { opts[:changecase] = :downcase }

        op.on('-E', '--escape',
              @japanese ?
              '正規表現のメタ文字を保護する。' : \
              'protect the meta character of the regular expression'
              ) { opts[:escape] = true }

        op.on('-q', '--quiet',
              @japanese ?
              'メッセージの出力を抑制する。' : \
              'do quiet run'
              ) { opts[:quiet] = true }

      when /chmod/, /chown/
        op.on('-d', '--dir',
              @japanese ?
              'ディレクトリを対象に含める。' : \
              'include directory'
              ) { opts[:directory] = true }
      end

      if @name !~ /sed/
        op.on('-R', '--readable',
              @japanese ?
              '読み込み権を持たないファイルを除く。' : \
              'execute readable files only'
              ) { opts[:readable] = true }

        op.on('-W', '--writable',
              @japanese ?
              '書き込み権を持たないファイルを除く。' : \
              'execute writable files only'
              ) { opts[:writable] = true }
      end

      if @name !~ /find/
        op.on('-n', '--no-exec',
              @japanese ?
              '実行結果のみ出力し、実行はしない。' : \
              'do not execute, display result only'
              ) { opts[:noop] = true }
      end
      return op, opts
    end

OptionParser オブジェクト op のヘルプメッセージを sort して配列で返す.

[Source]

# File recursiveutils.rb, line 2120
    def sort_help(op)
      x = op.help.to_a
      y = Array.new

      x[1..-1].each do |i|
        case i
        when /\A\s*\---backtrace/
          next
        when /\A\s*\-/
          y << i
        else
          y[-1] << i
        end
      end

      y.sort { |a, b|
        i = a.sub(/,.*/m, '').sub('--', '').squeeze
        j = b.sub(/,.*/m, '').sub('--', '').squeeze
        (i.upcase <=> j.upcase) * 2 + (j <=> i)
      }.unshift(x[0])
    end

USAGE 表示用メソッド.

[Source]

# File recursiveutils.rb, line 2143
    def usage(option)
      puts "  USAGE:#{@usage}\n\n  #{option}"
      exit true
    end

Version 情報表示用メソッド.

[Source]

# File recursiveutils.rb, line 2186
    def version
      puts "#{@name} Ver. #{@version}, Last Update: #{@update}"
      exit true
    end

[Validate]