結論
先に結論を書いておくと、以下で言われてることと同じ内容だった。
忘れそうなのでメモとして残しておく。
発端
予め定義された配列を部分的に扱うために、Arrayを継承したHogeクラスを作成しようとした。
具体的には、
- Hogeクラスは予め定義された配列を持っている
- newすると予め定義された配列の部分配列を返す
- newするときにoptionとして、afterとlimitを渡せる
- after : 予め定義された配列の先頭要素
- limit : 返す部分配列の要素数
- nextで次の部分配列をlimit分返してくれる
作ったクラス
ざっと以下のような感じ。
class Hoge < Array
ATOE = ["a", "b", "c"]
DEFAULT_LIMIT = 3
DEFAULT_AFTER = 0
def initialize(options={})
limit = (options[:limit] && options[:limit] > 0) ? options[:limit] : DEFAULT_LIMIT
after = (options[:after] && options[:after] > 0) ? options[:after] : DEFAULT_AFTER
st = after
ed = after + limit - 1
super(ATOE[st..ed])
@limit = limit
@after = after
end
def next
options = { limit: @limit, after: @after + @limit }
Hoge.new(options)
end
end
見えない配列とnil
使ってみると不思議な現象に遭遇。
hoge = Hoge.new(limit: 1, after: 0)
hoge #=> ["a"]
hoge = hoge.next #=> ["b"]
hoge = hoge.next #=> ["c"]
hoge = hoge.next #=> []
hoge = hoge.next #=> `initialize': no implicit conversion from nil to integer (TypeError)
エラーはArray.new(nil)したらしい・・・。
しかしその前の空配列は何・・・?
Arrayで確認。ふぉー。
ary = []
ary[0..0] #=> []
ary[1..1] #=> nil
ary[0..1] #=> []
ary[1..2] #=> nil
ary = ["a"]
ary[1..1] #=> []
ary[2..2] #=> nil
ary[1..2] #=> []
ary[2..3] #=> nil
ggってみたところ、記事先頭のリンク先のように、謎の要素があるらしい。
なので、
super(ATOE[st..ed]||[])
にして解決。
ちなみに、[]はsliceの別名メソッドなので、slice使った場合も同様。