コマンドラインアプリケーションの構築(CLI)

この記事は、David CopelandのRubyでのすばらしいコマンドラインアプリケーションの構築( 購入ダウンロード、 詳細 )の影響を受けて書かれました。 そのほとんどは、使用する言語に関係なく、CLIアプリケーションの設計の設計に専念します。 このプロセスでは、ルビーに固有の事項について説明しますが、それを知らなくても怖くはありません。コードが多すぎることはありません。 この記事は、自身の経験が散りばめられた前述の本のかなり詳細なレビューと考えることができます。 私は本を​​お勧めします!



まず、質問をします。 IT-shnikovのコミュニティを見ると、美しいグラフィカルインターフェイスを備えたプログラムが豊富にあるにもかかわらず、コマンドラインアプリケーションが非常に人気があることがわかります。 なんで?

いくつかの答えがあります。 まず、 非常に便利です。コマンドラインでコマンドを使用してタスクを記述できれば、マウスの動きを分析してさまざまなメニュー項目をクリックする必要がある場合よりも自動化がはるかに簡単になります。 第二に、信じられないほど多くの方法でプログラムを組み合わせることが可能になります。これは、グラフィカルインターフェイスを使用して達成することは困難です。

Unixの哲学は、多くの場合、それぞれ独自の特定のタスクを実行できる多くの小さなユーティリティが、1つの多機能ユニバーサルプログラムよりも優れているという原則に基づいています。 そして、これは、IT-shnikovの世界でUnixシステムが成功した理由の1つです。

おそらく、誰もがGUIからCLIに普通のユーザーを引き付けることができるとは考えにくいことを理解しており、「コンピューターサイエンティスト」という私たちに焦点を合わせて、CLIアプリケーションに対する希望を明確にしましょう。



一般的な要件



簡単に言えば、それらを単純に、しかし効率的に使用したいのです。 David Copelandは、これを達成するためのアプリケーション要件の包括的なリストを作成しました。



次に、これらのポイントについてさらに詳しく説明します。



使いやすい



ユーティリティとソフトウェアパッケージ。 どちらが便利ですか?


そのため、すべてのアプリケーションは、ユーティリティとソフトウェアパッケージ(元のコマンドスイート)の2つのタイプに条件付きで分割できます。



最初のタイプは、1つの目標と1つの操作モードを持つアプリケーションです。 このタイプのプログラムには数え切れないほどの例があり、ほとんどすべてのUnixコマンドは次のとおりです:ls、grep、diff、... さらに、連続処理のためにチェーンに接着するのが簡単です。 ここでは、次の例えが関係します。 あなたが家を建てていると想像してください。さらに、その家は標準モデルではありません。 モノリシックブロックからではなく、レンガから構築する方がはるかに便利です。場所によってはこれらのブロックをファイルする必要があり、どこかで石でジョイントを閉じる必要があるためです。 はい、ブロックはクレーンでしか引っ張ることができませんが、レンガは手で置くことができます。



2番目のタイプのプログラムは、スイスのナイフまたはフードプロセッサーと比較できます。 時には非常に便利です。 gitを見てください(ruby、gem、rails、bundleの世界ではすぐに記憶されます)-1つのプログラムですが、それをいくつ実行できますか。 そして、彼女はコミット/チェックアウトでき、自分で履歴を検索し、ファイル間の変更を検討します。 そのため、grep、diffなどが組み込まれています。Gitに何も組み合わせる必要はありません。彼はすべてを行う方法を知っています。 家との類推に戻ると、gitaにはあらゆる場面で標準的なプロジェクトがあります(そして、それらすべてを思い出そうとします)。

