Ruby で Redmine の Wiki を巡回
昨日、「Redmine 内の Wiki データをエクスポートする方法」を紹介しましたが、以下の点で気に入りませんでした。
- Redmine 標準のエクスポート機能
- ファイルが単一なのが嫌
- レイアウト・スタイルが通常と異なる
- 画像ファイルなど添付ファイルを取得するのが面倒
- 既存の巡回ソフト
結局、標準のエクスポート機能や、既存の巡回ソフトに満足できなかったので、 Ruby で作ってみました。ライブラリは、「Simple Crawler」を使用しています。 (scRUBYt! や Nokogiri、Hpricot、Mechanize なども検討したのですが、結局一番シンプルな形に落ち着きました。)
以下、ソースです。 Windows 環境で動かすことを前提にしているため、ファイル名を Shift-JIS に変換しています。 (ソースコードは UTF-8 です。) 取得したい Wiki のプロジェクト名を「project_name」変数に設定して使用してください。
# coding: utf8 require 'rubygems' require 'kconv' require 'uri' require 'fileutils' require 'net/http' require 'simplecrawler' server_name = "127.0.0.1" project_name = "project_name_here" crawler = SimpleCrawler::Crawler.new("http://#{server_name}:3000/projects/#{project_name}/wiki/Page_index") crawler.load_binary_data = true crawler.include_patterns = ["\\/projects\\/#{project_name}\\/wiki\\/", "\\/attachments\\/"] crawler.skip_patterns = ["\\/wiki\\/export", "\\/attachments\\/download\\/", "\\/history$", "\\/rename$", "\\/edit$", "\\?format"] attachments = {} output_dir = project_name HtmlPostfix = ".html" FileUtils.mkdir_p(output_dir) crawler.crawl do |document| next if document.http_status.nil? output_filename = File.join(output_dir, File.basename(URI.unescape(document.uri.to_s).tosjis)) data = document.data if document.headers["content-type"].include?("text/html") output_filename << HtmlPostfix data = URI.unescape(data) data.grep(%r|"/attachments/(\d+)/(.*?)"|) do attachments[$1] = $2 end # リンクを .html 形式に変換・階層の調整など data.gsub!(%r|/stylesheets/|, "") data.gsub!(%r|/javascripts/|, "") data.gsub!(%r|\?[\w\d=&;]+|, "") data.gsub!(%r|"/projects/#{project_name}(?:/wiki)?/(.*?)"|) { %("#{$1}#{HtmlPostfix}") } data.gsub!(%r|"/attachments(?:/download)?/(\d+)(?:.*?)"|) { %("#{attachments[$1]}") } end open(output_filename, "wb") { |f| f.write data } end # CSS などを別途取得 option_files = [ "/stylesheets/application.css", "/javascripts/prototype.js", "/javascripts/effects.js", "/javascripts/dragdrop.js", "/javascripts/controls.js", "/javascripts/application.js", "/stylesheets/jstoolbar.css", "/stylesheets/csshover.htc"] Net::HTTP.start(server_name, 3000) do |http| option_files.each do |file| response = http.get(file) open(File.join(output_dir, File.basename(file)), "wb") { |f| f.write response.body } end end
Ruby らしくない書き方や、よりよい書き方があれば教えてください。