動機
「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: ダー
参考
-
Ruby でモルダー、あなた疲れてるのよを出力する方法
- リスペクト元です
-
The X-Files - Wikipedia, the free encyclopedia
- 「スカリー」のスペルを調べるためだけにアクセスしました
個人的な疑問
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
と書くしかないのか。