Module | RecursiveUtils::FrontEnd |
In: |
recursiveutils.rb
|
RecursiveUtils::FullPathList, RecursiveUtils::Rename, RecursiveUtils::Sed, RecursiveUtils#chmod, RecursiveUtils#chown のフロントエンド
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)
フロントエンド: | find, rename, sed, chmod, chown |
ラッパー: | wrapper |
メッセージ処理: | usage, help, version, error |
オプション設定: | make_parser |
引数チェック: | check_code, check_number |
その他: | make_base_data, compare_version, sort_help |
RecursiveUtils#chmod のフロントエンド.
rchmod.rb [OPTIONS] mode file [file...]
-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 実行権を持たないファイルを除く。
# 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
RecursiveUtils#chown のフロントエンド.
rchown.rb [OPTIONS] mode file [file...]
-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 実行権を持たないファイルを除く。
# 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
RecursiveUtils::FullPathList#get のフロントエンド.
rfind.rb [OPTIONS] dir [dir...]
-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 実行権を持たないファイルを除く。
# 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
RecursiveUtils::Rename のフロントエンド.
rename.rb [OPTIONS] from to file [file...] rename.rb [-du] file [file...] rename.rb --code CODE file [file...]
-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 実行権を持たないファイルを除く。
# 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
RecursiveUtils::Sed のフロントエンド.
rsed.rb [OPTIONS] from to files [file...] rsed.rb [OPTIONS] [-du] file [file...]
-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 実行権を持たないファイルを除く。
# 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 に応じてフロントエンドメソッドを実行する.
# 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
引数チェック用メソッド. 日本語以外の文字コードだった場合は例外 ArgumentError を返す.
# 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 を返す.
# 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 を返す.
# 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
エラーメッセージ表示用メソッド.
# 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
ヘルプ表示用メソッド.
# 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
共通データを設定する.
# 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 オブジェクトを返す.
# 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 して配列で返す.
# 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