静岡理工科大学 菅沼ホーム Ruby 目次 索引

Ruby 概説

  1. Ruby の特徴
  2. プログラム
  3. クラスとメソッド
    1. クラス
    2. 配列
    3. メソッド
    4. リテラル
    5. 変数と定数
    6. モジュール
    7. 特異クラスと特異メソッド
    8. 演算子の再定義(オーバーロード)
    9. ブロック付きメソッド呼び出し
  4. 演算子
    1. 演算子の種類
    2. 多重代入
    3. 範囲式
  5. 制御構造
    1. 条件分岐
    2. 繰り返し
  6. 変数の有効範囲(スコープ)
  7. 使用方法
    1. コマンドラインとファイル
    2. フォームと Ruby

  1. Ruby の特徴

      Ruby は,Perl の後継を目指したオブジェクト指向プログラミング言語であり,以下に示すような特徴を持っています.しかし,かなり問題のある言語です.プログラムを実行するのはコンピュータですが,それを書くのは人間です.従って,プログラムを書くことにとって,最も重要なことは,「読みやすいこと,理解しやすいこと」です.プログラムを記述した言語に対してあまり知識がない人であっても,読めばある程度理解できることが必要です.その点,Perl は,知っている人にとっては書きやすい言語かもしれませんが,知らない人にとっては非常に読みにくい言語であり,最悪の言語です.Ruby は,読みやすさの点における改善はなされていますが,Perl の悪い箇所をそのまま継承しているように思えます.例えば,$_ などの意味のない記号に対して特別の意味を持たせる,などといったことは絶対にすべきでないと思います.そのような意味から,Ruby を使用することはあまり推奨できませんが,使用する場合には,できる限りわかりやすさに重点を置いて記述してもらいたいと思います.

    • インタプリタ言語である.

    • 変数の型宣言が不要である.ただし,変数の種類(ローカル変数,グローバル変数など)は変数名から知る事ができる.

    • ガーベージコレクションを実行してくれる.

    • 整数のような基本的なデータ型をはじめとして,全てのデータをオブジェクトとして統一的に取り扱う.

    • Perl をお手本とした強力な文字列操作や正規表現検索の機能がある.

    • 組み込みの多倍長整数機能があるので,メモリが許す限り,非常に大きな整数の演算も可能である.

  2. プログラム

      Ruby では,整数のような基本的なデータ型をはじめとして,全てのデータをオブジェクトとして統一的に取り扱います.Ruby のプログラムを書くことは,Object クラスを継承したクラスを定義することに相当します.

      プログラムは式を並べたものであり,式と式の間はセミコロン( ; ),または,改行で区切ります.ただし,バックスラッシュ( \ )に続く改行は文の区切りにならず,次の行へ継続します.

      また,プログラム内にコメントを挿入することができます.例えば,
    y = 10  # 変数 y に 10 を代入します
    			
    のように記述すると,#( ?# を除く)から行末までをコメントとみなします.複数行にわたるコメントを書きたいような場合は,次の例のように,「 =begin 」と「 =end 」を使用し,ドキュメントを埋め込むことにより可能です.
    =begin
    	~ に関するプログラム例です
    			coded by Y.Suganuma
    =end
    			

  3. クラスとメソッド

    1. クラス

        クラスの定義は,以下のようにして行われます.なお,「 < 」の後は継承するクラスを表しています.
      class 識別子 [ < superclass ]
        式(演算式,メソッド,クラスなど)
          ・・・
      end
      				
        クラス名はアルファベットの大文字で始まる識別子(定数)です.Ruby では,クラスもオブジェクトの一つであり,Class クラスのインスタンスです.クラス定義は,Class クラスのインスタンスを生成し,その名前を識別子で指定した定数へ代入することに相当します.そのため,C++ や Java とは異なり,後に示す例にも示すように,定義した時点で式が実行されます.

        あるクラスに宣言されているメソッドなどをすべて受け継ぎ(メソッドなどを利用できるようにする),それに新たなメソッドを追加,受け継いだメソッドの修正などを行い,新しいクラスを宣言することができます.これを,クラスの継承と呼びます.このとき,基になったクラスをスーパークラス(親クラス),新たに作成したクラスをサブクラス(子クラス)と呼びます.

    2. 配列

        配列は,複合データ型の一種であり,複数のデータを処理する場合に利用されます.Ruby においては Array クラスのインスタンスとして定義され,例えば,
      x = Array[1, 2.3, "abc"];   # x = [1, 2.3, "abc"]; でも可
      				
      のように宣言すれば,3 つのデータを記憶できる領域が確保され,各要素に記憶される値が 1,2.3,"abc" で初期設定されます.また,変数名と添え字を利用して,x[0],x[1],x[2] のようにして参照できます.この例に示すように,各要素は,必ずしも,同じデータ型である必要はありません.しかし,間違いの元になる可能性がありますので,配列は,同じデータ型だけで構成するようにした方が良いと思います.また,プログラムの実行時に,要素の追加,削除等を行うことが可能です.

        例えば,
      u1 = Array[1, "abc", 2];
      u2 = Array[1, "abc", 2];
      u3 = u1;
      				
      の最初の 2 行では,同じ値で初期設定された 2 つの配列 u1,u2 を定義し,次の行において u1 を u3 に代入しています.しかし,この代入は,整数型の場合のような代入ではありません.つまり,u1 の領域及びそこに記憶されている要素をすべてコピーし,u3 に代入しているわけではありません.ここでは,u1,u2,u3 をポインタとしてとらえた方が理解しやすいと思います.つまり,2 行目の代入によって,u1 に記憶されているアドレスが u3 に記憶され,u1 と u3 が同じ領域を指しているという意味です.実際,u1 の値を変更すれば,u3 の値も変化します(逆も同様).配列を関数の引数として渡す場合も,ポインタを引数とすることに相当しますので,関数内で配列の要素の値を変更すれば,関数を呼んだ側における対応する要素の値も変化します.このことを概念的に示せば以下のようになります.

        多次元の配列を扱うことも可能です.例えば,
      v1 = Array[[10, 20, 30], [40, 50, 60]];
      v2 = Array[[10, 20, 30], [40, 50, 60]];
      v3 = v1;
      				
      のように,配列の要素を,さらに配列として定義すれば,2 次元の配列を定義できます.この例では,2 行 3 列の配列になります.3 行目の記述によって,v3 も,v1 と同じ 2 行 3 列の配列になります.そのイメージは,new 演算子を使用した C++ の場合と同じく,以下のようになります.

        また,
      v4 = v1[0];   // v1,v3 の 1 行目
      				
      のように,各行を 1 次元配列として扱うことも可能です.勿論,v4 と v1[0] は同じ場所を指していますので,例えば,v4[1] の値を変更すれば,v1[0][1] の値も変化します(逆も同様).しかし,すべてのデータが連続した領域に確保されるとは限らないため,異なる行のデータを,連続した 1 次元配列とみなして参照することはできません.

    3. メソッド

        データを処理する方法は,メソッド関数)によって記述します.メソッドは,一般的に,
      def メソッド名 [ 引数の並び ]
         式
        ・・・
        [rescue [error_type,..] [=> evar] [then]
           式..]..
        [else
           式..]
        [ensure
           式..]
      end
      				
      のような形式で記述します.rescue 節には,本体の実行によってエラーが発生した場合の処理を記述します.else 節は,本体の実行によって例外が発生しなかった場合に評価されます.また,ensure 節が存在する時は,メソッド評価の最後に ensure 節の本体を評価します.なお,rescue 節,else 節,及び,ensure 節に関しては,制御構造を参照して下さい.

        メソッドの戻り値は,return 節 に渡した値です.return 節が呼び出されなかった場合は,メソッドの本体から ensure 節実行直前までの最後に評価した式の値を返します.retuen 節は,
      return [ 式 [ , 式 ... ] ]
      				
      のように記述され,式が 2 つ以上与えられた時には,それらを要素とする配列をメソッドの戻り値とします.また,式が省略された場合には,nil を戻り値とします.例えば,
      return 1, 2, 3
      				
      の場合は,3 つの値を配列に入れて返します.引数には,例えば,
      def func (par1, par2=10, par3=30)
      	x = par1 + par2 + par3
      	return x
      end
      print func(100, 50)
      				
      のように,デフォルト値を設定することができます(デフォルト引数).ただし,n 番目の引数にデフォルト値を設定した場合は,それ以降の引数に対してもデフォルト値を設定する必要があります.上の例の場合,3 番目の引数を省略したため,par3 の値は 30 であるとして処理され,結果は 180 になります.なお,この例の場合は,最後に処理された式の値がメソッドの返すべき値であるため,return 節が無くても,同じ結果になります.

        下に示す例のように,最後の仮引数の直前に「 * 」がある場合には,残りの実引数はみな配列としてこの引数に格納されます.可変長引数などと呼ばれる機能です.なお,このような引数は,1 つだけ使用できます.また,p は,出力を行うための組み込み関数です.「 p x 」と書かれても,何を意味するか全く分かりません.少なくとも,「 print x 」のような表現をすれば,Ruby を知らない人でもある程度理解できます.「 p x 」の表現が許される,この点が Ruby の最大の問題点です.
      def func (par, *x)
      	p x
      end
      func(0)          # 出力結果 []
      func(1, 10)      # 出力結果 [10]
      func(2, 10, 20)  # 出力結果 [10, 20]
      				
        最後の仮引数の直前に「 & 」があると,このメソッドに与えられているブロックProc クラスのオブジェクトとしてこの引数に格納されます.このような引数も,1 つだけ使用できます.詳細については,「ブロック付きメソッド呼び出し」を参照して下さい.

        メソッド定義において,仮引数はその種類毎に,以下に示す順序でしか指定することはできません.なお,いずれも省略することは可能です.

      • デフォルト式のない引数(複数指定可)
      • デフォルト式のある引数(複数指定可)
      • * を伴う引数(1つだけ指定可)
      • & を伴う引数(1つだけ指定可)

        メソッドは,publicprivateprotected の三通りの呼び出し制限を持ちます.public に設定されたメソッドは制限なしに呼び出せます.private,及び,protected に設定されたメソッドは,そのメソッドを持つオブジェクトのメソッド定義式内でなければ呼び出せません.また,private に設定されたメソッドは,関数形式( obj.func のように,ピリオドでオブジェクトを指定した部分がない形式)でしか呼び出せません.デフォルトでは,def 式がクラス定義の外(トップレベル)にあれば private,クラス定義の中にあれば public に定義します.

        下に示す例においては(行番号は,説明のために付けてあります),メソッド func_private は private,メソッド func_protected は protected,その他は public に設定してあります.例えば,private を記述すると,それ以降のメソッドはすべて private になります.しかし,
      private :func_private
      protected :func_protected
      				
      などの記述により,変更することが可能です.なお,この例において,self は自分自身のオブジェクトを指します.また,new は,新しいオブジェクトを生成するためのメソッドです.例えば,「 Test.new.func_public 」は,Test クラスのオブジェクトを生成し,そのクラスに定義されているメソッド func_public を呼ぶことを意味しています.このように,引数を持たないメソッドを呼ぶときは,括弧も必要ありません.
      01	class Test
      02		def func
      03			Test.new.func_protected
      04			printf " (in Method)\n"
      05			self.func_protected
      06			printf " (in Method)\n"
      07			func_private
      08			printf " (in Method)\n"
      09	#		self.func_private  関数形式だけが許される
      10		end
      11		def func_public
      12			printf "public method"
      13		end
      14		private
      15			def func_private
      16				printf "private method"
      17			end
      18		protected
      19			def func_protected
      20				printf "protected method"
      21			end
      22		Test.new.func_public
      23		printf " (in Class)\n"
      24	#	Test.new.func_protected   この位置では呼べない
      25	#	func_private   この位置では呼べない
      26	end
      27	
      28	Test.new.func_public
      29	printf "\n"
      30	Test.new.func
      				
      (出力)
      public method (in Class)      # 22, 23 行目の実行
      public method                 # 28, 29 行目の実行
      protected method (in Method)  # 30 行目の実行(メソッド func の実行)
      protected method (in Method)  # 30 行目の実行(メソッド func の実行)
      private method (in Method)    # 30 行目の実行(メソッド func の実行)
      				
    4. リテラル

        数値リテラルにおいて,整数や ?a などは,Integer クラス のサブクラスである Fixnum クラスのインスタンスです.ただし,整数の大きさが Fixnum によって表現できる範囲を超えると Bignum クラスのインスタンスとして扱われます.また,浮動小数点数は,Float クラスのインスタンスです.
      123,0d123      整数
      -123            符号つき整数
      123.45          浮動小数点数.ピリオド( . )で始まる浮動小数点数は許されません.0.1 などと書く必要があります.
      1.2e-3          浮動小数点数
      0xffff,0xFFFF  16 進整数
      0b1011          2 進整数
      0377,0o377     8 進整数
      ?a              文字 a のコード( 97 ).空白類を指定する場合は,?\s,?\t などとする必要があります.
      ?\C-a           コントロール a のコード( 1 )
      ?\M-a           メタ a のコード( 225 )
      ?\M-\C-a        メタ-コントロール a のコード( 129 )
      				
        文字列リテラルは,ダブルクォート「 " 」,または,シングルクォート「 ' 」で囲んで表現し,String クラスのインスタンスです.ダブルクォートで囲まれた文字列では,後に述べる,バックスラッシュ記法式展開が有効になります.シングルクォートで囲まれた文字列では,\\ (バックスラッシュそのもの)と \' (シングルクォート),行末の \ (改行を無視)を除いて文字列の中身の解釈は行われません.

        文字列は,複数行にわたって書くこともできます.この場合,含まれる改行文字は常に \n になります.また,空白を間に挟んだ文字列リテラルは,1 つの文字列リテラルと見倣されます.文字列の結合は,+ 演算子によって可能ですので,以下の 2 つの式は,同じ結果 abcefg を出力します.
      printf "abc" + "efg\n"
      printf "abc" "efg\n"
      				
        以下に示すように,バックスラッシュ( \ )を使用して,特別な文字(制御文字など)を表現することが可能です.これを,バックスラッシュ記法と呼びます.C/C++ などにおけるエスケープシーケンスに相当します.
      \t  タブ( 0x09 )
      \n  改行( 0x0a )
      \r  キャリッジリターン( 0x0d )
      \f  改ページ( 0x0c )
      \b  バックスペース( 0x08 )
      \a  ベル( 0x07 )
      \e  エスケープ( 0x1b )
      \s  空白( 0x20 )
      \nnn  8 進数表記( n は 0-7 )
      \xnn  16 進数表記( n は 0-9,a-f )
      \cx,      \C-x  コントロール文字( x は ASCII 文字)
      \M-x     メタ x ( c | 0x80 )
      \M-\C-x  メタコントロール x
      \x  文字 x そのもの
      				
        ダブルクォート「 " 」,または,バッククォート「 ` 」で囲まれた文字列,及び,正規表現の中では,#{ 式 } という形式で式の内容(式を評価した結果)を埋め込むことができます.この機能を式展開と呼びます.式が変数記号 $,または,@ で始まる変数の場合には { } を省略して,「#変数名」という形式でも展開できます.文字 # に続く文字が {,$,@ でなければ,そのまま文字 # として解釈されます.明示的に式展開を止めるには # の前にバックスラッシュを置きます.式展開の中には,ダブルクォートなども含めて Ruby の式をそのまま書くことができます.コメントも許されます.次の枠内に示すプログラムを実行すると,次のような結果が得られます.
      私は,山田太郎 です
      私は,山田 です
      私は,山田 です
      私は,#{ $sei } です
      				
      $sei = "山田"
      $nam = "太郎"
      print "私は,#{ $sei + $nam } です\n"
      print "私は,#{ $sei } です\n"
      print "私は,#$sei です\n"
      print "私は,\#{ $sei } です\n"  # 式展開が行われない
      				
        バッククォート「 ` 」で囲まれた文字列は,ダブルクォートで囲まれた文字列と同様に,バックスラッシュ記法の解釈と式展開が行なわれた後,コマンドとして実行され,その標準出力が文字列として与えられます.コマンドの終了ステータスを得るには,組み込み変数 $? を参照します.次の枠内に示すプログラムは,「 ls -l 」コマンドを実行し,その結果を変数 y に代入しています.このプログラムを実行すると,次のような結果が得られます.
      total 1
      -rwxr-xr-x   1 1005     everyone       44 Jun  8 13:45 test.rb
      
      終了ステータス 0
      				
      #! ruby -Ks
      y = ` ls -l `
      printf "%s\n", y
      printf "終了ステータス %d\n", $?
      				
        上で述べたように,普通の文字列リテラルは,デリミタ( ",',` など)で囲まれた文字列ですが,ヒアドキュメントは,
      <<識別子
        文字列
        ・・・
      識別子
      				
      のように,「<<識別子」を含む行の次の行から,「識別子」だけの行の直前までを文字列とする行指向のリテラルです.ヒアドキュメントも,通常の文字列と同様,String クラスのインスタンスです.例えば,
      <<EXAMPLE
        Test String 1
        Test String 2
      EXAMPLE
      				
      は," Test String 1\n Test String 2\n" と同じになります.

    5. 変数と定数

        Ruby の変数と定数の種別は変数名の最初の 1 文字によって,ローカル変数インスタンス変数クラス変数グローバル変数定数のいずれかに区別されます.2 文字目以降は英数字,または,「 _ 」であり,変数名の長さにはメモリのサイズ以外の制限はありません.

        小文字,または,「 _ 」で始まる識別子はローカル変数,または,メソッド呼び出しです.ローカル変数のスコープ(有効範囲)は,その変数を宣言した位置から,その変数が宣言されたブロック,メソッド定義,または,クラス定義,または,モジュール定義の終りまでです.また,「 $ 」で始まる変数はグローバル変数であり,プログラムのどこからでも参照できます.

        アルファベット大文字( [ A - Z ] )で始まる識別子は定数です.定数の定義は代入によって行われますが,メソッドの中では定義できません.また,一度定義された定数に再び代入を行おうとすると,警告メッセージが出ます(代入は可能です).定数は,その定数が定義されたクラス/モジュール定義の中(メソッド本体やネストしたクラス/モジュール定義中を含みます),クラスを継承しているクラス,モジュールをインクルードしているクラス,または,モジュールから参照することができます.

        「 @ 」で始まる変数は,インスタンス変数であり,特定のオブジェクトに所属しています.インスタンス変数はそのクラスまたはサブクラスのメソッドから参照できます.インスタンス変数は,クラスから生成されたインスタンス(オブジェクト)毎に別の値を持つことができるため,各オブジェクトの状態を表すためなどに使用されます.このように,インスタンス変数は,C/C++ における protected 指定されたメンバー変数と似た働きをします.従って,そのままでは,クラスの外部から参照することはできません.参照可能にするためには,Module クラス内の記述を参考にしてください.

        以下に示すのは,クラスの定義・参照方法,及び,変数・定数の使用方法に関するプログラム例と出力結果です.このプログラムにおいて,printf は,組み込み関数,つまり,Kernel モジュールで定義されているメソッドであり,全てのクラスから参照できます.Object クラスは,このモジュールをインクルードしています.printf は,C/C++ における printf 関数と似たメソッドであり,ほとんど同じように使用することができます.ただし,C/C++ とは異なり,引数リストを必ずしも括弧で囲む必要はありません(下に示すいずれの方法も可能).なお,この点は,他のメソッドにおいても同様です.
      printf "x = %d\n", x
      printf ("x = %d\n", x)
      				
      01	v_local_1  = 10
      02	$_global_1 = 100
      03	Const_1    = 1000
      04
      05	class Test
      06		v_local_2  = 20
      07		$_global_2 = 200
      08		Const_2    = 2000
      09		#printf "   ローカル変数 v_local_1 = %d (in class)\n", v_local_1  参照不可能
      10		printf "   グローバル変数 $_global_1 = %d (in class 変更前)\n", $_global_1
      11		$_global_1 = 500
      12		printf "   グローバル変数 $_global_1 = %d (in class 変更後)\n", $_global_1
      13		printf "   定数 Const_1 = %d (in class 定義前)\n", Const_1
      14		Const_1 = 5000
      15		printf "   定数 Const_1 = %d (in class 定義後)\n", Const_1
      16		printf "   ローカル変数 v_local_2 = %d (in class)\n", v_local_2
      17		printf "   グローバル変数 $_global_2 = %d (in class)\n", $_global_2
      18		printf "   定数(初期化) Const_2 = %d (in class)\n", Const_2
      19		def initialize(par = 100)
      20			@_par = par
      21		end
      22		def out
      23			printf "定数 Const_2 = %d, インスタンス変数 @_par = %d\n", Const_2, @_par
      24		end
      25	end
      26
      27	printf "\nローカル変数 v_local_1 = %d\n", v_local_1
      28	printf "グローバル変数 $_global_1 = %d\n", $_global_1
      29	printf "定数 Const_1 = %d\n", Const_1
      30	print "\n"
      31	#printf "   ローカル変数 v_local_2 = %d\n", v_local_2  参照不可能
      32	printf "グローバル変数 $_global_2 = %d\n", $_global_2
      33	printf "定数 Test::Const_1 = %d\n", Test::Const_1
      34	printf "定数 Test::Const_2 = %d\n", Test::Const_2
      35	print "\n"
      36	t_obj1 = Test.new
      37	t_obj1.out
      38	t_obj2 = Test.new 200
      39	t_obj2.out
      40	t_obj3 = Test.new(300)
      41	t_obj3.out
      42	print "\n"
      43	Test::Const_2 = 3000
      44	printf "定数(代入後) Const_2 = %d\n", Test::Const_2
      45
      46	print "\n"
      47	class Test_o
      48		printf "   定数 Const_1 = %d (in class Test_o)\n", Const_1
      49		printf "   定数 Const_2 = %d (in class Test_o)\n", Test::Const_2
      50	end
      
      (出力結果)
      
      01	   グローバル変数 $_global_1 = 100 (in class 変更前)
      02	   グローバル変数 $_global_1 = 500 (in class 変更後)
      03	   定数 Const_1 = 1000 (in class 定義前)
      04	   定数 Const_1 = 5000 (in class 定義後)
      05	   ローカル変数 v_local_2 = 20 (in class)
      06	   グローバル変数 $_global_2 = 200 (in class)
      07	   定数(初期化) Const_2 = 2000 (in class)
      08
      09	ローカル変数 v_local_1 = 10
      10	グローバル変数 $_global_1 = 500
      11	定数 Const_1 = 1000
      12
      13	グローバル変数 $_global_2 = 200
      14	定数 Test::Const_1 = 5000
      15	定数 Test::Const_2 = 2000
      16
      17	定数 Const_2 = 2000, インスタンス変数 @_par = 100
      18	定数 Const_2 = 2000, インスタンス変数 @_par = 200
      19	定数 Const_2 = 2000, インスタンス変数 @_par = 300
      20
      21	test.rb:43: warning: already initialized constant Const_2
      22	定数(代入後) Const_2 = 3000
      23
      24	   定数 Const_1 = 1000 (in class Test_o)
      25	   定数 Const_2 = 3000 (in class Test_o)
      				
        まず,1 ~ 3 行目において,ローカル変数 v_local_1,グローバル変数 $_global_1,及び,定数 Const_1 を定義しています.次の 5 ~ 25 行目において,クラス Test を定義しています.クラス定義の中では,各種変数,定数,及び,2 つのメソッドを定義しています.out は,インスタンス変数 @_par を出力するために作成したメソッドであり,また,initialize は,Object クラスのメソッドであり,その内容をこのクラス用にオーバーライド(書き直し)しています.

        クラスに対するインスタンスの生成には,36,38,及び,40 行目に示すように,Class クラスの new メソッドを利用します.new メソッドを利用してインスタンスを生成すると,もし,クラス定義の中に initialize が記述してある場合,その内容が最初に実行されます.つまり,initialize メソッドは,C/C++ や Java におけるコンストラクタに相当します.この例の場合,引数が 1 つで,かつ,そのデフォルト値が 100 である initialize が定義されており,その中で,受け渡された引数をインスタント変数に代入しているため,異なるインスタンス変数の値を持つインスタンスを生成することが可能です(他の定数・変数については共通).

        先に述べたように,クラス定義は,Class クラスのオブジェクトを生成することになりますので,クラス定義を行うだけで,その中に記述された printf メソッドによる出力結果が表示されます.しかし,new メソッドによるインスタンス生成の際には表示されません.これらの点は,C/C++ や Java におけるクラス定義と大きく異なります.つまり,Ruby においては,単なるクラスの定義ではないのです.

        次に,変数や定数について眺めてみます.1 行目で定義されたローカル変数 v_local_1 は,クラス定義の中では参照できません.逆に,クラス定義の中の 6 行目で定義されたローカル変数 v_local_2 は,クラス定義の外からは参照できません.しかし,グローバル変数 $_global_1 や $_global_2 は,どこからも参照でき,かつ,同じ変数名であれば,すべて同じ変数を表しています.

        定数は,再代入する際に警告メッセージが出力される( 43 行目)点を除くと,参照できる範囲の点から,グローバル変数と非常に似ています.しかし,そのスコープがクラスやモジュールの内部に制限されているため,多少異なってきます.13 行目において,定数 Const_1 の値を出力する際は,3 行目で定義された Const_1 を参照しています.しかし,14 行目においてクラス内で定数 Const_1 が定義されると,それ以降のクラス内においては,この定数が有効になります.つまり,3 行目で定義された Const_1 と,クラス内で定義された Const_1 は異なった定数になります.そして,クラスの外からクラス内の定数 Const_1 を参照するためには.「 Test::Const_1 」のように表記する必要があります.同じように,クラス内のメソッドを呼び出すためには,37,39,及び,41 行目のように,「 . 」を使用します.

        「 @@ 」で始まる変数はクラス変数と呼びます.クラス変数は,クラス定義の中で定義され,そのクラス,サブクラス,それらのインスタンスなどから参照できます.このような点から,クラス変数は,クラスやサブクラスなどで共有されるグローバル変数であるとみなすことができます.

        以下に示すプログラム例において,クラス Test は,クラス P_Test を継承しています.また,Ruby のプログラムを書くことは,Object クラスを継承したクラスを定義することに相当しますので,例に示すプログラム全体が,Object クラスを継承したサブクラスになっています.従って,プログラムのどこからでも,Object クラスに定義されているメソッドやクラス変数を参照可能です.

        クラス P_Test で定義されているクラス変数 @@_class やメソッド func は,クラス P_Test を継承しているクラス Test からも参照可能です.しかし,クラス Test 内にネストされたクラス Test_in (クラス Test との機能的な関係はない)やクラスの外からは参照できません.
      class P_Test
      	@@_class = 10
      	printf "クラス変数 @@_class = %d (in P_Test)\n", @@_class
      	def func
      		printf "こんにちは!!"
      	end
      end
      
      class Test < P_Test
      	printf "クラス変数 @@_class = %d (in Test)\n", @@_class
      	class Test_in
      #		printf "クラス変数 @@_class = %d (in Test)\n", @@_class  参照不可能
      	end
      end
      
      #printf "クラス変数 @@_class = %d\n", @@_class  参照不可能
      t_obj1 = P_Test.new
      t_obj1.func
      printf " (in P_Terst)\n"
      t_obj2 = P_Test.new
      t_obj2.func
      printf " (in Terst)\n"
      				
      (出力)
      クラス変数 @@_class = 10 (in P_Test)
      クラス変数 @@_class = 10 (in Test)
      こんにちは!! (in P_Terst)
      こんにちは!! (in Terst)
      				
        super は現在のメソッドがオーバーライドしているスーパークラスのメソッドを呼び出します.括弧と引数が省略された場合には現在のメソッドの引数がそのまま引き渡されます.引数を渡さずにオーバーライドしたメソッドを呼び出すには super() と括弧を明示します.以下に示すプログラムを実行すると,250 という出力が得られます.
      class P_Test
      	def add(p1, p2=20, p3=30)
      		return p1 + p2 + p3
      	end
      end
      
      class Test < P_Test
      	def add(p)
      		return p + super
      	end
      end
      
      print Test.new.add(100)
      				

    6. モジュール

        Ruby では,多重継承(複数のクラスを継承する機能)を許していません.その代わりに,モジュールという機能があります.モジュールはインスタンスを持たないクラスといっても良いかもしれません.クラスの定義において,Module クラスの include メソッドによりモジュールの機能を取りこんで使用します.このことを,Mix-in と呼びます.下の例では,モジュール Add_m をクラス Test に取り込んでいます.実行すると,30 と 90 という結果が得られます.
      module Add_m
      	Const = 100
      	def add(a, b)
      		return a + b
      	end
      end
      
      class Test
      	include Add_m
      	def sub(a, b)
      		return a - b + Const
      	end
      end
      
      printf "%d\n", Test.new.add(10, 20)
      printf "%d\n", Test.new.sub(10, 20)
      				
        下に示す例のように,クラスではなく特定のオブジェクトにだけモジュールの機能を追加することも可能です.その際には,Object クラスの extend メソッドを使用します。
      module Add_m
      	Const = 100
      	def add(a, b)
      		return a + b
      	end
      end
      
      class Test
      	include Add_m
      	def sub(a, b)
      		return a - b + Const
      	end
      end
      
      obj = Test.new
      obj.extend Add_m
      printf "%d\n", obj.add(10, 20)
      printf "%d\n", obj.sub(10, 20)
      				

    7. 特異クラスと特異メソッド

        特異クラス定義式を利用すると,クラス定義と同じ構文で,特定のオブジェクトにメソッドやインスタンス変数を定義/追加できます.この定義式の内部で定義したメソッドや定数は,指定したオブジェクトに対してだけ有効になります.Object クラスの clone や dup は,オブジェクトの複製を作成して返すメソッドですが,特異クラス定義式によって変更されたオブジェクトは,clone で生成したオブジェクトには引き継がれますが,dup で生成したオブジェクトには引き継がれません.以下に,特異クラス定義式を使用したプログラムとその出力結果を示しますが,この例では,メソッド func をオーバーライドしています.
      class Test
      	def func
      		printf "クラス Test\n"
      	end
      end
      
      obj1 = Test.new
      obj2 = Test.new
      
      class << obj2
      	def func
      		printf "クラス Test\n"
      		printf "   こんにちは!!\n"
      	end
      end
      
      obj1.func
      obj2.func
      				
      (出力)
      クラス Test
      クラス Test
         こんにちは!!
      				
        特異メソッドとは,特異クラスと似ていますが,特異クラスのようにオブジェクト全体の変更ではなく,ある特定のオブジェクトのメソッドだけを対象とした追加/修正です.上の例を,特異メソッドの定義式を使用して書き直すと以下のようになります.
      class Test
      	def func
      		printf "クラス Test\n"
      	end
      end
      
      obj1 = Test.new
      obj2 = Test.new
      
      def obj2.func
      	printf "クラス Test\n"
      	printf "   こんにちは!!\n"
      end
      
      obj1.func
      obj2.func
      				
        クラスメソッドとは,Java における static メソッドに相当し,
      クラス名.メソッド名
      				
      という方法で参照できます.クラスメソッドは,クラスの特異メソッドとして定義されます.Ruby では,クラスもオブジェクトなので,普通のオブジェクトと同様に特異メソッドを定義できます.したがって,何らかの方法でクラスオブジェクトにメソッドを定義すれば,それがクラスメソッドとなります.具体的には,以下のようにして定義することが出来ます(モジュールも同様です).なお,クラスの特異メソッドはそのサブクラスにも継承されます.
      class Test
      	def func
      		printf "クラス Test\n"
      	end
      end
      
      def Test.func
      	printf "クラス Test\n"
      	printf "   こんにちは!!\n"
      end
      
      Test.func
      				

    8. 演算子の再定義(オーバーロード)

        「再定義可能な演算子」に分類された演算子の実装はメソッドですので,再定義することが可能です.それらの演算子を定義する例を以下に示します.
      # 二項演算子
        def +(other)   # obj + other
        def -(other)   # obj - other
      # 単項プラス/マイナス
        def +@   # +obj
        def -@   # -obj
      # 要素代入
        def foo=(value)   # obj.foo = value
      # [] と []=
        def [](key)          # obj[key]
        def []=(key, value)      # obj[key] = value
        def []=(key, key2, value)   # obj[key, key2] = value
      				
        以下,+ 演算子,単項 - 演算子,及び,代入演算子に対するプログラム例と出力例を示します.

      + 演算子
      class Comp
      	def initialize(_real = 0, _imag = 0)
      		@_real = _real
      		@_imag = _imag
      	end
      	def out(cr = "")
      		printf "(%f, %f)%s", @_real, @_imag, cr
      	end
      	def real
      		return @_real
      	end
      	def imag
      		return @_imag
      	end
      	def +(obj)
      		c = Comp.new(@_real+obj.real, @_imag+obj.imag)
      		return c
      	end
      end
      
      a = Comp.new(1, 2)
      b = Comp.new(2, 3)
      a.out("\n")
      b.out("\n")
      c = a + b
      c.out("\n")
      				
      (出力)
      (1.000000, 2.000000)
      (2.000000, 3.000000)
      (3.000000, 5.000000)
      				
      単項 - 演算子
      class Comp
      	def initialize(_real = 0, _imag = 0)
      		@_real = _real
      		@_imag = _imag
      	end
      	def out(cr = "")
      		printf "(%f, %f)%s", @_real, @_imag, cr
      	end
      	def -@
      		c = Comp.new(-@_real, -@_imag)
      		return c
      	end
      end
      
      a = Comp.new(1, 2)
      a.out("\n")
      c = -a
      c.out("\n")
      				
      (出力)
      (1.000000, 2.000000)
      (-1.000000, -2.000000)
      				
      代入
      class Comp
      	def initialize(_real = 0, _imag = 0)
      		@_real = _real
      		@_imag = _imag
      	end
      	def out(cr = "")
      		printf "(%f, %f)%s", @_real, @_imag, cr
      	end
      	def real=(x)
      		@_real = x
      	end
      	def imag=(x)
      		@_imag = x
      	end
      end
      
      a = Comp.new(1, 2)
      a.out("\n")
      a.real = 10
      a.imag = 20
      a.out("\n")
      				
      (出力)
      (1.000000, 2.000000)
      (10.000000, 20.000000)
      				

    9. ブロック付きメソッド呼び出し

        ブロックとは,「 { ... } 」,または,「 do ... end 」のペアで囲まれた Ruby の文及び式の集まりです.ブロックの先頭には,縦棒 ( | ) で囲み,パラメータをカンマで区切って指定できます.ブロックは,
      method(arg1, arg2, ...)  do [ | 式 ... | ] 式 ... end
      method(arg1, arg2, ...) { [ | 式 ... | ] 式 ... }
      method(arg1, arg2, ..., &proc_object)   # proc_object は別に定義
      				
      のような形式で,メソッドに引数として渡すことができます.ブロックを引数として受け取るメソッドを,ブロック付きメソッドと呼びます.C/C++ について知っている人は,C/C++ における関数名を引数として渡す方法(関数のアドレスを引数として渡す方法)として考えれば分かり易いかと思います.ブロック付きメソッドは,制御構造の抽象化のために用いられるメソッドであり,最初はループの抽象化のために用いられていたため,特にイテレータと呼ばれることもあります.イテレータとは,簡単に言えば,以下のようなものです.通常の配列であれば,添え字などによって簡単に各要素を参照できます.しかし,その構造が複雑な場合は,それほど簡単ではありません.そこで,それを簡単に行えるようにしたものがイテレータです.

        以下に示すプログラムは,Integer クラスのブロック付きメソッドである times の使用例です.times は,与えられたブロックを self 回だけ( 0 から self-1 まで)繰り返します.1 行目ではパラメータを指定せず,2 行目では 1 つだけ指定しています.また,3 行目,及び,6 行目は,Proc クラスの new メソッドを使用してブロックオブジェクトを生成した後,それを引き渡しています.ブロックオブジェクトの生成は,4 行目,及び,5 行目に示すように,組み込み関数である proc や lambda によっても可能です.
      3.times {printf "test\n"}
      3.times {|m| printf "m = %d\n", m; printf "   result %d\n", 3*m}
      block = Proc.new {printf "test\n"}
      	# block = proc {printf "test\n"} この方法でも可
      	# block = lambda {printf "test\n"} この方法でも可
      3.times &block
      				
      (出力)
      test
      test
      test
      m = 0
         result 0
      m = 1
         result 3
      m = 2
         result 6
      test
      test
      test
      				
        yieldは,自分で定義したブロック付きメソッドにおいて,ブロックを呼び出すときに使われ,次のような形式で記述されます.
      yield ( [ 式 [, 式 ・・・ ] ] )
      yield [ 式 [, ' 式 ・・・ ] ]
      				
        yield に渡された値は,ブロック記法において | と | の間にはさまれた変数(ブロックの引数)に代入されます.また,Proc クラスの call メソッドを使ってブロックを実行することもできます.以下に示すプログラムは,上で述べた times を新たに定義した _times で置き換えた例です.
      def _times(n, &block)
      	k = 0
      	while k < n
      		yield(k)   # block.call k でも可
      		k += 1
      	end
      end
      
      block = Proc.new {|m| printf "m = %d\n", m; printf "   result %d\n", 3*m}
      _times 3, &block
      				

  4. 演算子

    1. 演算子の種類

        Ruby には以下にあげる演算子があります.なお,最初にあげた演算子ほど優先順位が高い演算子です.

      演算子 使用目的
      :: クラス内部の定数などの参照  例: Test::Const
      [] 配列要素などの参照  例: x[2]
      +(単項) 数値の符号
      ! 論理否定
      ~ ビット演算子(否定)
      ** べき乗  例: 2**0.5
      -(単項) 数値の符号
      * 乗算など
      / 除算
      % 余り演算など
      + 加算など
      - 減算など
      << ビット演算子(左シフト)など
      >> ビット演算子(右シフト)など
      & ビット演算子(論理積)など
      | ビット演算子(論理和)など
      ^ ビット演算子(排他的論理和)など
      > 比較演算子
      >= 比較演算子
      < 比較演算子
      <= 比較演算子
      <=> 比較を行い,正,0,負の判定など
      == 比較演算子
      === クラス又はそのサブクラスのインスタンスであるか否かの比較など
      != 比較演算子
      =~ 正規表現とのマッチ
      !~ 正規表現にマッチする場合に false,マッチしない場合に true
      && 論理積
      || 論理和
      .. 範囲式
      ... 範囲式
      ?: 条件演算子
      = 代入
      not 論理否定
      and 論理積
      or 論理和

        ほとんどの演算子は,特別な形式のメソッド呼び出しですので再定義(オーバーロード)可能です.しかし,一部のものは言語に組み込まれているため再定義できません.

    2. 多重代入

        多重代入は,複数の式または配列から同時に代入を行う方法です.左辺の式が一つしか与えられなかった場合,式を評価した値は配列に変換されて,右辺の各要素が左辺のそれぞれの式に代入されます.左辺の要素の数よりも右辺の要素の数の方が多い場合には,余った要素は無視されます.右辺の要素が足りない場合には,対応する要素の無い左辺には nil が代入されます.

        左辺の最後の式の直前に * がついていると,対応する左辺のない余った要素が,その式に配列として代入されます.余った要素が無い時には空の配列が代入されます.また,右辺の最後の式の直前に * がついていると,その式は配列として,各要素に分割されます.以下に示すのは,プログラムレ地とその出力結果です.
      a, b, c = 1, 2, 3
      printf "a = %d, b = %d, c = %d\n", a, b, c
      a = 1, 2, 3
      printf "a[0] = %d, a[1] = %d, a[2] = %d\n", a[0], a[1], a[2]
      a, b = 1, 2, 3
      printf "a = %d, b = %d\n", a, b
      a, b, c = 1, 2
      printf "a = %d, b = %d, c = %d\n", a, b, c
      a, *b = 1, 2, 3
      printf "a = %d, b[0] = %d, b[1] = %d\n", a, b[0], b[1]
      x = [1, 2, 3]
      a, b, c = 5, x
      p a
      p b
      p c
      a, b, c = 5, *x
      printf "a = %d, b = %d, c = %d\n", a, b, c
      				
      (出力)
      a = 1, b = 2, c = 3
      a[0] = 1, a[1] = 2, a[2] = 3
      a = 1, b = 2
      a = 1, b = 2, c = 0
      a = 1, b[0] = 2, b[1] = 3
      5
      [1, 2, 3]
      nil
      a = 5, b = 1, c = 2
      				
    3. 範囲式

        範囲式は,演算子「 .. 」,または,「 ... 」を使用して生成され,Range クラスのインスタンスです.「 .. 」演算子によって生成された範囲オブジェクトは終端を含み,「 ... 」演算子によって生成された範囲オブジェクトは終端を含みません.枠内に示すプログラムは,範囲式を使用した例です.
      for i in 1 .. 3
      	printf " %d", i
      end
      printf"\n"
      for k in "aa" .. "ac"
      	printf " %s", k
      end
      printf"\n"
      				
      (出力)
       1 2 3
       aa ab ac
      				
        範囲式で指定する式は,互いに演算子 「 <=> 」で比較できる必要があります.また,次の数値または文字列を返すメソッドである Integer クラスの succ,または,String クラスの succ などのメソッドを実行できるものでなければいけません.

  5. 制御構造

    1. 条件分岐

      1. if 文
        if 式1 [then]
        	式2
        [elsif 式3 [then]
        	式4 ]
        ・・・
        [else
        	式5 ]
        end
        					

      2. if 修飾子
        式1 if 式2
        					
          式2が真であれば,式1を評価してその結果を返します.

      3. unless 文
        unless 式1 [then]
        	式2
        [else
        	式3]
        end
        					
          if の逆であり,式1が偽であれば式2を,そうでなければ式3を実行します.

      4. unless 修飾子
        式1 unless 式2
        					
          式2が偽であれば,式1を評価してその結果を返します.

      5. case 文
        case [式0]
        	[when 式1 [, 式2] ・・・ [, *式m] [then]
        		式n]
        	・・・
        	[when *式p [then]
        		式q]
        	・・・
        	[else
        		式r]
        end
        					
          式0を評価した結果と,when 節で指定された各式を評価した結果とを,演算子 === を用いて比較し,一致する場合には when 節の本体を評価します.when 節の最後の式に * を前置すれば,その式は配列展開されます.以下に示すプログラムにおいて,コメント行で区切って示した各プログラムは,ほぼ等価であり,「結果は負」というメッセージを出力します.
        x = 5
        y = -6
        			# case 例1
        case x+y
        	when 1, 2, 3
        		printf "結果は正\n"
        	when -3, -2, -1
        		printf "結果は負\n"
        	else
        		printf "結果は0\n"
        end
        			# case 例2(範囲式)
        case x+y
        	when 1 .. 3
        		printf "結果は正\n"
        	when -3 .. -1
        		printf "結果は負\n"
        	else
        		printf "結果は0\n"
        end
        			# case 例3(配列)
        a = [1, 2, 3]
        b = [-3, -2, -1]
        case x+y
        	when *a
        		printf "結果は正\n"
        	when *b
        		printf "結果は負\n"
        	else
        		printf "結果は0\n"
        end
        			# case 例4( if による書き換え)
        z = x + y
        if z === 1 || z === 2 || z === 3
        	printf "結果は正\n"
        elseif z === -1 || z === -2 || z === -3
        	printf "結果は負\n"
        else
        	printf "結果は0\n"
        end
        					

    2. 繰り返し

      1. while 文
        while 式1 [do]
        	式2
        end
        					

      2. while 修飾子
        式1 while 式2
        					
          式2を評価した結果が真の間,式1を繰り返し実行します.以下は,そのプログラム例です.
        sleep(60) while io_not_ready?
        					
      3. until 文
        until 式1 [do]
        	式2
        end
        					
          式1を評価した結果が真になるまで,式2を繰り返して実行します.

      4. until 修飾子
        式1 until 式2
        					
          式2を評価した結果が真になるまで,式1を繰り返して実行します.

      5. for 文
        for ループ変数 in 式1 [do]
        	式2
        end
        					
          式1を評価した結果のオブジェクトの各要素に対して,式2を繰り返して実行します.プログラム例に示すように,複数のループ変数を指定することも可能です.
        for i in [1, 2, 3]
        	printf "%d ", i
        end
        printf "\n"
        			# 範囲式を利用
        for i in 1 .. 3
        	printf "%d ", i
        end
        printf "\n"
        			# 複数のループ変数
        for i, j in [[1, 2], [3, 4], [5, 6]]
        	printf "%d,%d ", i, j
        end
        printf "\n"
        					
        (出力)
        1 2 3
        1 2 3
        1,2 3,4 5,6
        					
      6. break 文
        break
        					
          もっとも内側のループを脱出します.使用方法に関しては,retry の項を参照して下さい.

      7. next 文
        next
        					
          もっとも内側のループの次の繰り返しにジャンプします.使用方法に関しては,retry の項を参照して下さい.

      8. redo 文
        redo
        					
          ループ条件のチェックを行なわず,現在の繰り返しをやり直します.使用方法に関しては,retry の項を参照して下さい.

      9. retry 文
        retry
        					
          イテレータ,ブロック,または,for 文の中で使われた場合には,そのイテレータを起動しなおします.イテレータの引数も再評価されます.retry を使うことである処理が成功するまで処理を繰り返すようなループを作ることができます.

          以下に示すのは,break,next,redo,及び,retry の違いを示したプログラム例とその出力結果です.
        printf "Example of break\n"
        for i in [1, 2, 3]
        	printf "   i(first) = %d\n", i
        	if i == 2
        		break
        	end
        	printf "   i(second) = %d\n", i
        end
        
        printf "Example of next\n"
        for i in [1, 2, 3]
        	printf "   i(first) = %d\n", i
        	if i == 2
        		next
        	end
        	printf "   i(second) = %d\n", i
        end
        
        printf "Example of redo\n"
        state = 0
        for i in [1, 2, 3]
        	printf "   i(first) = %d\n", i
        	if i == 2 && state == 0
        		state = 1
        		redo
        	end
        	printf "   i(second) = %d\n", i
        end
        
        printf "Example of retry\n"
        state = 0
        for i in [1, 2, 3]
        	printf "   i(first) = %d\n", i
        	if i == 2 && state == 0
        		state = 1
        		retry
        	end
        	printf "   i(second) = %d\n", i
        end
        					
        (出力)
        Example of break
           i(first) = 1
           i(second) = 1
           i(first) = 2
        Example of next
           i(first) = 1
           i(second) = 1
           i(first) = 2
           i(first) = 3
           i(second) = 3
        Example of redo
           i(first) = 1
           i(second) = 1
           i(first) = 2
           i(first) = 2
           i(second) = 2
           i(first) = 3
           i(second) = 3
        Example of retry
           i(first) = 1
           i(second) = 1
           i(first) = 2
           i(first) = 1
           i(second) = 1
           i(first) = 2
           i(second) = 2
           i(first) = 3
           i(second) = 3
        					

  6. 変数の有効範囲(スコープ)

    01	#***************************/
    02	# 変数の有効範囲(スコープ) */
    03	#      coded by Y.Suganuma */
    04	#***************************/
    05	
    06	#******************/
    07	# クラス Example1 */
    08	#******************/
    09	class Example1
    10		Const    = 1000;
    11		@@_class = 2000;
    12	
    13		def initialize
    14			@_pro = 3000;
    15		end
    16	
    17		def sub1()
    18			printf("sub1 Const %d @@_class %d @_pro %d\n", Const, @@_class, @_pro);
    19		end
    20	end
    21	
    22	#******************/
    23	# クラス Example2 */
    24	#******************/
    25	class Example2 < Example1
    26		public
    27			def sub2()
    28				printf("sub2 Const %d @@_class %d @_pro %d\n", Const, @@_class, @_pro);
    29			end
    30	
    31		attr_accessor("_pro");
    32	end
    33	
    34	#***********/
    35	# 関数 sub */
    36	#***********/
    37	def sub()   # この位置で定義する必要がある
    38		x = 40;
    39		printf("   sub x %d\n", x);
    40		printf("   sub z %d\n", $z);
    41	end
    42	
    43	#***************/
    44	# main program */
    45	#***************/
    46			# ブロック
    47	x  = 10;
    48	$z = 30;
    49	if x > 5
    50		printf("block x %d\n", x);
    51		x = 15;
    52		y = 20;
    53		printf("block x %d\n", x);
    54		printf("block y %d\n", y);
    55	else
    56		printf("block x %d\n", x);
    57		x = -15;
    58		printf("block x %d\n", x);
    59	end
    60	sub();
    61	printf("x %d\n", x);
    62	printf("y %d\n", y);   # 最初の x が 1 の時は,y が未定義のためエラー
    63			# クラス
    64	ex = Example2.new;
    65	ex.sub1();
    66	ex.sub2();
    67	printf("public member( Const ) %d\n", Example2::Const);
    68	printf("public member( @_pro ) %d\n", ex._pro);
    			
      まず,47 行目において,変数 x が定義され(変数 x に値が代入され),10 で初期設定されています.この変数 x は,この位置から main プログラムが終わる 68 行目まで有効になります.50 ~ 54 行目の if ブロック内の 50 行目において,変数 x の値が出力されていますが,当然,その結果は,47 行目で宣言されたときの値になります.しかし,51 行目において,再び,変数 x が宣言されていますが,Ruby の場合は,C++ の場合とは異なり,47 行目で宣言された変数 x に置き換わることになります.従って,ここで宣言された変数 x の有効範囲は,main プログラムの終わりである 68 行目までになります.実際,61 行目における出力文では,51 行目において宣言された変数 x の値が出力されます.同様に,52 行目で宣言された変数 y の有効範囲も 68 行目までとなります.この例では,問題がありませんが,47 行目における変数 x の初期値を 5 以下に設定すると,56 ~ 58 行目が実行されることになります.そのブロック内では,変数 y が使用されていませんので,62 行目の出力文はエラーになってしまいます.変数が定義されているか否か(変数に値が代入されているか否か)の見極めが困難である場合も多いと思いますので,十分注意してください.

      60 行目において関数 sub を呼んでいます.38 行目では,変数 x を宣言し,39 行目において,その値を出力しています.当然,38 行目の宣言を行わなければ,エラーになってしまいますし,また,38 行目の宣言によって,51 行目で宣言された x の値が影響を受けることはありません( 61 行目の出力文に対応する結果参照).しかし,変数 $z は関数 sub 内に宣言されておらず,main プログラムの 48 行目において宣言されています.このように,名前が $ で始まる変数はグローバル変数と呼ばれ,すべての関数等から参照が可能になります.逆に,変数 x や y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.以上,47 ~ 62 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block x 15
    block y 20
       sub x 40
       sub z 30
    x 15
    y 20
    				
      次に,クラスに付いて考えてみます.09 ~ 20 行目においてクラス Example1 が定義され,25 ~ 32 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.Ruby においては,クラス Example の各変数や関数のアクセス権は,そのままクラス Example2 に引き継がれます.

      64 行目において,Example2 のインスタンス ex を生成し,65 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しており,3 つの変数の値がそのまま出力されます.また,66 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.Ruby においては,大文字で始まる変数名は,定数とみなされ,クラスの外からも 67 行目のような形で参照可能です.また,@@ で始まるる変数名は,クラス変数と呼ばれ,クラス及びそのサブクラスで共通の値を持ちます.ただし,クラスの外からは,参照することはできません.さらに,@ で始まる変数は,インスタンス変数と呼ばれ,各インスタンス毎に異なる値を持つことができます.C++ における private 指定されたメンバー変数に似ています.そのため,そのままの状態では,クラスの外部から参照することはできません.しかし,31 行目のような指定( attr_accessor )を行うことによって,68 行目のような形でクラス外部から参照可能になります.以上,64 ~ 68 行目内の出力文によって,以下に示すような出力が得られます.
    sub1 Const 1000 @@_class 2000 @_pro 3000
    sub2 Const 1000 @@_class 2000 @_pro 3000
    public member( Const ) 1000
    public member( @_pro ) 3000
    				

  7. 使用方法

    1. コマンドラインとファイル

        Ruby インタプリタを起動するためには,以下のコマンドを入力します.
      ruby [ option ] [ programfile ] [ argument ]
      				
      ここで,
      option : インタプリータに対するオプション
      programfile : プログラムファイル
      argument : プログラムに対する引数
      				
      とします.これらを省略したり,`-' を指定した場合には,標準入力からプログラムが入力されるものとします.

        プログラムファイルの最初の行が `#!' で始まり,その行に `ruby' という文字列を含まない場合,OS に代わって `#!' に続く文字列をコマンドラインとみなしてそのインタプリタを起動します.例えば,以下のシェルスクリプトを ruby で実行すると sh を起動します.
      #!/bin/sh -vx
      				
        また,`ruby' という文字列が含まれる場合は,その文字列より左側は無視され,右側に `-' で始まる語があればインタプリータに対するオプションとして解釈します.例えば,以下の例においては,コマンドラインで -Ks オプション( Ruby の処理する文字コードが Shift JIS であることを指定した例)を指定した場合と同じ結果になります.
      #! ruby -Ks
      				
        また,
      irb
      				
      と入力することによって,ruby の式を標準入力から簡単に入力/実行できます.

    2. フォームと Ruby

      1. 一般的方法

          Ruby を CGI として利用する場合,その方法は,Perl などとほとんど同じです.まず,1 行目において,
        #!/usr/bin/ruby
        					
        のように,実行する Ruby プログラムの絶対パスを指定した後,Ruby のプログラムを書くことになります.Ruby のプログラムにおいては,送信されてきたデータを標準入力から入力し,結果を標準出力に出力することになります.出力を行う前に,
        "Content-type: text/html\n\n"
        "Content-type: text/plain\n\n"
        					
        などのように,出力結果に対する指定( HTTP header )を忘れないようにして下さい.

          ここでは,「フォームの例1」を例として,説明を行っていきます.「フォームの例1」においては,FORM 要素の中で,CGI プログラムとして test_gets.cgi を,また,送信フォームの MIME タイプ( ENCTYPE 属性)として text/plain を指定しています.test_gets.cgi の内容は以下に示す通りです.
        #!/usr/bin/ruby
        
        $KCODE = "SJIS"
        printf "Content-type: text/html\n\n"
        printf "<HTML>\n"
        printf "<HEAD>\n"
        printf "	<TITLE>CGIB の例</TITLE>\n"
        printf "	<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"../../master.css\">\n"
        printf "</HEAD>\n"
        printf "<BODY CLASS=\"white\">\n"
        while line = gets
        	printf "%s<BR>\n", line
        end
        printf "</BODY>\n"
        printf "</HTML>\n"
        					
          上記のプログラムは,組み込み関数 gets を利用して,標準入力から 1 行ずつ読み込み,それを標準出力へ出力しているだけです.チェックボックスにおいて「キャベツ」と「ジャガイモ」,また,リストにおいて「蜜柑」と「葡萄」を選択すると(以下の説明においても,常に,これらを選択するものとします).以下に示すような出力が得られます.
        name=菅沼 義昇 
        sex=Male 
        v1=on 
        v3=on 
        list=蜜柑 
        list=葡萄 
        					
      2. CGI クラスの利用

          一般的な方法に対する説明の項で述べたように,送信されてきたデータは,
        (NAME 属性で指定された)名前 = 値
        					
        という形をしています.そのため,これらのデータを利用するためには,「名前」や「値」の部分を取り出す必要があります.簡単な処理で可能ですが,PHP のように,「名前」を指定することによって「値」を得る方法があれば,より便利です.Ruby においても,以下に示す test.cgi のように,CGI クラスを利用することによって,このことが可能になります.
        #!/usr/bin/ruby
        
        $KCODE = "SJIS"
        printf "Content-type: text/html\n\n"
        printf "<HTML>\n"
        printf "<HEAD>\n"
        printf "	<TITLE>CGIB の例</TITLE>\n"
        printf "	<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"../../master.css\">\n"
        printf "</HEAD>\n"
        printf "<BODY CLASS=\"white\">\n"
        
        require "cgi"
        cgi = CGI.new
        p cgi
        printf "<BR>\n"
        p cgi['name']
        printf "<BR>\n"
        i = 0
        while i < 5
        	print cgi['list'][i], " "
        	i += 1
        end
        printf "<BR>\n"
        p cgi.params
        printf "<BR>\n"
        
        printf "</BODY>\n"
        printf "</HTML>\n"
        					
          「フォームの例2」においては,CGI として test.cgi を利用し,また,ENCTYPE 属性に対する指定を行っていません.このページに対して,先に述べた場合と同じ選択を行い,送信すると,以下に示すような結果が得られます.
        #["菅沼 義昇"], "list"=>["蜜柑", "葡萄"], "v1"=>["on"], "sex"=>["Male"], "v3"=>["on"]}, @cookies={}, @output_hidden=nil> 
        "菅沼 義昇" 
        蜜柑 葡萄 nil nil nil 
        {"name"=>["菅沼 義昇"], "list"=>["蜜柑", "葡萄"], "v1"=>["on"], "sex"=>["Male"], "v3"=>["on"]}
        					
          test.cgi においては,組み込み関数 require によって,CGI に関する拡張ライブラリをロードし,CGI クラスnew メソッドによって,CGI クラスのインスタンス cgi を生成しています.cgi には,上に示した出力結果からも明らかなように,送信されてきたデータに関する情報がすべて含まれています.その結果,cgi['name'] や cgi['list'][i] のように,「名前」を指定して「値」を得る(配列の添え字を指定してその値を得る)ことが可能になります.また,CGI クラスのメソッド params を利用して,ハッシュに変換することも可能です.

静岡理工科大学 菅沼ホーム Ruby 目次 索引