Ruby認定試験対策問題 解答・解説

問題こちらです

解答と解説 [印刷用]

1.実行環境

1.1.実行方法

  1. 正解は(2)「ruby test.rb」

    Rubyインタプリタであるrubyコマンドの起動は、以下の書式のコマンドライン により行います。

    ruby [オプション] [--] [Rubyスクリプトのファイル名] [引数]
  2. 正解は(3)「irb」

    Rubyを対話形式で実行するためのツールとして、irb(Interactive Ruby)が利 用できます。

  3. 正解は(3)「60」

    rubyコマンドのコマンドラインオプションとして、-eに続いてコードを指定できます。 -eを複数指定することもできます。

    例: -eを1つ指定して、「Hello World」を出力する。

    ruby -e 'puts("Hello World")'
    Hello World

    例: -eを複数指定し、1から10まで出力する。

    ruby -e '(1..10).each do |i|' -e 'puts(i)' -e 'end'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

1.2.コマンドラインオプション

  1. 正解は(3)「-d, --debug」
  2. 正解は(2)「スクリプト実行前に feature...」
  3. 正解は(1)「ruby -w - "Hello ...」
  4. 正解は(2)「Hello」 プログラム名、または「-」の後のコマンドライン引数は、ARGVとして参照できます。 ARGVは、指定された引数を文字列として格納した配列です。 C言語などと違い、ARGV[0]は1番目の引数です。 test.rbといったファイル名ではありません。

1.3.環境変数

  1. 正解は(4)「ENV」 OSの環境変数には、環境変数を表すオブジェクトであるENVを介してアクセスすることができます。 この変数はHashと同様に振舞います。

    例: 環境変数SHELLを参照する

    ENV["SHELL"]

    なお、ENVは実際にはHashではありませんが、ENV#to_hashメソッドを使用してHashに変換できます。

  2. 正解は(2)「Rubyライブラリの探索パス$:の...」
  3. 正解は(1)「screen」 Rubyプログラムでは、次のようにKernel#forkメソッドなどを使用して、子プ ロセスを作成することができます。

    fork do
      子プロセスの処理
    end

    ENVの操作による環境変数の変更が影響するのは、そのRubyプログラムを作成 したプロセス、およびそのプロセスの子プロセスだけですので、問題のプログ ラムを実行すると次のような動作になります。

    ENV["TERM"] = "screen" # => 親プロセスの環境変数TERMを"screen"に変更する。
    fork do
      # 子プロセスなので、親プロセスの環境変数TERMを引き継ぐ。
      # ここでは環境変数TERMは"screen"。
      ENV["TERM"] = "ansi" # => 子プロセスの環境変数TERMを"ansi"に変更する。
      fork do
        # 孫プロセスなので、子プロセスの環境変数TERMを引き継ぐ。
        # ここでは環境変数TERMは"ansi"。
        ENV["TERM"] = "xterm" #=> 孫プロセスの環境変数TERMを"xterm"に変更する。
      end
      Process.wait
    end
    Process.wait
    # 子や孫プロセスでの環境変数の変更の影響は受けないため、
    # 環境変数TERMを"screen"のまま。
    puts(ENV["TERM"]) #=> 「screen」を出力する。

