これは…

いつまで続くかわからないシリーズである.

tl;dr どのクラスのどのメソッドにするのか 進め方 ということで, 第一回目 ガチャを回す Time#tv_sec とは Time#tv_sec の 学習テスト Time#utc_offset とは Time#utc_offset の学習テスト 以上 tl;dr かなり古い WEB+DB PRESS (2011 Vol.63) の連載 (Ruby わくわく...

inokara.hateblo.jp

学習テストの成果は以下のリポジトリで管理している.

ruby-gakushu-test - 学習テスト!, 学習テスト!, 学習テスト!

github.com

ということで

がちゃ

今日のメソッドガチャは以下の通り.

$ bundle exec ruby gacha.rb 
クラス: Enumerator
メソッド: peek
メソッド: rewind
メソッド: each_with_index

この中から Enumerator#peek と Enumerator#rewind 及び Enumerator#each_with_index について学習テストしていく.

Enumerator#peek

[[m:Enumerator#next]] のように現在までの列挙状態に応じて「次」のオブジェクトを返しますが、next と異なり列挙状態を変更しません。

docs.ruby-lang.org

以下, ドキュメントより引用.

「次」のオブジェクトを返しますが、列挙状態を変化させません。 Enumerator#next のように 現在までの列挙状態に応じて「次」のオブジェクトを返しますが、 next と異なり列挙状態を変更しません。 列挙が既に最後へ到達している場合は、StopIteration 例外を発生します。

irb で動作確認.

irb(main):009:0> a = [1, 2, 3]
=> [1, 2, 3]
irb(main):010:0> e = a.to_enum
=> #<Enumerator: [1, 2, 3]:each>
irb(main):011:0> e.peek
=> 1
irb(main):012:0> e.peek
=> 1
irb(main):013:0> e.peek
=> 1
irb(main):014:0> e.next
=> 1
irb(main):015:0> e.peek
=> 2
irb(main):016:0> e.peek
=> 2
irb(main):017:0> e.next
=> 2
irb(main):018:0> e.peek
=> 3
irb(main):019:0> e.peek
=> 3
irb(main):020:0> e.next
=> 3
irb(main):021:0> e.peek
Traceback (most recent call last):
...
StopIteration (iteration reached an end)
  • Enumerator#peek だけ実行しても, 「次」のオブジェクトは返さない (= Enumerator#next と異なり列挙状態は変更されない)
  • Enumerator#next と比較すると使いドコロが分からない…スイマセン

テストコード.

# file name: 8.rb
require 'minitest/autorun'
require "minitest/reporters"
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]

class GakushuTest < Minitest::Test
  def setup
    a = [1, 2, 3]
    @e = a.to_enum
  end

  def test_peek_1
    assert_equal @e.peek, 1
  end

  def test_peek_2
    @e.next
    assert_equal @e.peek, 2
  end

  def test_peek_3
    @e.next
    @e.next
    assert_equal @e.peek, 3
  end

  def test_peek_exception
    @e.next
    @e.next
    @e.next
    assert_raises StopIteration do
      @e.peek
    end
  end
end

テスト実行.

$ bundle exec ruby 08.rb 
Started with run options --seed 14812

GakushuTest
  test_peek_2                                                     PASS (0.00s)
  test_peek_1                                                     PASS (0.00s)
  test_peek_3                                                     PASS (0.00s)
  test_peek_exception                                             PASS (0.00s)

Finished in 0.00095s
4 tests, 4 assertions, 0 failures, 0 errors, 0 skips

Enumerator#rewind

next メソッドによる外部列挙の状態を最初まで巻き戻します。 self を返します。

docs.ruby-lang.org

以下, ドキュメントより引用.

列挙状態を巻き戻します。 next メソッドによる外部列挙の状態を最初まで巻き戻します。 self を返します。 内包するオブジェクトが rewind メソッドを持つとき(respond_to?(:rewind) に 真を返すとき) は、その rewind メソッドを呼び出します。

irb にて動作確認.

irb(main):001:0> a = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> e = a.to_enum
=> #<Enumerator: [1, 2, 3]:each>
irb(main):003:0> e.next
=> 1
irb(main):004:0> e.rewind
=> #<Enumerator: [1, 2, 3]:each>
irb(main):005:0> e.next
=> 1
irb(main):006:0> e.next
=> 2
irb(main):007:0> e.rewind
=> #<Enumerator: [1, 2, 3]:each>
irb(main):008:0> e.next
=> 1
  • Enumerable なオブジェクトにおいて, 列挙状態を巻き戻している
  • ざっくり言うと, next で進めたオブジェクトを最初に戻すメソッド…これも, 使いドコロがイマイチ解らない…スンマセン

テストコード. rewind すると, 1 に巻き戻ることを期待する.

# file name: 8.rb
require 'minitest/autorun'
require "minitest/reporters"
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]

class GakushuTest < Minitest::Test
  def setup
    a = [1, 2, 3]
    @e = a.to_enum
  end

  def test_rewind_1
    @e.next
    @e.next
    @e.rewind
    assert_equal @e.next, 1
  end

  def test_rewind_2
    @e.next
    @e.next
    @e.next
    @e.rewind
    assert_equal @e.next, 1
  end
end

テスト実行.

$ bundle exec ruby 08.rb 
Started with run options --seed 32833

GakushuTest
  test_rewind_1                                                   PASS (0.00s)
  test_rewind_2                                                   PASS (0.00s)

Finished in 0.00150s
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

Enumerator#each_with_index

each 以外のメソッドにも ] の機能を提供するためのラッパークラスです。また、外部イテレータとしても使えます。

docs.ruby-lang.org

以下, ドキュメントより引用.

要素とそのインデックスをブロックに渡して繰り返します。 self を返します。 ブロックを省略した場合は、 要素とそのインデックスを繰り返すような Enumerator を返します。

irb で動作確認.

irb(main):003:0> ['a', 'b', 'c'].each_with_index do |n, index|
irb(main):004:1*   p [n, index]
irb(main):005:1> end
["a", 0]
["b", 1]
["c", 2]
=> ["a", "b", "c"]

Enumerable なオブジェクトから要素とそのインデックスを返す. たまに使う.

テストは以下の通り. どんなテストを書けば良いのか思いつかなかったので, 以下のようなテストで. インデックスは 0 から始まる点に注意が必要だと思ったので.

# file name: 8.rb
require 'minitest/autorun'
require "minitest/reporters"
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]

class GakushuTest < Minitest::Test
  def setup
    a = [1, 2, 3]
    @e = a.to_enum
  end

  def test_each_with_index_1
    index = []
    @e.each_with_index do |n, idx|
      index << idx
    end
    assert_equal index, [0, 1, 2]
  end

  def test_each_with_index_2
    numbers = []
    @e.each_with_index do |n, idx|
      numbers << n
    end
    assert_equal numbers, [1, 2, 3]
  end

  def test_each_with_index_3
    assert_equal @e.each_with_index.class, Enumerator
  end
end

テスト実行.

$ bundle exec ruby 08.rb 
Started with run options --seed 32833

GakushuTest
  test_each_with_index_1                                          PASS (0.00s)
  test_each_with_index_2                                          PASS (0.00s)
  test_each_with_index_3                                          PASS (0.00s)

Finished in 0.00150s
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips

ブロックを省略した場合には, Enumerator クラスのオブジェクトを返すことも確認.

以上

知らないメソッドだらけで楽しくなってきた.

フムフム.

元記事はこちら

Ruby の組み込みライブラリ (クラス) の「学習テスト」を書いて, 出来るだけ多くのメソッドと出会いたい (2)