REx模擬試験誤答一覧 その5

82点。 徐々に点数も安定してきた。

問5: class M::C

ここに質問を投げてみた。

Ruby - class A::Bとクラス定義を行ったとき、クラスBはクラスAのネストの中にあると考えて良いのか。|teratail

結論は

  • コンパクト記法class A::Bでクラスを指定しても、定義はあくまで「トップレベル」で行われているということ (回答していただいた方はコンパクト記法のことを『名前空間の修飾関係』と呼んでいる。)

  • 宣言時のネスト関係を「名前空間の修飾関係」によって再オープンすることが出来るが新しい名前空間の宣言にはなっていない。

問7: 実行オプション-l

実行オプション-lはload_file で、require, loadがなされたときに探し出すディレクトリを指定する。Rubyはこのディレクトリを4か所から探し出し、load_fileで指定するのは、定数$LOAD_PATHにセットされる最初に探し出す場所。

ここになかった場合、環境変数RUBYLIBディレクトリを見に行く。

問27: クラス変数のスコープ

class C
  class << self
    @@val = 10
  end
end

p C.class_variable_get(:@@val)

この問題に関して勘違いしていることがあって、クラス変数のスコープに関しては厳然としたルールが定まっていた。

クラス変数は、その場所を囲むもっとも内側の(特異クラスでない) class 式または module 式のボディをスコープとして持ちます。

変数と定数 (Ruby 2.6.0 リファレンスマニュアル)

つまり、特異クラス(メタクラス)をクラス定義内で定義した場合には参照可能だが、外側で定義した場合は参照不可能という変わった状態が発生しうる。

class Foo
  @@foo = 'Class Variable'
  class << Foo
    def class_method_a
      @@foo
    end
  end
  def bar
    puts @@foo
  end
end

class << Foo
  def class_method_b
    @@foo
  end
end

p Foo.class_method_a # "Class Variable"
p Foo.class_method_b # scope.rb:15:in `class_method_b': uninitialized class variable @@foo in Object (NameError)

では、外側の特異クラスでクラス変数を再定義した場合はどうか。

class Foo
  @@foo = 'Class Variable'
  class << Foo
    def class_method_a
      @@foo
    end
  end
  def bar
    puts @@foo
  end
end

class << Foo
  @@foo = 'class_variable redefine'
  def class_method_b
    @@foo
  end
end

p Foo.class_method_a # "class_variable redefine"
p Foo.class_method_b # "class_variable redefine"

クラス定義内と特異クラスの定義内で同じ変数を共有していることがわかる。

問29: alias

aliasの設定のとき、リテラルORシンボルで定義するのは合っているが,で区切る必要はない。 ただし、メソッド定義内でaliasを設定するときは、alias_methodを用い「文字列かシンボル」で指定し、,で名前を区切る必要がある。

問36: インスタンス変数のプロパティの設定

インスタンス変数をinitializeメソッドで定義しなくても、attr_accessor(およびreader, writer)をセットすればインスタンス変数として値を保持してくれる。書き込みの際に変数を初期化して、以降インスタンス変数として使えるということのようだ。

class Module (Ruby 2.6.0 リファレンスマニュアル)

問50: YAML to json

YAMLjsonはそれぞれ読み込み用(format -> Hash)のメソッドが

YAML.load(str/io)
JSON.load(str)
JSON.parse(str)

YAMLはioオブジェクトも引数に指定できるのに対して、jsonはそれが出来ない。

それぞれの出力用のメソッドは

YMAL.dump(obj)
JSON.dump(obj)
obj.to_json # Stringクラスのメソッド

となっている。出力はどちらもdumpが使える。YAMLに関してはloadのほかに、自分で普段使っているparseが使える点に注意。

CSVはこの2つとはやや異なる取り扱いをする。

読み書きの選択はCSVファイルをオープンした後、オプションで選択する。

CSV.open(filename, mode = 'r', opritons = {}){|csv| ... }
CSV.open(fielname, mode = 'w' options= {}){  |csv| ... } 

一方読み込み専用のメソッドも存在する。

CSV.read(filename)
CSV.readlines(filename)