aozora2html 0.7.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/rubocop.yml +19 -0
- data/.github/workflows/ruby.yml +37 -0
- data/.gitignore +8 -3
- data/.rubocop.yml +111 -0
- data/.rubocop_todo.yml +7 -0
- data/CHANGELOG.md +59 -0
- data/Gemfile +2 -0
- data/Guardfile +3 -1
- data/HACKING.md +45 -0
- data/LICENSE +116 -0
- data/README.md +29 -16
- data/Rakefile +12 -5
- data/aozora2html.gemspec +24 -24
- data/bin/aozora2html +25 -71
- data/lib/aozora2html/accent_parser.rb +99 -0
- data/lib/aozora2html/error.rb +17 -0
- data/lib/aozora2html/header.rb +141 -0
- data/lib/aozora2html/i18n.rb +48 -0
- data/lib/aozora2html/ruby_buffer.rb +116 -0
- data/lib/aozora2html/string_refinements.rb +36 -0
- data/lib/aozora2html/style_stack.rb +33 -0
- data/lib/aozora2html/tag/accent.rb +37 -0
- data/lib/aozora2html/tag/block.rb +21 -0
- data/lib/aozora2html/tag/chitsuki.rb +19 -0
- data/lib/aozora2html/tag/dakuten_katakana.rb +25 -0
- data/lib/aozora2html/tag/decorate.rb +19 -0
- data/lib/aozora2html/tag/dir.rb +17 -0
- data/lib/aozora2html/tag/editor_note.rb +19 -0
- data/lib/aozora2html/tag/embed_gaiji.rb +52 -0
- data/lib/aozora2html/tag/font_size.rb +20 -0
- data/lib/aozora2html/tag/gaiji.rb +12 -0
- data/lib/aozora2html/tag/img.rb +21 -0
- data/lib/aozora2html/tag/indent.rb +8 -0
- data/lib/aozora2html/tag/inline.rb +16 -0
- data/lib/aozora2html/tag/inline_caption.rb +17 -0
- data/lib/aozora2html/tag/inline_font_size.rb +19 -0
- data/lib/aozora2html/tag/inline_keigakomi.rb +17 -0
- data/lib/aozora2html/tag/inline_yokogumi.rb +17 -0
- data/lib/aozora2html/tag/jisage.rb +17 -0
- data/lib/aozora2html/tag/jizume.rb +19 -0
- data/lib/aozora2html/tag/kaeriten.rb +17 -0
- data/lib/aozora2html/tag/keigakomi.rb +19 -0
- data/lib/aozora2html/tag/kunten.rb +12 -0
- data/lib/aozora2html/tag/midashi.rb +20 -0
- data/lib/aozora2html/tag/multiline.rb +9 -0
- data/lib/aozora2html/tag/multiline_caption.rb +13 -0
- data/lib/aozora2html/tag/multiline_chitsuki.rb +10 -0
- data/lib/aozora2html/tag/multiline_jisage.rb +10 -0
- data/lib/aozora2html/tag/multiline_midashi.rb +25 -0
- data/lib/aozora2html/tag/multiline_style.rb +19 -0
- data/lib/aozora2html/tag/multiline_yokogumi.rb +14 -0
- data/lib/aozora2html/tag/okurigana.rb +17 -0
- data/lib/aozora2html/tag/oneline_chitsuki.rb +10 -0
- data/lib/aozora2html/tag/oneline_indent.rb +9 -0
- data/lib/aozora2html/tag/oneline_jisage.rb +10 -0
- data/lib/aozora2html/tag/reference_mentioned.rb +47 -0
- data/lib/aozora2html/tag/ruby.rb +202 -0
- data/lib/aozora2html/tag/un_embed_gaiji.rb +30 -0
- data/lib/aozora2html/tag.rb +57 -0
- data/lib/aozora2html/tag_parser.rb +60 -0
- data/lib/aozora2html/text_buffer.rb +50 -0
- data/lib/aozora2html/utils.rb +156 -0
- data/lib/aozora2html/version.rb +3 -1
- data/lib/aozora2html/yaml_loader.rb +37 -0
- data/lib/aozora2html/zip.rb +4 -0
- data/lib/aozora2html.rb +1359 -8
- data/lib/extensions.rb +12 -0
- data/lib/jstream.rb +139 -0
- data/sample/chukiichiran_kinyurei.html +15 -2
- data/sample/chukiichiran_kinyurei.txt +15 -2
- data/test/test_aozora2html.rb +323 -73
- data/test/test_aozora_accent_parser.rb +34 -6
- data/test/test_command_parse.rb +216 -0
- data/test/test_compat.rb +3 -4
- data/test/test_dakuten_katakana_tag.rb +12 -13
- data/test/test_decorate_tag.rb +11 -7
- data/test/test_dir_tag.rb +11 -7
- data/test/test_editor_note_tag.rb +9 -6
- data/test/test_exception.rb +11 -9
- data/test/test_font_size_tag.rb +22 -11
- data/test/test_gaiji_tag.rb +22 -14
- data/test/test_header.rb +45 -0
- data/test/test_helper.rb +3 -1
- data/test/test_i18n.rb +39 -0
- data/test/test_img_tag.rb +11 -6
- data/test/test_inline_caption_tag.rb +11 -7
- data/test/test_inline_font_size_tag.rb +15 -11
- data/test/test_inline_keigakomi_tag.rb +11 -7
- data/test/test_inline_yokogumi_tag.rb +11 -7
- data/test/test_jizume_tag.rb +11 -8
- data/test/test_jstream.rb +33 -30
- data/test/test_kaeriten_tag.rb +11 -7
- data/test/test_keigakomi_tag.rb +14 -11
- data/test/test_midashi_tag.rb +39 -0
- data/test/test_multiline_caption_tag.rb +11 -8
- data/test/test_multiline_midashi_tag.rb +26 -26
- data/test/test_multiline_style_tag.rb +11 -8
- data/test/test_multiline_yokogumi_tag.rb +11 -8
- data/test/test_okurigana_tag.rb +11 -7
- data/test/test_ruby_parse.rb +130 -0
- data/test/test_ruby_tag.rb +11 -7
- data/test/test_tag_parser.rb +31 -29
- data/vendor/jis2ucs/README.md +3 -6
- data/yml/accent_table.yml +240 -0
- data/yml/command_table.yml +61 -0
- data/yml/jis2ucs.yml +11234 -0
- metadata +99 -21
- data/.travis.yml +0 -12
- data/appveyor.yml +0 -23
- data/lib/accent_tag.rb +0 -23
- data/lib/aozora2html/jis2ucs.rb +0 -11237
- data/lib/embed_gaiji_tag.rb +0 -34
- data/lib/t2hs.rb +0 -2535
data/bin/aozora2html
CHANGED
@@ -1,79 +1,35 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'aozora2html'
|
4
5
|
require 'optparse'
|
5
|
-
require
|
6
|
-
|
7
|
-
# override Aozora2Html#push_chars
|
8
|
-
#
|
9
|
-
# Original Aozora2Html#push_chars does not convert "'" into '''; it's old behaivor
|
10
|
-
# of CGI.escapeHTML().
|
11
|
-
#
|
12
|
-
class Aozora2Html
|
13
|
-
def push_chars(obj)
|
14
|
-
if obj.is_a?(Array)
|
15
|
-
obj.each{|x|
|
16
|
-
push_chars(x)
|
17
|
-
}
|
18
|
-
elsif obj.is_a?(String)
|
19
|
-
if obj.length == 1
|
20
|
-
obj = obj.gsub(/[&\"<>]/, {'&' => '&', '"' => '"', '<' => '<', '>' => '>'})
|
21
|
-
end
|
22
|
-
obj.each_char{|x|
|
23
|
-
push_char(x)
|
24
|
-
}
|
25
|
-
else
|
26
|
-
push_char(obj)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def dispatch_gaiji
|
31
|
-
hook = @stream.peek_char(0)
|
32
|
-
if hook == "[".encode("shift_jis")
|
33
|
-
read_char
|
34
|
-
# embed?
|
35
|
-
command,raw = read_to_nest("]".encode("shift_jis"))
|
36
|
-
try_emb = kuten2png(command)
|
37
|
-
if try_emb != command
|
38
|
-
try_emb
|
39
|
-
elsif command.match(/U\+([0-9A-F]{4,5})/) && Embed_Gaiji_tag.use_unicode
|
40
|
-
unicode_num = $1
|
41
|
-
ch = Embed_Gaiji_tag.new(self, nil, nil, command)
|
42
|
-
ch.unicode = unicode_num
|
43
|
-
ch
|
44
|
-
else
|
45
|
-
# Unemb
|
46
|
-
escape_gaiji(command)
|
47
|
-
end
|
48
|
-
else
|
49
|
-
"※".encode("shift_jis")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
6
|
+
require 'tempfile'
|
7
|
+
require 'open-uri'
|
53
8
|
|
54
9
|
opt = OptionParser.new("Usage: aozora2html [options] <text file> [<html file>]\n")
|
55
10
|
opt.on('--gaiji-dir DIR', 'setting gaiji directory')
|
56
11
|
opt.on('--css-files FILES', 'setting css directory')
|
57
12
|
opt.on('--use-jisx0213', 'use JIS X 0213 character')
|
58
13
|
opt.on('--use-unicode', 'use Unicode character')
|
14
|
+
opt.on('--error-utf8', 'show error messages in UTF-8, not Shift_JIS')
|
59
15
|
opt.version = Aozora2Html::VERSION
|
60
16
|
options = opt.getopts
|
61
17
|
|
62
|
-
|
63
|
-
|
64
|
-
|
18
|
+
gaiji_dir = options['gaiji-dir'] || nil
|
19
|
+
|
20
|
+
css_files = options['css-files']&.split(',')
|
65
21
|
|
66
|
-
if options[
|
67
|
-
|
22
|
+
if options['use-jisx0213']
|
23
|
+
Aozora2Html::Tag::EmbedGaiji.use_jisx0213 = true
|
24
|
+
Aozora2Html::Tag::Accent.use_jisx0213 = true
|
68
25
|
end
|
69
26
|
|
70
|
-
if options[
|
71
|
-
|
72
|
-
Accent_tag.use_jisx0213 = true
|
27
|
+
if options['use-unicode']
|
28
|
+
Aozora2Html::Tag::EmbedGaiji.use_unicode = true
|
73
29
|
end
|
74
30
|
|
75
|
-
if options[
|
76
|
-
|
31
|
+
if options['error-utf8']
|
32
|
+
Aozora2Html::I18n.use_utf8 = true
|
77
33
|
end
|
78
34
|
|
79
35
|
if ARGV.size < 1 || ARGV.size > 2
|
@@ -85,36 +41,34 @@ src_file, dest_file = ARGV[0], ARGV[1]
|
|
85
41
|
|
86
42
|
Dir.mktmpdir do |dir|
|
87
43
|
if dest_file.nil?
|
88
|
-
dest_file = File.join(dir,
|
44
|
+
dest_file = File.join(dir, 'output.html')
|
89
45
|
end
|
90
|
-
if
|
91
|
-
require 'open-uri'
|
46
|
+
if /\Ahttps?:/.match?(src_file)
|
92
47
|
down_file = File.join(dir, File.basename(src_file))
|
93
48
|
begin
|
94
|
-
|
95
|
-
open(src_file){|f1| f0.write(f1.read)}
|
96
|
-
end
|
49
|
+
File.write(down_file, URI.parse(src_file).read)
|
97
50
|
src_file = down_file
|
98
|
-
rescue
|
51
|
+
rescue StandardError
|
99
52
|
$stderr.print "file not found: #{src_file}\n"
|
100
53
|
$stderr.print "Download Error: #{$!}\n"
|
101
54
|
exit 1
|
102
55
|
end
|
103
56
|
else
|
104
|
-
|
57
|
+
unless File.exist?(src_file)
|
105
58
|
$stderr.print "file not found: #{src_file}\n"
|
106
59
|
exit 1
|
107
60
|
end
|
108
61
|
end
|
109
62
|
|
110
|
-
if File.extname(src_file) ==
|
111
|
-
|
63
|
+
if File.extname(src_file) == '.zip'
|
64
|
+
require 'aozora2html/zip'
|
65
|
+
tmpfile = File.join(dir, 'aozora.txt')
|
112
66
|
Aozora2Html::Zip.unzip(src_file, tmpfile)
|
113
|
-
Aozora2Html.new(tmpfile, dest_file).process
|
67
|
+
Aozora2Html.new(tmpfile, dest_file, gaiji_dir: gaiji_dir, css_files: css_files).process
|
114
68
|
else
|
115
|
-
Aozora2Html.new(src_file, dest_file).process
|
69
|
+
Aozora2Html.new(src_file, dest_file, gaiji_dir: gaiji_dir, css_files: css_files).process
|
116
70
|
end
|
117
|
-
|
71
|
+
unless ARGV[1]
|
118
72
|
output = File.read(dest_file)
|
119
73
|
print output
|
120
74
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'ruby_buffer'
|
4
|
+
|
5
|
+
class Aozora2Html
|
6
|
+
# accent特殊文字を生かすための再帰呼び出し
|
7
|
+
class AccentParser < Aozora2Html
|
8
|
+
def initialize(input, endchar, chuuki, image, gaiji_dir:) # rubocop:disable Lint/MissingSuper
|
9
|
+
unless input.is_a?(Jstream)
|
10
|
+
raise ArgumentError, 'tag_parser must supply Jstream as input'
|
11
|
+
end
|
12
|
+
|
13
|
+
@stream = input
|
14
|
+
@gaiji_dir = gaiji_dir
|
15
|
+
@buffer = Aozora2Html::TextBuffer.new
|
16
|
+
@ruby_buf = Aozora2Html::RubyBuffer.new
|
17
|
+
@chuuki_table = chuuki
|
18
|
+
@images = image # globalな環境を記録するアイテムは共有する必要あり
|
19
|
+
@endchar = endchar # 改行は越えられない <br />を出力していられない
|
20
|
+
@closed = nil # 改行での強制撤退チェックフラグ
|
21
|
+
@encount_accent = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# 出力は配列で返す
|
25
|
+
def general_output
|
26
|
+
@ruby_buf.dump_into(@buffer)
|
27
|
+
unless @encount_accent
|
28
|
+
@buffer.unshift(ACCENT_BEGIN)
|
29
|
+
end
|
30
|
+
if @closed && !@encount_accent
|
31
|
+
@buffer.push(ACCENT_END)
|
32
|
+
elsif !@closed
|
33
|
+
@buffer.push("<br />\r\n")
|
34
|
+
end
|
35
|
+
@buffer
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse
|
39
|
+
loop do
|
40
|
+
first = read_char
|
41
|
+
|
42
|
+
found = Aozora2Html::ACCENT_TABLE[first]
|
43
|
+
if found
|
44
|
+
found2 = found[@stream.peek_char(0)]
|
45
|
+
if found2
|
46
|
+
if found2.is_a?(Hash)
|
47
|
+
found3 = found2[@stream.peek_char(1)]
|
48
|
+
if found3
|
49
|
+
first = Aozora2Html::Tag::Accent.new(self, *found3, gaiji_dir: @gaiji_dir)
|
50
|
+
@encount_accent = true
|
51
|
+
@chuuki_table[:accent] = true
|
52
|
+
read_char
|
53
|
+
read_char
|
54
|
+
end
|
55
|
+
elsif found2
|
56
|
+
first = Aozora2Html::Tag::Accent.new(self, *found2, gaiji_dir: @gaiji_dir)
|
57
|
+
@encount_accent = true
|
58
|
+
read_char
|
59
|
+
@chuuki_table[:accent] = true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
case first
|
65
|
+
when Aozora2Html::GAIJI_MARK
|
66
|
+
first = dispatch_gaiji
|
67
|
+
when COMMAND_BEGIN
|
68
|
+
first = dispatch_aozora_command
|
69
|
+
when Aozora2Html::KU
|
70
|
+
assign_kunoji
|
71
|
+
when RUBY_BEGIN_MARK
|
72
|
+
first = apply_ruby
|
73
|
+
end
|
74
|
+
if first == "\r\n"
|
75
|
+
if @encount_accent
|
76
|
+
puts I18n.t(:warn_invalid_accent_brancket, line_number)
|
77
|
+
end
|
78
|
+
throw :terminate
|
79
|
+
elsif first == ACCENT_END
|
80
|
+
@closed = true
|
81
|
+
throw :terminate
|
82
|
+
elsif first == RUBY_PREFIX
|
83
|
+
@ruby_buf.dump_into(@buffer)
|
84
|
+
@ruby_buf.protected = true
|
85
|
+
elsif (first != '') && !first.nil?
|
86
|
+
Utils.illegal_char_check(first, line_number)
|
87
|
+
push_chars(escape_special_chars(first))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def process
|
93
|
+
catch(:terminate) do
|
94
|
+
parse
|
95
|
+
end
|
96
|
+
general_output
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'i18n'
|
4
|
+
|
5
|
+
class Aozora2Html
|
6
|
+
# 例外class
|
7
|
+
class Error < StandardError
|
8
|
+
def initialize(msg)
|
9
|
+
super
|
10
|
+
@message = msg
|
11
|
+
end
|
12
|
+
|
13
|
+
def message(line = 0)
|
14
|
+
I18n.t(:error_stop, line, @message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Aozora2Html
|
4
|
+
# ヘッダ生成用
|
5
|
+
class Header
|
6
|
+
def initialize(css_files:)
|
7
|
+
@header = []
|
8
|
+
@css_files = css_files
|
9
|
+
end
|
10
|
+
|
11
|
+
def push(line)
|
12
|
+
@header.push(line)
|
13
|
+
end
|
14
|
+
|
15
|
+
def out_header_info(hash, attr, true_name = nil)
|
16
|
+
found = hash[attr]
|
17
|
+
if found
|
18
|
+
"<h2 class=\"#{true_name or attr}\">#{found}</h2>\r\n"
|
19
|
+
else
|
20
|
+
''
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def header_element_type(string)
|
25
|
+
original = true
|
26
|
+
string.each_char do |ch|
|
27
|
+
code = ch.unpack1('H*')
|
28
|
+
if ((code >= '00') && (code <= '7f')) || # 1byte
|
29
|
+
((code >= '8140') && (code <= '8258')) || # 1-1, 3-25
|
30
|
+
((code >= '839f') && (code <= '8491')) # 6-1, 7-81
|
31
|
+
# continue
|
32
|
+
else
|
33
|
+
original = false
|
34
|
+
break
|
35
|
+
end
|
36
|
+
end
|
37
|
+
if original
|
38
|
+
:original
|
39
|
+
elsif string.match(PAT_EDITOR)
|
40
|
+
:editor
|
41
|
+
elsif string.match(PAT_HENYAKU)
|
42
|
+
:henyaku
|
43
|
+
elsif string.match(PAT_TRANSLATOR)
|
44
|
+
:translator
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def process_person(string, header_info)
|
49
|
+
type = header_element_type(string)
|
50
|
+
case type
|
51
|
+
when :editor
|
52
|
+
header_info[:editor] = string
|
53
|
+
when :translator
|
54
|
+
header_info[:translator] = string
|
55
|
+
when :henyaku
|
56
|
+
header_info[:henyaku] = string
|
57
|
+
else
|
58
|
+
type = :author
|
59
|
+
header_info[:author] = string
|
60
|
+
end
|
61
|
+
type
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_title(header_info)
|
65
|
+
buf = [:author, :translator, :editor, :henyaku,
|
66
|
+
:title, :original_title,
|
67
|
+
:subtitle, :original_subtitle].filter_map { |item| header_info[item] }
|
68
|
+
buf_str = buf.join(' ')
|
69
|
+
"<title>#{buf_str}</title>"
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_header_info
|
73
|
+
header_info = { title: @header[0] }
|
74
|
+
case @header.length
|
75
|
+
when 2
|
76
|
+
process_person(@header[1], header_info)
|
77
|
+
when 3
|
78
|
+
if header_element_type(@header[1]) == :original
|
79
|
+
header_info[:original_title] = @header[1]
|
80
|
+
process_person(@header[2], header_info)
|
81
|
+
elsif process_person(@header[2], header_info) == :author
|
82
|
+
header_info[:subtitle] = @header[1]
|
83
|
+
else
|
84
|
+
header_info[:author] = @header[1]
|
85
|
+
end
|
86
|
+
when 4
|
87
|
+
if header_element_type(@header[1]) == :original
|
88
|
+
header_info[:original_title] = @header[1]
|
89
|
+
else
|
90
|
+
header_info[:subtitle] = @header[1]
|
91
|
+
end
|
92
|
+
if process_person(@header[3], header_info) == :author
|
93
|
+
header_info[:subtitle] = @header[2]
|
94
|
+
else
|
95
|
+
header_info[:author] = @header[2]
|
96
|
+
end
|
97
|
+
when 5
|
98
|
+
header_info[:original_title] = @header[1]
|
99
|
+
header_info[:subtitle] = @header[2]
|
100
|
+
header_info[:author] = @header[3]
|
101
|
+
if process_person(@header[4], header_info) == :author
|
102
|
+
raise Aozora2Html::Error, 'parser encounted author twice'
|
103
|
+
end
|
104
|
+
when 6
|
105
|
+
header_info[:original_title] = @header[1]
|
106
|
+
header_info[:subtitle] = @header[2]
|
107
|
+
header_info[:original_subtitle] = @header[3]
|
108
|
+
header_info[:author] = @header[4]
|
109
|
+
if process_person(@header[5], header_info) == :author
|
110
|
+
raise Aozora2Html::Error, 'parser encounted author twice'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
header_info
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_html
|
117
|
+
header_info = build_header_info
|
118
|
+
|
119
|
+
# <title> 行を構築
|
120
|
+
html_title = build_title(header_info)
|
121
|
+
|
122
|
+
# 出力
|
123
|
+
out_buf = []
|
124
|
+
out_buf.push("<?xml version=\"1.0\" encoding=\"Shift_JIS\"?>\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\r\n \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"ja\" >\r\n<head>\r\n <meta http-equiv=\"Content-Type\" content=\"text/html;charset=Shift_JIS\" />\r\n <meta http-equiv=\"content-style-type\" content=\"text/css\" />\r\n")
|
125
|
+
@css_files.each do |css|
|
126
|
+
out_buf.push("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"#{css}\" />\r\n")
|
127
|
+
end
|
128
|
+
out_buf.push("\t#{html_title}\r\n <script type=\"text/javascript\" src=\"../../jquery-1.4.2.min.js\"></script>\r\n <link rel=\"Schema.DC\" href=\"http://purl.org/dc/elements/1.1/\" />\r\n <meta name=\"DC.Title\" content=\"#{header_info[:title]}\" />\r\n <meta name=\"DC.Creator\" content=\"#{header_info[:author]}\" />\r\n <meta name=\"DC.Publisher\" content=\"#{AOZORABUNKO}\" />\r\n</head>\r\n<body>\r\n<div class=\"metadata\">\r\n")
|
129
|
+
out_buf.push("<h1 class=\"title\">#{header_info[:title]}</h1>\r\n" +
|
130
|
+
out_header_info(header_info, :original_title) +
|
131
|
+
out_header_info(header_info, :subtitle) +
|
132
|
+
out_header_info(header_info, :original_subtitle) +
|
133
|
+
out_header_info(header_info, :author) +
|
134
|
+
out_header_info(header_info, :editor) +
|
135
|
+
out_header_info(header_info, :translator) +
|
136
|
+
out_header_info(header_info, :henyaku, 'editor-translator'))
|
137
|
+
out_buf.push("<br />\r\n<br />\r\n</div>\r\n<div id=\"contents\" style=\"display:none\"></div><div class=\"main_text\">")
|
138
|
+
out_buf.join
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'string_refinements'
|
4
|
+
|
5
|
+
class Aozora2Html
|
6
|
+
# Internationalization(I18n) class
|
7
|
+
#
|
8
|
+
# コード内に日本語メッセージが氾濫しないようにするためのクラス
|
9
|
+
class I18n
|
10
|
+
@use_utf8 = nil
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :use_utf8
|
14
|
+
end
|
15
|
+
|
16
|
+
MSG = {
|
17
|
+
tag_syntax_error: '注記を重ねる際の原則、「狭い範囲を先に、広い範囲を後に」が守られていません。リンク先の指針を参考に、書き方をあらためてください',
|
18
|
+
undefined_header: '未定義な見出しです',
|
19
|
+
use_crlf: '改行コードを、「CR+LF」にあらためてください',
|
20
|
+
error_stop: "エラー(%d行目):%s. \r\n処理を停止します",
|
21
|
+
invalid_font_size: '文字サイズの指定が不正です',
|
22
|
+
unsupported_ruby: 'サポートされていない複雑なルビ付けです',
|
23
|
+
warn_onebyte: '警告(%d行目):1バイトの「%s」が使われています',
|
24
|
+
warn_chuki: '警告(%d行目):注記記号の誤用の可能性がある、「%s」が使われています',
|
25
|
+
warn_jis_gaiji: '警告(%d行目):JIS外字「%s」が使われています',
|
26
|
+
dont_crlf_in_style: '%s中に改行されました。改行をまたぐ要素にはブロック表記を用いてください',
|
27
|
+
terminate_in_style: '%s中に本文が終了しました',
|
28
|
+
invalid_closing: '%sを閉じようとしましたが、%s中ではありません',
|
29
|
+
invalid_nesting: '%sを終了しようとしましたが、%s中です',
|
30
|
+
dont_use_double_ruby: '同じ箇所に2つのルビはつけられません',
|
31
|
+
dont_allow_triple_ruby: '1つの単語に3つのルビはつけられません',
|
32
|
+
warn_invalid_accent_brancket: '警告(%d行目):アクセント分解の亀甲括弧の始めと終わりが、行中で揃っていません',
|
33
|
+
warn_unexpected_terminator: '警告(%d行目):予期せぬファイル終端',
|
34
|
+
warn_undefined_command: '警告(%d行目):「%s」は未対応のコマンドのため無視します'
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
using StringRefinements
|
38
|
+
|
39
|
+
def self.t(msg, *args)
|
40
|
+
if Aozora2Html::I18n.use_utf8
|
41
|
+
args_sjis = args.map { |arg| arg.is_a?(String) ? arg.to_sjis : arg }
|
42
|
+
(MSG[msg].to_sjis % args_sjis).force_encoding('cp932').to_utf8
|
43
|
+
else
|
44
|
+
MSG[msg].to_sjis % args
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'string_refinements'
|
4
|
+
|
5
|
+
class Aozora2Html
|
6
|
+
# ルビ文字列解析用バッファ
|
7
|
+
class RubyBuffer
|
8
|
+
# `|`が来た時に真にする。ルビの親文字のガード用。
|
9
|
+
attr_accessor :protected
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
clear
|
13
|
+
end
|
14
|
+
|
15
|
+
# バッファの初期化。`""`の1要素のバッファにする。
|
16
|
+
def clear
|
17
|
+
@ruby_buf = [+'']
|
18
|
+
@protected = nil
|
19
|
+
@char_type = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def empty?
|
23
|
+
@ruby_buf.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def present?
|
27
|
+
!empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_a
|
31
|
+
@ruby_buf
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_ruby(parser, ruby)
|
35
|
+
ans = +''
|
36
|
+
notes = []
|
37
|
+
|
38
|
+
@ruby_buf.each do |token|
|
39
|
+
if token.is_a?(Aozora2Html::Tag::UnEmbedGaiji)
|
40
|
+
ans.concat(GAIJI_MARK)
|
41
|
+
token.escape!
|
42
|
+
notes.push(token)
|
43
|
+
else
|
44
|
+
ans.concat(token.to_s)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
notes.unshift(Aozora2Html::Tag::Ruby.new(parser, ans, ruby))
|
49
|
+
clear
|
50
|
+
|
51
|
+
notes
|
52
|
+
end
|
53
|
+
|
54
|
+
def last
|
55
|
+
@ruby_buf.last
|
56
|
+
end
|
57
|
+
|
58
|
+
# バッファ末尾にitemを追加する
|
59
|
+
#
|
60
|
+
# itemとバッファの最後尾がどちらもStringであれば連結したStringにし、
|
61
|
+
# そうでなければバッファの末尾に新しい要素として追加する
|
62
|
+
def push(item)
|
63
|
+
if last.is_a?(String) && item.is_a?(String)
|
64
|
+
@ruby_buf.last.concat(item)
|
65
|
+
else
|
66
|
+
@ruby_buf.push(item)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def length
|
71
|
+
@ruby_buf.length
|
72
|
+
end
|
73
|
+
|
74
|
+
# buffer management
|
75
|
+
def dump_into(buffer)
|
76
|
+
if @protected
|
77
|
+
@ruby_buf.unshift(RUBY_PREFIX)
|
78
|
+
@protected = nil
|
79
|
+
end
|
80
|
+
top = @ruby_buf[0]
|
81
|
+
if top.is_a?(String) && buffer.last.is_a?(String)
|
82
|
+
buffer.last.concat(top)
|
83
|
+
buffer.concat(@ruby_buf[1, @ruby_buf.length])
|
84
|
+
else
|
85
|
+
buffer.concat(@ruby_buf)
|
86
|
+
end
|
87
|
+
clear
|
88
|
+
buffer
|
89
|
+
end
|
90
|
+
|
91
|
+
def push_char(char, buffer)
|
92
|
+
ctype = char_type(char)
|
93
|
+
if (ctype == :hankaku_terminate) && (@char_type == :hankaku)
|
94
|
+
push(char)
|
95
|
+
@char_type = :else
|
96
|
+
elsif @protected || ((ctype != :else) && (ctype == @char_type))
|
97
|
+
push(char)
|
98
|
+
else
|
99
|
+
dump_into(buffer)
|
100
|
+
push(char)
|
101
|
+
@char_type = ctype
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
using StringRefinements
|
108
|
+
|
109
|
+
def char_type(char)
|
110
|
+
## `String#char_type`も定義されているのに注意
|
111
|
+
char.char_type
|
112
|
+
rescue StandardError
|
113
|
+
:else
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Aozora2Html
|
4
|
+
# String extension
|
5
|
+
module StringRefinements
|
6
|
+
refine String do
|
7
|
+
# used in RubyBuffer#char_type
|
8
|
+
def char_type
|
9
|
+
case self
|
10
|
+
when Aozora2Html::REGEX_HIRAGANA
|
11
|
+
:hiragana
|
12
|
+
when Aozora2Html::REGEX_KATAKANA
|
13
|
+
:katakana
|
14
|
+
when Aozora2Html::REGEX_ZENKAKU
|
15
|
+
:zenkaku
|
16
|
+
when Aozora2Html::REGEX_HANKAKU
|
17
|
+
:hankaku
|
18
|
+
when Aozora2Html::REGEX_KANJI
|
19
|
+
:kanji
|
20
|
+
when /[.;"?!)]/
|
21
|
+
:hankaku_terminate
|
22
|
+
else
|
23
|
+
:else
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_sjis
|
28
|
+
encode(Encoding::Shift_JIS)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_utf8
|
32
|
+
encode(Encoding::UTF_8)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Aozora2Html
|
4
|
+
# スタイルの状態管理用スタック
|
5
|
+
#
|
6
|
+
# スタイルの入れ子を扱えるようにスタック構造になっている。
|
7
|
+
# 各要素は`[コマンド文字列, 閉じる際に使うHTML文字列]`という2要素の配列になっている。
|
8
|
+
class StyleStack
|
9
|
+
def initialize
|
10
|
+
@stack = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def push(elem)
|
14
|
+
@stack.push(elem)
|
15
|
+
end
|
16
|
+
|
17
|
+
def empty?
|
18
|
+
@stack.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def pop
|
22
|
+
@stack.pop
|
23
|
+
end
|
24
|
+
|
25
|
+
def last
|
26
|
+
@stack.last
|
27
|
+
end
|
28
|
+
|
29
|
+
def last_command
|
30
|
+
@stack.last[0]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Aozora2Html
|
4
|
+
class Tag
|
5
|
+
# 欧文アクセント文字用
|
6
|
+
class Accent < Aozora2Html::Tag::Inline
|
7
|
+
@use_jisx0213 = nil
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :use_jisx0213
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(parser, code, name, gaiji_dir:)
|
14
|
+
@code = code
|
15
|
+
@name = name
|
16
|
+
@gaiji_dir = gaiji_dir
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def jisx0213_to_unicode(code)
|
21
|
+
Aozora2Html::JIS2UCS[code]
|
22
|
+
end
|
23
|
+
|
24
|
+
def char_type
|
25
|
+
:hankaku
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
if Aozora2Html::Tag::Accent.use_jisx0213
|
30
|
+
jisx0213_to_unicode(@code.sub(%r{.*/}, '').to_sym)
|
31
|
+
else
|
32
|
+
"<img src=\"#{@gaiji_dir}#{@code}.png\" alt=\"" + GAIJI_MARK + "(#{@name})\" class=\"gaiji\" />"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Aozora2Html
|
4
|
+
class Tag
|
5
|
+
# ブロックタグ用class
|
6
|
+
#
|
7
|
+
# 各Tagクラスはこれを継承する
|
8
|
+
class Block < Aozora2Html::Tag
|
9
|
+
def initialize(parser, *_args)
|
10
|
+
super()
|
11
|
+
|
12
|
+
syntax_error unless parser.block_allowed_context?
|
13
|
+
end
|
14
|
+
|
15
|
+
# 必要に基づきmethod overrideする
|
16
|
+
def close_tag
|
17
|
+
'</div>'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|