Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyでコマンドラインアプリを作成する

ユーティリティスクリプトを1つだけ作成するのは楽しいことですが、神に正直なコマンドラインアプリケーションを作成する必要がある場合もあります。引数を取り、入力、出力、エラー報告などのUNIX規則とうまく連携するもの。

幸い、Rubyは、コマンドラインアプリケーションに必要なすべてのビルディングブロックをかなり簡単に提供します。この投稿では、通常の「gem Yを使用してXを実行する方法」のアプローチを超えて、一流のコマンドラインアプリを作成するために連携するすべての要素の概要を説明したいと思います。

入力:環境変数

環境変数は通常、しばらくの間保持したい短い構成値に使用されます。 APIキーは良い例です。

環境変数の設定

ユーザーは通常、bashなどのシェルを介して環境変数を設定します。特定のセッションに設定できます:

$ AWS_ACCESS_KEY_ID=FOO

現在のセッションに加えて、新しいbashセッションに設定できます:

$ export AWS_ACCESS_KEY_ID=FOO

または、単一のプログラムに設定することもできます:

$ env AWS_ACCESS_KEY_ID=FOO aws s3 mb s3://mybucket
環境変数の読み取り

ユーザーが環境変数をどのように設定するかに関係なく、RubyのENVを介してそれを読み取ることができます。 ハッシュ。

key_id = ENV["AWS_ACCESS_KEY_ID"]

環境変数は内部でどのように機能しますか?

すべてのプロセスには、それに関連付けられた環境変数のテーブルがあります。子プロセスを生成すると、親が実行したい変更とともに、そのテーブルのコピーを取得します。

泥のように澄んでいますか?

より読みやすい説明については、他のブログ投稿「Rubyist's GuidetoEnvironmentVariables」をご覧ください。

コマンドライン引数

コマンドライン引数は、ターミナルでプログラムを実行するときにプログラム名の後に付けるものです。

$ echo foo bar baz

上記の例では、「foo」、「bar」、「baz」はすべてコマンドライン引数です。

より現実的な例は次のようになります:

$ honeybadger deploy -v --environment staging

ただし、ここでも、コマンドライン引数は単なるテキストです。 --environment stagingが必要な場合 意味 何でも、私たちは自分たちでそれを理解する必要があります。

コマンドライン引数の送信

すでに次のように送信された引数を見てきました:

$ echo foo bar baz

しかし、Rubyはインタプリタ言語であるため、次のようなものに出くわす可能性もあります。

$ ruby myprog.rb foo

OSに関する限り、「ruby」と呼ばれるプログラムを実行し、それに2つの引数を渡します。

幸いなことに、Rubyは、引数「foo」がRuby自体ではなく、プログラムを対象としていることを知っているほど賢いです。したがって、プログラムには1つの引数"foo"が表示されます。 。

コマンドライン引数の読み取り

コマンドライン引数は、ARGVという配列に格納されます 。これはグローバル変数であるため、プログラムのどこからでもアクセスできます。

以下の例では、すべてをARGVで印刷しています。 。これをコピーして端末に貼り付けて、少し遊んでみてください。

$ ruby -e "puts ARGV.inspect" foo bar baz
["foo", "bar", "baz"]

ruby -eに見捨てられないでください 仕事。プログラムと実行結果を1行で表示できるため、ここでのみ使用しています。

コマンドライン引数の解析

コマンドライン引数は単なるテキストです。テキストを意味にしたい場合 何でも、あなたはそれを解析しなければならないでしょう。幸いなことに、解析に役立つ優れたライブラリがいくつかあります。

何年にもわたって、コマンドライン引数のやや標準的な構文が登場しました。次のようになります:

$ program -a --option foo

このスタイルでは、-hのようなブールフラグを使用できます。 ヘルプを表示します。また、値を使用してオプションを指定することもできます。

OptionParserの紹介

OptionParser クラスはRubyの標準ライブラリの一部です。上記のスタイルに一致するオプションを解析する簡単な方法を提供します。

こんにちはと言う簡単なアプリケーションを作りましょう。コマンドライン引数を使用して名前を指定できます。

require 'optparse'

# This will hold the options we parse
options = {}

OptionParser.new do |parser|

  # Whenever we see -n or --name, with an
  # argument, save the argument.
  parser.on("-n", "--name NAME", "The name of the person to greet.") do |v|
    options[:name] = v
  end
end.parse!

# Now we can use the options hash however we like.
puts "Hello #{ options[:name] }"  if options[:name]

それから私がそれを実行すると、それはうまくいきます:

$ ruby hello.rb --name Starr
Hello Starr

$ ruby hello.rb -n Starr
Hello Starr
「ヘルプ」画面の追加

