LoginSignup
9
9

More than 5 years have passed since last update.

Ruby で「モルダー、あなた疲れてるのよ」を出力したりしなかったりするクラスを作った

Last updated at Posted at 2016-03-31

動機

「Ruby で『モルダー、あなた疲れてるのよ』を出力したりしなかったりしたいなぁ」と思い悩んでいたところ、
Ruby でモルダー、あなた疲れてるのよを出力する方法 という素晴らしい記事に出会いました。ただ、もっと汎用的に「モルダー、あなた疲れてるのよ」を出力したりしなかったりしたいので、専用のクラスを作ってみました。

成果物

Enumerable で Mulderable な感じにしてみました。

class Mulder
  include Enumerable

  SCULLYS_WORDS = %w(モルダー あなた 疲れてる のよ).map(&:freeze).freeze
  SCULLYS_NATURAL_REMARK = SCULLYS_WORDS.dup.insert(1, '、').join.freeze

  def each(&block)
    @words ||=
      SCULLYS_WORDS
        .shuffle
        .each_slice(2)
        .map { |pair| join_capriciously(pair) }
        .flatten
        .insert(2, '、')

    @words.each(&block)
  end

  def to_s
    to_a.join
  end

  def natural?
    to_s == SCULLYS_NATURAL_REMARK
  end

  private

  def join_capriciously(pair)
    pair
      .map { |word| halve(word) }
      .flatten
      .tap { |words| break words.values_at(2, 1, 0, 3) if rand(2) == 0 }
  end

  def halve(word)
    word.chars.each_slice((word.size + 1) / 2).map(&:join)
  end
end

動作確認

loop.with_index(1) do |_, i|
  mulder = Mulder.new

  puts("#{i}: #{mulder}")
  break if mulder.natural?
end
1: あなた、モルダー疲れてるのよ
2: モルダー、あなたのてる疲れよ
3: あなた、モルダーのよ疲れてる
4: のよ、モルダーあなた疲れてる
5: あなてる、疲れたモルダーのよ
6: のよ、モルダーあなてる疲れた
7: 疲れてる、あなたモルよのダー
8: のよ、疲れてるモルダーあなた
9: 疲れよ、のてるモルダーあなた
10: 疲れてる、モルダーあなよのた
11: 疲れてる、あなたのダーモルよ
12: のた、あなよ疲れダーモルてる
13: 疲れダー、モルてるのたあなよ
14: あなよ、のた疲れダーモルてる
15: のてる、疲れよあなたモルダー
16: あなた、モルダー疲れてるのよ
17: モルてる、疲れダーあなよのた
18: あなよ、のたモルてる疲れダー
19: 疲れた、あなてるのダーモルよ
20: のよ、あなたモルダー疲れてる
21: 疲れダー、モルてるのたあなよ
22: 疲れよ、のてるモルダーあなた
23: のた、あなよモルダー疲れてる
24: あなダー、モルたのよ疲れてる
25: モルダー、のよ疲れてるあなた
26: モルよ、のダー疲れたあなてる
27: 疲れた、あなてるモルよのダー
28: モルダー、疲れてるのよあなた
29: あなた、のよ疲れダーモルてる
30: のよ、モルダーあなてる疲れた
31: あなた、モルダーのよ疲れてる
32: モルダー、のよあなてる疲れた
33: 疲れてる、あなたのダーモルよ
34: モルダー、のよあなた疲れてる
35: のよ、あなたモルダー疲れてる
36: あなてる、疲れたのダーモルよ
37: モルダー、疲れてるのよあなた
38: モルよ、のダーあなた疲れてる
39: モルダー、あなた疲れよのてる
40: あなた、疲れてるモルよのダー
41: モルよ、のダーあなた疲れてる
42: 疲れてる、モルダーのよあなた
43: のよ、あなた疲れダーモルてる
44: あなた、疲れてるモルよのダー
45: モルダー、あなた疲れてるのよ

また Enumerable を include しているので map などが使えます。to_a も自動で定義されます。

puts Mulder.new.map.with_index(1) { |word, i| "#{i}: #{word}" }.join("\n")
1: の
2: よ
3: 、
4: あな
5: た
6: モル
7: てる
8: 疲れ
9: ダー

参考

個人的な疑問

def each(&block)
  ### 略 ###

  @words.each(&block)
end

yield を使って書けないだろうか。

def each
  ### 略 ###

  @words.each { |word| yield(word) }
end

だと、ブロック無しで呼んだ場合に配列 @word を返してしまう。本当は Enumerator オブジェクトを返したい。

def each
  ### 略 ###

  if block_given?
    @words.each { |word| yield(word) }
  else
    @words.each
  end
end

と書くしかないのか。

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9