この気味悪いものを美しく
このFlickrのデータをどうすればいいのか ... うーん ... どう? このゴミの中のどこかに美しい写真があるのだから,絞り出すことにしよう。言い換えればJSONをパースしよう。app.rbの先頭に,以下の行を追加する。
require 'json'
これは最初にコピーしたjson.rbをロードする。これは単なるSystem::Json::JsonValueに対するモンキーパッチで,データへのアクセスを簡単にしてくれる。興味があるのなら,json.rbの該当部分はこれ。
require 'System.Json.dll' include System module System::Json class JsonValue def [](index) item = self.get_Item(index.to_clr_string) type = item.get_JsonType return item.to_string.to_s.to_f if type == JsonType.Number return item.to_string.to_s.split("\"").last if type == JsonType.String return System::Boolean.parse(item) if type == JsonType.Boolean item end def inspect to_string.to_s end end end
これはJsonValueに[]メソッドを追加して,foo = {'bar' : 'baz'}であるようなJSONの値にfoo['bar']とアクセスできるようにする。便利。それはともかく我々のコードに戻ろう。app.rbで,showメソッドを定義し直して,JSONをパースしてなんか役に立つことをするようにしよう。
def show @flickr = System::Json::JsonValue.parse(@response) render end def render @render = Render.new(@flickr, @options[:tags], @options[:page]) document.search_images[:innerHTML] = @render.generate_photos document.search_links[:innerHTML] = @render.generate_pages @render.hook_page_events('search_links') document.images_loading.style[:display] = "none" document.search_results.style[:display] = "block" end
showはFlickrのレスポンスに対してSystem::Json::JsonValue.parseを呼ぶだけになり,次にレンダリングを新しいクラスRender(あとで定義する)に委譲して,ロード中インジケータを止めるrenderという新しいメソッドを書いた。render.rbというファイルを作り,app.rbの中でrequireしよう。
require 'render'
render.rbを開き,写真のレンダリングにとりかかろう。
class Render def initialize(flickr, tags, current_page) @flickr = flickr @tags = tags @current_page = current_page end def generate_photos if @flickr['stat'] == "ok" && @flickr['photos']['total'].to_i > 0 tag(:div, :class => 'images') do @flickr['photos']['photo'].collect do |p| photo(p) end.join end else "No images found!" end end def photo(p) source = "http://farm#{p['farm'].to_i}.static.flickr.com/#{p['server']}/#{p['id']}_#{p['secret']}" thumb = "#{source}_s.jpg" img = "#{source}.jpg" tag(:div, :class => 'image') do tag(:a, :href => "#{img}") do tag(:img, :src => "#{thumb}") end end end def generate_pages "" end def hook_page_events(div) end private def tag(name, options, &block) output = "" output << "<#{name}" keyvalue = options.collect do |key, value| "#{key}=\"#{value}\"" end output << " #{keyvalue.join(" ")}" if keyvalue.size > 0 if block output << ">" output << yield output << "</#{name}>" else output << " />" end output end end
ちょっとばかりコードがあるが,tagの呼び出し以外は素直なものだ。プライベートメソッドのtagは,nameとoptionsに基づいてHTMLを生成すること以外の大半の仕事をする。HTMLをよりrubyらしく出力する(The private tag method does most of the work here, but generating HTML based on a name and options; it makes writing HTML more ruby-esk.)。またgenerate_pagesとhook_page_eventsが実装されていないことに気づいたことだろう。これらは今のところ実装できない。ブラウザをリロードして検索を行えば,イメージを取得できる。