それでも、すべてのプログラムが多機能である必要はありません。すべて同じように、すべてのユースケースを実行するわけではありません。 この論文をサポートするために、cd、ls、pwd、diff、df、および便利な操作を1つのコマンドで実行できる「マルチツール」を想像することをお勧めします。オプションを少し変更するだけです(たとえば、ファイルシステムの変更、ファイルシステムの表示、 ) 使いますか? 私はあなたが過度のかさばりのために捨てると思います。 ソフトウェアパッケージは非常に便利ですが、8つの触手でケンタウロスを書く前に慎重に考えることは理にかなっています。



ところで、多数のユーティリティを作成し、それをソフトウェアパッケージにしたい場合は、修正するのはそれほど難しくありません。 コマンドをルーティングするラッパーを作成するだけです。 知らないかもしれませんが、gitはコマンドの種類に基づいてgitコマンドが制御を転送するgit-commit、git-show、git-hash-object、git-cat-file、git-update-indexなどの多数のユーティリティで構成されていますオプション(もちろん、ユーティリティ呼び出しの単一チェーンが1つのコマンドの背後にある場合があります)。 そのため、将来結合する小さなプログラムのセットで大規模なプロジェクトを開始することをお勧めします。 作成、デバッグ、保守、使用が簡単です。



コマンドライン引数の構文または「この家には独自の伝統があります。」


用語から始めます。 コマンドラインアプリケーションを起動するときに、いくつかのパラメーターセットを指定します。 それらは次のタイプに分けられます:オプションと引数。 David Copelandは、オプションをさらに2つのサブタイプ(フラグとスイッチ)に分割します。

概略的には、次のexecutable [options] <arguments>



としてこれを表すことができexecutable [options] <arguments>



。 すべてが最新であると思いますが、念のため、角括弧内のパラメータはオプションであり、山括弧内のパラメータは必須であることを説明します。



引数(または位置引数)は、プログラムが機能するために指定する必要があるパラメーターです。 それらの順序は厳密に定義されています。

オプションはオプションのパラメーターです。 それらは任意の順序で指定できます。

スイッチタイプオプションはブールオプションであり、プログラムはその有無をチェックします。 例:-- --ignore-case



(または、 --ignore-case



--no-ignore-case



)。

フラグタイプオプションは、パラメータ付きのオプションです。 このパラメーターにはデフォルト値があります。 たとえば、私のバージョンではgrep -C ...



grep -C 2 ...



場合、grepユーティリティは同等です。

引数とオプションの両方にデフォルト値がある場合がありますが、そうでない場合があります。



例として、 grep --ignore-case -r - 4 "some string" /tmp



引数は"some string" /tmp



であり、オプションは--ignore-case -r - 4



です。 同時に、 --ignore-case



-r



はスイッチであり、 -C 4



はフラグです。



オプションの規則


オプションは、短い-i



形式と長い--ignore-case



形式の両方で指定できます。 原則として、スクリプトのコマンドラインオプションを直接キャプチャできるため、オプション形式を好きなように楽しむことを妨げるものは何もありません。 しかし、Unixコミュニティによって開発されたルールを順守することをお勧めします。ルールは時を経て研ぎ澄まされ、ほとんどの人がそれに慣れています。 さらに、これらのオプションを簡単に操作できる既製のライブラリがあります。

これらのルールは次のとおりです。





長い選択肢があることが常に推奨される理由


通常、オプションの長い形式は、アプリケーションを使用してスクリプトを記述する際に使用されます。 長いオプションは自己文書化する必要があります。 sysadminがcronを調べて、理解できないオプション-zsf -m 100



れるデータベースバックアップタスクの起動を確認したとします。 彼がスクリプトの作成者でない場合は、何を意味するのかを理解するために、彼は助けに潜り込む必要があります。 同意して、オプションのセット--scheme --max-size 100 --gzip --force



は彼にもっと多くを伝え、時間を無駄にしないようにします。

さらに、めったに使用されないオプションの短いオプションを作成することは推奨されません。 まず、アルファベットのすべての行のオプションにそれらを費やすほど多くの文字がありません。 第二に、さらに重要なことは、短いオプションがないことで、このオプションは通常の操作では二次的または望ましくないことであり、単純にできるからといって軽率に使用しないでください。

