2013-08-11 2 views
0

나는 보석에 맞붙고있다. 소스 코드를 체크 아웃하는 경우 https://github.com/scaryguy/vakit수업 내에서 Nokogiri 요청을 여러 번 피하는 방법은 무엇입니까?

, 당신은 내가 그것에서 일부 데이터를 필터링하는 외부 HTML 페이지를 구문 분석하고있어 것을 알 수 있습니다 : 은 여기의 홈페이지입니다.

문제는 하나의 요청으로 모든 데이터를 가져 오지만 Vakit.sabah 또는 Vakit.oglen을 호출 할 때마다 새로운 요청이 이루어집니다.

require "vakit/version" 
require 'vakit/connect' 
require 'Nokogiri' 
require 'open-uri' 

module Vakit 

    def self.today 
    Vakit::Connect.shaber 
    end 

    def self.imsak 
    Vakit::Connect.shaber[:imsak] 
    end 

    def self.sabah 
    Vakit::Connect.shaber[:sabah] 
    end 

    def self.oglen 
    Vakit::Connect.shaber[:oglen] 
    end 

    def self.ikindi 
    Vakit::Connect.shaber[:ikindi] 
    end 

    def self.aksam 
    Vakit::Connect.shaber[:aksam] 
    end 

    def self.yatsi 
    Vakit::Connect.shaber[:yatsi] 
    end 

end 

나는 그것이 효율적인 방법이라고 생각하지 않습니다.

새로운 요청없이 내 해쉬의 속성에 액세스 할 수 있어야합니다. 그렇지 않아도됩니까?

module Vakit 
class Connect 
    def initialize(opt={}) 
     @path = opt[:path] 
    end 

    def self.shaber 
     doc = Nokogiri::HTML(open('http://www.samanyoluhaber.com/')) 
     x = doc.css('#hnmzT') 

     times = [] 
     x.each do |vakit| 
      data = vakit.children.first.children.last.content 
      data_add = data.slice(0..data.length-2) 
      times.push(data_add) 
     end 
     times 
     vakit = { 

      imsak: times[0], 
      sabah: times[1], 
      oglen: times[2], 
      ikindi: times[3], 
      aksam: times[4], 
      yatsi: times[5] 


     } 

    end 

end 
end 

나는 어떤 깨달음이 필요합니다.

+0

코드를 작성하여 도움을 요청하지 마십시오. http://sscce.org/ –

+0

업데이트 된 질문보기 – scaryguy

답변

0

이 줄 doc = Nokogiri::HTML(open('http://www.samanyoluhaber.com/'))은 요청 된 전화를 여러 번 만드는 것입니다.

나는 이것을 보석과 함께 테스트했는데 이것이 효과가 있다고합니다.

if @doc.nil? 
    @doc = Nokogiri::HTML(open('http://www.samanyoluhaber.com/')) 
end 

는 vakit.rb 변화에 더하여

require 'Nokogiri' to require 'nokogiri' I는 다음과 같은 제안을한다

+0

고맙습니다. 키워드가 인스턴스 변수의 힘을 사용하고 있습니다! – scaryguy

+0

종종 이런 종류의 단순한 lazy eval/caching은 Ruby에서'if' 블록없이'@doc || = ...'로 쓰여지지만, 대답은 그대로입니다. –

0

(단순 N)

  1. Vakit::Connect 클래스 내부 인스턴스 메소드이어야한다. 그래서 메모리에 저장된 &을 인스턴스화 할 수 있습니다. 이 방법으로 각 요청은 동일한 객체의 다른 인스턴스가됩니다. 클래스가 존재하지 않는 경우. 그것을 만드십시오.
  2. memorization을 사용하면 값 비싼 작업을 캐시 할 수 있습니다.
  3. 작업에 시간이 오래 걸리면 3 초 이상 걸립니다. 그것은 배경 작업으로 변환 & 그들을 처리하는 노동자를 사용합니다. 당신이 보석을 제작하고 있기 때문에,. 나는이 책임을 보석을 사용하는 개발자에게 공개해야한다고 생각합니다.

그래서 나는 그에게 이런 짓을 할 것이다 : 연결 클래스 :

module Vakit 
class Connect 
attr_accessor :path, :doc 
def initialize(opt={}, url) 
    @path = opt[:path] 
    @doc = Nokogiri::HTML(open(url)) 
end 

