aozora2html 0.7.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rubocop.yml +19 -0
  3. data/.github/workflows/ruby.yml +37 -0
  4. data/.gitignore +8 -3
  5. data/.rubocop.yml +111 -0
  6. data/.rubocop_todo.yml +7 -0
  7. data/CHANGELOG.md +59 -0
  8. data/Gemfile +2 -0
  9. data/Guardfile +3 -1
  10. data/HACKING.md +45 -0
  11. data/LICENSE +116 -0
  12. data/README.md +29 -16
  13. data/Rakefile +12 -5
  14. data/aozora2html.gemspec +24 -24
  15. data/bin/aozora2html +25 -71
  16. data/lib/aozora2html/accent_parser.rb +99 -0
  17. data/lib/aozora2html/error.rb +17 -0
  18. data/lib/aozora2html/header.rb +141 -0
  19. data/lib/aozora2html/i18n.rb +48 -0
  20. data/lib/aozora2html/ruby_buffer.rb +116 -0
  21. data/lib/aozora2html/string_refinements.rb +36 -0
  22. data/lib/aozora2html/style_stack.rb +33 -0
  23. data/lib/aozora2html/tag/accent.rb +37 -0
  24. data/lib/aozora2html/tag/block.rb +21 -0
  25. data/lib/aozora2html/tag/chitsuki.rb +19 -0
  26. data/lib/aozora2html/tag/dakuten_katakana.rb +25 -0
  27. data/lib/aozora2html/tag/decorate.rb +19 -0
  28. data/lib/aozora2html/tag/dir.rb +17 -0
  29. data/lib/aozora2html/tag/editor_note.rb +19 -0
  30. data/lib/aozora2html/tag/embed_gaiji.rb +52 -0
  31. data/lib/aozora2html/tag/font_size.rb +20 -0
  32. data/lib/aozora2html/tag/gaiji.rb +12 -0
  33. data/lib/aozora2html/tag/img.rb +21 -0
  34. data/lib/aozora2html/tag/indent.rb +8 -0
  35. data/lib/aozora2html/tag/inline.rb +16 -0
  36. data/lib/aozora2html/tag/inline_caption.rb +17 -0
  37. data/lib/aozora2html/tag/inline_font_size.rb +19 -0
  38. data/lib/aozora2html/tag/inline_keigakomi.rb +17 -0
  39. data/lib/aozora2html/tag/inline_yokogumi.rb +17 -0
  40. data/lib/aozora2html/tag/jisage.rb +17 -0
  41. data/lib/aozora2html/tag/jizume.rb +19 -0
  42. data/lib/aozora2html/tag/kaeriten.rb +17 -0
  43. data/lib/aozora2html/tag/keigakomi.rb +19 -0
  44. data/lib/aozora2html/tag/kunten.rb +12 -0
  45. data/lib/aozora2html/tag/midashi.rb +20 -0
  46. data/lib/aozora2html/tag/multiline.rb +9 -0
  47. data/lib/aozora2html/tag/multiline_caption.rb +13 -0
  48. data/lib/aozora2html/tag/multiline_chitsuki.rb +10 -0
  49. data/lib/aozora2html/tag/multiline_jisage.rb +10 -0
  50. data/lib/aozora2html/tag/multiline_midashi.rb +25 -0
  51. data/lib/aozora2html/tag/multiline_style.rb +19 -0
  52. data/lib/aozora2html/tag/multiline_yokogumi.rb +14 -0
  53. data/lib/aozora2html/tag/okurigana.rb +17 -0
  54. data/lib/aozora2html/tag/oneline_chitsuki.rb +10 -0
  55. data/lib/aozora2html/tag/oneline_indent.rb +9 -0
  56. data/lib/aozora2html/tag/oneline_jisage.rb +10 -0
  57. data/lib/aozora2html/tag/reference_mentioned.rb +47 -0
  58. data/lib/aozora2html/tag/ruby.rb +202 -0
  59. data/lib/aozora2html/tag/un_embed_gaiji.rb +30 -0
  60. data/lib/aozora2html/tag.rb +57 -0
  61. data/lib/aozora2html/tag_parser.rb +60 -0
  62. data/lib/aozora2html/text_buffer.rb +50 -0
  63. data/lib/aozora2html/utils.rb +156 -0
  64. data/lib/aozora2html/version.rb +3 -1
  65. data/lib/aozora2html/yaml_loader.rb +37 -0
  66. data/lib/aozora2html/zip.rb +4 -0
  67. data/lib/aozora2html.rb +1359 -8
  68. data/lib/extensions.rb +12 -0
  69. data/lib/jstream.rb +139 -0
  70. data/sample/chukiichiran_kinyurei.html +15 -2
  71. data/sample/chukiichiran_kinyurei.txt +15 -2
  72. data/test/test_aozora2html.rb +323 -73
  73. data/test/test_aozora_accent_parser.rb +34 -6
  74. data/test/test_command_parse.rb +216 -0
  75. data/test/test_compat.rb +3 -4
  76. data/test/test_dakuten_katakana_tag.rb +12 -13
  77. data/test/test_decorate_tag.rb +11 -7
  78. data/test/test_dir_tag.rb +11 -7
  79. data/test/test_editor_note_tag.rb +9 -6
  80. data/test/test_exception.rb +11 -9
  81. data/test/test_font_size_tag.rb +22 -11
  82. data/test/test_gaiji_tag.rb +22 -14
  83. data/test/test_header.rb +45 -0
  84. data/test/test_helper.rb +3 -1
  85. data/test/test_i18n.rb +39 -0
  86. data/test/test_img_tag.rb +11 -6
  87. data/test/test_inline_caption_tag.rb +11 -7
  88. data/test/test_inline_font_size_tag.rb +15 -11
  89. data/test/test_inline_keigakomi_tag.rb +11 -7
  90. data/test/test_inline_yokogumi_tag.rb +11 -7
  91. data/test/test_jizume_tag.rb +11 -8
  92. data/test/test_jstream.rb +33 -30
  93. data/test/test_kaeriten_tag.rb +11 -7
  94. data/test/test_keigakomi_tag.rb +14 -11
  95. data/test/test_midashi_tag.rb +39 -0
  96. data/test/test_multiline_caption_tag.rb +11 -8
  97. data/test/test_multiline_midashi_tag.rb +26 -26
  98. data/test/test_multiline_style_tag.rb +11 -8
  99. data/test/test_multiline_yokogumi_tag.rb +11 -8
  100. data/test/test_okurigana_tag.rb +11 -7
  101. data/test/test_ruby_parse.rb +130 -0
  102. data/test/test_ruby_tag.rb +11 -7
  103. data/test/test_tag_parser.rb +31 -29
  104. data/vendor/jis2ucs/README.md +3 -6
  105. data/yml/accent_table.yml +240 -0
  106. data/yml/command_table.yml +61 -0
  107. data/yml/jis2ucs.yml +11234 -0
  108. metadata +99 -21
  109. data/.travis.yml +0 -12
  110. data/appveyor.yml +0 -23
  111. data/lib/accent_tag.rb +0 -23
  112. data/lib/aozora2html/jis2ucs.rb +0 -11237
  113. data/lib/embed_gaiji_tag.rb +0 -34
  114. 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 "tempfile"
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(/[&\"<>]/, {'&' => '&amp;', '"' => '&quot;', '<' => '&lt;', '>' => '&gt;'})
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
- if options["gaiji-dir"]
63
- $gaiji_dir = options["gaiji-dir"]
64
- end
18
+ gaiji_dir = options['gaiji-dir'] || nil
19
+
20
+ css_files = options['css-files']&.split(',')
65
21
 
66
- if options["css-files"]
67
- $css_files = options["css-files"].split(",")
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["use-jisx0213"]
71
- Embed_Gaiji_tag.use_jisx0213 = true
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["use-unicode"]
76
- Embed_Gaiji_tag.use_unicode = true
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, "output.html")
44
+ dest_file = File.join(dir, 'output.html')
89
45
  end
90
- if src_file =~ /\Ahttps?:/
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
- open(down_file, "wb") do |f0|
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
- if !File.exist?(src_file)
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) == ".zip"
111
- tmpfile = File.join(dir, "aozora.txt")
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
- if !ARGV[1]
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