QA@IT
«回答へ戻る

「直列に処理されない」というのがちょっとよくない表現でした

142
 
 > * なぜ SimpleDelegator を継承したクラスの `method_missing` で `NoMethodError` を補足しているのに例外が発生するのか?
 
-これは、rescue(begin-rescue-end)は直列に処理されないので、このようにrescue節内でふたたびrescueしてやればいいです。
+これは、begin - rescue - end の形とするとbeginからrescueの間の例外しか捕捉されないので、このようにrescue節内でふたたびrescueしてやればいいです。
 
 ```ruby
   def method_missing(method, *args)
  • なぜ OpenStruct でラップしたオブジェクトが知らないメソッドを呼び出すと NoMethodError 例外が発生するのか?
    • そもそも OpenStruct でラップしたオブジェクトに直接 env.unknown_environment_variable などとすると nil が返るので、それをそのまま返して欲しいのにそうならないのは何故か?

OpenStructのインスタンスは、知らないメソッドを呼ばれるとnilを返しますが、respond_to?にはfalseを返します。
そして、Delegatorは委譲先のメソッドを呼び出す前にまずrespond_to?を呼び、それがtrueであることを確認してからメソッドを呼ぶようになっています。もしfalseの場合はsuperするので、BasicObjectにないメソッドの場合はそこでNoMethodError例外となる、というわけです。

ですから、OpenStructのnilをそのまま返してほしいのであれば、OpenStructのrespond_to?をオーバーライドする必要があります。
しかし、それでは「小文字がないとき大文字」の処理ができなくなるので、method_missingをオーバーライドするという方針でいいと思います。

  • なぜ SimpleDelegator を継承したクラスの method_missingNoMethodError を補足しているのに例外が発生するのか?

これは、begin - rescue - end の形とするとbeginからrescueの間の例外しか捕捉されないので、このようにrescue節内でふたたびrescueしてやればいいです。

  def method_missing(method, *args)
    super
  rescue NoMethodError
    begin
      super(method.upcase, *args)
    rescue NoMethodError
      nil
    end
  end
> * なぜ OpenStruct でラップしたオブジェクトが知らないメソッドを呼び出すと `NoMethodError` 例外が発生するのか?
>    - そもそも OpenStruct でラップしたオブジェクトに直接 `env.unknown_environment_variable` などとすると `nil` が返るので、それをそのまま返して欲しいのにそうならないのは何故か?

OpenStructのインスタンスは、知らないメソッドを呼ばれるとnilを返しますが、`respond_to?`にはfalseを返します。
そして、Delegatorは委譲先のメソッドを呼び出す前にまず`respond_to?`を呼び、それがtrueであることを確認してからメソッドを呼ぶようになっています。もしfalseの場合はsuperするので、BasicObjectにないメソッドの場合はそこで`NoMethodError`例外となる、というわけです。

ですから、OpenStructのnilをそのまま返してほしいのであれば、OpenStructの`respond_to?`をオーバーライドする必要があります。
しかし、それでは「小文字がないとき大文字」の処理ができなくなるので、`method_missing`をオーバーライドするという方針でいいと思います。

> * なぜ SimpleDelegator を継承したクラスの `method_missing` で `NoMethodError` を補足しているのに例外が発生するのか?

これは、begin - rescue - end の形とするとbeginからrescueの間の例外しか捕捉されないので、このようにrescue節内でふたたびrescueしてやればいいです。

```ruby
  def method_missing(method, *args)
    super
  rescue NoMethodError
    begin
      super(method.upcase, *args)
    rescue NoMethodError
      nil
    end
  end
```

回答を投稿

  • なぜ OpenStruct でラップしたオブジェクトが知らないメソッドを呼び出すと NoMethodError 例外が発生するのか?
    • そもそも OpenStruct でラップしたオブジェクトに直接 env.unknown_environment_variable などとすると nil が返るので、それをそのまま返して欲しいのにそうならないのは何故か?

OpenStructのインスタンスは、知らないメソッドを呼ばれるとnilを返しますが、respond_to?にはfalseを返します。
そして、Delegatorは委譲先のメソッドを呼び出す前にまずrespond_to?を呼び、それがtrueであることを確認してからメソッドを呼ぶようになっています。もしfalseの場合はsuperするので、BasicObjectにないメソッドの場合はそこでNoMethodError例外となる、というわけです。

ですから、OpenStructのnilをそのまま返してほしいのであれば、OpenStructのrespond_to?をオーバーライドする必要があります。
しかし、それでは「小文字がないとき大文字」の処理ができなくなるので、method_missingをオーバーライドするという方針でいいと思います。

  • なぜ SimpleDelegator を継承したクラスの method_missingNoMethodError を補足しているのに例外が発生するのか?

これは、rescue(begin-rescue-end)は直列に処理されないので、このようにrescue節内でふたたびrescueしてやればいいです。

  def method_missing(method, *args)
    super
  rescue NoMethodError
    begin
      super(method.upcase, *args)
    rescue NoMethodError
      nil
    end
  end
> * なぜ OpenStruct でラップしたオブジェクトが知らないメソッドを呼び出すと `NoMethodError` 例外が発生するのか?
>    - そもそも OpenStruct でラップしたオブジェクトに直接 `env.unknown_environment_variable` などとすると `nil` が返るので、それをそのまま返して欲しいのにそうならないのは何故か?

OpenStructのインスタンスは、知らないメソッドを呼ばれるとnilを返しますが、`respond_to?`にはfalseを返します。
そして、Delegatorは委譲先のメソッドを呼び出す前にまず`respond_to?`を呼び、それがtrueであることを確認してからメソッドを呼ぶようになっています。もしfalseの場合はsuperするので、BasicObjectにないメソッドの場合はそこで`NoMethodError`例外となる、というわけです。

ですから、OpenStructのnilをそのまま返してほしいのであれば、OpenStructの`respond_to?`をオーバーライドする必要があります。
しかし、それでは「小文字がないとき大文字」の処理ができなくなるので、`method_missing`をオーバーライドするという方針でいいと思います。

> * なぜ SimpleDelegator を継承したクラスの `method_missing` で `NoMethodError` を補足しているのに例外が発生するのか?

これは、rescue(begin-rescue-end)は直列に処理されないので、このようにrescue節内でふたたびrescueしてやればいいです。

```ruby
  def method_missing(method, *args)
    super
  rescue NoMethodError
    begin
      super(method.upcase, *args)
    rescue NoMethodError
      nil
    end
  end
```