1.4.Irb

  1. 正解は(1)「Rubyの式を標準入力から簡単に入...」
  2. 正解は(2)「irbを起動後、"irb/comp...」

    回答1について

    「conf.use_prompt = true/false」は、プロンプト表示するかどうかの設定です。 デフォルトはプロンプトを表示します。つまり、「conf.use_prompt = true」。

    回答2について

    irbの設定ファイル(~/.irbrcなど)に次の設定を行うことでも、 補完入力機能を有効にできます。

    require "irb/completion"

    回答3について

    「IRB.conf[:ECHO]」は、実行結果を表示するかどうかの設定です。 この設定値がfalse以外の場合、実行結果を表示します。 デフォルトは実行結果を表示します。「IRB.conf[:ECHO] = nil」です。

    IRB.conf[:ECHO]の値を設定する以外に、irbのコマンドラインオプションとし て、--echoや--noechoを指定することにより、それぞれ実行結果を表示する/ しないを設定できます。

    回答4について

    --readlineコマンドラインオプションを指定すると、readlineライブラリを利 用します。

  3. 正解は(3)「10」

    irbは入力された文を直ちに実行します。 最初の「eval "var = 10"」を入力した時に、ローカル変数としてvarが作られます。 そのため、次の「var」は、ローカル変数varの参照として正しく認識されます。

    なお、irbで次のように入力すると、Rubyインタプリタと同様な動作をします。

    $ irb
    irb(main):001:0> eval "var = 10"; var
    NameError: undefined local variable or method `var' for main:Object
            from (irb):1
  4. 正解は(1)「10」

    サブirbコマンドのローカル変数はそれぞれ別のものとして認識されます。

2.文法

2.1.コメント

  1. 正解は(4)「た行を表示するプログラム」

    =begin =endはかならず行頭に書く必要があります。

  2. 正解は(1)「解答1」

    正規表現のコメントは(?#なんとか)です。

  3. 正解は(3)「配列に分割される」

    リテラルの問題な気がしますが、文字列リテラル中に#を含む事が可能です。文字列リテラル中の#はコメントとして解釈されません。

2.2.リテラル

  1. 正解は(4)「2」

    リテラルの定義 "数字の1や文字列"hello world"のようにRubyのプログラムの中に直接記述できる値"

  2. 正解は(4)「解答4」

    .を改行にマッチさせる正規表現リテラルを書くためには最後にmを付ける

  3. 正解は(4)「解答4」

    object_idが同じことから想像がつく。「name」という文字列情報の表現 'name',:nameのいずれも"name"というも文字列の情報を表している.違いは文字列は表記した個数だけのオブジェクトが存在するのに対して,シンボルは何度でどこで表記しても全て同一のオブジェクトを示すという点である.

2.3.変数/定数とスコープ

  1. 正解は(2)「example」

    ローカル変数は、英語の小文字またはアンダースコアで始まる。 それ以外の文字で始まる変数は、ローカル変数ではない。

  2. 正解は(1)「200 が出力される」

    ifやcaseなどの制御構文は、スコープを作らない(イテレータ などのブロックはスコープを作る)。 本問題では、if文の条件は成立しているため、val2はそのまま 200が代入され、if文の外側でもそのまま参照可能。

  3. 正解は(3)「親クラスを継承したサブクラスのインスタンスからは、親クラスのクラス変数を参照・代入できない」 クラス変数は、継承関係にあるサブクラスからならば、親クラス のクラス変数を参照・代入可能。
  4. 正解は(3)「定義されていない定数を参照すると、nilを返す。」 未定義定数を参照すると、「uninitialized constant」のエラー になり、nilは返らない。 既に値が入っている定数への代入は、 「warning: already initialized constant」 の警告は出るが、デフォルトではエラーにはならない。

2.4.演算子

  1. 正解は(1)「C行, D行がエラーとなった。」

    Float には、<< 演算子が定義されていません。 また、Integer型に、<< 演算子の引数として、浮動小数点を渡しても、引数は自動的にInteger型に変換され、正しく処理されます。

  2. 正解は(2)「85.0」

    Integer型同士の演算の場合は、実行結果もInteger型となります。また、演算子の優先順位は、+ - よりも、* / の方が上です。

  3. 正解は(3)「def +=(value) ... end」

    「def `(arg) ... end」はバッククォート記法(`arg`)の定義です。 「def -(other) ... end」は二項演算子(obj - other)の定義です。 「def -@ ... end」は単項マイナス演算子(-obj)の定義です。 また、自己代入演算子(+=)は再定義する事ができません。

2.5.条件分岐

  1. 正解は(4) Aは 「unless」, Bは 「>」が入る。
    1. x == y が真の場合、"xはyより大きいです。"と出力されるので、間違い。
    2. x > y が真の場合、"xはyより大きくないです。"と出力されるので、間違い。
    3. x < y が真の場合、"xはyより大きいです。"と出力されるので、間違い。いかなる数値x, yであっても例のような正しい出力が得られるのは、(4)のみ。
  2. 正解は(3) Aは「case」, Bは「when」が入る。

    Rubyに switch文はないので、(1), (2)は不正解。Rubyに when文はないので、(4)は不正解。よって、(3)が正解になる。

  3. 正解は(1)「"syntax error" と出力される。」

    Rubyでは、"else if"という書き方を許していない。正しくは、"elsif"

2.6.ループ

  1. 正解は(1)「45と表示される。」

    iに代入される数値は、順に、

    0, 1, 2, 3, 4, 5, 6, 7, 8, 9

    よって、答えは45となる。

  2. 正解は(3)「11回」

    until i < 0 の文は、i が 0 の時も「偽」となり、method_a()が呼び出されることに注意。

  3. 正解は(1)「each, loop 共にメソッドである。」

    loopがメソッドであることは見落としやすいので注意。