ヘルプ機能の追加も同様に簡単です。テキストを入力し、-hのコマンドを追加するだけです。 :

OptionParser.new do |parser|
  parser.banner = "Usage: hello.rb [options]"

  parser.on("-h", "--help", "Show this help message") do ||
    puts parser
  end

  ...
end.parse!

これで助けを求めることができます:

$ ruby hello.rb -h
Usage: hello.rb [options]
    -h, --help                       Show this help message
    -n, --name NAME                  The name of the person to greet.
型キャスト引数

すべてのコマンドライン引数は文字列ですが、ユーザーに数値または日付を指定してもらいたい場合があります。手作業で変換を行うのは面倒な場合があるため、OptionParser あなたのためにそれをします。

以下の例では、プログラムがhelloと言うべき回数をユーザーが指定できる「カウント」オプションを追加します。私はOptionParserに言っています Integerにキャストする 、それはします。

OptionParser.new do |parser|

  ...

  # Note the `Integer` arg. That tells the parser to cast the value to an int.
  # I could have used `Float`, `Date`, or a number of other types.
  parser.on("-c", "--count COUNT", Integer, "Repeat the message COUNT times") do |v|
    options[:count] = v
  end

end.parse!

if options[:name]
  options.fetch(:count, 1).times do
    puts "Hello #{ options[:name] }"
  end
end

これで、プログラムを実行すると、何度も挨拶されます:

$ ruby hello.rb -n Starr -c 5
Hello Starr
Hello Starr
Hello Starr
Hello Starr
Hello Starr
命名規則

プログラミングの最も難しい側面の1つは、名前を付けることです。コマンドライン引数も例外ではありません。あなたを助けるために、私は一般的な議論とそれらの意味の短い表をまとめました:

フラグ 一般的な意味
-a すべて、追加
-d デバッグモード、またはディレクトリを指定
-e 何かを実行するか、編集します
-f ファイルを指定するか、操作を強制します。
-h ヘルプ
-m メッセージを指定する
-o 出力ファイルまたはデバイスを指定します
-q 静かなモード
-v 詳細モード。現在のバージョンを印刷する
-y プロンプトに「はい」と言ってください

OptionParserの代替

OptionParser いいですが、制限があります。最も明らかに、それは近年普及しているコマンドベースの構文をサポートしていません:

$ myprog command subcommand -V

幸いなことに、トンがあります そこにライブラリを解析するオプションの。あなたが好きなものを見つけることができると確信しています。興味深いと思われる3つを次に示します。

  • GLI-「Gitのようなインターフェイス」コマンドラインパーサーを使用すると、gitのように、複数のコマンドを含む単一の実行可能ファイルであるアプリケーションを簡単に作成できます。
  • CRI-ネストされたコマンドをサポートするコマンドラインツールを構築するための使いやすいライブラリ。
  • メタドン-メタドンはDSLを解析する独自のオプションを提供しますが、それをはるかに超えています。それはあなたのためのディレクトリ構造、テストスイートとロギングをセットアップします。これは、CLIのRailsのようなものです。

STDINを使用して大量のデータを入力する

コマンドライン引数は、大量のデータを入力するのには適していません。そのためには、IOストリームを使用する必要があります。そして、STDINはそこにある最も便利なIOストリームの1つです。

ほとんどのプログラムには、オペレーティングシステムによって自動的にSTDINが割り当てられます。これは、OSがアプリデータの送信に使用する読み取り専用ファイルのようなものです。これは、ユーザーからキーボード入力を取得するために使用できます。しかし、さらに重要なことは、パイプを介して他のプログラムからデータを受信するために使用できることです。

読み取り専用ファイルを使用するのと同じように、STDINを使用します。ここでは、プログラムのSTDINにテキストをパイプしています。次に、readを使用します フェッチするメソッド。

$ echo "hello world" | ruby -e "puts STDIN.read.upcase"
HELLO WORLD

Rubyでは、Enumerableを使用できます IOオブジェクトの機能。そしてSTDINも例外ではありません。つまり、あらゆる種類のトリックを実行できるということです。

# Get the first 20 lines
STDIN.first(20)

# Convert to integers and reject odds
STDIN.map(&:to_i).reject(&:odd)

...etc
結果をSTDOUTに出力する

STDOUTは、オペレーティングシステムがプログラムに割り当てる書き込み専用のIOストリームです。

STDOUTに書き込むことにより、ユーザーの端末にテキストを送信できます。ユーザーは、出力をファイルにリダイレクトしたり、別のプログラムにパイプしたりできます。

他の書き込み専用ファイルを使用するのと同じように、STDOUTを使用します。

