2009/05/20

足もとの Windows

こうして


$ cp /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/public.generic-pc.icns  ~/Desktop/
$ open ~/Desktop/public.generic-pc.icns 

目をこらして読むと ...CTRL-ALT-DELETE ... あ
こんなものがはいっていたとは。 Apple.
もうそろそろ Boot Camp Assistant.app を OS X に紛れ込ませるのはやめた方がいいと思う。

遊びついでに *ruby*png で検索してみたら ~/Pictures/iChat Icons/Gems 以外のをみつけた。


$ cp /System/Library//Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/libxml-ruby-0.9.5/doc/img/xml-ruby.png ~/Desktop/
$ open ~/Desktop/open xml-ruby.png

libxml-ruby-0.9.5 は OS X 10.5.7 で新たに入ったのか前からあったのか不明。

こんなのもあった


/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/libxml-ruby-0.9.5/doc/img/red-cube.jpg

なぜキューブなんだろう。

2009/05/19

BloggerAPI POST XML


# coding: utf-8
=begin
# post_xml.rb
# 2009-05-18.

# BloggerAPI POST Request で必要な XML の生成
<entry xmlns='http://www.w3.org/2005/Atom'>
<published>2009-06-01T00:00:00+09:00</published>
<app:control xmlns:app='http://www.w3.org/2007/app'>
<app:draft>yes</app:draft></app:control>
<title type='text'>test_title</title>
<category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/>
<category scheme='http://www.blogger.com/atom/ns#' term='test'/>
<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
<p>xxx<a href='http://www.google.com'>google</a><br/><img src='ddd.png'/></p>
<pre><code>
  def aaa
  end
</code></pre>
<p>end.</p></div></content></entry>
# 実際は code element 以外,改行なし
=end

# You can redistribute it and/or modify it under the same terms as Ruby.
require "rexml/document"
require 'time'

