ようへいの日々精進XP

よかろうもん

2018 年 06 月 04 日 (月)

ジョギング

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

なんだか

  • 頭の中がガチャガチャして集中出来ていない
  • 一旦, 色々とリセットしたい気分

今日のるびぃ ~ REx - Ruby Examination にチャレンジ (18) ~

REx - Ruby Examination の問題を自分なりにアレンジした上で 1 〜 3 問くらいずつ解いていく. 正直言ってかなり難しい. 尚, irb に動作確認環境は以下の通り.

$ ruby --version
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
$ irb --version
irb 0.9.6(09/06/30)

Enumerator オブジェクト

以下のコードの実行結果を得るために __(1)__ に適切なメソッドをすべて選ぶ.

# コード
module Enumerable
  def with_prefix(prefix)
    return to_enum(__(1)__, prefix) { size } unless block_given?

    each do |char|
      yield "#{prefix} #{char}"
    end
  end
end

[1, 2, 3, 4, 5].with_prefix('foobarbaz').reverse_each {|char|
  puts char
}

# 実行結果
foobarbaz 5
foobarbaz 4
foobarbaz 3
foobarbaz 2
foobarbaz 1

以下, irb による確認.

# :with_prefix
irb(main):001:0> module Enumerable
irb(main):002:1>   def with_prefix(prefix)
irb(main):003:2>     return to_enum(:with_prefix, prefix) { size } unless block_given?
irb(main):004:2> 
irb(main):005:2*     each do |char|
irb(main):006:3*       yield "#{prefix} #{char}"
irb(main):007:3>     end
irb(main):008:2>   end
irb(main):009:1> end
=> :with_prefix
irb(main):010:0> 
irb(main):011:0* [1, 2, 3, 4, 5].with_prefix('foobarbaz').reverse_each {|char|
irb(main):012:1*   puts char
irb(main):013:1> }
foobarbaz 5
foobarbaz 4
foobarbaz 3
foobarbaz 2
foobarbaz 1
=> #<Enumerator: [1, 2, 3, 4, 5]:with_prefix("foobarbaz")>
# __method__
irb(main):001:0> module Enumerable
irb(main):002:1>   def with_prefix(prefix)
irb(main):003:2>     return to_enum(__method__, prefix) { size } unless block_given?
irb(main):004:2> 
irb(main):005:2*     each do |char|
irb(main):006:3*       yield "#{prefix} #{char}"
irb(main):007:3>     end
irb(main):008:2>   end
irb(main):009:1> end
=> :with_prefix
irb(main):010:0> 
irb(main):011:0* [1, 2, 3, 4, 5].with_prefix('foobarbaz').reverse_each {|char|
irb(main):012:1*   puts char
irb(main):013:1> }
foobarbaz 5
foobarbaz 4
foobarbaz 3
foobarbaz 2
foobarbaz 1
=> #<Enumerator: [1, 2, 3, 4, 5]:with_prefix("foobarbaz")>

以下, 解説より抜粋.

  • ブロックを渡さない場合は, Enumerator オブジェクトを作成してメソッドをチェーン出来るようにする
  • Enumerator オブジェクトを作成するためには, to_enum または, enum_for を呼ぶ
  • これら (to_enum 又は enum_for) の引数にメソッド名をシンボルで指定して, チェーン先でブロックを渡されたときにどのメソッドを評価すればよいかが分かる
  • 設問では, with_prefix を再評価する必要があるので, __method__ または :with_prefix を引数に指定する
  • __method__ はメソッドの中で呼び出すと, そのメソッド名となる
irb(main):014:0> def foobarbaz
irb(main):015:1>   __method__
irb(main):016:1> end
=> :foobarbaz
irb(main):017:0> 
irb(main):018:0* p foobarbaz
:foobarbaz
=> :foobarbaz

protected

以下のコードを実行するとどうなるか.

class C
  protected
  def initialize
  end
end

p C.new.methods.include?(:initialize)

true が表示される

以下, irb にて確認.

irb(main):001:0> class C
irb(main):002:1>   protected
irb(main):003:1>   def initialize
irb(main):004:2>   end
irb(main):005:1> end
=> :initialize
irb(main):006:0> 
irb(main):007:0* p C.new.methods.include?(:initialize)
true
=> true

以下, メモ.

  • initialize メソッドは private メソッドである
  • protected に設定されたメソッドは, そのメソッドを持つオブジェクトが self であるコンテキスト(メソッド定義式やinstance_eval)でのみ呼び出せる
  • Object#methods は, そのオブジェクトに対して呼び出せるメソッド名の一覧を返す, このメソッドは public メソッドおよび protected メソッドの名前を返す

以下, initialize メソッドが private メソッドである確認.

irb(main):001:0> class C
irb(main):002:1>   def initialize
irb(main):003:2>   end
irb(main):004:1> end
=> :initialize
irb(main):005:0> 
irb(main):006:0* p C.new.methods.include?(:initialize)
false
=> false

ちなみに, initialize メソッドは, 可視性を public にすることは出来ないが, protected にすることは出来る.

irb(main):001:0> class C
irb(main):002:1>   public
irb(main):003:1>   def initialize
irb(main):004:2>   end
irb(main):005:1> end
=> :initialize
irb(main):006:0> p C.new.methods.include?(:initialize)
false
=> false
irb(main):007:0> class C
irb(main):008:1>   protected
irb(main):009:1>   def initialize
irb(main):010:2>   end
irb(main):011:1> end
=> :initialize
irb(main):012:0> p C.new.methods.include?(:initialize)
true
=> true

フムフム.