wtex 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Akira FUNAI <akira -at- funai -dot- com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,2 @@
1
+ See README.ja.* :-)
2
+ README.en is on the way.
Binary file
@@ -0,0 +1,249 @@
1
+ !!! このソフトについて
2
+
3
+ WTeXは、WikiマークアップとTeXマークアップが混在した文書から、LaTeXでタイプセット可能なTeX文書を生成するユーティリティです。段落・見出し・強調・ルビなどのマークアップを、可読性の高いWiki形式で記述し、make一発でTeX→PDFに変換することができます。また、TeXマークアップを混在させることで、高度なレイアウトや数式も表現可能です。
4
+
5
+ ソース:
6
+ |このように、***Wiki***と{\LARGE\bf TeX}の混在した文書《ソース》から、PDFが作れます。
7
+
8
+ 出力:
9
+ ]このように、***Wiki***と{\LARGE\bf TeX}の混在した文書《ソース》から、PDFが作れます。
10
+
11
+ ※作者本人は、プレーンテキスト→縦書きPDFがやりたかっただけなので、その他の機能はオマケ気味です。それなりに御用心ください。ライセンスにもある通り、完全に無保証です。
12
+
13
+ !!! インストールと実行
14
+
15
+ !! 必要条件
16
+
17
+ WTeXでPDFを出力するには、以下のソフトが必要です。
18
+
19
+ * Ruby 1.8/1.9
20
+ * UTF-8を扱えるLaTeX環境(TeX Live 2010、MacTeXで確認しています)
21
+ * GNU互換make
22
+
23
+ !! インストール
24
+
25
+ | gem install wtex
26
+
27
+ !! PDFの作成
28
+
29
+ 適当なディレクトリで、以下を実行します。
30
+
31
+ | wikitex init my_project
32
+
33
+ 生成されたディレクトリ「my_project」には、以下のファイルがコピーされています。
34
+
35
+ | Makefile
36
+ | body.txt
37
+ | head.tex
38
+ | tmpl.tex.report
39
+ | tmpl.tex.tbook
40
+ | out/
41
+
42
+ 最初に、tmpl.tex.*のいずれかをtmpl.texとしてコピーします。tmpl.tex.reportが横書き、tmpl.tex.tbookが縦書きのサンプルです。
43
+
44
+ | cp -p tmpl.tex.report tmpl.tex
45
+
46
+ body.txtに、Wiki/TeXマークアップでソースを記述します。head.texには文書タイトルや著者情報が、tmpl.texにはTeX文書の外枠がありますので、これらも必要に応じて適宜編集してください。完成したら、
47
+
48
+ | make
49
+
50
+ で、(うまく行けば)ディレクトリ内に「body.tex」および「book.pdf」が生成されます。
51
+
52
+ !! Ruby からの利用
53
+
54
+ | require 'rubygems'
55
+ | require 'wtex'
56
+ |
57
+ | wt = WTeX.new
58
+ | tex = wt.tex '***Wiki***{\LARGE\bf TeX}'
59
+
60
+ !!! マークアップ
61
+
62
+ !! 段落と改行
63
+
64
+ 段落の区切りは空行(TeXと同じです)。
65
+ ただし、TeXと違い、段落内の改行は、そのまま反映されます。
66
+
67
+ 段落頭の字下げは、デフォルトでは手動です。
68
+
69
+ !! Wikiマークアップ
70
+
71
+ ! 見出し
72
+
73
+ 1〜3ケの「!」を行の頭に置くと、それぞれ小節・節・章の見出しになります。また、「!」の直後に「*」を付けると、連番が出力されなくなります。
74
+
75
+ ソース:
76
+ | !!! 章
77
+ | !! 節
78
+ | ! 小節
79
+ | !* 小節(番号なし)
80
+
81
+ ! 区切り
82
+
83
+ ハイフン3つ「---」を行の頭に置くと、小節の区切り記号になります。
84
+
85
+ ---
86
+
87
+ ! 強調
88
+
89
+ 2〜4ヶの「*」で文章を囲むと、その範囲が***強調***(デフォルトでは太字&大文字)されます。「*」を増やすほど、大きな文字になります。
90
+
91
+ ソース:
92
+ | これは****ひどい****。
93
+
94
+ 出力:
95
+ ] これは****ひどい****。
96
+
97
+ ! 傍点・アンダーライン
98
+
99
+ 2ケの「_」で文章を囲むと、その範囲に__傍点__(横書きの場合、アンダーライン)が適用されます。
100
+
101
+ ソース:
102
+ | これは__ひどい__。
103
+
104
+ 出力:
105
+ ] これは__ひどい__。
106
+
107
+ ! ルビ
108
+
109
+ 「\verb|ルビ《るび》|」のように記述すると、ルビ《るび》を振ることができます。ルビの適用範囲は自動的に判定されますが、複合語などの場合、「|」記号で区切ることで、部分|指定《してい》も可能です(青空文庫形式に準拠)。
110
+
111
+ ソース:
112
+ | これは酷《ひど》い三|馬鹿《ばか》ですね。
113
+
114
+ 出力:
115
+ ] これは酷《ひど》い三|馬鹿《ばか》ですね。
116
+
117
+ ! ボックス
118
+
119
+ 行の先頭に「]」記号、または「|」記号を置くと、その行は枠付きボックスとして表示されます。行の直前に「foo.rb:」のようにコロン「:」で終わる行を書くと、ボックスのタイトルとして扱われます。「]」で始まるブロックの内部では、WikiマークアップおよびTeXマークアップが利用可能です。「|」で始まるブロックの内部では、WikiマークアップもTeXマークアップも使用できず、ソースの文字がすべてそのまま表示されます。
120
+
121
+ ソース:
122
+ | foo_bar.tex:
123
+ | ]foo,bar,
124
+ | ]{\large\bf bar},**baz**
125
+
126
+ \begin{WTbox}{出力(マークアップが評価される)}
127
+ \begin{WTbox}{foo\_{}bar.tex}
128
+ foo,bar,\\
129
+ {\large\bf bar},{\large\bf baz}
130
+ \end{WTbox}
131
+ \end{WTbox}
132
+
133
+ ソース:
134
+ | foo_bar.tex:
135
+ | |foo,bar,
136
+ | |{\large\bf bar},**baz**
137
+
138
+ \begin{WTbox}{出力(マークアップは評価されない)}
139
+ \begin{WTcode}{foo\_{}bar.tex}
140
+ foo,bar,
141
+ {\large\bf bar},**baz**
142
+ \end{WTcode}
143
+ \end{WTbox}
144
+
145
+ ! 引用
146
+
147
+ 行の先頭に「>」記号を置くと、その行は引用として扱われます。引用の内部では、WikiマークアップおよびTeXマークアップが利用可能です。
148
+
149
+ ソース:
150
+ | >吾輩は猫である。
151
+ | >名前は__まだ無い__。
152
+
153
+ \begin{WTbox}{出力}
154
+ \begin{quote}
155
+ 吾輩は猫である。\\
156
+ 名前は\WTunderline{まだ無い}。
157
+ \end{quote}
158
+ \end{WTbox}
159
+
160
+ ! リスト
161
+
162
+ 行の先頭に「*」または「+」記号を置くと、その行はリストアイテムとして扱われます。「*」は序数なし、「+」だと序数ありです。強調の「\verb|**foo**|」と区別するため、記号とアイテムの間には、必ず空白を入れてください。
163
+
164
+ ソース:
165
+ | * foo
166
+ | * bar
167
+ | *baz←くっつけて書くとリストにならない
168
+
169
+ \begin{WTbox}{出力}
170
+ \begin{itemize}
171
+ \item foo
172
+ \item bar
173
+ \end{itemize}
174
+ *baz←くっつけて書くとリストにならない
175
+ \end{WTbox}
176
+
177
+ リストを入れ子にすることもできます。
178
+
179
+ ソース:
180
+ | + foo
181
+ | +* bar
182
+ | +* baz
183
+ | + qux
184
+
185
+ \begin{WTbox}{出力}
186
+ \begin{enumerate}
187
+ \item foo\begin{itemize}
188
+ \item bar
189
+ \item baz
190
+ \end{itemize}
191
+
192
+ \item qux
193
+ \end{enumerate}
194
+ \end{WTbox}
195
+
196
+ ! テーブル・表
197
+
198
+ 今のところ、Wikiマークアップはありません。TeXで書きましょう。
199
+
200
+ !! TeXとの混在
201
+
202
+ ! 特殊記号の自動エスケープ
203
+
204
+ TeXの特殊記号は、自動的にエスケープされます。「#」「%」「@」などは、そのまま記述可能です。ただし、バックスラッシュ「\verb|\|」・ドル記号「\${}」・中括弧「\verb|{}|」の3種だけは、\verb|\verb|等によるエスケープが必要です。
205
+
206
+ ソース:
207
+ | #, %, &
208
+ | \verb|\|, \${}, \verb|{}|
209
+
210
+ 出力:
211
+ ] #, %, &
212
+ ] \verb|\|, \${}, \verb|{}|
213
+
214
+ ! TeXコマンド、環境、グルーピング
215
+
216
+ 「\verb|\|」で始まるコマンド、「\verb|\begin{...}...\end{...}|」で指定された環境、「\verb|{...}|」内部のグルーピングは、Wikiをスルーして出力されるので、TeXマークアップをそのまま記述することが可能です。
217
+
218
+ ソース:
219
+ | \verb|***Wiki***|
220
+ | \begin{huge}Wiki《るび》\end{huge}
221
+ | {\large\bf Wiki$\heartsuit$}
222
+
223
+ 出力:
224
+ ] \verb|***Wiki***|
225
+ ] \begin{huge}Wiki《るび》\end{huge}
226
+ ] {\large\bf Wiki$\heartsuit$}
227
+
228
+ ! 数式モード
229
+
230
+ 「\verb|$|」または「\verb|$$|」で囲まれた内部は、TeXの数式モードとして扱われます。
231
+
232
+ ソース:
233
+ | これはひどい $x^2 + \sqrt{y}$ です。
234
+
235
+ 出力(テキスト数式モード):
236
+ ] これはひどい $x^2 + \sqrt{y}$ です。
237
+
238
+ ソース:
239
+ | これはひどい $$x^2 + \sqrt{y}$$ です。
240
+
241
+ 出力(ディスプレイ数式モード):
242
+ ] これはひどい $$x^2 + \sqrt{y}$$ です。
243
+
244
+
245
+
246
+ !!! ライセンス
247
+
248
+ 配布条件はMITライセンスとします。
249
+ 詳細は、gem同梱のLICENSEでご確認ください。
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ # Author:: Akira FUNAI
5
+ # Copyright:: Copyright (c) 2011 Akira FUNAI
6
+
7
+ require 'rubygems'
8
+ require 'fileutils'
9
+
10
+ $LOAD_PATH.unshift ::File.expand_path('../lib', ::File.dirname(__FILE__))
11
+ require 'wtex'
12
+
13
+ case ARGV.shift
14
+ when 'init'
15
+ work_name = ARGV.shift || 'my_work'
16
+ work_dir = ::File.expand_path work_name
17
+
18
+ if ::File.exists? work_dir
19
+ $stderr.puts "#{work_dir} already exists."
20
+ exit 1
21
+ else
22
+ $stderr.puts "Setting up files in #{work_dir}..."
23
+ ::FileUtils.cp_r(
24
+ ::File.expand_path('../skel',WTeX.libdir),
25
+ work_name,
26
+ :verbose => :true
27
+ )
28
+ end
29
+ when 'correct'
30
+ when 'convert'
31
+ wt = WTeX.new
32
+ src = nil
33
+ ::File.open('./body.txt', 'r') {|f|
34
+ f.flock ::File::LOCK_SH
35
+ src = f.read
36
+ f.flock ::File::LOCK_UN
37
+ }
38
+
39
+ tex = wt.tex src
40
+ ::File.open('./body.tex', 'a') {|f|
41
+ f.flock ::File::LOCK_EX
42
+ f.seek 0
43
+ f.truncate 0
44
+ f << tex
45
+ f.flock ::File::LOCK_UN
46
+ }
47
+ else
48
+ $stderr.puts 'Usage: wikitex {init NAME|correct|convert}'
49
+ exit 1
50
+ end
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ # Author:: Akira FUNAI
5
+ # Copyright:: Copyright (c) 2011 Akira FUNAI
6
+
7
+ require 'strscan'
8
+
9
+ class WTeX
10
+
11
+ module Characters
12
+ SPECIAL_MAP = {
13
+ '#' => '\\#{}',
14
+ '%' => '\\%{}',
15
+ '&' => '\\&{}',
16
+ '_' => '\\_{}',
17
+ '<' => '\\textless{}',
18
+ '>' => '\\textgreater{}',
19
+ '^' => '\\textasciitilde{}',
20
+ '|' => '\\textbar{}',
21
+ '~' => '\\textasciicircum{}',
22
+ }
23
+ SPECIAL = SPECIAL_MAP.keys.join
24
+ WITHOUT_RUBY = '\s||ぁ-んゝゞ 、。,.?!´`/∥…‥‘’“”()〔〕[]{}〈〉《》「」『』【】♪'
25
+ end
26
+
27
+ def self.libdir
28
+ ::File.dirname __FILE__
29
+ end
30
+
31
+ def tex(str)
32
+ _tex str
33
+ end
34
+
35
+ private
36
+
37
+ def _tex(str)
38
+ tex = ''
39
+ body = ''
40
+ line = ''
41
+ type = :blank
42
+
43
+ markups = []
44
+ rex_line = /(.*?)(\\|\$\$?|\{|\n|\z)/
45
+ s = StringScanner.new str
46
+
47
+ while !s.eos? && s.scan(rex_line)
48
+ line += s[1]
49
+
50
+ if s[2] =~ /\\|\$|\{/
51
+ line += skip_tex_markup(s, s[2], markups)
52
+ next unless s.match? /\z/
53
+ end
54
+
55
+ new_type = wiki_type(line, s)
56
+
57
+ if (new_type != type) || single_line?(type)
58
+ tex += __send__("element_#{type}", body.to_s)
59
+ body = ''
60
+ end
61
+
62
+ body << line << "\n"
63
+ type = new_type
64
+ line = ''
65
+ end
66
+
67
+ tex += __send__("element_#{type}", body.to_s)
68
+ tex.gsub(/\x00(\d+)/) { markups[$1.to_i] }
69
+ end
70
+
71
+ def skip_tex_markup(s, type, markups)
72
+ if type == '\\'
73
+ if s.scan /begin\{(.+?)\}/
74
+ markups << scan_inner_contents(s, "\\begin{#{s[1]}}", "\\end{#{s[1]}}")
75
+ elsif s.scan /verb/
76
+ markups << (s.scan(/(.).*?\1/) ? "\\verb#{s[0]}" : '$\backslash$verb')
77
+ elsif s.scan /.\w*/
78
+ markups << ('\\' + s[0]) # command or escaped character
79
+ end
80
+ elsif type == '$$'
81
+ markups << (s.scan(%r/.*?[^\\]\$\$|\$\$/m) ? "$$#{s[0]}" : '\\${}\\${}')
82
+ elsif type == '$'
83
+ markups << (s.scan(%r/.*?[^\\]\$|\$/m) ? "$#{s[0]}" : '\\${}')
84
+ elsif type == '{'
85
+ markups << scan_inner_contents(s, '{', '}')
86
+ else
87
+ return '???'
88
+ end
89
+ "\x00#{markups.size - 1}"
90
+ end
91
+
92
+ def scan_inner_contents(s, open_tag, close_tag)
93
+ contents = ''
94
+ rex = /(.*?)(\\?#{Regexp.quote(open_tag)}|\\?#{Regexp.quote(close_tag)}|\z)/m
95
+ gen = 1
96
+ until s.eos? || (gen < 1)
97
+ contents << s.scan(rex)
98
+ gen += 1 if s[2] == open_tag
99
+ gen -= 1 if s[2] == close_tag
100
+ end
101
+ open_tag + contents
102
+ end
103
+
104
+ def wiki_type(line, s)
105
+ case line
106
+ when /^!/
107
+ :heading
108
+ when /^\]/
109
+ :box
110
+ when /^\|/
111
+ :code
112
+ when /^>/
113
+ :quote
114
+ when /^\*[\*\+]*\s/
115
+ :itemize
116
+ when /^\+[\*\+]*\s/
117
+ :enumerate
118
+ when /^---+$/
119
+ :separator
120
+ when /^$/
121
+ :blank
122
+ when /:$/
123
+ if s.match? /^\]/
124
+ :box
125
+ elsif s.match? /^\|/
126
+ :code
127
+ else
128
+ :p
129
+ end
130
+ else
131
+ :p
132
+ end
133
+ end
134
+
135
+ def single_line?(type)
136
+ [:heading, :newpage].include? type
137
+ end
138
+
139
+ def element_heading(body)
140
+ body.chomp!
141
+ body.gsub!(/(!+)(\*?)\s*/, '')
142
+ case $1
143
+ when '!'
144
+ "\\subsection#{$2}{#{body}}\n"
145
+ when '!!'
146
+ "\\section#{$2}{#{body}}\n"
147
+ else
148
+ "\\chapter#{$2}{#{body}}\n"
149
+ end
150
+ end
151
+
152
+ def element_box(body)
153
+ _box(body, :box)
154
+ end
155
+
156
+ def element_code(body)
157
+ _box(body, :code)
158
+ end
159
+
160
+ def _box(body, type = :box)
161
+ if body.gsub!(/\A([^\]\|].*):\n/, '')
162
+ title = escape_specials $1
163
+ end
164
+ body.gsub!(/^(\]|\|)/m, '')
165
+ body = element_p(body) if type == :box
166
+ if title
167
+ <<_eos
168
+ \\begin{WT#{type}}{#{title}}
169
+ #{body}\\end{WT#{type}}
170
+ _eos
171
+ else
172
+ <<_eos
173
+ \\begin{WT#{type}-without-title}
174
+ #{body}\\end{WT#{type}-without-title}
175
+ _eos
176
+ end
177
+ end
178
+
179
+ def element_quote(body)
180
+ body.gsub!(/^>/m, '')
181
+ <<_eos
182
+ \\begin{quote}
183
+ #{element_p body}\\end{quote}
184
+ _eos
185
+ end
186
+
187
+ def element_itemize(body)
188
+ _list(body, 'itemize')
189
+ end
190
+
191
+ def element_enumerate(body)
192
+ _list(body, 'enumerate')
193
+ end
194
+
195
+ def _list(body, item_enum)
196
+ items = []
197
+ lines = []
198
+ type = nil
199
+ (body + "\n\n").each_line {|line|
200
+ line.sub!(/^(\*|\+)/, '')
201
+
202
+ unless line =~ /^(\*|\+)/ || lines.empty?
203
+ item = inline lines.shift.to_s.chomp
204
+ unless lines.empty?
205
+ lines = lines.join
206
+ item += (lines =~ /\A\*/) ? element_itemize(lines) : element_enumerate(lines)
207
+ end
208
+ items << "\\item#{item}\n" if item != ''
209
+ lines = []
210
+ end
211
+
212
+ lines << line
213
+ }
214
+
215
+ <<_eos
216
+ \\begin{#{item_enum}}
217
+ #{items.join}\\end{#{item_enum}}
218
+ _eos
219
+ end
220
+
221
+ def element_separator(body)
222
+ "\\WTseparator{}\n"
223
+ end
224
+
225
+ def element_p(body)
226
+ body.gsub!(/\n*\Z/, '')
227
+ body.gsub!(/\n/, "\\\\\\\\\n")
228
+ "#{inline body}\n"
229
+ end
230
+
231
+ def element_blank(body)
232
+ body
233
+ end
234
+
235
+ def inline(body)
236
+ body = convert_ruby body
237
+ body = convert_strong body
238
+ body = convert_underline body
239
+ body = escape_specials body
240
+ end
241
+
242
+ def convert_ruby(body)
243
+ body.gsub!(/[|\|]?([^#{Characters::WITHOUT_RUBY}]+)《(.+?)》/u, '\\\\ruby{\\1}{\\2}')
244
+ body
245
+ end
246
+
247
+ def convert_strong(body)
248
+ body.gsub!(/(\*{2,})(.*?)\1/) {
249
+ case $1
250
+ when '**'
251
+ "{\\large\\bf #{$2}}"
252
+ when '***'
253
+ "{\\LARGE\\bf #{$2}}"
254
+ else
255
+ "{\\Huge\\bf #{$2}}"
256
+ end
257
+ }
258
+ body
259
+ end
260
+
261
+ def convert_underline(body)
262
+ body.gsub!(/__(.*?)__/, '\\WTunderline{\1}')
263
+ body
264
+ end
265
+
266
+ def escape_specials(body)
267
+ body.gsub!(/[#{Characters::SPECIAL}]/) { Characters::SPECIAL_MAP[$&] }
268
+ body
269
+ end
270
+
271
+ end