module BloggerContentDiv

  def setup_div
    ary = @entry.content.strip.lines.to_a
    return nil if ary.empty?
    ary.each_with_index{|x,i|
      to_tag(x)
      tag_p if ary.size == i + 1
    }
    return @div
  end

  def to_tag(x)
    on = {"<pre>"=>"pre","<blockquote>"=>"blockquote"}
    off = {"</pre>"=>true,"</blockquote>"=>true}
    if on[x.strip]
      tag_p unless @str_plain.empty?
      @tag = on[x.chop]
    elsif off[x.strip]
      my_tag
      @tag = nil
    else
      @str_plain << x unless @tag
      @str_tag << x if @tag
    end
  end

  private

  def tag_p
    str = @str_plain.strip
    return nil if str.empty?
    @e_p = @div.add_element("p")
    str.each_line{|w|
      @m = /<(a)|<(img)|<(del)/.match(w)
      @m ? sub_tag_p(w) : @e_p.add_text(w.strip)
      @e_p.add_element("br") if /\n/.match(w)
    }
    @str_plain = ""
    return @div
  end

  def sub_tag_p(line)
    pre_str unless @m.pre_match.empty?
    if @m[1] then tag_a(line)
    elsif @m[2] then tag_img(line)
    elsif @m[3] then tag_del(line)
    end
    s = /<.*?\/>/.match(line)
    post_str(s) if s
  end

  def tag_del(line)
    del = /<del>(.*?)<\/del>/.match(line)
    @e_p.add_element("del").add_text(del[1])
  end

  def tag_img(line)
    href = /<img\ssrc=["'](.*?)["']/.match(line)
    alt = /alt=["'](.*?)["']/.match(line)
    return nil unless href
    img = @e_p.add_element("img",{'src'=>href[1]})
    img.add_attribute({'alt'=>alt[1]}) if alt
  end

  def tag_a(line)
    all = /<a\shref=["'](.*?)["']>(.*?)<\/a>/.match(line)
    @e_p.add_element("a",{'href'=>all[1]}).add_text(all[2])
  end

  def pre_str
    @e_p.add_text(@m.pre_match.chop)
  end

  def post_str(s)
    @e_p.add_text(s.post_match.chop) 
  end

  def my_tag
    case @tag
      when "pre" then tag_pre
      when "blockquote" then tag_block
    end
    @str_tag = ""
  end

  def tag_pre
    @div.add_text("\n")
    str = @str_tag
    e1 = @div.add_element("pre")
    e2 = e1.add_element("code").add_text("\n")
    e2.add_text(str)
    @div.add_text("\n")
  end

  def tag_block
    e1 = @div.add_element("blockquote")
    e2 = e1.add_element("p")
    @str_tag.strip.each_line{|w|
      e2.add_text(w.strip)
      e2.add_element("br") if /\n/.match(w)
    }
  end

end

class BloggerEntry

  attr_reader :title, :content, :published, :category, :control
  attr_accessor :editid, :updated

  def initialize
    @published = nil
    @control = nil
    @title = nil
    @content = nil
    @category = nil
    # these value, after post request
    @editid = nil
    @updated = nil
  end

  def setup(h)
    h.each{|k, v|
      i = "@#{k}".downcase.to_sym
      set_ins(i, v) if i_defined?(i)
    }
    return self
  end

  def to_xml_post
    return BloggerXML.new(self).post_data
  end

  private

  def set_ins(i,v)
    self.instance_variable_set(i, v)
  end

  def i_defined?(i)
    self.instance_variable_defined?(i)
  end

end

class BloggerXML

  include BloggerContentDiv

  def initialize(entry)
    @entry = entry
    @str_plain = ""
    @str_tag = ""
    @tag = nil
  end

  def post_data
    doc = REXML::Document.new()
    doc << REXML::XMLDecl.new(version="1.0", encoding="utf-8" )
    # entry
    @e = doc.add_element("entry", {'xmlns'=>'http://www.w3.org/2005/Atom'})
    # published
    set_published
    # App control element
    set_control
    # Title
    @e.add_element("title", {'type'=>'text'}).add_text(@entry.title.strip)
    # Category
    set_category
    # Content
    content = @e.add_element("content", {'type'=>'xhtml'})
    @div = content.add_element("div", {'xmlns'=>'http://www.w3.org/1999/xhtml'})
    setup_div
   return @e
  end

  private

  def set_published
    unless @entry.published
      n = Time.now.iso8601.to_s
    else
      n = Time.parse(@entry.published).iso8601.to_s
    end
    @e.add_element("published").add_text(n.to_s)
  end

  def set_control
    if @entry.control
      ac = @e.add_element("app:control",
        {'xmlns:app'=>'http://www.w3.org/2007/app'})
      ac.add_element("app:draft").add_text("#{@entry.control}")
    end
  end

  def set_category
    @entry.category.split(",").to_a.each{|c|
      @e.add_element("category",{"scheme"=>'http://www.blogger.com/atom/ns#',  "term"=>"#{c}"})
    }
  end

end

#--- test
title = 'test_title'
content =<<EOF 
xxxx<a href='http://www.google.com'>google</a>
<img src='ddd.png' alt='fff'>
<pre>
   def aaa
   end
</pre>
end.
EOF

category = "Blogger,test"
control = "yes"
h = {:title=>title, :content=>content, :category=>category, :control=>control, :published=>'2009-06-01'}
entry = BloggerEntry.new().setup(h)
puts data = entry.to_xml_post

#--- Start Post
# require 'gdata'
#begin
#  blogID = 'xxxxxxxxxxxx'
#  url = "http://www.blogger.com/feeds/#{blogID}/posts/default"
#  client = GData::Client::Blogger.new
#  client.source = sourcename
#  clientlogin('username', 'password')
#  client.post(url, data.to_s)
#rescue GData::Client::AuthorizationError => e
#  print "gData error\n"
#  print e.message
#end

content =<<EOF
中の pre は本当は小文字 < >で囲まれてる

修正
100 行目あたり
def pre_str
@e_p.add_text(@m.pre_match.chop)
@e_p.add_text(@m.pre_match)
end

def post_str(s)
@e_p.add_text(s.post_match.chop)
@e_p.add_text(s.post_match)
end

2009/05/17

BloggerAPI-パースエラー

ブラウザから手入力して投稿した記事の場合


 <content type='html'><div xmlns='http://www.w3.org/1999/xhtml'>

を含んでいなかったりする。入力してないのだから当たり前に、ない。その為 Blogger API を利用して GET Request し獲得した XML の content 要素は REXML ではパースエラーになってしまう。これを解消する方法をあれこれ考えてみたけれども挫折中。

パースエラーになるってことは例えばカテゴリをいっぺんに変換したくてもできない記事が存在してしまうってことになる。なぜなら、PUT Request でカテゴリを変更するリクエストを投げる時、その xml データには新規記事と全く同様の要素(タイトル、コンテンツ、カテゴリなど)が必要なのであって content は変更しないので含めませんでした、ではリクエストは通らない。

# 試しに content なしのデータを PUT リクエストしてみたところ BadRequest エラーだった。

でも、content を変えたいわけじゃなくてカテゴリーだけ変えたい。content は元のままを維持したい。それで Get で得られた xml の content をパースしてその要素をそのまんま PUT リクエストデータの content にしてしまえば楽だしミスがない。でもパースできないやつがあるってことが分かった。なぜなら div がないから。あるいはひょっとしてタイプミスして変なタグいれちゃったからなんだけど.. orz

# 結局、BloggerAPI からコントロールしたければ全ての記事の content には div 要素が必要だってことは明白になったので元の文章がちゃんとテキストで保存されていて尚かつ変更しやすそうな記事だけ div 要素を加えることができた。

簡単なテスト


  # coding: utf-8
 str=<<EOF
  # ここにパースエラーになった記事の content 要素内容をはりつける。
  # Get Request で得られた XML の entry.elements['content'].text
 EOF

  doc = REXML::Document.new()
  doc << REXML::XMLDecl.new(version="1.0", encoding="utf-8" )
  # Entry element
  x = doc.add_element(
  "entry",
  {'gd'=>'http://schemas.google.com/g/2005','xmlns'=>'http://www.w3.org/2005/Atom'}
  )
  begin
   # div 要素が存在し かつ ほかの要素も xhtml的に正しければこの行でパースが成功する。
    div = REXML::Document.new(str)
    div.add_namespace({ 'xmlns'=>'http://www.w3.org/1999/xhtml'})
    c = x.add_element('content', {'type'=>'xhtml'})
    c.add_element(div)
    puts c
  rescue REXML::ParseException
    # div 要素がない。あるいは div があってもタグがどっかおかしかったりとか変な br があったりとか? 未知
    # 記事中に Ruby の継承である記号があらわれただけでエラーになったりする
    # gstr = str.gsub(" < ", ' &lt; ').gsub("<<","&lt;&lt;")
    # この先どうすべきやら
  end

memo
カテゴリーを指定して Get Request を発行する場合のURL
#参照
# http://code.google.com/intl/ja/apis/blogger/docs/2.0/developers_guide_protocol.html

# URL 例:
# http://www.blogger.com/feeds/blogID/posts/default/-/Fritz/Laurie

eco

子供ダマシにもほどがある・・・
http://takedanet.com/2009/05/post_a6ca.html

同感。二酸化炭素をより多く排出する人々が優遇されてて京都議定書なんて軽く無視どころか真逆の方向で大丈夫なんだろうか。そんなことよりお金の流れ?なんですかね。経済効果を狙うなら電車で高い特急料金支払った人も優遇すべきだろうに。

エコポイントなんかも子供だましにみえる。エコポイントはテレビの場合画面のサイズが大きければ大きいほどポイントが高いらしい。不況下の電気メーカー救済したいってちゃんと公表してくれたらよかったのに。

2009/05/09

update gdata-ruby 1.1

download gdata-1.1.0.gem (2009.04.28)
http://code.google.com/p/gdata-ruby-util/downloads/list

% gem19 unpack gdata-1.1.0.gem 
# 
# Unpacked gem: 'download/gdata-1.1.0'
% diff gdata-1.0.0/lib/gdata/ gdata-1.1.0/lib/gdata/
% vi gdata-1.1.0/lib/gdata.rb
# require 'jcode'
# $KCODE = 'UTF8'

# 2009-05-16 category 変更
# 2010-01-06 最新 mblogger