def shaber 
x = @doc.css('#hnmzT') 
    #no changes here 
end 
end 

Vakit 모듈이

module Vakit 
class Main #name it something more meaningful 
    def initialize(opt={}) 
    @connected = Connect.new(opt[:path], 'http://www.samanyoluhaber.com/') 
    end 
    def today 
    @connected.shaber 
    end 

    def imsak 
    today[:imsak] 
    end 

    def sabah 
    today[:sabah] 
    end 

    def oglen 
    today[:oglen] 
    end 

    def ikindi 
    today[:ikindi] 
    end 

    def aksam 
    today[:aksam] 
    end 

    def yatsi 
    today[:yatsi] 
    end 

end 

다음 코드에서이 같이 사용할 수 있습니다

@v = Vakit::Main.new 
@v.aksam 

이것은 100 % 완전하지 않을 수 있습니다. ause 나는 코드의 목적을 이해하지 못한다. 왜 그 일을하는지 이해하지만 왜 그런지는 모른다. 그러나 해시에 액세스 할 때마다 새로운 요청을하지는 않습니다.

+0

자세한 답변 해 주셔서 감사합니다.하지만 솔루션과 함께 모듈 이름의 별명을 지정하는 방법은 무엇입니까? – scaryguy

+0

다른 상수에 'Valkit'을 지정할 수 있습니다. 'V = Vakit; @v = V :: Main.new'. 이게 당신이 묻는거야? – CuriousMind

+0

보석을 사용하는 동안 사용자는 'Vakit.sabah'와 같이 호출 할 수 있어야합니다. 당신의 솔루션에는'Vakit :: Main.sabah'가 있어야합니다. 어떻게 별칭을 만드시겠습니까? – scaryguy

1

shaber을 사용할 때마다 명시 적으로 open을 사용하고 내용을 다시 채 웁니다. 콘텐츠 나 구문 분석 된 DOM을 로컬에 저장하려고하지 않고 이미 가지고 있는지 확인합니다.

대신 doc =을 사용하고 을 @@doc으로 변경하십시오.

||= 연산자는 @@doc이 비어있는 경우에만 할당합니다. non-nil 또는 false가 아닌 값에 할당되면 다시 트리거되지 않으므로 가난한 사람의 "메모"가됩니다.

클래스 메서드를 사용하고 있으므로 클래스 변수를 사용하는 것이 좋습니다. 다른 페이지를보고있는 클래스의 인스턴스가 여러 개있는 경우 @@doc은 인스턴스 변수 @doc이 될 수 있습니다. 하나의 페이지 만 하드 코딩했기 때문에 그다지 효과적이지는 않지만 향후 코드 확장을 위해 유용 할 수 있습니다.


페이지에 액세스하기 위해 작성한 코드는 매우 관용적 인 Ruby가 아닙니다. 나는 더 많은 URL이 충분한 시간 값이있는 페이지를 반환하지 않기 때문에 작동하지 않습니다 다음,처럼 써서 :

require 'nokogiri' 
require 'open-uri' 

module Vakit 

    URL = 'http://www.samanyoluhaber.com/' 

    class Connect 
    def initialize(opt={}) 
     @path = opt[:path] 
     @url = opt[:url] || URL 
    end 

    def shaber(url=nil) 
     doc = Nokogiri::HTML(open(url || @url)) 
     doc.at_css('#hnmzT').to_html # => "<li id=\"hnmzT\" name=\"imsak\"><a id=\"at\"><span>\u0130msak:</span>4:22\u00A0</a></li>" 

     x = doc.at_css('li#hnmzT a') 
     x.to_html # => "<a id=\"at\"><span>\u0130msak:</span>4:22\u00A0</a>" 

     times = x.text.scan(/\d+:\d+/) 

     Hash[[:imsak, :sabah, :oglen, :ikindi, :aksam, :yatsi].zip(times)] 
    end 

    end 
end 

connection = Vakit::Connect.new 
connection.shaber # => {:imsak=>"4:22", :sabah=>nil, :oglen=>nil, :ikindi=>nil, :aksam=>nil, :yatsi=>nil} 

Connect 클래스를위한 좋은 이름이 아닙니다. 클래스는 객체입니다. Connect은 어떤 것이 발생하거나 발생하는 동사입니다. connect은 메소드에 적합한 이름입니다.

+0

답변 해 주셔서 감사합니다. – scaryguy

관련 문제