Bash on Railsを作る(8) bashでオブジェクト指向
bashの内蔵コマンドだけでいかにRuby on Railsっぽいことをやるかというパロディ企画です。1000speakers:2デビューを狙ってましたが、発表者枠が分速で埋まったようなので、のんびりとブログで解説します。
今回は、予告どおり、bashでオブジェクト指向(もどき)を実現するしくみについて、使う側から解説します。bashでOO、略してbashOO(ばしょー)というところでしょうか。O/Rマッパー(もどき)など、Bash on Railsの多くの部分で利用しています。
前提:あくまでもbash
「bashでオブジェクト指向言語を作る」のではなく、「bashの解釈系のままで、オブジェクト指向っぽい書き方をできるようにする」のを目指しました。bashOOの呼び出しは、すべてbashのコマンドとして実行されています。
基本はObjectクラス
一般的な仕様どおり、bashOOでも、Objectクラスが最も基本的なクラスです。
インスタンスを作るのは、クラスメソッドnewです。
Object.new objectA
これで、インスタンスobjectAが作られます。
インスタンスメソッドを呼ぶ
作られたインスタンスのメソッドを実行してみます。ここではclassメソッドを呼んでみます。
objectA.class
クラスメソッドclassが呼ばれ、インスタンスが属するクラスの名前である「Object」が標準出力に出力されます。
注意:オブジェクトになるのは名前
ここで注意したいのは、オブジェクトになるのは、変数の内容ではなくて、変数の名前だということです。たとえば、以下のように、ほかの変数に代入してメソッドを実行しようとすると、エラーになります。
objectB=objectA objectB.class
継承クラスを定義:まずインスタンスメソッドを定義
言語を作るわけではないので、いまのところObjectクラスには機能はほとんどありません。そこで、Objectクラスを継承して新しいクラスを作ってみましょう。ここでは、Humanクラスを作ってみます。
まず、インスタンスメソッドhelloを定義します。インスタンスメソッドは、「(クラス名)::instance.(メソッド名)」という名前の関数として定義します。
function Human::instance.hello() { echo 'Hello!' }
引数のあるメソッドも定義できます。
function Human::instance.speak() { local self=$1 local message=$2 echo "$message" }
第1引数がselfなんて、PerlかPythonみたいですね。いや、それを狙ったんですが。
クラスメソッドを定義
なんとなく気づいた方もいるかもしれませんが、クラスメソッドは、「(クラス名)::class.(メソッド名)」という名前の関数として定義します。
function Human::class.amounts() { local class=$1 echo "$class lives: 6,400million" }
クラスメソッドの第1引数はclassです。Perlのnewみたいですね。いや、それを狙ったんですが。
継承クラスを定義:実行
あとは、実際に継承を実行します。
Object.extend Human
クラスメソッドを試してみましょう。
Human.amounts
標準出力に「Human lives: 6,400million」と出力されます。
インスタンスを作ってみます。
Human.new ore
インスタンスメソッドを呼び出してみます。
ore.hello ore.speak 'Hello!'
どちらも、標準出力に「Hello!」と出力されます。
さらに継承:コンストラクタとインスタンス変数
もちろん、Humanから継承クラスを作ることもできます。ここでは、Bikerクラスを作ってみます。
ついでに、コンストラクタも解説します。コンストラクタは、そのクラスのinitializeというインスタンスメソッドです。Rubyっぽいですね。いや、それを狙ったんですが。
function Biker::instance.initialize() { local self=$1 local name=$2 eval "${self}_name='${name}'" }
インスタンス変数は、「(インスタンス名)_(メンバー名)」という変数とします。代入のためにevalを使っているのはご愛嬌ということで。
インスタンス変数を参照するメソッドも作ってみましょう。
function Biker::instance.name() { local self=$1 local name_var="${self}_name" echo "${!name_var}" }
「${!hoge}」は、変数の間接参照です。詳しくはman bashをご覧ください。
メソッドの継承
親クラスのメソッドは上書きできます。
function Biker::instance.hello() { echo "Hey!" }
では継承クラスを作ります。
Human.extend Biker
インスタンスを作ってみましょう。
Biker.new wyatt 'Captain America'
新しく定義したインスタンス変数を呼んでみます。
wyatt.name wyatt.hello
それぞれ「Captain America」「Hey!」と出力されます。
親クラスのメソッドは、そのまま使えます。
wyatt.speak 'Easy come, easy go.'
まとめ
bashの解釈系(シンタックス)の中で、オブジェクト指向っぽい書き方(セマンティックス)を実現してみました。
bashOOも、bashOO自身で実装しています。そのへんのブートストラップの仕組みは、そのうち。
コメント
コメントの投稿
トラックバック
https://emasaka.blog.fc2.com/tb.php/355-d23f709f