50
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RubyでCLIツールを作成する手順まとめ

Posted at

ちょっとしたCLIツールを自作しようと思い色々と調べてみたところ、RubyのThorというgemを使用することで非常に簡単にCLIツールを作成できるようだったので試してみました。

本記事ではRubyでThorを使用してCLIツールを作成し、コマンドとして実行するまでの手順についてざっくりとまとめていきます。

開発環境

  • OS: macOS Sierra 10.12.6
  • Ruby: 2.5.1(rbenvでインストール)

手順

Step 1. gemパッケージの雛形を作成

$ gem install bundlerでbundlerをインストールした後(インストール済みであれば省略)、$ bundle gem {gemパッケージ名} -bでgemパッケージの雛形を作成します。

以下の例では、str_convert_utilsという名称でgemを作成していきます。

# bundlerをインストール
$ gem install bundler

# gemパッケージの雛形を作成
$ bundle gem str_convert_utils -b
Creating gem 'str_convert_utils'...
      create  str_convert_utils/Gemfile
      create  str_convert_utils/lib/str_convert_utils.rb
      create  str_convert_utils/lib/str_convert_utils/version.rb
      create  str_convert_utils/str_convert_utils.gemspec
      create  str_convert_utils/Rakefile
      create  str_convert_utils/README.md
      create  str_convert_utils/bin/console
      create  str_convert_utils/bin/setup
      create  str_convert_utils/.gitignore
      create  str_convert_utils/exe/str_convert_utils
Initializing git repo in /PATH/TO/str_convert_utils

Step 2. gemspecファイルを修正

{gemパッケージ名}.gemspecを修正します。
spec.summaryspec.descriptionTODOまたはFIXMEの文言を含んでいる場合や、spec.homepageがURIとして不正な形式である場合、後ほど$ bundle installを実行する際にエラーとなるので修正しておきます。

str_convert_utils.gemspec

 lib = File.expand_path("../lib", __FILE__)
 $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
 require "str_convert_utils/version"

 Gem::Specification.new do |spec|
   spec.name          = "str_convert_utils"
   spec.version       = StrConvertUtils::VERSION

   ...

-  spec.summary       = %q{TODO: Write a short summary, because RubyGems requires one.}  # この行を修正
-  spec.description   = %q{TODO: Write a longer description or delete this line.}        # この行を修正
-  spec.homepage      = "TODO: Put your gem's website or public repo URL here."          # この行を修正
+  spec.summary       = "string convert utilities"
+  spec.description   = "string convert utilities (e.g. snake, camelize, etc.)"
+  spec.homepage      = "https://github.com/akisame338/str_convert_utils"

   ...

   spec.add_development_dependency "bundler", "~> 1.16"
   spec.add_development_dependency "rake", "~> 10.0"
+
+  spec.add_dependency "thor"  # この行を追加
end

Step 3. CLIクラスを作成

続いて、lib/{gemパッケージ名}/cli.rbを新規作成します。
Thorを継承したクラスでpublicメソッドを定義することで、当該メソッドをコマンドとして扱うことができます。
メソッド上部のdescの部分については、desc "{usage}", "{description}"と定義することで、ヘルプにて使い方({usage}部分)と説明({description}部分)を表示できるようになります。

以下の例では、こちらの記事を参考にしてsnake_caseをCamelCaseに変換して出力するcamelizeコマンドとCamelCaseをsnake_caseに変換して出力するsnakeコマンドを定義しています。

lib/str_convert_utils/cli.rb
require "str_convert_utils"
require "thor"

module StrConvertUtils
  class CLI < Thor
    desc "camelize {snake_case_string}", "convert {snake_case_string} to {camelCaseString}"
    def camelize(str)
      puts str.split("_").map{|w| w[0] = w[0].upcase; w}.join
    end

    desc "snake {CamelCaseString}", "convert {CamelCaseString} to {snake_case_string}"
    def snake(str)
      puts str
        .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
        .gsub(/([a-z\d])([A-Z])/, '\1_\2')
        .tr("-", "_")
        .downcase
    end
  end
end

Step 4. 実行部分の実装

lib/{gemプロジェクト名}.rbを修正して、Step. 3で作成したlib/{gemパッケージ名}/cli.rbを読み込むようにします。

lib/str_convert_utils.rb
 require "str_convert_utils/version"
+require "str_convert_utils/cli"  # この行を追加

 module StrConvertUtils
   # Your code goes here...

また、exe/{gemプロジェクト名}(実行ファイル)を修正して、{gemパッケージのモジュール名}::{CLIクラス名}.startを実行するようにします。

この実行ファイルはbin/exe/のどちらに置くべきなのか?と少し悩みましたが、こちらの記事によると

rubygems が bin を見てることはないし、bin は setup や console といった開発の際に使うファイルを置きたい。あなたが作った executables なコマンドは exe で面倒見ようよ。って感じ。

とのことなので、exe/以下に置いておけばよさそうです。(gemspecファイルの初期設定もspec.bindir = "exe"となっているので)

exe/str_convert_utils
 #!/usr/bin/env ruby

 require "str_convert_utils"
+
+StrConvertUtils::CLI.start  # この行を追加

Step 5. コマンド実行

$ bundle installを実行してThor等のインストールが完了したら、あとは$ bundle exec exe/{gemパッケージ名} {コマンド名}でコマンドが実行できるようになります!

# Thor等のgemをインストール
$ bundle install

# コマンド一覧
$ bundle exec exe/str_convert_utils
Commands:
  str_convert_utils camelize {snake_case_string}  # convert {snake_case_string} to {CamelCaseString}
  str_convert_utils help [COMMAND]                # Describe available commands or one specific command
  str_convert_utils snake {CamelCaseString}       # convert {CamelCaseString} to {snake_case_string}

# camelizeコマンド実行
$ bundle exec exe/str_convert_utils camelize snake_case_string
SnakeCaseString

# snakeコマンド実行
$ bundle exec exe/str_convert_utils snake CamelCaseString
camel_case_string

Step 6. より便利にコマンド実行できるようにする

Step. 5までの手順で一応CLIツールとして使えるようになりましたが、このままだと毎回gemパッケージのディレクトリに移動して$ bundle exec ...としなければコマンドが実行できないため少し不便です。そこで、作成したgemパッケージをインストールして$ {gemパッケージ名} {コマンド名}としてコマンド実行できるようにします。
作成したgemをインストールできるようにするにはRubyGems.orgにアップロードして公開するのが一般的らしいですが、今回はこちらの記事を参考にして、RubyGems.orgを使用せずに作成したgemパッケージをインストールしてみます。

specific_installというgemを使用するとgithubに公開しているgemをグローバルな場所(rbenvを使用している場合は~/.rbenv/shims以下)にインストールできるそうなので、こちらを使用して作成したgemパッケージをインストールします。
これによって、どのディレクトリにいても今回作成したgemパッケージのコマンドを実行できるようになります!

# specific_installをインストール
$ gem install specific_install

# 自作gemパッケージをグローバルな場所にインストール
$ gem specific_install -l https://github.com/akisame338/str_convert_utils.git

# camelizeコマンド実行
$ str_convert_utils camelize snake_case_string
SnakeCaseString

# snakeコマンド実行
$ str_convert_utils snake CamelCaseString
camel_case_string

参考記事

50
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?