PRagger その2

下のエントリをポストするのに使った publish::hatena_diary_writer.rb プラグインがちょっと使いにくい。

今日の日記にしかポストできないのはとりあえずおいとくとしても,ポストするたびに下に追加ってのは1日1ファイルにしてる俺のやり方とは違う。

ここはやっぱり全面的に置き換えるのがいい。

というわけでちょっと手を入れてみた。

config[“mode”] が replace なら上書き,add なら下に追記,insert なら上に挿入だ(文字化けしてるのはsvnのせいみたい)。

ついでに proxy にも対応。環境変数 http_proxy が設定されていればそれを使う。

追記:おっと。http_proxy の文字列にはスキーマも含むのか。というわけで以下のコードは差し替えた。

Index: hatena_diary_writer.rb
===================================================================
--- hatena_diary_writer.rb	(リビジョン 57)
+++ hatena_diary_writer.rb	(作業コピー)
@@ -1,12 +1,19 @@
#!/usr/bin/env ruby
# hatena_diary_writer.rb
#
+require 'uri'
class HatenaDiaryWriter
def initialize(id,password)
@id = id
@password = password
@agent = WWW::Mechanize.new
+    if proxy = ENV['http_proxy']
+      proxy = URI.parse(proxy)
+      proxy_addr = proxy.host
+      proxy_port = proxy.port
+      @agent.set_proxy(proxy_addr, proxy_port)
+    end
@diary = @agent.get("http://d.hatena.ne.jp/#{id}/")
end
@@ -21,11 +28,18 @@
@diary_page = @agent.get(@diary_link.href)
end
-  def edit(content)
+  def edit(content, mode)
edit_link = @diary_page.links.text("譌・險倥r譖ク縺・.toeuc)
      edit_page = @agent.get(edit_link.href)
      edit_form = edit_page.forms.name("edit").first
 -    edit_form["body"] += content
 +    case mode
 +    when 'add'
 +      edit_form["body"] += content
 +    when 'insert'
 +      edit_form["body"] = content + edit_form["body"]
 +    when 'replace'
 +      edit_form["body"] = content
 +    end
      ok_button = edit_form.buttons.name("edit")
      @agent.submit(edit_form, ok_button)
    end
 @@ -42,5 +56,5 @@
      content << ("* "+line.title+"\n"+line.link+"\n"+line.description rescue line.to_s)
    end
    diary.login
 -  diary.edit(content.toeuc)
 +  diary.edit(content.toeuc, config['mode'])
  end

設定ファイルはこんな感じ。

- module: stdin
config:
input: nothing
- module: publish::hatena_diary_writer
config:
user_id: takatoh
password: xxxxxxxx
mode: replace

日記のファイルはコマンドラインで指定する。

^o^>pragger -c hatena.yaml 2007-02-24.txt
exec plugin stdin
exec plugin publish::hatena_diary_writer

ところで

data.each do |line|
content << ("* "+line.title+"\n"+line.link+"\n"+line.description rescue line.to_s)
end

の line がどんなデータを想定してるのかわからないんですが。

クラスはよくてもモジュールは?

いままで気にしたことなんて無かったけど……

cf. Matzにっき – jijixi’s diary – Ruby の文法的欠陥

cf. じじぃの日記、ツッコミ可 – Ruby の文法的欠陥

jijixiさんのいう”欠陥”(というと言いすぎのような気もする,といっているけど)というのは

『新しいクラスを作ってるつもりで、知らないうちに既存のクラスを上書きする可能性がある』

で,これに対するまつもとさんの対策が

* ちゃんと名前空間を分離する

* クラスを定義する時にはスーパークラスを明示する

2つ目の方は,クラスを定義するときに指定したスーパークラスが合わないとエラーになるってことだな。

D:\>irb
irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> class Bar; end
=> nil
irb(main):003:0> class Baz < Foo; end
=> nil
irb(main):004:0> class Baz < Bar; end
TypeError: superclass mismatch for class Baz
from (irb):4
from :0

そうは言っても class Foo < Object って書いてるのは見たこと無いけど。

さて,クラスはいいとしてもモジュールはどうだろう。

スーパークラスの明示みたいなものはないし,トップレベルで定義されたモジュールでは名前空間の分離もできない。

……ってことは,気をつけるしかないのか。

ちなみに,素の状態で定義されているモジュールは

D:\>type modules.rb
ObjectSpace.each_object(Object){|o| puts o.name if o.class == Module}
D:\>ruby modules.rb
Marshal
ObjectSpace
GC
Math
Process::Sys
Process::GID
Process::UID
Process
Signal
File::Constants
FileTest
Errno
Precision
Enumerable
Comparable
Kernel

意外に少ない。

テキストでプログレスバー

cf. Ruby/ProgressBar: プログレスバーをテキストで表示する Ruby用のライブラリ

via 趣味的にっき – プログレスバーをテキストで表示する関数

インストールは progressbar.rb をライブラリパスの通ったところにおけばいいだけ。

ProgressBar のインスタンスをつくっておいて ProgressBar#inc か ProgressBar#set で進捗を表示する。

まずは記事にある使用例で試してみよう。

D:\>irb -rprogressbar
irb(main):001:0> pbar = ProgressBar.new("title", 100)
=> #<ProgressBar:0/100>                                        | ETA:  --:--:--
irb(main):002:0> (1..100).each{|i| sleep(0.1); pbar.set(i)}; pbar.finish
title:         100% |oooooooooooooooooooooooooooooooooooooooooo| Time: 00:00:35
=> Thu Dec 21 21:29:46 +0000 2006

ProgressBar#file_transfer_mode を使うと,ファイルの転送バイト数と転送速度を表示できる。

こんな感じ。

require 'progressbar'

fname1 = ARGV.shift
fname2 = ARGV.shift

f1 = File.open(fname1, "rb")
f2 = File.open(fname2, "wb")
size = File.size(fname1)

pbar = ProgressBarnew("transfer file", size)
pbar.file_transfer_mode

until f1.eof?
  f2.write(f1.read(1000))
  pbar.inc(1000)
end
pbar.finish

f1.close
f2.close

ファイルのコピーを低レベルでやらなきゃいけないけど。

実行例。

D:\>copy_pbar.rb projects.xls copy_projects.xls
transfer file: 100% |oooooooooooooooooooooooo|   5.0MB  35.5MB/s Time: 00:00:00