aozora2html 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rubocop.yml +19 -0
  3. data/.github/workflows/ruby.yml +4 -1
  4. data/.rubocop.yml +36 -152
  5. data/.rubocop_todo.yml +7 -0
  6. data/CHANGELOG.md +26 -0
  7. data/Gemfile +2 -0
  8. data/Guardfile +3 -1
  9. data/HACKING.md +45 -0
  10. data/README.md +14 -6
  11. data/Rakefile +12 -5
  12. data/aozora2html.gemspec +24 -22
  13. data/bin/aozora2html +21 -19
  14. data/lib/aozora2html/accent_parser.rb +62 -54
  15. data/lib/aozora2html/error.rb +5 -4
  16. data/lib/aozora2html/header.rb +20 -18
  17. data/lib/aozora2html/i18n.rb +40 -20
  18. data/lib/aozora2html/ruby_buffer.rb +63 -28
  19. data/lib/aozora2html/string_refinements.rb +36 -0
  20. data/lib/aozora2html/style_stack.rb +6 -0
  21. data/lib/aozora2html/tag/accent.rb +10 -12
  22. data/lib/aozora2html/tag/block.rb +11 -9
  23. data/lib/aozora2html/tag/chitsuki.rb +6 -2
  24. data/lib/aozora2html/tag/dakuten_katakana.rb +10 -8
  25. data/lib/aozora2html/tag/decorate.rb +4 -3
  26. data/lib/aozora2html/tag/dir.rb +4 -2
  27. data/lib/aozora2html/tag/editor_note.rb +7 -4
  28. data/lib/aozora2html/tag/embed_gaiji.rb +15 -11
  29. data/lib/aozora2html/tag/font_size.rb +5 -2
  30. data/lib/aozora2html/tag/gaiji.rb +4 -3
  31. data/lib/aozora2html/tag/img.rb +4 -4
  32. data/lib/aozora2html/tag/indent.rb +3 -3
  33. data/lib/aozora2html/tag/inline.rb +10 -7
  34. data/lib/aozora2html/tag/inline_caption.rb +4 -2
  35. data/lib/aozora2html/tag/inline_font_size.rb +4 -3
  36. data/lib/aozora2html/tag/inline_keigakomi.rb +4 -2
  37. data/lib/aozora2html/tag/inline_yokogumi.rb +4 -3
  38. data/lib/aozora2html/tag/jisage.rb +3 -1
  39. data/lib/aozora2html/tag/jizume.rb +3 -0
  40. data/lib/aozora2html/tag/kaeriten.rb +4 -2
  41. data/lib/aozora2html/tag/keigakomi.rb +15 -9
  42. data/lib/aozora2html/tag/kunten.rb +4 -4
  43. data/lib/aozora2html/tag/midashi.rb +3 -1
  44. data/lib/aozora2html/tag/multiline.rb +3 -0
  45. data/lib/aozora2html/tag/multiline_caption.rb +6 -8
  46. data/lib/aozora2html/tag/multiline_chitsuki.rb +3 -1
  47. data/lib/aozora2html/tag/multiline_jisage.rb +3 -1
  48. data/lib/aozora2html/tag/multiline_midashi.rb +6 -3
  49. data/lib/aozora2html/tag/multiline_style.rb +5 -3
  50. data/lib/aozora2html/tag/multiline_yokogumi.rb +6 -9
  51. data/lib/aozora2html/tag/okurigana.rb +4 -2
  52. data/lib/aozora2html/tag/oneline_chitsuki.rb +3 -2
  53. data/lib/aozora2html/tag/oneline_indent.rb +8 -1
  54. data/lib/aozora2html/tag/oneline_jisage.rb +3 -0
  55. data/lib/aozora2html/tag/reference_mentioned.rb +22 -21
  56. data/lib/aozora2html/tag/ruby.rb +174 -70
  57. data/lib/aozora2html/tag/un_embed_gaiji.rb +8 -2
  58. data/lib/aozora2html/tag.rb +40 -38
  59. data/lib/aozora2html/tag_parser.rb +23 -16
  60. data/lib/aozora2html/text_buffer.rb +50 -0
  61. data/lib/aozora2html/utils.rb +113 -50
  62. data/lib/aozora2html/version.rb +3 -1
  63. data/lib/aozora2html/yaml_loader.rb +8 -2
  64. data/lib/aozora2html/zip.rb +4 -0
  65. data/lib/aozora2html.rb +1358 -3
  66. data/lib/extensions.rb +2 -34
  67. data/lib/jstream.rb +96 -25
  68. data/sample/chukiichiran_kinyurei.html +15 -2
  69. data/sample/chukiichiran_kinyurei.txt +15 -2
  70. data/test/test_aozora2html.rb +137 -148
  71. data/test/test_aozora_accent_parser.rb +26 -9
  72. data/test/test_command_parse.rb +25 -22
  73. data/test/test_compat.rb +3 -4
  74. data/test/test_dakuten_katakana_tag.rb +10 -12
  75. data/test/test_decorate_tag.rb +9 -6
  76. data/test/test_dir_tag.rb +9 -6
  77. data/test/test_editor_note_tag.rb +8 -5
  78. data/test/test_exception.rb +10 -8
  79. data/test/test_font_size_tag.rb +16 -13
  80. data/test/test_gaiji_tag.rb +15 -14
  81. data/test/test_header.rb +25 -40
  82. data/test/test_helper.rb +3 -1
  83. data/test/test_i18n.rb +22 -6
  84. data/test/test_img_tag.rb +9 -5
  85. data/test/test_inline_caption_tag.rb +9 -6
  86. data/test/test_inline_font_size_tag.rb +13 -10
  87. data/test/test_inline_keigakomi_tag.rb +9 -6
  88. data/test/test_inline_yokogumi_tag.rb +9 -6
  89. data/test/test_jizume_tag.rb +9 -7
  90. data/test/test_jstream.rb +33 -30
  91. data/test/test_kaeriten_tag.rb +9 -6
  92. data/test/test_keigakomi_tag.rb +11 -9
  93. data/test/test_midashi_tag.rb +15 -14
  94. data/test/test_multiline_caption_tag.rb +7 -5
  95. data/test/test_multiline_midashi_tag.rb +24 -25
  96. data/test/test_multiline_style_tag.rb +9 -7
  97. data/test/test_multiline_yokogumi_tag.rb +7 -5
  98. data/test/test_okurigana_tag.rb +9 -6
  99. data/test/test_ruby_parse.rb +14 -14
  100. data/test/test_ruby_tag.rb +9 -6
  101. data/test/test_tag_parser.rb +28 -26
  102. metadata +60 -14
  103. data/.travis.yml +0 -12
  104. data/lib/t2hs.rb +0 -1607
