LoginSignup
6
6

More than 5 years have passed since last update.

Ruby: Enumerator::Lazy で URI生成

Posted at

末尾に「/page=n/」(n はページ番号)がつくような URI を生成したい場面の話です。

Enumerator::Lazy で URI生成

URI生成の簡単な例です。

sample1.rb
mk_uri_gen = -> n = 0 { -> { "http://hoge/hoge/page=#{n += 1}/" } }

ug = mk_uri_gen.()
p ug.()       #=> "http://hoge/hoge/page=1/"
p ug.()       #=> "http://hoge/hoge/page=2/"
p ug.()       #=> "http://hoge/hoge/page=3/"
  :

これは、Enumerator::Lazy の仕組みを使い以下のようにできます。

sample2.rb
ug = (1..Float::INFINITY).lazy.map{|n| "http://hoge/hoge/page=#{n}/" }

p ug.next     #=> "http://hoge/hoge/page=1/"
p ug.next     #=> "http://hoge/hoge/page=2/"
p ug.next     #=> "http://hoge/hoge/page=3/"
  :

Enumerator::Lazy を使う場合は rewind や take, each などが使えて便利です。

   :
p ug.next     #=> "http://hoge/hoge/page=4/"
p ug.next     #=> "http://hoge/hoge/page=5/"
ug.rewind  # 巻き戻し
p ug.next     #=> "http://hoge/hoge/page=1/"
p ug.next     #=> "http://hoge/hoge/page=2/"
   :
# 最初の5つ分の繰り返し
ug.take(5).each do |uri|
  p uri
end
# 無限の繰り返し (注)ずっと処理が続きます
ug.each do |uri|
  p uri
  gets      # ここで、キー押下待ちになります。処理をやめるときは Ctrl-C を押しましょう
end

URI テンプレートのパラメタ化

URI のテンプレートをパラメタとして渡せるようにしたいとします。

パーセント記法による書式文字列を渡す方法が考えられます。

sample3.rb
hoge = 'http://hoge/hoge/page=%{n}'

mk_uri_gen = -> tmpl { (1..Float::INFINITY).lazy.map {|n| tmpl % {n:n} } }

ug = mk_uri_gen.(hoge)
p ug.next    #=> "http://hoge/hoge/page=1/"
p ug.next    #=> "http://hoge/hoge/page=2/"
p ug.next    #=> "http://hoge/hoge/page=3/"
    :

固定文字列をパラメタにしたい場合は上のようになりますが、ラムダを渡す方がより柔軟に処理できます。

sample4.rb
          # 1ページ目以前には「/page=n/」をつけない URI を生成するラムダ
hoge = -> n { %(http://hoge/hoge/#{"page=#{n}/" if n > 1}) }

mk_uri_gen = -> tmpl { (1..Float::INFINITY).lazy.map(&tmpl) }

ug = mk_uri_gen.(hoge)
p ug.next    #=> "http://hoge/hoge/"
p ug.next    #=> "http://hoge/hoge/page=2/"
p ug.next    #=> "http://hoge/hoge/page=3/"
    :

Nokogiri::HTML::Document を返すジェネレータの例

sample5.rb
require 'open-uri'
require 'nokogiri'

hoge = -> n { %(http://hoge/hoge/#{"page=#{n}/" if n > 1}) }

conv       = -> uri { Nokogiri::HTML open uri }
mk_doc_gen = -> tmpl { (1..Float::INFINITY).lazy.map(&tmpl).map(&conv) }

dg = mk_doc_gen.(hoge)
                  # dg は Document を返すジェネレータ
dg.each do |doc|  # doc は URIが指定するページを読み込んだ Nokogiri::HTML::Document オブジェクト
  puts (doc/:title).map(&:text) * ' '

  gets   # キー押下待ち
end

おわりに

本稿内容の動作確認は以下の環境で行っています。

$ ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-linux]
$ gem list nokogiri

*** LOCAL GEMS ***

nokogiri (1.6.5)
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.1 LTS
Release:    14.04
Codename:   trusty

参考

6
6
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
6
6