TDD ã§ä½ã RakuAPI ã©ã¤ãã©ãª
RakuAPI - 楽天å¸å ´ éå
¬å¼ã¦ã§ããµã¼ãã¹
ã¨ãã楽天ã®éå
¬å¼ API ã®ã©ã¤ãã©ãªãä½ãã®ãæµè¡ã¿ãããªã®ã§ä½ã£ã¦ã¿ã¾ããããã ããã ãã§ã¯é¢ç½ããªãã®ã§ãæè¿èªåã TDD ã§ã©ã¤ãã©ãªä½ãã¨ãã®æ¹æ³ã軽ããç´¹ä»ãã¾ãã
ã¾ãã¯ã¤ã³ã¿ã¼ãã§ã¤ã¹ã®æ§æ³
ä½ã¯ã¨ããããã©ããªã¤ã³ã¿ã¼ãã§ã¤ã¹ãå®ç¾©ãã¦ãã©ããªçµæãè¿ã£ã¦ããã®ããã¤ã¡ã¼ã¸ã§ããªãã¨ã©ã¤ãã©ãªã¯ä½ãã«ããã§ããã¨ããããã§ãã£ããæåã«æ§æ³ãç·´ãã¾ãã
RakuAPI ã®å ´å㯠WebAPI ãã·ã³ãã«ã«ä½¿ãã¦è¯ãæããªã®ã§ãæ§æ³ãç·´ãã®ã«èãè¾¼ããã¨ããã®ã¯ããã¾ããã§ããã
ãããªãã§ãRakuAPI.new ã§ã¤ã³ã¹ã¿ã³ã¹ãåå¾ãã¦ãsearch ã¡ã½ããã§ç¬¬ä¸å¼æ°ã«æ¤ç´¢æååã第äºå¼æ°ã¯ãªãã·ã§ã³ã§ã¸ã£ã³ã«ããã©ã¤ã¹ã渡ããããã«ãçµæã¯é
åã«Struct ãæ ¼ç´ããã¦ãæãã«ããããã¨èãã¾ããã
ãã¹ããæ¸ã
æ§æ³ãããã°ããã«æ²¿ã£ã¦æ¸ãã ãã§ãã®ã§è¶ ç°¡åãsearch ã¡ã½ããã§æ¤ç´¢ããçµæãæ§é ä½ã§ä¸èº«ã®ã¡ã³ãã¯äºã ãã¨ããã®ãæ¸ãã ãã§ãããã¡ãªã¿ã«ãã¤ããããªæãã®ãã£ã¬ã¯ããª/ãã¡ã¤ã«æ§æã§ãã£ã¦ã¾ãã
RakuAPI |-- lib | `-- raku_api.rb `-- test `-- test_rakuapi.rb
ãããæ©é test æ¸ãã¾ãããxUnit äºæã® Test::Unit ã使ãã¾ãã
# ä¸ã®é層㮠lib ãã£ã¬ã¯ããªãã©ã¤ãã©ãªãã¹ã«è¿½å $LOAD_PATH << File.dirname(__FILE__) + '/../lib' require 'test/unit' require 'raku_api' class RakuAPITest < Test::Unit::TestCase def setup @raku_api = RakuAPI.new end def test_instance assert_instance_of RakuAPI, @raku_api end def test_search results = @raku_api.search 'Core 2 Duo', :genre => :pc assert_instance_of Array, results results.each do |result| # æ§é ä½ãã©ãã assert_kind_of Struct, result # æ§é ä½ã®æå®ããã¡ã³ãã®åãã§ã㯠assert_instance_of Fixnum, result.price struct_methods_call result, %w(title tax url thumbnail_url shop_name shop_url) do |method| assert_instance_of String, method end # url 㯠http ã§å§ã¾ã£ã¦ããã©ãã struct_methods_call result, %w(url thumbnail_url shop_url) do |method| assert_match /^http/, method end end end def struct_methods_call(struct, methods) methods.each do |method| yield struct.send(method) end end end
ãã¦ãsearch ã¡ã½ããã§æ¤ç´¢ãã¦ãçµæãã¡ããã¨åå¾ã§ãããã©ãããã®ãã¹ããããã§æ¸ãçµããã¾ãããæ©éå®è¡ãã¦ã¿ãã¨â¦ã
Loaded suite test_rakuapi Started EE Finished in 0.006955 seconds. 1) Error: test_instance(RakuAPITest): NameError: uninitialized constant RakuAPITest::RakuAPI test_rakuapi.rb:8:in `setup' 2) Error: test_search(RakuAPITest): NameError: uninitialized constant RakuAPITest::RakuAPI test_rakuapi.rb:8:in `setup' 2 tests, 0 assertions, 0 failures, 2 errors
ã¨ã¾ãå½ããåã®ããã«å¤±æãã¾ããã§ããã¹ããå
ã«æ¸ãã¨ããããã楽ã§ãraku_api.rb ã®æ¹ã§å®è£
ãæ¸ããããã¹ããå®è¡ããã ããã§ãæçµçã«å
¨é¨ãã¹ããéãã¾ã§ raku_api.rb ãå®è£
ãã¦ã¨ããããåãå½¢ã«ãã¦ããã®å¾ãªãã¡ã¯ã¿ãªã³ã°ã§ãããããã or éãåä½ããã³ã¼ããªã©å¥½ãã«ã¢ã¬ã³ã¸ãã¾ãã
å®éã«ããã£ãæéã¯ããã¹ãæ¸ãã®ã«10åãå®è£
ã«15åãããã§ãã¹ãæ¸ãã®ã«å
¨ä½ã® 40%ãããã¦ããããï¼ã¨æãããããããã¾ããããããã¹ããæ¸ããã¨ã«ãã£ã¦ãå®è£
æã®ãã§ãã¯ããã¡ãã¡ print ãããã°ã®ãããªæ¹æ³ãè¡ããªãã¦ãããã§æéãåæ¸ã§ãã¾ããããªã«ããå®è£
æã®ã¹ãã¬ã¹ã軽æ¸ãããã®ã§æ¥½ã§ãããªã®ã§ã©ã¤ãã©ãªã®ãããªç©ãä½ãã¨ãã¯ãå°ç©ã§ããã¹ããå
ã«æ¸ãã¦ããã¨ã ãã¶æ¥½ã«ãªãã¾ãã
ã§ãæçµå½¢ã® raku_api.rb ã¯ãããªæãã«ã
#!/usr/bin/env ruby begin require 'rubygems' require_gem 'scrapi' rescue LoadError require 'scrapi' end require 'uri' class RakuAPI RAKU_API_URI = 'http://rakuapi.ddo.jp/api' class RakuScraper < Scraper::Base def self.decamelize(str) str.gsub(/(^.+)([A-Z])/, '\1_\2').downcase end elements = %w(Title Price Tax Url ThumbnailUrl ShopName ShopUrl) elements.each {|el| process el, decamelize(el) => :text } def collect self.price = price.to_i end result *elements.map {|el| decamelize(el) } end attr_accessor :options def initialize(options = {}) @options = { :parser => :html_parser }.update options end def search(keyword, options = {}) uri = URI.parse(RAKU_API_URI) uri.query = queryize options.update(:keyword => keyword) Scraper.define do process 'Result', 'results[]' => RakuScraper result :results end.scrape(uri, self.options) end private def queryize(hash) hash.map {|i| i.map {|j| URI.escape j.to_s }.join '=' }.join('&') end end
XML ãªãã ãããã¼ã¹ã«ã¯ rexml ã¨ãã§ããããããã¨æãããããã¾ãããã scrAPI ã使ããã¨ã§ããããã Struct ä½ããªãã¦ããçµæãèªåã§æ§é ä½ã«ãããã³ã°ããã¦ã¡ãã楽ãã§ããcollect ã¡ã½ãããå®ç¾©ãããã¨ã§ãæçµçãªåå¤æãªã©ãæãã®ã¾ã¾ã«è¡ãã¾ããscrAPI ã¤ããããã ãã¡ããããã¨äºãããããããªæ°ããã¾ããæ°ã«ãã¾ããã
ã§ããã¹ããéã£ã¦ãã£ããã§ããã
Loaded suite test_rakuapi Started .. Finished in 0.213071 seconds. 2 tests, 112 assertions, 0 failures, 0 errors
ãã®ã©ã¤ãã©ãªã®ä½¿ãæ¹ã¯ãããªæãã§ã(ã¨ãã£ã¦ã test ã¾ãã¾ã§ããã©)
require 'raku_api' $KCODE = 'u' raku_api = RakuAPI.new results = raku_api.search 'Perfume', :genre => :cddvd, :row => 2 require 'pp' pp results
çµæ
[#<struct title="PerfumeãCompleteãBestã", price=2999, tax="ç¨è¾¼ãéæè¾¼", url="http://item.rakuten.co.jp/book/4061751/", thumbnail_url= "http://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/ogs_410606/4106060429.jpg?_ex=64x64", shop_name="楽天ããã¯ã¹", shop_url="http://www.rakuten.co.jp/book/">, #<struct title="Perfume", price=3058, tax="ç¨è¾¼ãéæå¥", url="http://item.rakuten.co.jp/book/3991671/", thumbnail_url= "http://thumbnail.image.rakuten.co.jp/@0_mall/book/cabinet/ogs_410603/4106031362.jpg?_ex=64x64", shop_name="楽天ããã¯ã¹", shop_url="http://www.rakuten.co.jp/book/">]
ã¨ããããã§ãäºç´°ãªã©ã¤ãã©ãªã§ã TDD ã ã¨æ¥½ã ãã¼ãã¨ããã話ã§ãããã¡ãªã¿ã« TDD ã«ã¯âã®æ¬ããå
¥ãã¾ããã