@@ -1,16 +1,18 @@
1
- # encoding: utf-8
2
- require 'aozora2html/ruby_buffer'
3
- class Aozora2Html
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ruby_buffer'
4
4
 
5
+ class Aozora2Html
5
6
  # accent特殊文字を生かすための再帰呼び出し
6
7
  class AccentParser < Aozora2Html
7
-
8
- def initialize(input, endchar, chuuki, image)
9
- if not(input.is_a?(Jstream))
10
- raise ArgumentError, "tag_parser must supply Jstream as input"
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
11
  end
12
+
12
13
  @stream = input
13
- @buffer = []
14
+ @gaiji_dir = gaiji_dir
15
+ @buffer = Aozora2Html::TextBuffer.new
14
16
  @ruby_buf = Aozora2Html::RubyBuffer.new
15
17
  @chuuki_table = chuuki
16
18
  @images = image # globalな環境を記録するアイテムは共有する必要あり
@@ -19,71 +21,77 @@ class Aozora2Html
19
21
  @encount_accent = nil
20
22
  end
21
23
 
22
- def general_output # 出力は配列で返す
24
+ # 出力は配列で返す
25
+ def general_output
23
26
  @ruby_buf.dump_into(@buffer)
24
- if !@encount_accent
25
- @buffer.unshift("〔".encode("shift_jis"))
27
+ unless @encount_accent
28
+ @buffer.unshift(ACCENT_BEGIN)
26
29
  end