そのため、頻繁に使用されるオプションは短いものと長いものの両方であり、めったに使用されないオプションは長いだけです。



単機能アプリケーションと多機能アプリケーションのコマンドラインオプションの違い


これらの2つのタイプのアプリケーションは、呼び出されたときに引数の順序がわずかに異なります。

最初のタイプのアプリケーションの場合、呼び出しは通常次のようになります。 executable [options] <arguments>





ソフトウェアパッケージの場合、形式はやや複雑です。 executable [global options] <command> [command options] <arguments>





この本の例を次に示しますgit --no-pager push -v origin_master



--no-pager



は、任意のgitコマンドに適用できるオプションです。 --no-pager



git --no-pager push -v origin_master



は、pushコマンドに固有のオプションです。 グローバルオプションとコマンド固有のオプションは同じ名前を持つことができることに注意してください。 ただし、この場合、すべてのツールがそれらの処理に適しているわけではありません。たとえば、標準のOptionParser ruby​​ライブラリは、オプションが満たされた場所を区別しないため、このタスクに対処しません。 ソフトウェアパッケージを作成する場合は、GLIライブラリをより適切に使用してください。



念のため、入力プログラムは技術的にはパラメーターの文字列ではなく、既に要素に分割されたパラメーターの配列を受け取っていることを読者に思い出させます。 ルビーでは、この配列はARGV



と呼ばれます。 私たちが直接または特別な図書館の助けを借りて働くのは彼と一緒です。 スペースで要素に分割されていないことに注意してください(そうでない場合、たとえば、スペースを含むファイル名にすることはできません)、シェルのルールはやや複雑です。 また、文字のエスケープとグループ化のための引用符の使用も含まれます。 パラメータ文字列をスクリーニング、接着、または配列にカットする必要がある場合、またはその逆の場合-標準シェルワードライブラリをご覧ください。 これらの目的のために、 String#shellescape



String#shellescape



Array#shelljoin



の3つのメソッドのみで構成されています。



rubyコミュニティでは、ほとんどのコマンドラインアプリケーションはOptionParserまたはそれに基づくライブラリを使用します。 構成に関するセクションで-もう少し学習したら、OptionParserを使用して作成したコードの例を示します。



役に立つ



使用するawesome_programプログラムを初めて見たときを想像してください。 経験豊富なユーザーとしては、恐らくawesome_program --help



して、引数の順序、一連のオプション、および使用例を確認することを期待します。 プログラムをリリースするとき、最初に見たユーザーがおそらく最初に同じことをすることを覚えておいてください。したがって、 -h



、-- --help



オプションを用意しておいてください。 タイプOptionParserのライブラリを使用する場合、プログラムが指定した説明とともに認識するすべてのオプションのリストが、プロンプト行に自動的に追加されます。



ヘルプ行に加えて、拡張ヘルプを人で書くことは理にかなっています。 ただし、私の知る限り、rubygemsはmanでページを自動的に設定しません。 ただし、システムにインストールされたgemのマニュアルドキュメントページを表示できるgem-man gemがあります。

マニュアルを作成するには、難しいnroff形式のファイルを作成する必要があります。 タスクを簡素化するには、ronnコンバーターライブラリを使用します。これにより、ドキュメントページをより単純な形式で作成できます。 すべての準備ができたら、 gem man awesome_gem



使用して、ヘルプ行を確認できます。 または、 alias gem='gem man -s'



記述できます。 この場合、manコマンドはgem manコマンドに置き換えられ、gemのヘルプを探すことができます。 gem-manが処理できなかったリクエストに対して、通常のmanの対応するページへの自動リダイレクトが発生します。

あなた自身のマンチップを作ることを計画しているなら、本を見てください、これにより多くの注意が払われます。



