JRuby/PukiWiki2Markdown のバックアップ(No.2)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- JRuby/PukiWiki2Markdown へ行く。
- 1 (2012-11-30 (金) 21:31:22)
- 2 (2012-12-03 (月) 18:37:18)
- 3 (2012-12-04 (火) 17:06:38)
- 4 (2012-12-05 (水) 18:59:38)
- 5 (2012-12-10 (月) 15:52:18)
- 6 (2012-12-25 (火) 17:53:23)
- 7 (2013-01-07 (月) 12:04:05)
- 8 (2013-01-10 (木) 00:53:09)
- 9 (2013-03-22 (金) 19:23:47)
- 10 (2013-03-25 (月) 16:41:49)
- 11 (2013-05-07 (火) 16:38:06)
- 12 (2013-05-09 (木) 14:28:18)
- 13 (2013-05-24 (金) 18:45:04)
- 14 (2013-09-01 (日) 23:52:46)
- 15 (2013-09-14 (土) 17:37:31)
- 16 (2014-01-16 (木) 16:04:05)
- 17 (2014-06-05 (木) 02:39:52)
- 18 (2014-08-29 (金) 16:20:58)
- 19 (2014-09-01 (月) 18:21:40)
- 20 (2014-09-04 (木) 01:44:07)
- 21 (2014-09-22 (月) 17:22:16)
- 22 (2014-09-25 (木) 17:00:08)
- 23 (2014-09-25 (木) 18:54:41)
- 24 (2014-09-28 (日) 01:55:38)
- 25 (2014-11-07 (金) 16:08:49)
- 26 (2014-11-08 (土) 01:41:12)
- 27 (2015-09-29 (火) 19:39:14)
- 28 (2015-10-26 (月) 20:36:17)
- 29 (2015-11-09 (月) 21:02:30)
- 30 (2016-01-07 (木) 15:31:05)
- 31 (2016-01-27 (水) 18:30:35)
- 32 (2016-03-07 (月) 12:32:08)
- 33 (2016-04-25 (月) 15:29:18)
- 34 (2016-06-24 (金) 20:14:18)
- 35 (2017-03-03 (金) 20:51:01)
- 36 (2017-05-26 (金) 21:30:26)
- 37 (2017-10-27 (金) 16:26:13)
- 38 (2017-12-12 (火) 18:02:05)
- 39 (2024-02-21 (水) 02:06:36)
TITLE:PukiWiki形式のテキストをMarkdown形式のファイルに変換する
Posted by aterai at 2012-09-27
PukiWiki形式のテキストをMarkdown形式のファイルに変換する
概要
このサイトで使用しているPukiWiki形式のテキストをMarkdown形式のファイルに変換するテスト。
- 以下のソースコードは、Rubyist Magazine - あなたの Ruby コードを添削します 【第 1 回】 pukipa.rb より引用、改変
- 注: このサイトを変換することだけが目的なので、テストしていない、適当、制限多数
> jruby -E UTF-8 p2m.rb .\wiki
ソースコード
# -*- mode: ruby; encoding: utf-8 -*-
require 'uri'
module HTMLUtils
ESC = {
'&' => '&',
'"' => '"',
'<' => '<',
'>' => '>'
}
def escape(str)
table = ESC # optimize
str.gsub(/[&"<>]/n) {|s| table[s]} #"
end
CODE = {
'<' => '<',
'>' => '>',
'&' => '&'
}
def code_escape(str)
table = CODE
str.gsub(/[<>&]/n) {|s| table[s]}
end
URIENC = {
'(' => '%28',
')' => '%29',
' ' => '%20'
}
def uri_encode(str)
table = URIENC
str.gsub(/[\(\) ]/n) {|s| table[s]}
end
def urldecode(str)
str.gsub(/[A-F\d]{2}/) {|x| [x.hex].pack('C*')}
end
end
class PukiWikiParser
include HTMLUtils
def initialize()
@h_start_level = 2
end
def filename(pw_name)
decoded_name = HTMLUtils.urldecode(pw_name).sub(/\:/, '_').downcase.split("/").last
md = decoded_name.sub(/\.txt$/, '.md')
if @timestamp.nil? || @timestamp.size===0
md_name = md
else
md_name = "#{@timestamp}-#{md}"
end
return md_name
end
# def timestamp()
# @timestamp
# end
def to_md(src, page_names, page, base_uri = 'http://terai.xrea.jp/', suffix= '/')
@page_names = page_names
@base_uri = base_uri
@page = page.sub!(/\.txt$/, '')
@pagelist_suffix = suffix
@inline_re = nil # invalidate cache
@timestamp = ''
@title = ''
@author = ''
buf = []
lines = src.rstrip.split(/\r?\n/).map {|line| line.chomp }
while lines.first
case lines.first
when ''
buf.push lines.shift
when /\ATITLE:/
@title = lines.shift.sub(/\ATITLE:/, '')
when /\ARIGHT:/
/at (\w{4}-\w{2}-\w{2})/ =~ lines.first
@timestamp = $1
buf.push parse_inline(lines.shift.sub(/\ARIGHT:/, '').concat("\n"))
#buf.concat [%Q|<div style="text-align:right">|, parse_inline(lines.shift.sub(/\ARIGHT:/, '')), "</div>\n"]
when /\A----/
lines.shift
buf.push '- - - -' #hr
when /\A\*/
buf.push parse_h(lines.shift)
when /\A\#code.*\{\{/
buf.concat parse_pre2(take_multi_block(lines))
when /\A\#.+/
#lines.shift
buf.push parse_block_plugin(lines.shift) #'' #("aaaaaaaaaaaaaaaaa")
when /\A\s/
buf.concat parse_pre(take_block(lines, /\A\s/))
when /\A\/\//
#buf.concat parse_comment(take_block(lines, /\A\/\//))
take_block(lines, /\A\/\//)
when /\A>/
buf.concat parse_quote(take_block(lines, /\A>/))
when /\A-/
#buf.push parse_inline(lines.shift)
#buf.push ''
buf.concat parse_list('ul', take_list_block(lines))
when /\A\+/
#buf.push "1. ".concat(parse_inline(lines.shift))
buf.concat parse_list('ol', take_block(lines, /\A\+/))
when /\A:/
buf.concat parse_dl(take_block(lines, /\A:/))
else
buf.concat parse_p(take_block(lines, /\A(?![*\s>:\-\+\#]|----|\z)/))
end
end
buf.join("\n")
head = []
head.push("---")
head.push("layout: post")
head.push("title: #{@title}")
head.push("category: swing")
head.push("tags: [Java, Swing]")
head.push("author: #{@author}")
head.push("---")
head.join("\n").strip.concat(buf.join("\n"))
#head.concat(buf).join("\n").strip
end
private
def take_block(lines, marker)
buf = []
until lines.empty?
break unless marker =~ lines.first
if /\A\/\// =~ lines.first then
lines.shift
else
buf.push lines.shift.sub(marker, '')
end
end
buf
end
def take_multi_block(lines)
buf = []
until lines.empty?
l = lines.shift
break if /^\}\}$/ =~ l
next if /^.code.*$/ =~ l
buf.push l
end
buf
end
def parse_h(line)
level = @h_start_level + (line.slice(/\A\*{1,4}/).length - 1)
h = "#"*level
# content = line.sub(/\A\*+/, '')
content = line.gsub(/\A\*+(.+) \[#\w+\]$/) { $1 }
#"<h#{level}>#{parse_inline(content)}</h#{level}>"
"#{h} #{parse_inline(content)}"
end
def take_list_block(lines)
marker = /\A-/
buf = []
codeblock = false
listblock = false
until lines.empty?
#break unless marker =~ lines.first
#while lines.first
case lines.first
when /\A\/\//
lines.shift
when /\A----/
if codeblock then
buf.push "<!-- dummy comment line for breaking list -->"
end
#buf.push "<!-- dummy comment line for breaking list -->"
break
when marker
l = lines.shift
#puts l
buf.push l #lines.shift #.sub(marker, '')
listblock = true;
codeblock = false;
#puts buf.last
# when /\A$/
# buf.push lines.shift
when /\A\s/
buf.push '#' + lines.shift.strip
codeblock = true;
listblock = false;
when /\A\#code.*\{\{/
array = []
until lines.empty?
l = lines.shift
array.push l
break if /^\}\}$/ =~ l
end
buf.concat array
codeblock = true;
listblock = false;
else
if listblock then
buf.push "<!-- dummy comment line for breaking list -->"
break
elsif codeblock then
buf.push lines.shift
else
break;
end
end
end
buf
end
def parse_list(type, lines)
marker = ((type == 'ul') ? /\A-+/ : /\A\++/)
parse_list0(type, lines, marker)
end
def parse_list0(type, lines, marker)
buf = []
level = 0
blockflag = false
until lines.empty?
line = lines.shift.strip
aaa = line.slice(marker)
if aaa then
level = aaa.length - 1
line = line.sub(marker,'').strip
#else
# level = 0
end
h = " "*level
s = (type == 'ul') ? '-' : '1.'
if line.empty? then
#buf.push line
elsif line.start_with?('#code') then
array = take_multi_block(lines).map{|ll| code_escape(ll)}
hh = " "*(level+1)
line = array.shift.strip
buf.concat [hh, %Q|#{hh}<pre class="prettyprint"><code>|.concat(line), array.join("\n"), "</code></pre>"]
blockflag = false
elsif line.start_with?('#') then
unless blockflag then
blockflag = true
buf.push h
end
x = "\t"*2
line = code_escape(line.sub(/\A\#/, '').strip)
buf.push "#{h}#{x}#{line}"
elsif line.start_with?('<!--') then
buf.concat ['', line]
break
else
blockflag = false
#puts "#{level}: #{line}"
buf.push "#{h}#{s} #{parse_inline(line)}"
end
end
buf
end
def parse_dl(lines)
buf = ["<dl>"]
lines.each do |line|
dt, dd = *line.split('|', 2)
buf.push "<dt>#{parse_inline(dt)}</dt>"
buf.push "<dd>#{parse_inline(dd)}</dd>" if dd
end
buf.push "</dl>"
buf
end
def parse_quote(lines)
["<blockquote><p>", lines.join("\n"), "</p></blockquote>"]
end
def parse_pre(lines)
#[%Q|#{lines.map {|line| "\t".concat(line) }.join("\n")}|, %Q|{:class="prettyprint"}|]
lines.map{|line| "\t".concat(line)} #.join("\n")
end
def parse_pre2(lines)
array = lines.map{|line| code_escape(line)}
array[0] = %Q|<pre class="prettyprint"><code>|.concat(array[0])
[array.join("\n"), "</code></pre>"]
end
def parse_pre3(lines)
["```java", lines.join("\n"), "```"]
end
def parse_comment(lines)
["<!-- #{lines.map {|line| escape(line) }.join("\n")}",
' -->']
end
def parse_p(lines)
lines.map {|line| parse_inline(line)}
end
def parse_inline(str)
str.gsub!('%%', '~~') #<del>, <strike>
str.gsub!("\'\'", '**') #<strong>
@inline_re ||= %r!
&([A-Za-z]+); # $1: plugin
| &([A-Za-z]+)\(([^\)]+)\); # $2: plugin, $3: parameter
| &([A-Za-z]+){([^}]+)}; # $4: plugin, $5: parameter
| \[\[([^>]+)>?([^\]]*)\]\] # $6: label, $7: URI
| \[(https?://\S+)\s+([^\]]+)\] # $8: label, $9: URI
| (#{autolink_re()}) # $10: Page name autolink
| (#{URI.regexp('http')}) # $11: URI autolink
!x
#"
str.gsub(@inline_re) {
case
when plugin = $1 then parse_inline_plugin(plugin.strip, '')
when plugin = $2 then parse_inline_plugin(plugin.strip, $3)
when plugin = $4 then parse_inline_plugin(plugin.strip, $5)
when bracket = $6 then a_href($7.strip, bracket, 'pagelink')
when bracket = $9 then a_href($8.strip, bracket, 'outlink')
when pagename = $10 then a_href(page_uri(pagename), pagename, 'pagelink')
when uri = $11 then a_href(uri, uri, 'outlink')
else
raise 'must not happen'
end
}
end
#"
# def _parse_inline_plugin(line)
# buf = []
# case line
# when /\Ajar$/
# buf.push %Q|<a href="#{@base_uri}#{@page.downcase}/example.jar" onclick="_gaq.push(['_trackEvent', 'Jar', 'Download', '#{@page}']);">jar file(example.jar)</a>|
# when /\Ajnlp$/
# buf.push %Q|<img style="cursor:pointer" width="88" height="23" src="http://lh4.ggpht.com/_9Z4BYR88imo/TRD2KGq73BI/AAAAAAAAAwA/N8-6EXongNk/s800/webstart.png" onclick="_gaq.push(['_trackEvent', 'WebStart', 'Launch', '#{@page}']);location.href='#{@base_uri}#{@page.downcase}/example.jnlp'" onkeypress="location.href='#{@base_uri}#{@page.downcase}/example.jnlp'" title="Java Web Start" alt="Launch" />|
# when /\Azip$/
# buf.push %Q|<a href="#{@base_uri}#{@page.downcase}/src.zip" onclick="_gaq.push(['_trackEvent', 'Source', 'Download', '#{@page}']);">Source(src.zip)</a>|
# buf.push %Q|-<a href="http://java-swing-tips.googlecode.com/svn/trunk/#{@page.sub(/Swing\//,'')}" onclick="_gaq.push(['_trackEvent', 'Subversion', 'View', '#{@page}']);">Repository(svn repository)</a>|
# when /\Aauthor/
# buf.push %Q|<a href="#{@base_uri}#{line.sub(/author\(/,'')}">aterai</a>|
# else
# buf.push 'EEE'
# end
# buf.join("\n")
# end
def parse_inline_plugin(plugin, para)
case plugin
when 'jnlp'
%Q|{% jnlp %}|
when 'jar'
%Q|{% jar %}|
when 'zip'
%Q|{% src %}\n- {% svn %}|
when 'author'
@author = para.strip #.delete("()")
%Q|[#{@author}](#{@base_uri}#{@author}.html)|
when 'new'
para.strip #.delete("{}")
else
#"&#{plugin};"
plugin
end
end
def parse_block_plugin(line)
# content = line.sub(/\A\*+/, '')
# plugin = line.sub(/\A\#([^\(]+)/) { $1 }
@plugin_re = %r<
\A\#([^\(]+)\(?([^\)]*)\)?
>x
args = []
line.gsub(@plugin_re) {
args.push $1
args.push $2 #.slice(",")
}
buf = []
case args.first
when 'ref'
buf.push %Q<![screenshot](#{args[1]})>
else
buf.push ''
end
buf
end
def a_href(uri, label, cssclass)
str = label.strip
if(cssclass.casecmp('pagelink')==0) then
if(uri.size===0) then
%Q<[#{str}](#{@base_uri}#{escape(str)}.html)>
else
%Q<[#{str}](#{@base_uri}#{escape(uri.strip)}.html)>
end
else
#%Q<[#{str}](#{URI.escape(uri.strip)})>
%Q<[#{str}](#{uri_encode(uri.strip)})>
end
end
def autolink_re
Regexp.union(* @page_names.reject {|name| name.size <= 3 })
end
def page_uri(page_name)
"#{@base_uri}#{urldecode(page_name)}#{@pagelist_suffix}"
end
end
def main
include HTMLUtils
srcpath = ARGV[0]
tgtpath = ARGV[1]
if File.exist?(srcpath)
Dir::glob("#{srcpath}/5377696E672F*.txt").each {|f|
#Dir::glob("#{srcpath}/*.txt").each {|f|
fname = File.basename(f)
tbody = File.read(f)
page_names = []
parser = PukiWikiParser.new()
buf = parser.to_md(tbody, page_names, HTMLUtils.urldecode(fname))
tmp = parser.filename(fname)
#unless /^[0-9_]/ =~ tmp
nname = [tgtpath, tmp].join('/')
puts tmp
outf = open(nname, "w")
outf.puts(buf)
outf.close()
#end
}
else
puts srcpath
puts "No such directory"
end
end
main
Jekyll
- 注意: Jekyll 書出しディレクトリの削除
- Jekyll happily destroys all dot files when building the site · Issue #534 · mojombo/jekyll · GitHub
- Add source and destination directory protection by jasonroelofs · Pull Request #535 · mojombo/jekyll · GitHub
- jekyll c:\public_html\jekyll c:\public_html (jekyll . ..)とかやると、public_html内のディレクトリ、ファイルを全削除してファイル生成が行われる
- 同名ファイルは上書きされるだろうと思っていたけど、まさか関係ないファイルが消されるとは…
- jekyllディレクトリ自身とか、.git とか、ローカルメモ(Pukiwikiのtxt)とか、数週間分のログファイルとか、全部消えて脱力中
- 静的サイト生成ツールを調査中: Static Site Generators — Gist
- Jekyll 0.11.2 で、以下のように変換結果の表示してテスト
- Windows 7 64bit版
- ruby 1.9.3p194 (2012-04-20) [i386-mingw32]
> set LANG=ja_JP.UTF-8 > jekyll --server --auto > http://localhost:4000/swing/2011/09/26/swing-linesplittinglabel/
- イタリック
1.6.0_02 で発生し、1.7.0_05 で修正された
- などで、「02 で発生し、1.7.0」がイタリックになってしまう
- リストがうまく変換されない場合がある
- Maruku: <a href="...">...</a> のようなリンクだけで文字列がないリストを作成しようとすると空になる?
- Kramdown: リストとブロック要素の間に空行が必要? redcarpet でも同様?
- Kramdownで変換する場合、以下のような数値文字参照(Numeric character reference)をコードブロック(<pre><code>)に変換するときにエラー*1になる?
JEditorPane OK: �� JEditorPane NG: 𦹀
- Kramdownで変換する場合、以下のような数値文字参照(Numeric character reference)をコードブロック(<pre><code>)に変換するときにエラー*1になる?
- 上記のようにリスト中にコードブロックがある場合、- で始まる行の後に、空行(もしくは空白文字のみのインデント)が必要だが、p2m.rbでは生成できていない
- コードブロックも、(リスト階層+1)*4スペース(もしくはタブ)のインデントが必要だが、p2m.rbでは生成できていない
- markdownのパーサーをredcarpetに変更
#_config.yml に追加 markdown: redcarpet
もしくは
> jekyll --server --auto --redcarpet
Liquid
PukiWikiのプラグインをLiquid タグに移植
- C:\jekyll-bootstrap\_plugins\src.rb
# -*- encoding: utf-8 -*- class Src < Liquid::Tag def initialize(tagName, id, tokens) super @id = id end def render(context) #page_url = context.environments.first["page"]["url"] url = "src.zip" gaq = %Q|_gaq.push(['_trackEvent', 'Source', 'Download', '#{@id}']);location.href='#{url}'| %Q|<a href="#{url}" onclick="#{gaq}">Source code(src.zip)</a>| end Liquid::Template.register_tag "src", self end
PukiWikiプラグインの&zip(swing/surrogatepair); などを {% src swing/surrogatepair %} に置き換える
Jekyll で google-code-prettify
- 参考: fnordig.de
パーサーをkramdownにして、行頭タブ(4スペース)ブロックの直後に {:class="prettyprint"}、または {:.prettyprint} を追加
def parse_pre(lines) [%Q|#{lines.map {|line| "\t".concat(line) }.join("\n")}|, %Q|{:class="prettyprint"}|] end
### サンプルコード trayIcon.displayMessage("caption", "text", TrayIcon.MessageType.ERROR); {:class="prettyprint"}
結果
<h3 id="section">サンプルコード</h3>
<pre class="prettyprint"><code>trayIcon.displayMessage("caption", "text", TrayIcon.MessageType.ERROR);
</code></pre>
default.htmlに.js, .cssを追加
<link href="{{ ASSET_PATH }}/css/prettify.css" type="text/css" rel="stylesheet" /> </head> <body onload="prettyPrint()"> ... <script src="{{ ASSET_PATH }}/js/prettify.js"></script> </body>