読者です 読者をやめる 読者になる 読者になる

basyura's blog

あしたになったらほんきだす。

redmine のチケット一覧を表示する unite-yarm を作ってみた

vim ruby redmine

会社をずる休みして redmine のチケット一覧を表示する unite-yarm を作ってみた。

以前から pure vimredmine のクライアントを書きたいと思っていたのだけど、力不足すぎて手が出せずにいた。チケットの一覧を取ってきて中身を表示するとこまでやったけど、xml 解析や文字列のエスケープ、さらに xml 生成がクソめんどくさくて放置。
そこに mattn さんの webapi-vim 登場。

webapi-vim: Vim Interface to Web API

Description:
    Interface to WEB APIs.
    Currently this library support following protocols.

    * Basic HTTP
    * OAuth
    * Atompub
    * SOAP (in progress)

    This library include:
        XML Parser
        BASE64 Hash Algorism
        SHA1 Hash Algorism
        HMAC HASH Algorism

スゴイとしか言いようがない。自分も vim に限らず core なライブラリを書けるようになってみたいものだ。
試しに redmineapi を叩いてみる。

let res = http#get('http://localhost:3000/issues.xml')
let xml = xml#parse(res.content)

2 行でゲット出来る!!(認証周りはまだ試してないのでスルー api acces key に対応)
(追記) と思ったら1行で行けるよ!

let xml = xml#parseURL(url)

各チケットに対しても簡単にアクセスできる(s:to_value は他では使ってほしくないけどちょっとだけ使いたい function として定義したんだけど、この場合どうしたらいいんだろう。あと、dictionary に詰め替えるのではなくオブジェクト指向っぽく属性の取得を a:xml に移譲したい)。

for dom in xml.childNodes('issue')
  call add(issues , s:to_issue(dom))
endfor
function! s:to_issue(xml)
  " i want this to be inner function
  function! s:to_value(v)
    return empty(a:v) ? '' : a:v[0]
  endfunction
  let issue = {
        \ 'id'              : s:to_value(a:xml.childNode('id').child) ,
        \ 'project'         : a:xml.childNode('project').attr['name'] ,
        \ 'tracker'         : a:xml.childNode('tracker').attr['name'] ,
        \ 'status'          : a:xml.childNode('status').attr['name'] ,
        \ 'priority'        : a:xml.childNode('priority').attr['name'] ,
        \ 'author'          : a:xml.childNode('author').attr['name'] ,
        \ 'subject'         : s:to_value(a:xml.childNode('subject').child) ,
        \ 'description'     : s:to_value(a:xml.childNode('description').child) ,
        \ 'start_date'      : s:to_value(a:xml.childNode('start_date').child) ,
        \ 'due_date'        : s:to_value(a:xml.childNode('due_date').child) ,
        \ 'estimated_hours' : s:to_value(a:xml.childNode('estimated_hours').child) ,
        \ 'done_ratio'      : s:to_value(a:xml.childNode('done_ratio').child) ,
        \ 'created_on'      : s:to_value(a:xml.childNode('created_on').child) ,
        \ 'updated_on'      : s:to_value(a:xml.childNode('updated_on').child) ,
        \}
  let issue.unite_word = '#' . issue.id . ' ' . issue.subject

  return issue
endfunction

これに気を良くして、unite の source を作ってみた。

Unite redmine


チケットを選択すると

ここからどうするかはまだ考えていなくて、unite の何かしらの口を使って更新できたらいいなぁと思うけど。filetype (redmine) にイベントを設定して unite とは別に更新するのが現実的なのかな。

rubykaigi 2010 があった 3 ヶ月前に比べたら、ちょっとだけ vimscript を読み書きできるようになったけど未だに

  • どう書いたら読みやすいのか
  • モジュール?メソッド?script?分割はどうしたら分かりやすいのか

よく分からない。自分で書いておきながら頭に入りいくいのは作法が違うんだろうなぁと思う。

ちなみに、unite-yarm は yet another redmine の略で、本家が無いのに yet もクソもないけど、きっといいのが出てくるだろうということで unite-redmine は遠慮。
チケットのキャッシュ&破棄をどうするか、soruce に詰め替えたあとはどこまで残るのか(action実行後に破棄されるのか)、気になるところはいっぱい。