作成するスクリプトがある程度大きくなると、 プログラムの各部分が相互に及ぼす悪影響をうまく排除する必要が出てくる。 このためには、プログラムの働きを大きなかたまりに分解し、 それぞれの独立性を高めた設計とする。これをプログラムのモジュール 化という。
ある種類のモノを考える。それに備わる性質を変数として、
動きや働きかけなどをメソッドとしてひとつの仲間にまとめ上げたものを
クラスという。クラス定義には class を使う。
class SomeClass 〜〜定義本体〜〜 end
クラス名は大文字で始める。クラス定義にはメソッド定義, 定数定義,呼出し制限,またはさらに別のクラス定義を書ける。
定義したクラスの実体にあたるものをインスタンスという。 これまでよく用いた以下のような文はインスタンスの生成を意味する。
score = Array.new
この例は,様々な性質やメソッドを持つよう設計されたArrayクラスの,
実働的役割を担うモノ,つまりインスタンスを1つ作り,
それを score 変数に代入している。
配列(Arrayクラス)をずっと単純化して, 「日曜から土曜までの予定」7つの文字列しか保持できないクラス, Weekを定義してみる。クラス名は大文字で始める。
#!/usr/bin/env ruby
class Week
def initialize(owner = "名なしの権兵衛")
@week = Hash.new
@days = %w(sun mon tue wed thu fri sat)
setowner(owner)
for day in @days
@week[day] = ""
end
end
def canonicalize_day(day)
day[0,3].downcase
end
def set(day, plan)
d = canonicalize_day(day)
if @week.has_key?(d) then
@week[d] = plan
else
STDERR.puts "#{day} という曜日はないのさ"
nil
end
end
def get(day)
d = canonicalize_day(day)
if @week.has_key?(d) then
@week[d]
else
nil
end
end
def getowner()
@name
end
def setowner(name)
@name = name
end
def display()
printf("------ %sさんの予定 ------\n", @name)
for d in @days do
printf("%3s\t%s\n", d.capitalize, get(d))
end
end
end
taro = Week.new("太郎")
hana = Week.new("花子")
taro.set("Thursday", "焼き肉")
taro.setowner("TALOW!")
hana.set("Thursday", "花見")
taro.display
hana.display
@で始まる変数はインスタンス変数
といい,1つのインスタンスの内部に閉じ込められ,そのインスタンス
からしかアクセスできない変数である。
Rubyでは変数(ローカル変数)をメソッド間で共有することができない。 トップレベルで定義した変数も、メソッド内からは参照できない。
def foo() p x end x = 5 foo()
としても foo メソッド内ではトップレベルの変数
x にはアクセスできない。グローバル変数にすれば、
メソッド内からもアクセスできるようになるが、グローバル変数の使用は
プログラムの保守性、独立性、見通しのよさを著しく下げるため、
一定規模以上のプログラムでは通常用いない。複数のメソッド間で
値を共有する場合、通常は引数を用いる。値の永続性と適用範囲が
大きくなるものを作成する場合は、メソッド群をクラス化し
インスタンス変数を適切に利用する。
インスタンスが生成されるときに必ず呼ばれるメソッドを
コンストラクタ という。Rubyではコンストラクタを
initialize という名前のメソッドが担う。new
されるタイミングで自動的に呼ばれるので,ここにインスタンス変数の定義
など,初期化に必要なコードを入れる。
インスタンスを作る必要のないもの,すなわち同じ種類の仕事をする
メソッドのみをグルーピングする目的のために module が
利用できる。module は class 文と同じ
形式で定義する。
#!/usr/bin/env ruby
module Menseki
def sankaku(tei, tak)
tei.to_f * tak / 2
end
def daikei(jotei, katei, tak)
(jotei+katei)*tak/2.0
end
module_function :sankaku, :daikei
end
if $0 == __FILE__
p Menseki.sankaku(3,4)
p Menseki.daikei(3,4)
end
モジュール関数として外部から利用できるメソッド名を
module_function で指定する。