bluefeather 0.10 → 0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,7 +9,7 @@ BlueFeather マニュアル
9
9
  → [English version](en/index.html)
10
10
 
11
11
 
12
- (2009-02-22 バージョン 0.10 準拠)
12
+ (2009-02-27 バージョン 0.11 準拠)
13
13
 
14
14
  BlueFeather は、拡張 Markdown 記法で書かれたテキストを html に変換するソフトウェアです。
15
15
  コマンドラインツールと、Ruby スクリプト内で変換を行うためのライブラリがセットになっています。
@@ -0,0 +1,46 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <title>BlueFeather マニュアル</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
+ <link rel="stylesheet" type="text/css" href="black.css" />
7
+ </head>
8
+ <body>
9
+
10
+ <div class="back"><a> </a></div>
11
+
12
+ <h1 id="bfheader-28315721066bd2a19c72b35d15dde831">BlueFeather マニュアル</h1>
13
+
14
+ <p>→ <a href="en/index.html">English version</a></p>
15
+
16
+ <p>(2009-02-27 バージョン 0.11 準拠)</p>
17
+
18
+ <p>BlueFeather は、拡張 Markdown 記法で書かれたテキストを html に変換するソフトウェアです。
19
+ コマンドラインツールと、Ruby スクリプト内で変換を行うためのライブラリがセットになっています。</p>
20
+
21
+ <p>広く使われている Markdown 実装である <a href="http://www.deveiate.org/projects/BlueCloth">BlueCloth</a> をベースとしつつ、既知のバグの修正やインターフェースの変更、そして記法・機能へのさまざまな拡張を施しています。</p>
22
+
23
+ <p>なお、このマニュアルページそのものも、 BlueFeather を用いて生成された html 文書です。変換前のテキストファイルは <code>doc</code> ディレクトリ内に同梱しています。</p>
24
+
25
+ <ul>
26
+ <li><a href="basic-usage.html">インストール・基本的な使い方</a></li>
27
+ <li><a href="difference.html">BlueCloth との違い</a></li>
28
+ <li><a href="format-extension.html">Markdown 記法の拡張</a></li>
29
+ </ul>
30
+
31
+
32
+
33
+ <ul>
34
+ <li><a href="class-reference.html">クラスリファレンス</a></li>
35
+ <li><a href="metadata-reference.html">メタデータリファレンス</a></li>
36
+ </ul>
37
+
38
+
39
+
40
+ <ul>
41
+ <li><a href="author-and-license.html">連絡先・ライセンス</a></li>
42
+ <li><a href="http://ruby.morphball.net/bluefeather/">BlueFeather 配布サイト(http://ruby.morphball.net/bluefeather/)</a></li>
43
+ </ul>
44
+
45
+ </body>
46
+ </html>
@@ -0,0 +1,108 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <title>メタデータリファレンス - BlueFeather マニュアル</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
+ <link rel="stylesheet" type="text/css" href="black.css" />
7
+ </head>
8
+ <body>
9
+
10
+ <div class="back"><a href="index.html">BlueFeather マニュアル</a></div>
11
+
12
+ <h1 id="bfheader-ec2fa92527c99540ee3b2d491da72acf">メタデータリファレンス</h1>
13
+
14
+ <p>文書ファイル(*.bfdoc)の頭に、<code>:</code> 記号で区切られたキーと値の組(ヘッダー)を書いておくことで、その文書にタイトルなどの情報(メタデータ)を付け加えることができます。</p>
15
+
16
+ <pre><code>Title: 文書名
17
+ CSS: style.css
18
+ Atom-Feed: info/atom.xml
19
+
20
+ ここから本文
21
+ </code></pre>
22
+
23
+ <p>これらの文書メタデータは、<code>parse_document</code> や <code>parse_document_file</code> などのメソッドを使って解釈したときにのみ有効です。</p>
24
+
25
+ <p>キー名の大文字/小文字は区別されません。</p>
26
+
27
+ <ul>
28
+ <li><a href="#bfheader-b13845a04c80670ed2ad55f11258c690" rel="toc">重要なメタデータ</a>
29
+ <ul>
30
+ <li><a href="#css" rel="toc">CSS:</a></li>
31
+ <li><a href="#encoding" rel="toc">Encoding:</a></li>
32
+ <li><a href="#title" rel="toc">Title:</a></li>
33
+ </ul></li>
34
+ <li><a href="#bfheader-97acdc6f75044864bf5fdb105b98da3a" rel="toc">補助的なメタデータ</a>
35
+ <ul>
36
+ <li><a href="#atom-feed" rel="toc">Atom-Feed:</a></li>
37
+ <li><a href="#rdf-feed" rel="toc">RDF-Feed:</a></li>
38
+ <li><a href="#rss-feed" rel="toc">RSS-Feed:</a></li>
39
+ <li><a href="#description" rel="toc">Description:</a></li>
40
+ <li><a href="#keywords" rel="toc">Keywords:</a></li>
41
+ </ul></li>
42
+ </ul>
43
+
44
+ <h2 id="bfheader-b13845a04c80670ed2ad55f11258c690">重要なメタデータ</h2>
45
+
46
+ <h3 id="css">CSS:</h3>
47
+
48
+ <pre><code>CSS: http://example.net/style.css
49
+ </code></pre>
50
+
51
+ <p>CSS スタイルシートの URL。生成される html 文書の head 要素内に、そのスタイルシートへのリンクが付け加えられる。</p>
52
+
53
+ <h3 id="encoding">Encoding:</h3>
54
+
55
+ <pre><code>Encoding: utf-8
56
+ </code></pre>
57
+
58
+ <p>その文書のマルチバイトエンコーディングを表す。utf-8, euc-jp, shift-jis, ascii のいずれかが有効(小文字と大文字は区別しない)。
59
+ html の head 要素内に出力される Content-Type の値、および変換処理に影響する。</p>
60
+
61
+ <p>なお、他のヘッダーの値をマルチバイト文字列で記述する場合、 <em>Encoding はそれらのヘッダーよりも先に記述されていなければならない。</em>
62
+ そのため、このヘッダーは常に文書ファイルの最初に記述しておくことが推奨される。</p>
63
+
64
+ <p>省略された場合には、<em>エンコーディングが UTF-8 であるものとして取り扱う。</em></p>
65
+
66
+ <h3 id="title">Title:</h3>
67
+
68
+ <pre><code>Title: にんじんの美味しい調理法
69
+ </code></pre>
70
+
71
+ <p>その文書の名前(表題)。生成されるhtml文書の title 要素に、ここで指定した値が使われる。
72
+ 省略された場合には、本文中にレベル1の見出し(h1)があればその内容を title 要素とし、なければ「no title」とする。</p>
73
+
74
+ <h2 id="bfheader-97acdc6f75044864bf5fdb105b98da3a">補助的なメタデータ</h2>
75
+
76
+ <h3 id="atom-feed">Atom-Feed:</h3>
77
+
78
+ <h3 id="rdf-feed">RDF-Feed:</h3>
79
+
80
+ <h3 id="rss-feed">RSS-Feed:</h3>
81
+
82
+ <pre><code>Atom-Feed: example.xml
83
+ </code></pre>
84
+
85
+ <p>ニュースフィードの URL。生成される html 文書の head 要素内に、以下のようなリンクが付け加えられ、RSS リーダーなどから登録できるようになる(オートディスカバリー)。</p>
86
+
87
+ <pre><code>&lt;link rel="alternate" type="application/atom+xml" href="example.xml" /&gt;
88
+ </code></pre>
89
+
90
+ <p>どのヘッダー名を用いるかによって、生成される link 要素の type 属性値が異なる。
91
+ 基本的には RSS 1.0 なら RDF-Feed を、RSS 2.0 なら RSS-Feed を、Atom (Atom Syndication Format) なら Atom-Feed を使うことが推奨される。</p>
92
+
93
+ <h3 id="description">Description:</h3>
94
+
95
+ <pre><code>Description: 簡単にチャレンジできる、にんじんの美味しい調理法についての解説。
96
+ </code></pre>
97
+
98
+ <p>その文書の説明。<code>&lt;meta name="description" content="~"&gt;</code> の内容になる。</p>
99
+
100
+ <h3 id="keywords">Keywords:</h3>
101
+
102
+ <pre><code>Description: にんじん,レシピ,料理
103
+ </code></pre>
104
+
105
+ <p>その文書を表すキーワード。<code>&lt;meta name="keywords" content="~"&gt;</code> の内容になる。</p>
106
+
107
+ </body>
108
+ </html>
@@ -38,11 +38,12 @@ require 'digest/md5'
38
38
  require 'logger'
39
39
  require 'strscan'
40
40
  require 'stringio'
41
+ require 'uri'
41
42
 
42
43
 
43
44
  module BlueFeather
44
- VERSION = '0.10'
45
- VERSION_NUMBER = 0.10
45
+ VERSION = '0.11'
46
+ VERSION_NUMBER = 0.11
46
47
 
47
48
 
48
49
  # Fancy methods
@@ -1272,7 +1273,8 @@ module BlueFeather
1272
1273
  # not adapted addresses:
1273
1274
  # <"Abc@def"@example.com> (refer to quoted-string of RFC 5321)
1274
1275
 
1275
- AutoAnchorURLRegexp = /<([a-z]+:[^'">\s]+)>/ # $1 = url
1276
+
1277
+ AutoAnchorURLRegexp = /<(#{URI.regexp})>/ # $1 = url
1276
1278
 
1277
1279
  AutoAnchorEmailRegexp = /<([^'">\s]+?\@[^'">\s]+[.][a-zA-Z]+)>/ # $2 = address
1278
1280
 
@@ -1280,8 +1282,9 @@ module BlueFeather
1280
1282
  ### it.
1281
1283
  def transform_auto_links( str, rs )
1282
1284
  @log.debug " Transforming auto-links"
1283
- str.gsub( AutoAnchorURLRegexp, %{<a href="\\1">\\1</a>}).
1284
- gsub( AutoAnchorEmailRegexp ) {|addr|
1285
+ str.gsub(AutoAnchorURLRegexp){
1286
+ %|<a href="#{Util.escape_html($1)}">#{Util.escape_html($1)}</a>|
1287
+ }.gsub( AutoAnchorEmailRegexp ) {|addr|
1285
1288
  encode_email_address( unescape_special_chars($1) )
1286
1289
  }
1287
1290
  end
@@ -23,10 +23,48 @@ module BlueFeather
23
23
  }
24
24
 
25
25
  ENCODING_LIST = %w(shift-jis euc-jp utf-8 ascii)
26
+
27
+ HELP = <<-EOS
28
+ bluefeather - Extended Markdown Converter
29
+
30
+ Usage: bluefeather [options] file1 [file2 file3 ..]
31
+
32
+ Options:
33
+ -e, --encoding NAME parse input files as encoding of NAME.
34
+ (s[hift-jis] / e[uc-jp] / u[tf-8] / a[scii]
35
+ default: 'utf-8')
36
+ -f, --format TYPE specify format.
37
+ (t[ext] => text mode
38
+ d[ocument] => document mode)
39
+ --force write even if target files have not changed.
40
+ (default: only if target files have changed)
41
+ -h, --help show this help.
42
+ -o, --output DIR output files to DIR. (default: same as input file)
43
+ -q, --quiet no output to stderr.
44
+ --suffix .SUF specify suffix of output files. (default: '.html')
45
+ -v, --verbose verbose mode - output detail of operation.
46
+ --version show BlueFeather version.
47
+
48
+ Advanced Usage:
49
+ * If specify files only '-', bluefeather read from stdin and write to stdout.
50
+
51
+
52
+ Example:
53
+ bluefeather *.bftext *.bfdoc
54
+ bluefeather -v --sufix .xhtml -o ../ sample.markdown
55
+ bluefeather -
56
+
57
+ More info:
58
+ see <http://ruby.morphball.net/bluefeather/>
59
+ EOS
26
60
 
27
61
  def self.run(*args)
28
62
  self.new.run(*args)
29
63
  end
64
+
65
+
66
+
67
+ attr_reader :stdout, :stderr, :stdin
30
68
 
31
69
  def initialize(stdout = $stdout, stderr = $stderr, stdin = $stdin)
32
70
  @stdout, @stderr, @stdin = stdout, stderr, stdin
@@ -37,6 +75,7 @@ module BlueFeather
37
75
 
38
76
  verbose = false
39
77
  quiet = false
78
+ force = false
40
79
  suffix = '.html'
41
80
  format = nil
42
81
  output_dir_path = nil
@@ -48,6 +87,7 @@ module BlueFeather
48
87
 
49
88
  op.on('-e', '--encoding NAME', ENCODING_LIST){|x| encoding = x}
50
89
  op.on('-f', '--format TYPE', FORMAT_TYPE_TABLE){|x| format = x}
90
+ op.on('--force'){|x| force = true}
51
91
  op.on('-v', '--verbose'){ verbose = true }
52
92
  op.on('-o', '--output DIR', String){|x| output_dir_path = Pathname.new(x)}
53
93
  op.on('-q', '--quiet'){ message_out = StringIO.new }
@@ -57,37 +97,7 @@ module BlueFeather
57
97
  return false
58
98
  }
59
99
  op.on('-h', '--help'){
60
- @stdout.puts <<-HELP
61
- bluefeather - Extended Markdown Converter
62
-
63
- Usage: bluefeather [options] file1 [file2 file3 ..]
64
-
65
- Options:
66
- -e, --encoding NAME parse input files as encoding of NAME.
67
- (s[hift-jis] / e[uc-jp] / u[tf-8] / a[scii]
68
- default: 'utf-8')
69
- -f, --format TYPE specify format.
70
- (t[ext] => text mode
71
- d[ocument] => document mode)
72
- -h, --help show this help.
73
- -o, --output DIR output files to DIR. (default: same as input file)
74
- -q, --quiet no output to stderr.
75
- --suffix .SUF specify suffix of output files. (default: '.html')
76
- -v, --verbose verbose mode - output detail of operation.
77
- --version show BlueFeather version.
78
-
79
- Advanced Usage:
80
- * If specify files only '-', bluefeather read from stdin and write to stdout.
81
-
82
-
83
- Example:
84
- bluefeather *.bftext *.bfdoc
85
- bluefeather -v --sufix .xhtml -o ../ sample.markdown
86
- bluefeather -
87
-
88
- More info:
89
- see <http://ruby.morphball.net/bluefeather/>
90
- HELP
100
+ @stdout.puts HELP
91
101
  return false
92
102
  }
93
103
 
@@ -150,6 +160,8 @@ More info:
150
160
 
151
161
  if ext == suffix then
152
162
  message_out.puts "#{src} skipped. (suffix = #{suffix})" if verbose
163
+ elsif not force and dest.exist? and (dest.mtime > src.mtime) then
164
+ message_out.puts "#{src} skipped. (not changed)" if verbose
153
165
  else
154
166
  # judge by extname if format is not specified
155
167
  unless current_format then
@@ -0,0 +1,73 @@
1
+ require 'pathname'
2
+ require(Pathname.new(__FILE__).parent + 'lib/common.rb')
3
+
4
+ require 'stringio'
5
+ require 'bluefeather/cui'
6
+
7
+ include BlueFeather
8
+
9
+ describe 'CUI:' do
10
+ def clear_io
11
+ @stdout.string = ''
12
+ @stderr.string = ''
13
+ end
14
+
15
+ before(:each) do
16
+ @stdout = StringIO.new
17
+ @stderr = StringIO.new
18
+ @stdin = StringIO.new
19
+ @cui = CUI.new(@stdout, @stderr, @stdin)
20
+ end
21
+
22
+ specify 'no argument' do
23
+ @cui.run([])
24
+ @cui.should_not wrote_to_stdout
25
+ @cui.should wrote_to_stderr("ERROR: please text file paths, patterns, or '-' (stdin-mode).\nEx) bluefeather *.bfdoc\n")
26
+ end
27
+
28
+
29
+ specify '-h / --help' do
30
+ @cui.run(%w(-h))
31
+ @cui.should wrote_to_stdout(CUI::HELP)
32
+ @cui.should_not wrote_to_stderr
33
+
34
+ clear_io
35
+
36
+ @cui.run(%w(-h unknown-file))
37
+ @cui.should wrote_to_stdout(CUI::HELP)
38
+ @cui.should_not wrote_to_stderr
39
+ end
40
+
41
+ specify '--version' do
42
+ @cui.run(%w(--version unknown-file))
43
+ @cui.should wrote_to_stdout("bluefeather #{BlueFeather::VERSION}\n")
44
+ @cui.should_not wrote_to_stderr
45
+ end
46
+
47
+ describe 'Encoding Option:' do
48
+ specify "-e == --encoding" do
49
+ Proc.new{@cui.run(['-e', 's'])}.should_not raise_error
50
+ end
51
+
52
+ specify "name is required" do
53
+ Proc.new{@cui.run(['--encoding'])}.should raise_error(OptionParser::MissingArgument)
54
+ end
55
+
56
+ valids = %w(s shift-jis u utf-8)
57
+ valids.each do |name|
58
+ specify "'#{name}' is valid" do
59
+ @cui.run(['--encoding', name])
60
+ end
61
+ end
62
+
63
+ invalids = %w(sjis euc_jp none jis UTF-8)
64
+ invalids.each do |name|
65
+ specify "'#{name}' is invalid" do
66
+ Proc.new{@cui.run(['--encoding', name])}.should raise_error(OptionParser::InvalidArgument)
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+
73
+ end
@@ -77,6 +77,91 @@ alias have_elements_as have_elements
77
77
 
78
78
 
79
79
 
80
+
81
+
82
+ module CUIMatcher
83
+ class WriteToIOBase
84
+ def initialize(expected = nil)
85
+ # if expected is nil, allow any outputs.
86
+ @expected = expected
87
+ end
88
+
89
+ def description
90
+ "write to IO"
91
+ end
92
+
93
+ def matches?(cui)
94
+ @cui = cui
95
+
96
+ if @expected then
97
+ return get_written_string(@cui) == @expected
98
+ else
99
+ return !(get_written_string(@cui).empty?)
100
+ end
101
+
102
+ end
103
+
104
+ def get_written_string(cui)
105
+ # not implemented
106
+ end
107
+
108
+ def failure_message
109
+ if @expected then
110
+ %Q|expected: #{@expected.inspect}\n got: #{get_written_string(@cui).inspect})|
111
+ else
112
+ %Q|expected: any\n got: #{get_written_string(@cui).inspect})|
113
+ end
114
+ end
115
+
116
+ def negative_failure_message
117
+ if @expected then
118
+ %Q|not expected: #{@expected.inspect}\n got: #{get_written_string(@cui).inspect})|
119
+ else
120
+ %Q|not expected: any\n got: #{get_written_string(@cui).inspect})|
121
+ end
122
+ end
123
+ end
124
+
125
+ class WriteToStdout < WriteToIOBase
126
+ def description
127
+ "write to stdout"
128
+ end
129
+
130
+
131
+ def get_written_string(cui)
132
+ cui.stdout.string
133
+ end
134
+
135
+ end
136
+
137
+ class WriteToStderr < WriteToIOBase
138
+ def description
139
+ "write to stderr"
140
+ end
141
+
142
+
143
+ def get_written_string(cui)
144
+ cui.stderr.string
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+
151
+ def write_to_stdout(expected = nil)
152
+ CUIMatcher::WriteToStdout.new(expected)
153
+ end
154
+
155
+ alias wrote_to_stdout write_to_stdout
156
+
157
+ def write_to_stderr(expected = nil)
158
+ CUIMatcher::WriteToStderr.new(expected)
159
+ end
160
+
161
+ alias wrote_to_stderr write_to_stderr
162
+
163
+
164
+
80
165
  =begin
81
166
  # new matcher
82
167
  class String