ユーザーがコマンドを実行しやすくするために、シェルレベルでチームを自動補完することができます(すべてのシェルで機能するわけではありません)。 これにより、タブボタンを押して、コマンド名、ファイル名などを自動的に補完できます。 ユーザーはスペルミスをする可能性が低くなり、コマンドを書く時間を大幅に短縮できます。



タブ補完を行い、プログラム内のコマンドの履歴を保存するには(irbなどのプログラムの対話モードで)、rubyに組み込まれたreadlineライブラリを使用するだけで十分です。 gets



代わりにReadline.readline



コマンドを使用して、入力したすべてのコマンドの履歴を自動的に保存できます。



タブ補完は次のように行われます。 Readline.completion_proc=(block)



Readline.completion_proc=(block)



メソッドに返されます。このメソッドは、既に入力されたテキストの行に追加可能な配列を返します。これがタスク全体です。 例:

 Readline.completion_proc = proc { |input| allowed_commands.grep /^#{input}/ }
      
      







すでに実行中のプログラムのレベルではなく、シェルのレベルでタブ補完が必要な場合、これはやや複雑です。 .bashrc



をいじる必要があり.bashrc





最初に、行complete -F get_my_app_completions my_app



追加complete -F get_my_app_completions my_app





これで、 my_app()[- ]



を入力してからmy_app()[- ]



を入力するmy_app()[- ]



に、 get_my_app_completions



関数が呼び出されます。 この関数は、可能な自動補完オプションをCOMPREPLY



変数にCOMPREPLY



ます。この変数は、シェルがユーザーに追加オプションを提供するために使用します。 .bashrc



この関数を定義する必要があります。 todoアプリケーションの本から例を示します。

 function get_todo_completions() { if [ -z $2 ] ; then #    COMPREPLY=(`todo help -c`) else #      ,   $2 COMPREPLY=(`todo help -c $2`) fi } complete -F get_todo_completions todo
      
      





ここで、プログラムで次の動作を実装する必要があります(これは簡単な演習として残しましょう)。

1)コマンドラインでtodo help -c



を手動で入力すると、アプリケーションコマンドのリストが表示されます:list、add、complete、help(それぞれ独自の行にあります)

2) todo help -c complete



、開始されたがまだ完了していないすべてのタスクのリストが表示されます(完全なコマンドを適用できるタスク)。



help -c [...]



はサービスコマンドです。その存在は簡単なヘルプで省略できます。 ユーザーが使用するのではなく、 .bashrc



スクリプトを使用することを前提としてい.bashrc





このスクリプトでは、関数は既に入力されているものに基づいて、何を置換できるかをアプリケーション自体に尋ねます(これはhelp -



オプションの後に渡されます)。 プログラムは、アプリケーションにこのような特別なパラメーターセットが与えられたときの状況を監視し、標準出力にすべてのオプションのリストを表示します(既に見たように)、そこから直接シェルスクリプトCOMPREPLY



送信されCOMPREPLY





この本の著者は、独自のGLIライブラリを使用しています。GLIライブラリは、このようなオプションセットを自動的に追跡します。 GLIの助けを借りずに、この機能を簡単に実装できます。 ご覧のとおり、ここには魔法はありません。



他の人とうまく遊ぶ



プログラム間の便利な相互作用の必要性の問題については議論しません。Unixで働いた誰もがこれがどれほど重要かを評価できます。 主な問題は、これを達成する方法です。



リターンコード


まず、リターンコードを使用します。 プログラムが正常に完了した場合-0、エラーが発生した場合-ゼロ以外のさまざまなリターンコード。 シェルスクリプトは、最後に完了したプログラムのステータスを$?



変数から要求することにより、プログラムが正常に動作したかどうかを判断できるため、これは重要$?



。 戻りステータスを返すために、rubyはexit(exit_status)



メソッドを使用します。