27
- if @closed and !@encount_accent
28
- @buffer.push("〕".encode("shift_jis"))
29
- elsif not(@closed)
30
+ if @closed && !@encount_accent
31
+ @buffer.push(ACCENT_END)
32
+ elsif !@closed
30
33
  @buffer.push("<br />\r\n")
31
34
  end
32
35
  @buffer
33
36
  end
34
37
 
35
38
  def parse
36
- first = read_char
37
- if found = Aozora2Html::ACCENT_TABLE[first]
38
- if found2 = found[@stream.peek_char(0)]
39
- if found2.is_a?(Hash)
40
- if found3 = found2[@stream.peek_char(1)]
41
- first = Aozora2Html::Tag::Accent.new(self, *found3)
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)
42
57
  @encount_accent = true
43
- @chuuki_table[:accent] = true
44
- read_char
45
58
  read_char
59
+ @chuuki_table[:accent] = true
46
60
  end
47
- elsif found2
48
- first = Aozora2Html::Tag::Accent.new(self, *found2)
49
- @encount_accent = true
50
- read_char
51
- @chuuki_table[:accent] = true
52
61
  end
53
62
  end
54
- end
55
- case first
56
- when Aozora2Html::GAIJI_MARK
57
- first = dispatch_gaiji
58
- when "[".encode("shift_jis")
59
- first = dispatch_aozora_command
60
- when Aozora2Html::KU
61
- assign_kunoji
62
- when "《".encode("shift_jis")
63
- first = apply_ruby
64
- end
65
- if first == "\r\n"
66
- if @encount_accent
67
- puts "警告(#{line_number}行目):アクセント分解の亀甲括弧の始めと終わりが、行中で揃っていません".encode("shift_jis")
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))
68
88
  end
69
- throw :terminate
70
- elsif first == "〕".encode("shift_jis")
71
- @closed = true
72
- throw :terminate
73
- elsif first == RUBY_PREFIX
74
- @ruby_buf.dump_into(@buffer)
75
- @ruby_buf.protected = true
76
- elsif first != "" and first != nil
77
- illegal_char_check(first, line_number)
78
- push_chars(first)
79
89
  end
80
90
  end
81
91
 
82
92
  def process
83
93
  catch(:terminate) do
84
- loop do
85
- parse
86
- end
94
+ parse
87
95
  end
88
96
  general_output
89
97
  end
@@ -1,10 +1,12 @@
1
- require "aozora2html/i18n"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'i18n'
2
4
 
3
- # 例外class
4
5
  class Aozora2Html
6
+ # 例外class
5
7
  class Error < StandardError
6
-
7
8
  def initialize(msg)
9
+ super
8
10
  @message = msg
9
11
  end
10
12
 
@@ -13,4 +15,3 @@ class Aozora2Html
13
15
  end
14
16
  end
15
17
  end
16
-
@@ -1,8 +1,11 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
2
3
  class Aozora2Html
4
+ # ヘッダ生成用
3
5
  class Header
4
- def initialize()
6
+ def initialize(css_files:)
5
7
  @header = []
8
+ @css_files = css_files
6
9
  end
7
10
 
8
11
  def push(line)
@@ -14,17 +17,17 @@ class Aozora2Html
14
17
  if found
15
18
  "<h2 class=\"#{true_name or attr}\">#{found}</h2>\r\n"
16
19
  else
17
- ""
20
+ ''
18
21
  end
19
22
  end
20
23
 
21
24
  def header_element_type(string)
22
25
  original = true
23
26
  string.each_char do |ch|
24
- code = ch.unpack("H*")[0]
25
- if ("00" <= code and code <= "7f") or # 1byte
26
- ("8140" <= code and code <= "8258") or # 1-1, 3-25
27
- ("839f" <= code and code <= "8491") # 6-1, 7-81
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
28
31
  # continue
29
32
  else
30
33
  original = false
@@ -61,13 +64,13 @@ class Aozora2Html
61
64
  def build_title(header_info)
62
65
  buf = [:author, :translator, :editor, :henyaku,
63
66
  :title, :original_title,
64
- :subtitle, :original_subtitle].map{|item| header_info[item]}.compact
65
- buf_str = buf.join(" ")
67
+ :subtitle, :original_subtitle].filter_map { |item| header_info[item] }
68
+ buf_str = buf.join(' ')
66
69
  "<title>#{buf_str}</title>"
