pseudohikiparser 0.0.0.11.develop → 0.0.0.12.develop
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/pseudohiki2html.rb +1 -410
- data/lib/pseudohiki/converter.rb +411 -0
- data/lib/pseudohiki/htmlformat.rb +4 -0
- data/lib/pseudohiki/htmlplugin.rb +10 -0
- data/lib/pseudohiki/inlineparser.rb +2 -5
- data/lib/pseudohiki/markdownformat.rb +0 -6
- data/lib/pseudohiki/plaintextformat.rb +25 -15
- data/lib/pseudohiki/sinatra_helpers.rb +23 -0
- data/lib/pseudohiki/version.rb +1 -1
- data/lib/pseudohikiparser.rb +95 -0
- data/test/test_htmlformat.rb +4 -0
- data/test/test_plaintextformat.rb +19 -0
- data/test/test_pseudohiki2html.rb +159 -0
- data/test/test_pseudohikiparser.rb +142 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab6d03f5f2b3131e62af81faa6540355f115b489
|
4
|
+
data.tar.gz: d95e43ed55af9b8b0ecb6868b7075315e1a8e5e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66e3bec04f94faa3cbbd21b6e945ad46e23e58d1ffd8b0e36cb1c400e4caee43a4e9ce55e0fdfd70bf5ce6b65a5bf877f979882ae6190f348db5cbdef7cea392
|
7
|
+
data.tar.gz: 7a0be29c24383e9ff375404413df96ca209d7c885dc13eec566828c84ad19dd7cbd9a6029e7cbb0cadaa280aa5746dad8c5bf34e0fc5620db99a2bf962c3d1ac
|
data/bin/pseudohiki2html.rb
CHANGED
@@ -1,415 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# -*- coding: utf-8 -*-
|
3
2
|
|
4
|
-
require '
|
5
|
-
require 'erb'
|
6
|
-
require 'pseudohiki/blockparser'
|
7
|
-
require 'pseudohiki/htmlformat'
|
8
|
-
require 'pseudohiki/plaintextformat'
|
9
|
-
require 'pseudohiki/markdownformat'
|
10
|
-
require 'htmlelement/htmltemplate'
|
11
|
-
require 'htmlelement'
|
12
|
-
|
13
|
-
module PseudoHiki
|
14
|
-
class PageComposer
|
15
|
-
HEADING_WITH_ID_PAT = /^(!{2,3})\[([A-Za-z][0-9A-Za-z_\-.:]*)\]\s*/o
|
16
|
-
|
17
|
-
PlainFormat = PlainTextFormat.create
|
18
|
-
|
19
|
-
def initialize(options)
|
20
|
-
@options = options
|
21
|
-
end
|
22
|
-
|
23
|
-
def formatter
|
24
|
-
@formatter ||= @options.html_template.new
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_plain(line)
|
28
|
-
PlainFormat.format(BlockParser.parse(line.lines.to_a)).to_s.chomp
|
29
|
-
end
|
30
|
-
|
31
|
-
def create_plain_table_of_contents(lines)
|
32
|
-
toc_lines = lines.grep(HEADING_WITH_ID_PAT).map do |line|
|
33
|
-
m = HEADING_WITH_ID_PAT.match(line)
|
34
|
-
heading_depth = m[1].length
|
35
|
-
line.sub(/^!+/o, '*'*heading_depth)
|
36
|
-
end
|
37
|
-
|
38
|
-
@options.formatter.format(BlockParser.parse(toc_lines))
|
39
|
-
end
|
40
|
-
|
41
|
-
def create_html_table_of_contents(lines)
|
42
|
-
toc_lines = lines.grep(HEADING_WITH_ID_PAT).map do |line|
|
43
|
-
m = HEADING_WITH_ID_PAT.match(line)
|
44
|
-
heading_depth, id = m[1].length, m[2].upcase
|
45
|
-
"%s[[%s|#%s]]"%['*'*heading_depth, to_plain(line.sub(HEADING_WITH_ID_PAT,'')), id]
|
46
|
-
end
|
47
|
-
@options.formatter.format(BlockParser.parse(toc_lines)).tap do |toc|
|
48
|
-
toc.traverse do |element|
|
49
|
-
if element.kind_of? HtmlElement and element.tagname == "a"
|
50
|
-
element["title"] = "toc_item: " + element.children.join.chomp
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def create_table_of_contents(lines)
|
57
|
-
return "" unless @options[:toc]
|
58
|
-
return create_plain_table_of_contents(lines) unless @options.html_template
|
59
|
-
create_html_table_of_contents(lines)
|
60
|
-
end
|
61
|
-
|
62
|
-
def split_main_heading(input_lines)
|
63
|
-
return "" unless @options[:split_main_heading]
|
64
|
-
h1_pos = input_lines.find_index {|line| /^![^!]/o =~ line }
|
65
|
-
return "" unless h1_pos
|
66
|
-
tree = BlockParser.parse([input_lines.delete_at(h1_pos)])
|
67
|
-
@options.formatter.format(tree)
|
68
|
-
end
|
69
|
-
|
70
|
-
def create_plain_main(toc, body, h1)
|
71
|
-
contents = [body]
|
72
|
-
contents.unshift toc unless toc.empty?
|
73
|
-
contents.unshift @options.formatter.format(BlockParser.parse("!!" + @options[:toc])) if @options[:toc]
|
74
|
-
contents.unshift h1 unless h1.empty?
|
75
|
-
contents.join($/)
|
76
|
-
end
|
77
|
-
|
78
|
-
def create_html_main(toc, body, h1)
|
79
|
-
return nil unless @options[:toc]
|
80
|
-
toc_container = formatter.create_element("section").tap do |element|
|
81
|
-
element["id"] = "toc"
|
82
|
-
element.push formatter.create_element("h2", @options[:toc]) unless @options[:toc].empty?
|
83
|
-
element.push toc
|
84
|
-
end
|
85
|
-
contents_container = formatter.create_element("section").tap do |element|
|
86
|
-
element["id"] = "contents"
|
87
|
-
element.push body
|
88
|
-
end
|
89
|
-
main = formatter.create_element("section").tap do |element|
|
90
|
-
element["id"] = "main"
|
91
|
-
element.push h1 unless h1.empty?
|
92
|
-
element.push toc_container
|
93
|
-
element.push contents_container
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def create_main(toc, body, h1)
|
98
|
-
return create_plain_main(toc, body, h1) unless @options.html_template
|
99
|
-
create_html_main(toc, body, h1)
|
100
|
-
end
|
101
|
-
|
102
|
-
def create_style(path_to_css_file)
|
103
|
-
style = formatter.create_element("style").tap do |element|
|
104
|
-
element["type"] = "text/css"
|
105
|
-
open(File.expand_path(path_to_css_file)) do |css_file|
|
106
|
-
element.push css_file.read
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def compose_body(input_lines)
|
112
|
-
tree = BlockParser.parse(input_lines)
|
113
|
-
@options.formatter.format(tree)
|
114
|
-
end
|
115
|
-
|
116
|
-
def compose_html(input_lines)
|
117
|
-
h1 = split_main_heading(input_lines)
|
118
|
-
css = @options[:css]
|
119
|
-
toc = create_table_of_contents(input_lines)
|
120
|
-
body = compose_body(input_lines)
|
121
|
-
title = @options.title
|
122
|
-
main = create_main(toc,body, h1)
|
123
|
-
|
124
|
-
if @options[:template]
|
125
|
-
erb = ERB.new(@options.read_template_file)
|
126
|
-
html = erb.result(binding)
|
127
|
-
else
|
128
|
-
html = @options.create_html_template_with_current_options
|
129
|
-
html.head.push create_style(@options[:embed_css]) if @options[:embed_css]
|
130
|
-
html.push main||body
|
131
|
-
end
|
132
|
-
|
133
|
-
html
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
class OptionManager
|
138
|
-
include HtmlElement::CHARSET
|
139
|
-
|
140
|
-
PlainVerboseFormat = PlainTextFormat.create(:verbose_mode => true)
|
141
|
-
MDFormat = MarkDownFormat.create
|
142
|
-
GFMFormat = MarkDownFormat.create(:gfm_style => true)
|
143
|
-
|
144
|
-
class Formatter < Struct.new(:version, :formatter, :template, :ext, :opt_pat)
|
145
|
-
end
|
146
|
-
|
147
|
-
VERSIONS = [
|
148
|
-
["html4", HtmlFormat, HtmlTemplate, ".html", /^h/io],
|
149
|
-
["xhtml1", XhtmlFormat, XhtmlTemplate, ".html", /^x/io],
|
150
|
-
["html5", Xhtml5Format, Xhtml5Template, ".html", /^h5/io],
|
151
|
-
["plain", PageComposer::PlainFormat, nil, ".plain", /^p/io],
|
152
|
-
["plain_verbose", PlainVerboseFormat, nil, ".plain", /^pv/io],
|
153
|
-
["markdown", MDFormat, nil, ".md", /^m/io],
|
154
|
-
["gfm", GFMFormat, nil, ".md", /^g/io]
|
155
|
-
].map {|args| Formatter.new(*args) }
|
156
|
-
|
157
|
-
ENCODING_REGEXP = {
|
158
|
-
/^u/io => 'utf8',
|
159
|
-
/^e/io => 'euc-jp',
|
160
|
-
/^s/io => 'sjis',
|
161
|
-
/^l[a-zA-Z]*1/io => 'latin1'
|
162
|
-
}
|
163
|
-
|
164
|
-
BOM = "\xef\xbb\xbf"
|
165
|
-
BOM.force_encoding("ASCII-8BIT") if BOM.respond_to? :encoding
|
166
|
-
FILE_HEADER_PAT = /^\/\//
|
167
|
-
|
168
|
-
ENCODING_TO_CHARSET = {
|
169
|
-
'utf8' => UTF8,
|
170
|
-
'euc-jp' => EUC_JP,
|
171
|
-
'sjis' => SJIS,
|
172
|
-
'latin1' => LATIN1
|
173
|
-
}
|
174
|
-
|
175
|
-
attr_accessor :need_output_file, :default_title
|
176
|
-
attr_reader :input_file_basename
|
177
|
-
|
178
|
-
def self.remove_bom(input=ARGF)
|
179
|
-
bom = input.read(3)
|
180
|
-
input.rewind unless BOM == bom
|
181
|
-
end
|
182
|
-
|
183
|
-
def initialize(options=nil)
|
184
|
-
@options = options||{
|
185
|
-
:html_version => VERSIONS[0],
|
186
|
-
:lang => 'en',
|
187
|
-
:encoding => 'utf8',
|
188
|
-
:title => nil,
|
189
|
-
:css => "default.css",
|
190
|
-
:embed_css => nil,
|
191
|
-
:base => nil,
|
192
|
-
:template => nil,
|
193
|
-
:output => nil,
|
194
|
-
:force => false,
|
195
|
-
:toc => nil,
|
196
|
-
:split_main_heading => false
|
197
|
-
}
|
198
|
-
@written_option_pat = {}
|
199
|
-
@options.keys.each {|opt| @written_option_pat[opt] = /^\/\/#{opt}:\s*(.*)$/ }
|
200
|
-
end
|
201
|
-
|
202
|
-
def [](key)
|
203
|
-
@options[key]
|
204
|
-
end
|
205
|
-
|
206
|
-
def[]=(key, value)
|
207
|
-
@options[key] = value
|
208
|
-
end
|
209
|
-
|
210
|
-
def win32?
|
211
|
-
true if RUBY_PLATFORM =~ /win/i
|
212
|
-
end
|
213
|
-
|
214
|
-
def value_given?(value)
|
215
|
-
value and not value.empty?
|
216
|
-
end
|
217
|
-
|
218
|
-
def html_template
|
219
|
-
self[:html_version].template
|
220
|
-
end
|
221
|
-
|
222
|
-
def formatter
|
223
|
-
self[:html_version].formatter
|
224
|
-
end
|
225
|
-
|
226
|
-
def charset
|
227
|
-
ENCODING_TO_CHARSET[self[:encoding]]
|
228
|
-
end
|
229
|
-
|
230
|
-
def base
|
231
|
-
base_dir = self[:base]
|
232
|
-
if base_dir and base_dir !~ /[\/\\]\.*$/o
|
233
|
-
base_dir = File.join(base_dir,".")
|
234
|
-
base_dir = "file:///"+base_dir if base_dir !~ /^\./o and win32?
|
235
|
-
end
|
236
|
-
base_dir
|
237
|
-
end
|
238
|
-
|
239
|
-
def title
|
240
|
-
self[:title]||@default_title||"-"
|
241
|
-
end
|
242
|
-
|
243
|
-
def read_template_file
|
244
|
-
File.read(File.expand_path(self[:template]), :encoding => self.charset)
|
245
|
-
end
|
246
|
-
|
247
|
-
def set_html_version(version)
|
248
|
-
VERSIONS.each do |v|
|
249
|
-
if v.version == version
|
250
|
-
return self[:html_version] = v
|
251
|
-
else
|
252
|
-
self[:html_version] = v if v.opt_pat =~ version
|
253
|
-
end
|
254
|
-
end
|
255
|
-
STDERR.puts "\"#{version}\" is an invalid option for --format-version. \"#{self[:html_version].version}\" is chosen instead."
|
256
|
-
end
|
257
|
-
|
258
|
-
def set_html_encoding(given_opt)
|
259
|
-
if ENCODING_REGEXP.values.include? given_opt
|
260
|
-
self[:encoding] = given_opt
|
261
|
-
else
|
262
|
-
ENCODING_REGEXP.each do |pat, encoding|
|
263
|
-
self[:encoding] = encoding if pat =~ given_opt
|
264
|
-
end
|
265
|
-
STDERR.puts "\"#{self[:encoding]}\" is chosen as an encoding system, instead of \"#{given_opt}\"."
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
def set_encoding(given_opt)
|
270
|
-
return nil unless String.new.respond_to? :encoding
|
271
|
-
external, internal = given_opt.split(/:/o)
|
272
|
-
Encoding.default_external = external if external
|
273
|
-
Encoding.default_interanl = internal if internal
|
274
|
-
end
|
275
|
-
|
276
|
-
def parse_command_line_options
|
277
|
-
OptionParser.new("** Convert texts written in a Hiki-like notation into HTML **
|
278
|
-
USAGE: #{File.basename(__FILE__)} [options]") do |opt|
|
279
|
-
opt.on("-f [html_version]", "--format-version [=format_version]",
|
280
|
-
"HTML version to be used. Choose html4, xhtml1, html5, plain, plain_verbose, markdown or gfm (default: #{self[:html_version].version})") do |version|
|
281
|
-
self.set_html_version(version)
|
282
|
-
end
|
283
|
-
|
284
|
-
opt.on("-l [lang]", "--lang [=lang]",
|
285
|
-
"Set the value of charset attributes (default: #{self[:lang]})") do |lang|
|
286
|
-
self[:lang] = lang if value_given?(lang)
|
287
|
-
end
|
288
|
-
|
289
|
-
opt.on("-e [encoding]", "--format-encoding [=encoding]",
|
290
|
-
"Available options: utf8, euc-jp, sjis, latin1 (default: #{self[:encoding]})") do |given_opt|
|
291
|
-
self.set_html_encoding(given_opt)
|
292
|
-
end
|
293
|
-
|
294
|
-
opt.on("-E [ex[:in]]", "--encoding [=ex[:in]]",
|
295
|
-
"Specify the default external and internal character encodings (same as the option of MRI") do |given_opt|
|
296
|
-
self.set_encoding(given_opt)
|
297
|
-
end
|
298
|
-
|
299
|
-
#use '-w' to avoid the conflict with the short option for '[-t]emplate'
|
300
|
-
opt.on("-w [(window) title]", "--title [=title]",
|
301
|
-
"Set the value of the <title> element (default: the basename of the input file)") do |title|
|
302
|
-
self[:title] = title if value_given?(title)
|
303
|
-
end
|
304
|
-
|
305
|
-
opt.on("-c [css]", "--css [=css]",
|
306
|
-
"Set the path to a css file to be used (default: #{self[:css]})") do |css|
|
307
|
-
self[:css] = css
|
308
|
-
end
|
309
|
-
|
310
|
-
opt.on("-C [path_to_css_file]", "--embed-css [=path_to_css_file]",
|
311
|
-
"Set the path to a css file to embed (default: not to embed)") do |path_to_css_file|
|
312
|
-
self[:embed_css] = path_to_css_file
|
313
|
-
end
|
314
|
-
|
315
|
-
opt.on("-b [base]", "--base [=base]",
|
316
|
-
"Specify the value of href attribute of the <base> element (default: not specified)") do |base_dir|
|
317
|
-
self[:base] = base_dir if value_given?(base_dir)
|
318
|
-
end
|
319
|
-
|
320
|
-
opt.on("-t [template]", "--template [=template]",
|
321
|
-
"Specify a template file written in eruby format with \"<%= body %>\" inside (default: not specified)") do |template|
|
322
|
-
self[:template] = template if value_given?(template)
|
323
|
-
end
|
324
|
-
|
325
|
-
opt.on("-o [output]", "--output [=output]",
|
326
|
-
"Output to the specified file. If no file is given, \"[input_file_basename].html\" will be used.(default: STDOUT)") do |output|
|
327
|
-
self[:output] = File.expand_path(output) if value_given?(output)
|
328
|
-
self.need_output_file = true
|
329
|
-
end
|
330
|
-
|
331
|
-
opt.on("-F", "--force",
|
332
|
-
"Force to apply command line options.(default: false)") do |force|
|
333
|
-
self[:force] = force
|
334
|
-
end
|
335
|
-
|
336
|
-
opt.on("-m [contents-title]", "--table-of-contents [=contents-title]",
|
337
|
-
"Include the list of h2 and/or h3 headings with ids.(default: nil)") do |toc_title|
|
338
|
-
self[:toc] = toc_title
|
339
|
-
end
|
340
|
-
|
341
|
-
opt.on("-s", "--split-main-heading",
|
342
|
-
"Split the first h1 element") do |should_be_split|
|
343
|
-
self[:split_main_heading] = should_be_split
|
344
|
-
end
|
345
|
-
|
346
|
-
opt.parse!
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
def check_argv
|
351
|
-
case ARGV.length
|
352
|
-
when 0
|
353
|
-
if self.need_output_file and not self[:output]
|
354
|
-
raise "You must specify a file name for output"
|
355
|
-
end
|
356
|
-
when 1
|
357
|
-
self.read_input_filename(ARGV[0])
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
def set_options_from_command_line
|
362
|
-
parse_command_line_options
|
363
|
-
check_argv
|
364
|
-
@default_title = @input_file_basename
|
365
|
-
end
|
366
|
-
|
367
|
-
def set_options_from_input_file(input_lines)
|
368
|
-
input_lines.each do |line|
|
369
|
-
break if FILE_HEADER_PAT !~ line
|
370
|
-
line = line.chomp
|
371
|
-
@options.keys.each do |opt|
|
372
|
-
if @written_option_pat[opt] =~ line and not self[:force]
|
373
|
-
self[opt] = $1
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
|
-
def create_html_template_with_current_options
|
380
|
-
return [] unless self.html_template
|
381
|
-
html = self.html_template.new
|
382
|
-
html.charset = self.charset
|
383
|
-
html.language = self[:lang]
|
384
|
-
html.default_css = self[:css] if self[:css]
|
385
|
-
html.base = self.base if self[:base]
|
386
|
-
html.title = self.title
|
387
|
-
html
|
388
|
-
end
|
389
|
-
|
390
|
-
def read_input_filename(filename)
|
391
|
-
@input_file_dir, @input_file_name = File.split(File.expand_path(filename))
|
392
|
-
@input_file_basename = File.basename(@input_file_name,".*")
|
393
|
-
end
|
394
|
-
|
395
|
-
def output_filename
|
396
|
-
return nil unless self.need_output_file
|
397
|
-
if self[:output]
|
398
|
-
File.expand_path(self[:output])
|
399
|
-
else
|
400
|
-
File.join(@input_file_dir, @input_file_basename + self[:html_version].ext)
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
def open_output
|
405
|
-
if self.output_filename
|
406
|
-
open(self.output_filename, "w") {|f| yield f }
|
407
|
-
else
|
408
|
-
yield STDOUT
|
409
|
-
end
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end
|
3
|
+
require 'pseudohiki/converter'
|
413
4
|
|
414
5
|
options = PseudoHiki::OptionManager.new
|
415
6
|
options.set_options_from_command_line
|