CocoaPodsのプラグインを作る
Dec 14th, 2013
この記事はiOS Second Stage Advent Calendar 2013の14日目の記事です。
概要
Cocoaのライブラリ管理ツールであるCocoaPodsですが、2013年11月14日にリリースされたバージョン0.28で、プラグイン機能が導入されました。
本記事ではこのプラグインの作り方を紹介します。
CocoaPodsプラグインとは
CocoaPodsのプラグイン機能を利用すると、pod
コマンドに任意のサブコマンドを追加することができます。標準サブコマンドのpod install
やpod update
と同列な、新たなサブコマンドの作成が可能です。
CocoaPodsはRubyで作られたツールなので、プラグインもRubyで書く必要があります。また、プラグインの配布にはRubyGemsを利用します。
このプラグインの仕組みそのものは、CocoaPodsプロジェクトが依存gemとして利用しているCLAideによって可能になりました。
プラグインを作る
ここではcheck-latest
というサブコマンドを定義する、cocoapods-check_latest
というgemを作ることにします。これは指定したライブラリのpodの最新バージョンが、そのライブラリのGitHubリポジトリの最新のバージョンタグと同一かどうかをチェックするコマンドです。
試しにCocoaPodsで導入してみたライブラリがうまく動作しないと思ったら、実は最新のpodspecで指定されているライブラリのバージョンが、そのライブラリの本当の最新バージョンではなかった(この表現わかりにくいですね)という場面がたまにあったりします。なので事前にpodspecが最新かどうかチェックしたいのですが、そのライブラリのGitHubのリポジトリをブラウザで開いてタグ一覧を確認、というのも割と面倒なルーチンワークなので、この作業を自動化することにします。
まずは新しくgemのプロジェクトを作成します。Bundlerを利用するのが良いでしょう。なお、gem名はcocoapods-プラグイン名
にすることが公式に推奨されています。そうしないとプラグインとして動作しない訳ではありませんが、RubyGemsでの検索のしやすさも考慮した慣例になっています。RubyGemsをcocoapods-
で検索すれば、現在公開されているプラグインの一覧が見られる訳ですね。
$ bundle gem cocoapods-check_latest
...
$ cd cocoapods-check_latest
コマンドクラスを作成する
Pod::Command
クラスを継承したコマンドクラスを作成します。
# lib/pod/command/check_latest.rb
module Pod
class Command
# クラス名からサブコマンド名が自動生成される。
# CamelCaseの単語間には"-"が挿入されるため、この場合"check-latest"になる。
class CheckLatest < Command
# 必須。`pod help`時に一行で表示される概要を記述する。
self.summary = 'Check if the latest version of a pod is up to date'
# 任意。`pod help check-latest`時に表示される、より詳細な説明を記述する。
# 未指定の場合、summaryの内容が表示される。
self.description = 'Some long description...'
# コマンドラインから引数を受け取るコマンドの場合は必須。
# `pod help check-latest`時に、
#
# Usage:
# $ pod check-latest [NAME]
# ^^^^^^ ここに表示される。
self.arguments = '[NAME]'
# 引数を受け取るコマンドの場合は必須。
# argvから、後の処理で必要な引数をインスタンス変数に取り出しておく。
# この処理はsuper呼び出し前に行うこと。
# argvは、CLAide::ARGVのインスタンス。
# https://github.com/CocoaPods/CLAide/blob/v0.4.0/lib/claide/argv.rb
def initialize(argv)
@name = argv.shift_argument
super
end
# 引数を受け取るコマンドの場合は必須。
# 引数が不正な場合はhelp!メソッドにメッセージを渡して中断する。
def validate!
super
help!('A pod name is required.') unless @name
end
# 実際の処理を記述する。
def run
# 長いので省略。実際の内容は以下を参照して下さい。
# https://github.com/yujinakayama/cocoapods-check_latest/blob/v0.0.1/lib/pod/command/check_latest.rb
end
end
end
end
ちなみに、CocoaPodsのサブコマンドを定義するということは、CocoaPods本体のAPIを利用できる訳ですが、現時点ではどのクラスやメソッドがpublic APIであるかという宣言がされていません。将来的にはこの辺りも整備されてくるとは思いますが、現状では利用対象のクラスやメソッドが存在しているかどうかのチェックや、例外処理などをこまめに行うしかない模様です。どちらにしてもCocoaPodsは未だにバージョン1.0未満の初期開発段階なので、Semantic Versioning的にもAPIの互換性はあまり重視されないフェーズではあるのですが。
作成したコマンドが、pod
コマンド実行時に読み込まれるようにする
コマンドを作成しただけでは、CocoaPods本体がその存在を認識できません。
Rubyの$LOAD_PATH
に登録されたパス直下(通常はプロジェクトのlib
ディレクトリ直下)に、cocoapods_plugin.rb
というファイルを作成し、その中で上記のコマンドクラスが記述されたファイルをrequire
します。これによってpod
コマンド実行時にカスタムコマンドクラスがロードされるようになります。
# lib/cocoapods_plugin.rb
require 'pod/command/check_latest'
動作確認をする
実際にpod
コマンド経由で動くか確認してみましょう。
$ echo "gem 'cocoapods', '~> 0.28'" >> Gemfile
$ bundle install
...
$ bundle exec pod help | grep check-latest
* check-latest Check if the latest version of a pod is up to date
$ bundle exec pod check-latest viewcontroller
-> AMBubbleTableViewController
- Homepage: https://github.com/andreamazz/AMBubbleTableView
- Latest pod version:0.5.1
- Latest version in original repo:0.5.1
-> APPinViewController
- Homepage: https://github.com/Alterplay/APPinViewController
- Latest pod version:1.0.2
- Latest version in original repo:1.0.2
-> ARGenericTableViewController
- Homepage: https://github.com/arconsis/ARGenericTableViewController
- Latest pod version:1.0.0
- Latest version in original repo:1.0.1
Outdated!
...
プラグインを配布する
あとはRubyGemsのルールに則ってgemを公開しましょう。
cocoapods-check_latest.gemspec
のdescription
, summary
, homepage
あたりの項目を記述し、BundlerのRakeタスクで公開します。
$ rake release
おわりに
実際に作成したcocoapods-check_latestプラグインを公開しました。gem install cocoapods-check_latest
でインストールができます。