さまざまなエラーにさまざまなリターンコードを割り当てると、自分のプログラムを使用する別のプログラムが問題を修正できるかどうか、および注意を払う価値があるかどうかを判断できる可能性があります。 プログラムの外では、プログラムが「クラッシュ」したかどうかが怖いかどうかを確認する方が良いでしょう。 異なるリターンコードは異なる例外クラスのようなものです。RAMがないという事実にエラーがあるか、ネットワークが一瞬消えただけで再試行する価値があります。 一部のプログラムは、いくつかのエラーにより同時にクラッシュする場合があります。 一度に複数の問題を報告する必要がある場合は、ビットマスクを使用します。 ネットワークには、どのエラーに対してどのリターンコードを使用するのが一般的かについての推奨事項があります。GNU (非常に一般的な)およびFreeBSD (非常に具体的な)サイトでそれについて読むことができます。 エラーコードを気にしたくない場合は、少なくとも最小限の努力をしてください-エラーが発生した場合、少なくともいくつかのゼロ以外の値を返します。 そうしないと、他のプログラムはあなたのプログラムが正常に動作したかどうかを知ることさえできません。



ところで、シェルスクリプトからだけでなく、rubyスクリプトからもプログラムを実行できます。 これを行うには、 Kernel.system



IO.popen



など、いくつかのオプションがありますIO.popen



詳細については、ドキュメントをご覧ください。 system



を使用して別のプログラムを呼び出す場合、同様のシェル変数$?



でその戻りコードを見つけることができます$?







I / Oストリームとエラーストリーム。 パイプ


コマンドラインから起動されるプログラムの相互作用の主な方法はパイプです。 パイプは、あるプログラムの出力を別のプログラムの入力にリダイレクトする方法です。 縦棒でマークされたパイプ|



。 たとえば、 ls | sort



ls | sort



、最初の部分-lsは画面に何も表示しませんが、代わりにその出力をsortプログラムの入力にリダイレクトします。 また、ソートプログラムは入力ストリームからテキストを1行ずつ取得し、すでにソートされたリストが画面に表示されます。 一方では、ls自体がファイルをソートできますが、これは意図されていません。 同時に、ソートはこの目的のためだけに必要であり、多くのオプションがあります。 たとえば、名前が数字で始まる場合は、辞書式ではなく行を並べ替えることができます(そうでない場合、順序は1.jpg、10.jpg、100.jpg、2.jpg、...のようになります)。 または、逆の順序で並べ替えます。 さらに、特別なプログラム(awk、sedなど)を使用して、文字列を並べ替える前に、それを修正できます(たとえば、プレフィックスを消去します)。 パイプは任意の数のプログラムで構成できることに注意してください。 だからls | sort -n | tail



ls | sort -n | tail



ls | sort -n | tail



は、番号順にソートされたファイルのリストの最後の10行を表示します。



プログラムで入出力ストリームが必要になる理由を考えてください。 出力ストリームに書き込む内容、およびエラーストリームに書き込む内容。 最初に2番目の質問を扱います。出力ストリーム(stdout)とエラー(stderr)の違いは何ですか? 1つのスレッドがパイプに接続し、もう1つのスレッドが接続しないという事実。 stderrストリームは、エラーの出力だけでなく、プログラム実行の段階、デバッグ情報など、ワークプロセスに関する情報の出力にも使用されます。 この情報は、別のプログラムの入力に渡されるべきではなく、ユーザーの便宜のためにのみ必要です。 stdoutストリームは、プログラムの結果など、他のすべての情報に使用されます。



人だけでなく、マシンもプログラムの出力を処理する必要があるため、出力形式について考える必要があります。 オプション--format=<plain|csv|pretty|html|table|...>



を作成するのは理にかなっています。 人間が読める形式(pretty / html / table)を指定する場合、出力の解析の利便性を考慮せずに、目を楽にする方法で情報を表示できます。 機械可読形式(plain / csv)を指定する場合、結果が美しく見えるかどうかは関係ありません-主なことは、解析を容易にすることです。 構文解析の利便性のために、タブ区切り値またはコンマ区切り値(csv)を使用するか、形式は1行-値、または最適な別の形式です。 また、Delight Usersセクションで、できる限り快適な結論を出す方法についても説明します。

