class Tumblr4r::Site

ConnectionオブジェクトとParserオブジェクトを組み合わせて、 TumblrAPIとRubyオブジェクトの相互変換を行う TODO: private な post だけを取得する API が無いのだなぁ

Constants

API_READ_MAX_ALLOWED_COUNT
SLEEP_SECONDS_FOR_EVERY_FETCH

Attributes

cname[RW]
description[RW]
email[RW]
feeds[RW]
hostname[RW]
logger[RW]
name[RW]
password[RW]
timezone[RW]
title[RW]

Public Class Methods

find(hostname, email=nil, password=nil, http=nil) { |post| ... } click to toggle source

TODO: unit test

# File lib/tumblr4r.rb, line 50
def find(hostname, email=nil, password=nil, http=nil, &block)
  site = self.new(hostname, email, password, http)
  result = site.find(:all)
  if block_given?
    result.each do |post|
      yield post
    end
  else
    return result
  end
end
new(hostname, email=nil, password=nil, http = nil, logger = nil) click to toggle source
# File lib/tumblr4r.rb, line 63
def initialize(hostname, email=nil, password=nil, http = nil, logger = nil)
  @hostname = hostname
  @email = email
  @password = password
  @logger = logger || Logger.new(STDERR)
  @logger.level = @@default_log_level
  @conn = XMLConnection.new(http || @hostname, email, password, @logger)
  @parser = XMLParser.new
  self.site_info
end

Public Instance Methods

count(options = { }) click to toggle source
# File lib/tumblr4r.rb, line 198
def count(options = { })
  params = { }
  [:id, :type, :filter, :tagged, :search].each do |option|
    params[option] = options[option] if options[option]
  end
  params[:num] = 1
  params[:start] = 0
  xml = @conn.get(params)
  posts, start, total = @parser.posts(xml)
  return total
end
dashboard(options = { }) click to toggle source

, :search,

@param [Hash] options :offset, :limit, :type, :filter
@return [Array<Post>]
# File lib/tumblr4r.rb, line 133
def dashboard(options = { })
  limit = options[:limit] ? options[:limit].to_i : nil
  offset = options[:offset].to_i
  result = []
  params = {:likes => "1" }
  [:type, :filter].each do |option|
    params[option] = options[option] if options[option]
  end

  total = 1000 # 明記されてないがたぶん1000件ぐらいが上限?
  last_fetched_at = nil
  each_fetch(limit, offset, API_READ_MAX_ALLOWED_COUNT, total) do |offset, num|
    params[:start] = offset
    params[:num] = num
    sleep_secs = last_fetched_at ? SLEEP_SECONDS_FOR_EVERY_FETCH - (Time.now - last_fetched_at) : 0
    if sleep_secs > 0
      logger.debug("sleeping #{sleep_secs} secs.")
      sleep sleep_secs
    end
    xml = @conn.dashboard(params)
    last_fetched_at = Time.now
    posts, start, total = @parser.posts(xml)
    result += posts
    if posts.size == 0
      # Tumblr API の total で得られる値は全く信用ならない。
      # 検索条件を考慮した件数を返してくれない。
      # (つまり、goalは信用ならない)ので、posts.sizeも終了判定に利用する。
      # TODO: もしくは:numの値を足し合わせていって、それとgoalを比較する?
      break
    end
    posts.size
  end
  result
end
delete(post_id_or_post) click to toggle source

@param [Integer|Post] post_id_or_post

# File lib/tumblr4r.rb, line 222
def delete(post_id_or_post)
  post_id = nil
  case post_id_or_post
  when Tumblr4r::Post
    post_id = post_id_or_post.post_id
  when Integer
    post_id = post_id_or_post
  else
    raise ArgumentError.new("post_id_or_post must be Tumblr4r::Post or Integer, but was #{post_id_or_post}(<#{post_id_or_post.class}>)")
  end
  return @conn.delete(post_id)
end
each_fetch(limit, offset, max_at_once, total) { |start, num| ... } click to toggle source
# File lib/tumblr4r.rb, line 168
def each_fetch(limit, offset, max_at_once, total, &block)
  return if offset && offset.to_i < 0

  # 取得開始位置の初期化
  start = offset || 0
  if limit
    goal = [total - start, limit].min
  else
    goal = total - start
  end
  # 取得件数の初期化
  num = [goal, max_at_once].min
  if num < 0
    return
  end

  all_fetched = 0
  while all_fetched < goal
    fetched_count = yield(start, num)
    @logger.info("size: #{fetched_count}")
    @logger.info("start: #{start}")
    @logger.info("total: #{total}")
    all_fetched += fetched_count
    # 取得開始位置の調整
    start += num
    # 取得件数の調整
    num = [goal - fetched_count, max_at_once].min
  end
end
find(id_or_type, options = { }) click to toggle source

@param [Symbol|Integer] id_or_type :all, id @param [Hash] options :offset, :limit, :type, :filter, :tagged, :search, @return [Array<Post>|Post]

# File lib/tumblr4r.rb, line 77
def find(id_or_type, options = { })
  if id_or_type == :all
    normal_find(options)
  elsif id_or_type.kind_of?(Integer)
    xml = @conn.get({:id => id_or_type})
    posts, start, total = @parser.posts(xml)
    @logger.info("size: #{posts.size}")
    @logger.info("start: #{start}")
    @logger.info("total: #{total}")
    return posts[0]
  else
    raise ArgumentError.new("id_or_type must be :all or Integer, but was #{id_or_type}(<#{id_or_type.class}>)")
  end
end
normal_find(options) click to toggle source

TODO: ループごとに実行して欲しい処理をblockで渡せるようにするといいかも? そのブロック引数にエラー情報も渡してあげれば、エラーが起きたのならretryだな、みたいな 指示ができない、、、、かな

# File lib/tumblr4r.rb, line 95
def normal_find(options)
  limit = options[:limit] && options[:limit].to_i
  offset = options[:offset].to_i
  total = self.count(options)
  result = []
  params = { }
  [:type, :filter, :tagged, :search].each do |option|
    params[option] = options[option] if options[option]
  end
  last_fetched_at = nil
  each_fetch(limit, offset, API_READ_MAX_ALLOWED_COUNT, total) do |offset, num|
    params[:start] = offset
    params[:num] = num
    # APIマニュアルにはこっちのスリープ時間については明記されてないが、dashboardと同じ秒数SLEEPしとく
    sleep_secs = last_fetched_at ? SLEEP_SECONDS_FOR_EVERY_FETCH - (Time.now - last_fetched_at) : 0
    if sleep_secs > 0
      logger.debug("sleeping #{sleep_secs} secs.")
      sleep sleep_secs
    end
    xml = @conn.get(params)
    last_fetched_at = Time.now
    posts, start, total = @parser.posts(xml)
    result += posts
    if posts.size == 0
      # Tumblr API の total で得られる値は全く信用ならない。
      # 検索条件を考慮した件数を返してくれない。
      # (つまり、goalは信用ならない)ので、posts.sizeも終了判定に利用する。
      # TODO: もしくは:numの値を足し合わせていって、それとgoalを比較する?
      break
    end
    posts.size
  end
  result
end
save(post) click to toggle source
# File lib/tumblr4r.rb, line 215
def save(post)
  post_id = @conn.write(post.params)
  new_post = self.find(post_id)
  return new_post
end
site_info() click to toggle source
# File lib/tumblr4r.rb, line 210
def site_info
  xml = @conn.get(:num => 1)
  @parser.siteinfo(self, xml)
end