スクリプト公開

id:sshiに期待してもらったので、はてダラ-howm連携スクリプト公開。

$ ./hw-howm.rb howm_dir target_dir

とやればhowm_dirから再帰的にhowmファイルを探しだしてtarget_dirにYYYY-MM-DD.txtとして格納してくれます。

メモの書き方ですが、メモの一行目に{hw}という文字列を入れて本文中に%%%が行頭となる行を書けば、その行より下が変換対象となります。日付はhowmファイル名のものが使用されますが、{hw}のかわりに{hw:YYYY-MM-DD}を用いると対応する日付のはてダラファイルに変換されます。


こんな感じ

 = {hw:2006-06-17} スクリプトテスト
[2006-06-18 15:15] >>> ~/howm/2006/06/2006-06-18-095939.howm

ここは変換されません。

%%% ここより下が変換対象
*[hatena] test
test

これを変換すると2006-06-17.txtというファイルになります。


特徴とか問題点とかいろいろ

  • 同じ日付の日記が複数のhowmファイルにあっても問題なし。ただしその場合記事の順番はhowmファイル名順になります。
  • deleteには対応してません。YYYY-MM-DD.txtファイルに直接記述してください。ただし一度deleteを書けばファイルを上書きしてもdeleteは消えません。
  • -tオプションでtimestampファイルを指定できます。このオプションを指定すると、timestampファイルより新しいhowmファイルのみ変換対象となります。
  • その日のタイトルにも対応していません -> deleteと同じ
  • 変換後に{hw:YYYY-MM-DD}の日付部分を変えて再度変換すると二重に出力されることになります。以前の日付のYYYY-MM-DD.txtを削除して再度変換するとか、手で編集する必要があります。
  • 画像転送に対応してない。
  • 異常処理とかまだダメダメ。


以下スクリプト本体です。

#!/usr/bin/ruby -w
#
# hw-howm.rb -- howmメモをはてダラで扱える形式にする.
#
require "optparse"
require "fileutils"

begin
  opt = OptionParser.new
  OPTS = {}
  opt.banner= "usage: #$0 [options] src_dir target_dir"
  opt.on_tail("-h", "--help", "show this message") {puts opt; exit 0}
  opt.on("-t", "--timestamp=filename", "timestamp file(default: none)") {|v| OPTS[:t] = v} # touch file path
  opt.parse!(ARGV)
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
  puts $!
  puts opt
  exit 1
end

srcdir = ARGV[0]
updir = ARGV[1]

if !srcdir or !updir
  puts opt
  exit 1
end

[srcdir, updir].each do |dir|
  unless FileTest.directory? dir
    puts "invalid directory: #{dir}"
    puts opt
    exit 1
  end
end

touch_mtime = Time.at(0)
if OPTS.key?(:t) && FileTest.file?(OPTS[:t])
  touch_mtime = File.mtime(OPTS[:t])
end

# ファイルの再帰探索
IGNORE_DIR = %w(. ..)
def scan_files (path, &block)
  if FileTest.directory?(path)
    Dir.foreach(path) do |file|
      next if IGNORE_DIR.include? file
      scan_files("#{path}/#{file}", &block)
    end
  else
    block.call(path)
  end
end

# メインの処理
scan_files(srcdir) do |path|
  next unless FileTest.readable?(path)

  # touchファイルより新しいか
  next if touch_mtime > File.mtime(path)

  # howm形式のファイル名か
  next unless /(\d{4}-\d{2}-\d{2}).*\.howm$/ =~ path
  date = $1

  fio = File.open(path)
  next if fio.eof? or fio.readline !~ /\{hw(:(\d{4}-\d{2}-\d{2}))?\}/
  date = $2 if defined? $2  #日付指定があればそれを使う

  # 記事格納用ハッシュ
  content = Hash.new("")

  # はてダラファイルの先頭部分はcontent["0"]に格納
  key = "0"
  # はてダラファイルの内容をハッシュに格納
  uppath = "#{updir}/#{date}.txt"
  if FileTest.file?(uppath)
    File.foreach(uppath) do |line|
      if /^><!--(\d{4}-\d{2}-\d{2}.*\.howm)--><$/ =~ line
        key = $1
        next
      end
      content[key] += line
    end
  elsif FileTest.exist?(uppath)
    puts "#{uppath} is not file."
    next
  end
  
  # はてダラファイルがなかったとき
  # とりあえずファイルの先頭は空行にしておく
  content["0"] = "\n" unless content.key?("0")

  # howmファイルの内容をハッシュに格納
  filename = File.basename(path)  
  content[filename] = ""
  fio.each_line do |line|
    if line =~ /^%%%/
      # %%%行より下を格納
      content[filename] = fio.readlines.join('')
    end
  end    

  # はてダラファイルへ書き込み
  File.open(uppath, "w+") do |io|
    io << content["0"]
    content.keys.sort.each do |key|
      if key != "0" && content[key] != ""
        io << "><!--#{key}--><\n"
        io << content[key]
      end
    end
  end

end

# touch
if OPTS.key?(:t)
    FileUtils.touch(OPTS[:t])
end

exit 0

ライセンスはRubyライセンスで。
バグ報告大歓迎(対応できるか微妙ですが…)