この気味悪いものを美しく

この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が実装されていないことに気づいたことだろう。これらは今のところ実装できない。ブラウザをリロードして検索を行えば,イメージを取得できる。