STDOUT.write("Hi!\n")
# hi

そしてもちろん、puts およびprint 両方ともSTDOUTに出力します。

STDERRへのステータス情報の送信

STDERRは、さらに別の書き込み専用IOストリームです。一般的な出力用ではありません。これは特にステータスメッセージ用であるため、実際のの邪魔になりません。 出力。

STDERRは通常、ユーザーがSTDOUTをファイルまたは別のプログラムにリダイレクトしている場合でも、ユーザーの端末に表示されます。

以下の例では、curlを使用してWebページをフェッチしています。 WebページのコンテンツをSTDOUTに出力し、進行状況情報をSTDERRに表示します:

$ curl "https://www.google.com/" > /tmp/g.html
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  151k    0  151k    0     0   277k      0 --:--:-- --:--:-- --:--:--  277k

独自のプログラムからSTDERRへの書き込みは簡単です。 IOオブジェクトのように扱ってください:

STDERR.write("blah\n")
STDERR.puts("blah")
かわいいスティックで叩く

これまで見てきた例は、デザイン賞を受賞することはありません。しかし、コマンドラインアプリが醜い、または非対話型である必要がある理由はありません。

あなたがあなたのアプリを強化することに決めたなら、重労働のいくつかをするためのたくさんの素晴らしい宝石があります。これが私が好きな3つです:

  • highline-Highlineは、ユーザー入力の収集、検証、型キャストから多くの作業を省く優れたライブラリです。
  • command_line_reporter-ASCII進捗レポートを簡単に生成できます。
  • ペイント-ANSIカラーコードを簡単に追加して、退屈な古いテキストに色を付けることができます。

より網羅的なリストを見る

終了ステータス

プログラムがエラーで終了する場合は、終了コードを使用してOSに通知する必要があります。これが、このようなbashコードが機能することを可能にするものです:

$ prog1 && prog2

bashの&&に慣れていない場合 演算子、それは単に「prog1が正常に終了した場合にのみprog2を実行する」という意味です。

Rubyは、デフォルトでは「成功」コードで終了し、例外では「失敗」コードで終了します。他のすべてを実装するのはあなた次第です。幸い、それは簡単です:

# Any nonzero argument to `exit` counts as failure
exit(1)

詳細については、他の投稿「Rubyプログラムを終了する方法」をご覧ください。

プロセス名の設定

コマンドラインプログラムがしばらく実行される場合は、システムプロセスを一覧表示するときに、それが何であるかを人々が知っていることが重要です。通常、Rubyプログラムのプロセス名は、プログラムを実行するために入力したすべてのもので構成されます。したがって、ruby myapp -vと入力した場合 、それがプロセスの名前です。

プログラムに多くの引数がある場合、これは判読できなくなる可能性があります。したがって、よりわかりやすいプロセス名を設定することをお勧めします。あなたはそのようにこれを行うことができます:

Process.setproctitle("My Awesome Command Line App")

気になる場合は、プロセスタイトルを使用して、特定の瞬間にプロセスが実行していることに関する情報をユーザーに提供できます。

Process.setproctitle("Mail Sender: initializing")
init(...)
Process.setproctitle("Mail Sender: connecting")
connect(...)
Process.setproctitle("Mail Sender: sending")
send(...)

詳細については、私の投稿をチェックしてください:topとpsで示されているようにRubyスクリプトのプロセス名を変更する方法


  1. Ruby2.6の9つの新機能

    Rubyの新しいバージョンには、新しい機能とパフォーマンスの改善が含まれています。 変更についていきますか? 見てみましょう! 無限の範囲 Ruby 2.5以前のバージョンは、すでに1つの形式の無限範囲をサポートしています( Float ::INFINITY を使用) )、しかしRuby2.6はこれを次のレベルに引き上げます。 新しい無限の範囲 次のようになります: (1..) これは、(1..10)のような終了値がないため、通常の範囲とは異なります。 。 使用例 : [a, b, c].zip(1..) # [[a, 1], [b, 2], [c, 3]] [1,2,3,

  2. iPad 向けライティング アプリ ベスト 8

    キーボード アタッチメントを備えた iPad は、非常にポータブルで便利なため、完璧なライティング セットアップになります。この方程式の重要な部分は、使用する書き込みプログラムです。 iPad には、ワープロに使用するのに完全に受け入れられる Pages アプリが付属していますが、Pages が執筆状況で機能しない場合、または単に気に入らない場合は、試してみたい代替手段がたくさんあります。 この iPad 用ライティング アプリのリストでは、さまざまな種類のライティングに最適なアプリや、生産的で刺激的なライティング環境を作成するのに最適なアプリを見つけることができます。何のために書いている