67
70
  end
68
71
 
69
72
  def build_header_info
70
- header_info = {:title => @header[0]}
73
+ header_info = { title: @header[0] }
71
74
  case @header.length
72
75
  when 2
73
76
  process_person(@header[1], header_info)
@@ -96,7 +99,7 @@ class Aozora2Html
96
99
  header_info[:subtitle] = @header[2]
97
100
  header_info[:author] = @header[3]
98
101
  if process_person(@header[4], header_info) == :author
99
- raise Aozora2Html::Error, "parser encounted author twice"
102
+ raise Aozora2Html::Error, 'parser encounted author twice'
100
103
  end
101
104
  when 6
102
105
  header_info[:original_title] = @header[1]
@@ -104,14 +107,14 @@ class Aozora2Html
104
107
  header_info[:original_subtitle] = @header[3]
105
108
  header_info[:author] = @header[4]
106
109
  if process_person(@header[5], header_info) == :author
107
- raise Aozora2Html::Error, "parser encounted author twice"
110
+ raise Aozora2Html::Error, 'parser encounted author twice'
108
111
  end
109
112
  end
110
113
  header_info
111
114
  end
112
115
 
113
116
  def to_html
114
- header_info = build_header_info()
117
+ header_info = build_header_info
115
118
 
116
119
  # <title> 行を構築
117
120
  html_title = build_title(header_info)
@@ -119,8 +122,8 @@ class Aozora2Html
119
122
  # 出力
120
123
  out_buf = []
121
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")
122
- $css_files.each do |css|
123
- out_buf.push("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"" + css + "\" />\r\n")
125
+ @css_files.each do |css|
126
+ out_buf.push("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"#{css}\" />\r\n")
124
127
  end
125
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")
126
129
  out_buf.push("<h1 class=\"title\">#{header_info[:title]}</h1>\r\n" +
@@ -130,10 +133,9 @@ class Aozora2Html
130
133
  out_header_info(header_info, :author) +
131
134
  out_header_info(header_info, :editor) +
132
135
  out_header_info(header_info, :translator) +
133
- out_header_info(header_info, :henyaku, "editor-translator"))
136
+ out_header_info(header_info, :henyaku, 'editor-translator'))
134
137
  out_buf.push("<br />\r\n<br />\r\n</div>\r\n<div id=\"contents\" style=\"display:none\"></div><div class=\"main_text\">")
135
- out_buf.join("")
138
+ out_buf.join
136
139
  end
137
-
138
140
  end
139
141
  end
@@ -1,28 +1,48 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'string_refinements'
4
+
2
5
  class Aozora2Html
6
+ # Internationalization(I18n) class
7
+ #
8
+ # コード内に日本語メッセージが氾濫しないようにするためのクラス
3
9
  class I18n
10
+ @use_utf8 = nil
11
+
12
+ class << self
13
+ attr_accessor :use_utf8
14
+ end
15
+
4
16
  MSG = {
5
- :tag_syntax_error => "注記を重ねる際の原則、「狭い範囲を先に、広い範囲を後に」が守られていません。リンク先の指針を参考に、書き方をあらためてください",
6
- :undefined_header => "未定義な見出しです",
7
- :use_crlf => "改行コードを、「CR+LF」にあらためてください",
8
- :error_stop => "エラー(%d行目):%s. \r\n処理を停止します",
9
- :invalid_font_size => "文字サイズの指定が不正です",
10
- :unsupported_ruby => "サポートされていない複雑なルビ付けです",
11
- :warn_onebyte => "警告(%d行目):1バイトの「%s」が使われています",
12
- :warn_chuki => "警告(%d行目):注記記号の誤用の可能性がある、「%s」が使われています",
13
- :warn_jis_gaiji => "警告(%d行目):JIS外字「%s」が使われています",
14
- :dont_crlf_in_style => "%s中に改行されました。改行をまたぐ要素にはブロック表記を用いてください",
15
- :terminate_in_style => "%s中に本文が終了しました",
16
- :invalid_closing => "%sを閉じようとしましたが、%s中ではありません",
17
- :invalid_nesting => "%sを終了しようとしましたが、%s中です",
18
- :dont_use_double_ruby => "同じ箇所に2つのルビはつけられません",
19
- :dont_allow_triple_ruby => "1つの単語に3つのルビはつけられません",
20
- :warn_unexpected_terminator => "警告(%d行目):予期せぬファイル終端",
21
- :warn_undefined_command => "警告(%d行目):「%s」は未対応のコマンドのため無視します",
22
- }
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
23
38
 