2.7.例外処理

  1. 正解は(1) rescue
  2. 正解は(4) error 1.

    raise "メッセージ" は RuntimeError を発生させるメソッドです。したがって、処理は rescue 節に移り $! を出力します。$! には、最初に発生した例外がセットされているので、このプログラムの実行結果は error 1. となります。

  3. 正解は(3) RuntimeError--end--

    raise "メッセージ"は RuntimeError を発生させるメソッドです。したがって、処理は rescue 節に移り例外の種類(RuntimeError)が出力されます。ensure 節は、begin 〜 end で囲まれた部分から抜ける場合には必ず実行されるため、exit メソッドでプログラムは終了ステータスに入っていますが、最後に --end-- が出力されます。出力は print メソッドで行っているため、実行結果には改行が含まれず RuntimeError--end-- となります。

2.8.メソッド呼び出し

  1. 正解は(1) (2) (3) (4)

    すべて正解です。

    1. Procのインスタンスを作ってそれをRangeのeachメソッドのブロックとして渡している.
    2. 5から9-1までのRangeオブジェクトを作ってfor文で繰返している.
    3. ブロック付きメソッド呼び出しでto_procが呼ばれることを使っている.
    4. 自明.
  2. 正解は(1) nil

    answer メソッドの return の引数が省略されているため nil が返されます。したがって、puts Entyuu.new(2, 3).answer の出力結果は nil となります。

2.9.ブロック

  1. 正解は(3)
    1. 直接参照することはできない.
    2. Procオブジェクトに変換された場合は生き続ける.
    3. ブロックパラメーターはyieldの引数を代入したもの.
    4. 渡すことができる.
  2. 正解は(3)

    ブロックはメソッドの呼出し先のselfを継承します.

  3. 正解は(1)

    ブロックには変数をシャドーウィングする機能がないため

2.10.メソッド定義

  1. 正解は(3)

    3は制御構造である. 3以外はメソッドなので再定義できる.

  2. 正解は(3)

    foo()とすることでメソッド呼び出しと解釈される. 最初のdef fooはインスタンスメソッドの定義であり,def self.fooはトップレベルmainオブジェクトの特異メソッドとして定義される. メソッド呼び出しでは特異メソッドが優先されるため,3になる.

  3. 正解は(4)

    一番目の引数にはデフォルト値がついていないので,省略できない.

2.11.クラス定義

  1. 正解は(4)「クラス定義の中に、別のクラス定義を記述することはできない。」

    クラス定義内に別のクラス定義を記述することは可能なので、(4)の回答は誤り。

  2. 正解は(2)「bar が出力される」

    クラスを定義した後で、同名のクラスを再定義した場合、 最初の定義に後から再定義した内容が追加される。 本問題の例では、最初に定義したbarメソッドはそのまま Fooクラスに残るので、使用可能。

  3. 正解は(2)「<<」

    本問題では、オブジェクトstrに対してfooメソッドを追加 しているので、空白箇所の行では、特異メソッドの定義を 行っていることになる。 特異メソッド定義は“class”構文に「<< オブジェクト」 を加えて宣言する。

2.12.モジュール定義

  1. 正解は(3)「モジュール定義内に別のモジュール定義を記述するには「expand モジュール名」と記述する。」

    モジュール定義内に別のモジュールをネストして定義する場合は、 通常のモジュール定義と同じ「module モジュール名」構文で定義 する。

  2. 正解は(1)「baz が出力される。」

    モジュールを定義後、同名のモジュールを再定義し、既に 定義済みのメソッドを定義すると、メソッドの内容は上書 きされる。

  3. 正解は(4)「何も出力されない。」

    initializeメソッドが特別な意味を持つのは、クラス定義 のみで、モジュールでは特別な意味は無い。 単にincludeしただけでは、何も起きない。

3.組み込みライブラリ