ユーザーは、プログラムを起動するたびに出力形式を指定したくないため、すべての場合に選択することも常に可能とは限りません。 出力が人の目か機械の目かを自動的に判断するトリック、つまりIO#tty?



メソッドはありIO#tty?



$stdout.tty?



出力が端末に向けられているかどうかを教えてくれます。 そうでない場合、プログラムの出力はパイプにls > output.txt



れるか、ファイルにリダイレクトされます(次のように: ls > output.txt



)。 端末への出力とリダイレクトされたストリームへの出力では、異なるデフォルトのフォーマットoptions[:format] = $stderr.tty? ? 'table' : 'csv'



選択できますoptions[:format] = $stderr.tty? ? 'table' : 'csv'



options[:format] = $stderr.tty? ? 'table' : 'csv'





また、たとえば、人向けの出力形式でファイルに結果を出力する場合は、形式を明示的に指定するだけです。



次に、入力ストリームについて説明します。 プログラムは入力ストリームからどのようなデータを受け入れるべきですか? もちろん、これはプログラムの詳細に依存します。 考えてみましょう、どのデータを入力ストリームに入れることができますか? 明らかな答えは、他のプログラムが出力に持っているものです。 たとえば、マトリックスファイルを別の形式に変換し、別の拡張子を持つファイルに書き込むプログラムがあります。 入力ストリームから行列を受け入れることは理にかなっていますか? 私の意見では、そうではありません。この行列がどのように、そしてなぜ入力ストリームに入るのでしょうか? 一度に多くのファイルを処理するために、多数のファイル名を受け入れる方がはるかに便利です。 これは、たとえばlsコマンドが提供できるデータです。

, , . -, . , , , (, — — Windows-). , , . , .

, , $stdin.tty?









, , ( ) — . , , -, , . ( SIGHUP), , , , . SIGINT, Ctrl+C. Signal.trap



. , , . ( , ) POSIX-, .. Unix, Windows. , , Windows , Unix, - , — , .

— , , Ctrl+C , , :

 Signal.trap("SIGINT") do FileUtils.rm output_file exit 1 end
      
      









Has sensible defaults but is configurable



, . , - . , -- .



. , — -.

, . , ( ), . , . , — , . ( --use-nonstandard-mode



-u



).



. « -- »? , . , . - (, --no-scheme --gzip



), db_backup my_db



.

, . db_backup --scheme my_db



, . , , , , -… --login



, --password



, --host



, --force



, , -. , , - .



~/.myapp.rc



. , . -. — . — . .rc — .

? , . YAML. :

 --- :gzip: false :force: true :user: "Bob" :password: "Secr3t!"
      
      







, .

 require 'yaml' require 'optparse' #  - options = { :gzip => true, :force => false } #     # (     ,    HOME) CONFIG_FILE = File.join(ENV['HOME'],'.db_backup.rc.yaml') if File.exists? CONFIG_FILE #     config_options = YAML.load_file(CONFIG_FILE) #     -     options.merge!(config_options) end #       #       ,    option_parser = OptionParser.new do |opts| #    . #__FILE__    ,        opts.banner = "Usage: #{__FILE__} [options] <db_name>" #   -u  --username   ,     opts.on("-u USER", "--username", "Database username, in first.last format") do |user| options[:user] = user end #     ,      opts.on("-p PASSWORD", "--password", "Database password") do |password| options[:password] = password end #     ,     .   ,   . #   --gzip      true. #      ,     - #     false     --no-gzip opts.on("--[no-]gzip", "Compress or not the backup file") do |gzip| options[:gzip] = gzip end end #       ,    option_parser. #    ARGV    , #        options # (     ) option_parser.parse!(ARGV) #    db_name = ARGV.shift
      
      