24
39
  def self.t(msg, *args)
25
- (MSG[msg].encode("shift_jis") % 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
26
46
  end
27
47
  end
28
48
  end
@@ -1,24 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'string_refinements'
4
+
1
5
  class Aozora2Html
6
+ # ルビ文字列解析用バッファ
2
7
  class RubyBuffer
3
-
4
8
  # `|`が来た時に真にする。ルビの親文字のガード用。
5
9
  attr_accessor :protected
6
10
 
7
- # @ruby_buf内の文字のchar_type
8
- attr_accessor :char_type
9
-
10
- def initialize(item=nil)
11
- clear(item)
11
+ def initialize
12
+ clear
12
13
  end
13
14
 
14
- # バッファの初期化。引数itemがあるときはその1要素のバッファに、
15
- # 引数がなければ`""`の1要素のバッファにする。
16
- def clear(item=nil)
17
- if item
18
- @ruby_buf = [item]
19
- else
20
- @ruby_buf = [""]
21
- end
15
+ # バッファの初期化。`""`の1要素のバッファにする。
16
+ def clear
17
+ @ruby_buf = [+'']
22
18
  @protected = nil
23
19
  @char_type = nil
24
20
  end
@@ -35,30 +31,46 @@ class Aozora2Html
35
31
  @ruby_buf
36
32
  end
37
33
 
38
- def each(&block)
39
- @ruby_buf.each(&block)
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
40
52
  end
41
53
 
42
54
  def last
43
55
  @ruby_buf.last
44
56
  end
45
57
 
58
+ # バッファ末尾にitemを追加する
59
+ #
60
+ # itemとバッファの最後尾がどちらもStringであれば連結したStringにし、
61
+ # そうでなければバッファの末尾に新しい要素として追加する
46
62
  def push(item)
47
- @ruby_buf.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
48
68
  end
49
69
 
50
70
  def length
51
71
  @ruby_buf.length
52
72
  end
53
73
 
54
- def last_concat(item)
55
- @ruby_buf.last.concat(item)
56
- end
57
-
58
- def last_is_string?
59
- @ruby_buf.last.is_a?(String)
60
- end
61
-
62
74
  # buffer management
63
75
  def dump_into(buffer)
64
76
  if @protected
@@ -66,9 +78,9 @@ class Aozora2Html
66
78
  @protected = nil
67
79
  end
68
80
  top = @ruby_buf[0]
69
- if top.is_a?(String) and buffer.last.is_a?(String)
81
+ if top.is_a?(String) && buffer.last.is_a?(String)
70
82
  buffer.last.concat(top)
71
- buffer.concat(@ruby_buf[1,@ruby_buf.length])
83
+ buffer.concat(@ruby_buf[1, @ruby_buf.length])
72
84
  else
73
85
  buffer.concat(@ruby_buf)
74
86
  end
@@ -76,6 +88,29 @@ class Aozora2Html
76
88
  buffer
77
89
  end
78
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
79
115
  end
80
116
  end
81
-
@@ -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
@@ -1,4 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Aozora2Html
4
+ # スタイルの状態管理用スタック
5
+ #
6
+ # スタイルの入れ子を扱えるようにスタック構造になっている。
7
+ # 各要素は`[コマンド文字列, 閉じる際に使うHTML文字列]`という2要素の配列になっている。
2
8
  class StyleStack
3
9
  def initialize
4
10
  @stack = []
@@ -1,21 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Aozora2Html
2
4
  class Tag
3
- class Accent < Aozora2Html::Tag
4
-
5
+ # 欧文アクセント文字用
6
+ class Accent < Aozora2Html::Tag::Inline
5
7
  @use_jisx0213 = nil
6
8
 
7
- def self.use_jisx0213=(val)
8
- @use_jisx0213 = val
9
- end
10
-
11
- def self.use_jisx0213
12
- @use_jisx0213
9
+ class << self
10
+ attr_accessor :use_jisx0213
13
11
  end
14
12
 
15
- include Aozora2Html::Tag::Inline
16
- def initialize(parser, code, name)
13
+ def initialize(parser, code, name, gaiji_dir:)
17
14
  @code = code
18
15
  @name = name
16
+ @gaiji_dir = gaiji_dir
19
17
  super
20
18
  end
21
19
 
@@ -29,9 +27,9 @@ class Aozora2Html
29
27
 
30
28
  def to_s
31
29
  if Aozora2Html::Tag::Accent.use_jisx0213
32
- jisx0213_to_unicode(@code.sub(%r|.*/|,"").to_sym)
30
+ jisx0213_to_unicode(@code.sub(%r{.*/}, '').to_sym)
33
31
  else
34
- "<img src=\"#{$gaiji_dir}#{@code}.png\" alt=\"" + GAIJI_MARK + "(#{@name})\" class=\"gaiji\" />"
32
+ "<img src=\"#{@gaiji_dir}#{@code}.png\" alt=\"" + GAIJI_MARK + "(#{@name})\" class=\"gaiji\" />"
35
33
  end
36
34
  end
37
35
  end
@@ -1,19 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Aozora2Html
2
4
  class Tag
3
- module Block
4
- def initialize(parser, *args)
5
- if parser.block_allowed_context?
6
- nil
7
- else
8
- syntax_error
9
- end
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?
10
13
  end
11
14
 
12
15
  # 必要に基づきmethod overrideする
13
16
  def close_tag
14
- "</div>"
17
+ '</div>'
15
18
  end
16
19
  end
17
20
  end
18
21
  end
19
-
@@ -1,14 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Aozora2Html
2
4
  class Tag
5
+ # 地付き記法
6
+ #
7
+ # 直接使わない。実際に使うのはサブクラス
3
8
  class Chitsuki < Aozora2Html::Tag::Indent
4
-
5
9
  def initialize(parser, length)
6
10
  @length = length
7
11
  super
8
12
  end
9
13
 
10
14
  def to_s
11
- '<div class="chitsuki_' + @length + '" style="text-align:right; margin-right: ' + @length + 'em">'
15
+ "<div class=\"chitsuki_#{@length}\" style=\"text-align:right; margin-right: #{@length}em\">"
12
16
  end
13
17
  end
14
18
  end
@@ -1,12 +1,13 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
2
3
  class Aozora2Html
3
4
  class Tag
4
- class DakutenKatakana < Aozora2Html::Tag
5
- include Aozora2Html::Tag::Inline
6
-
7
- def initialize(parser, n, katakana)
8
- @n = n
5
+ # 濁点つきカタカナ用
6
+ class DakutenKatakana < Aozora2Html::Tag::Inline
7
+ def initialize(parser, num, katakana, gaiji_dir:)
8
+ @n = num
9
9
  @katakana = katakana
10
+ @gaiji_dir = gaiji_dir
10
11
  super
11
12
  end
12
13
 
@@ -14,10 +15,11 @@ class Aozora2Html
14
15
  :katakana
15
16
  end
16
17
 
18
+ using StringRefinements
19
+
17
20
  def to_s
18
- "<img src=\"#{$gaiji_dir}/1-07/1-07-8#{@n}.png\" alt=\"" + "※(濁点付き片仮名「".encode("shift_jis") + @katakana + "」、1-07-8".encode("shift_jis") + "#{@n})\" class=\"gaiji\" />"
21
+ "<img src=\"#{@gaiji_dir}/1-07/1-07-8#{@n}.png\" alt=\"" + '※(濁点付き片仮名「'.to_sjis + @katakana + '」、1-07-8'.to_sjis + "#{@n})\" class=\"gaiji\" />"
19
22
  end
20
23
  end
21
24
  end
22
25
  end
23
-