3.1.組み込み関数

  1. 正解は(2)「hello, <改行>ruby!」

    Rubyリファレンスマニュアル組み込み関数::exec より、exec(command)は「command で指定されたコマンドを実行し ます。プロセスの実行コードはそのコマンド(あるいは shell。後述)にな るので、起動に成功した場合、この関数からは戻りません。」 上記のように動作するため、puts("world!")が実行される事はありません。

  2. 正解は(1) 「SyntaxErrorが発生する」

    組み込み関数randの引数を省略した場合、0以上1未満の実数値を返します。 そのため、rand()の実行結果から、「パー」が表示されそうです。ただし、 case文は「{}」を使用できる文法ではないため、SyntaxErrorが発生しま す。

  3. 正解は(3) 「例外ではないクラスやオブジェクトを第一引数に指定した場合、実際に発生する例外は全てRuntimeErrorになります。」

    Rubyリファレンスマニュアル組み込み関数::raise より、「例外ではないクラスやオブジェクトを第一引数に指定した場合、 実際に発生する例外はそのオブジェクトの exception メソッドが返す値 になります。」

3.2.組み込みクラス

  1. 正解は(4)「invertメソッドはキーから値へのハッシュを返します。」

    invertメソッドは「値」から「キー」のハッシュを返します。

  2. 正解は(1)「puts ruby_recipe_book.price」

    priceに2800、publisherに"ソフトバンククリエイティブ"を指定して、 Book構造体を生成します。priceメソッドを参照する事で2800を取得でき ます。

  3. 正解は(1)「(A)が4、(B)がnil、(C)が5」

    ary[nth]では、配列aryのnth番目の要素を返します。先頭の要素が0番目 になります。nthの値が負の時には末尾からのインデックスと見倣します (末尾の要素が-1 番目)。nth 番目の要素が存在しない時には nil を返し ます。

  4. 正解は(3)「python<改行>python<改行>ruby」

    「if line =~ /python/ .. line =~ /ruby/」などのような条件式中の範 囲式は特別な動きをします。この場合、最初にlineがpythonにマッチして から、次にlineがrubyにマッチするまでの間、常に真となります。

    詳しくは、Rubyリファレンスマニュアルの「Rubyで使われる記号の意味」 をご覧ください。

4.オブジェクト指向

4.1.ポリモルフィズム

  1. 正解は(4)「to_s」

    printメソッドは,文字列でないオブジェクトはto_sを呼ぶなどして文字列化した結果を出力するためである.

  2. 正解は(1)「width.to_i * height.to_i」

    atoi,atofといったメソッドは標準では存在しない. よって(2)と(4)は×である. 出力結果は整数値が出ているため,(3)は×である.

  3. 正解は(2)「引数の数と名前が一致するメソッドを用意する.」と(3)「既存のクラスに対しても特異メソッド定義を行うことで対応できる.」

4.2.継承

  1. 正解は(3)「NoMethodError例外が発生する」

    クラスBarはクラスFooと継承による親子関係に無く、クラスBarからクラスFoo のメソッドをアクセスすることはできない.

  2. 正解は(4)「ArgumentError例外が投げられる」

    クラスBarのfooメソッドでは、superで親クラスFooのfooメソッドを実行して いるが、superで親クラスの同名メソッドをコールする場合、引数の数は一致 していなければならない.

  3. 正解は(4)「true が表示される」

    クラスBazはクラスFooを継承しており、クラスBazのインスタンスに、is_a? メソッドでクラスFooへの所属関係を問えば、trueが返される.

4.3.mix-in

  1. 正解は(1)「foo」と出力される

    RubyリファレンスマニュアルFAQ::メソッドより,「特異メソッド、自クラスで定義されたメソッド、スーパークラス(Mix-inされたモジュールを含む。クラス名.ancestorsで表示される。)で定義されたメソッドの順に最初に見つかったメソッドが実行されます。」

    includeを後に書いても自クラスで定義されたメソッドが優先されるため,(1)になります.

  2. 正解は(2)「Bar.foo」

    RubyリファレンスマニュアルObjectより,extendは「引数で指定したモジュールのインスタンスメソッドを self の特異メソッドとして追加します。」

    この場合は,Barクラスでextend Fooと書くことによってBarクラスオブジェクトの特異メソッド(Barクラスのクラスメソッド)として,fooが追加されました. そのため,(2)になります.

  3. 正解は(2)「Bazが出力される」

    Bazクラスは,自クラスのメソッドとしてinitializeメソッドが定義してあります. また,superによる呼び出しをしていないためFizz#initializeは呼ばれません. そのため,Baz.newの時点で生成したオブジェクトの@barは"Baz"になります.

    Bazクラスは,FooモジュールをincludeしたFizzクラスを継承しています. そのため,.fooの呼び出しでFoo#fooが呼ばれ,Bazが出力されます.