— . , — .

 --- :filename: ~/.todo.txt :url: http://jira.example.com :username: davec :password: S3cr3tP@ss :commands: :new: :f: true :group: Analytics Database :list: :format: pretty :done: {}
      
      







, YAML — . , — . , , gem rspec, git.



Installs painlessly



, . , rubygems — , :

gem install/update gemname







— , , , , ( ). - rubygems.org . , , (, , ) gem .

gem install



, rubygems , ( ) . , , , ( -, ). , . , rails 2.3.8 rails 3.2, activesupport-, , .



, , , — . , , ruby .

, . « ». : Major.Minor.Patch. — - . API, -. , . , , , : 1.13.2.

, , - minor-. , , , . , API, .



— . , bin , ( bundler -). .../ruby/bin - ( , -, , ). , ruby PATH — . .

Windows , , — bat-, . , .



?

-, -, .rb. Unix, Windows. , .

-, : #!/usr/bin/env ruby





, /usr/bin/ruby



. env



, , rvm.

-, , lib/my_exec.rb, require. , . :

 #!/usr/bin/env ruby require 'rubygems' #    ruby 1.9   require 'your-gem' require 'your-gem/my_exec'
      
      







, -? , , . , my_app value1 value2



. ? , ['value1', 'value2']



. ? Unix , . Windows , .. my_app



Windows, , ( ruby.exe). , , , ruby. つまり : ruby my_app value1 value2



, ruby, , .



, , rubygems bat-? bat- , . rubygems . : . Hello World . , , ( , Windows- , Unix-). , , , rspec. git- ( , ruby). , Windows, - — .





Fails gracefully



.

. stderr , (, , ). , . - , .

- , , ? , , . , , --force



. , .

? , . rm -rf * .log



, , , .





Gets new features and bug fixes easily



— , . , , . , . , , . …

, , ( ) . , , . ( HDD — ). - .

aruba , Cucumber CLI. , , , , , - .

( ) — TestUnit rspec- fakefs . , , — , , . mock- , File



, Dir



( ) , , . . 美人! , ( , Kernel.system



, ) lib/my_exec .



, aruba, , ? stdout stderr StringIO



. «». : out, err = MiniTest::Assertions.capture_io{ ... }



, , .

! -: STDOUT



$stdout



. StringIO, , . , warning, , . , puts



- , .

, ( STDOUT.puts 'smth'



), , , STDOUT



, STDIN



STDERR



.



. , . ARGV



. , , ? : . shellwords String#shellsplit



.

, , , , ARGV



: ARGV.replace(new_array)



.

, OptionParser#parse!



ARGV



OptionParser#parse!(new_array)



, , ARGV



. , — .



— . . .



Delights users



.



テーブル


, : , , , . : . — terminal-table .





, . . : /. - . — rainbow term-ansicolor . , . , — — . Windows- , . , .



, 10% . , , . diff , . , , , .

! machine-readable — , . , , « » .





. Readline, . , : . rubygems thor , say ask.

? irb rails console. : , JSON- , . JSON, cd, ls, rm mknode. , . .





, , . , , . : ? ? , ? , , stderr - ( , , flush



, - , ).

! , . \r



— . \r



, (, «» ). , puts



, .. . print



, :

 (0..100).each do |i| $stderr.print("\r#{i}% done") sleep(0.1) end
      
      





, , : stderr stdout , , .



.



-, rake , thor . — , DSL , .



Rake — make ruby. Rakefile . , bundler Rakefile : build, install, release, . rake — rake release build release. , rake , . , , rake.



Thor — rake. «» . .

, , . . , Ruby on Rails , , .



OptionParser ruby. , . , , — , . , OptionParser , ( — . ) .

OptionParser : ( ; , , , git). OptionParser- ( , ) — . , , — .



GLI . , . .



, , — docopt . — , , OptionParser . python . . , , .



PS , , , ARGF



. — , ARGF



— .



All Articles