Module: VivlioStarter::CLI::Import::SideimageRestorer
- Defined in:
- lib/vivlio_starter/cli/import/sideimage_restorer.rb
Overview
//sideimage の復元
Constant Summary collapse
- SIDEIMAGE_OPEN =
//sideimage[画像][幅][オプション]{ %r{\A//sideimage\[([^\]]*)\]\[([^\]]*)\]\[([^\]]*)\]\{\s*\z}- BLOCK_CLOSE =
Re:VIEW のブロック終端
//} %r{\A//\}\s*\z}- STOP_LINE =
画像の脇に置く本文を数えるとき、ここに来たら必ず打ち切る (見出し・別の囲み・水平線・次の画像)
/\A(?:\#{1,6}\s|:::|---\s*\z|!\[)/- DEFAULT_TEXT_WIDTH_MM =
判型が読めないときの版面幅(mm)。B5 標準相当
137.0- WIDTH_PERCENT_RANGE =
画像列の比率の下限・上限。極端な指定で本文の列が潰れるのを防ぐ
(10..60).freeze
- PAGE_PRESETS_FILE =
'config/page_presets.yml'
Class Method Summary collapse
-
.body_end(lines, image_idx, blocks) ⇒ Object
画像行のうしろから、原稿にあったぶんの本文ブロックを数えて終端の行を返す.
- .build_directive(match, body) ⇒ Object
-
.find_image_line(lines, image, from) ⇒ Object
画像行を探す。取り込み時と同じ正規化を通した名前で照合する.
-
.image_line_with_width(line, directive, text_mm) ⇒ Object
画像行へ
{width=NN%}を添える。Vivlio ではこの値がそのまま画像列の比率になる. -
.locate_spans(lines, directives, md_path) ⇒ Object
.re の並び順に、Markdown 側の [画像行, 本文の最終行, 指示] を求める.
-
.parse_directives(re_lines) ⇒ Object
.re から sideimage の指示を出現順に取り出す.
-
.restore!(temp_dir, starter_dir) ⇒ void
temp/ の Markdown に対して sideimage の囲みを復元する.
-
.restore_chapter!(md_path, re_path, text_mm) ⇒ Object
1 章ぶんを復元し、復元できた件数を返す.
-
.review_contents_dir(starter_dir) ⇒ Object
Re:VIEW の原稿ディレクトリ(config.yml の contentdir。既定は contents).
-
.target_page_preset(starter_dir) ⇒ Object
取り込み先で使う判型プリセットの中身.
-
.text_area_width_mm(starter_dir) ⇒ Object
版面幅(mm)= 紙幅 − ノド − 小口。Re:VIEW の mm 指定を比率へ直す基準.
-
.text_block_count(body) ⇒ Object
本文のブロック数。
//blanklineのように「Markdown では空行にしかならない」 命令だけのブロックは数えない——数えると本文を 1 つ多く巻き込む。. - .text_line?(line) ⇒ Boolean
-
.warn_unplaced(md_path, directive) ⇒ Object
置き場所が決まらなかった指示は、著者が手で直せるように名指しで知らせる.
- .width_percent(width_mm, text_mm) ⇒ Object
Class Method Details
.body_end(lines, image_idx, blocks) ⇒ Object
画像行のうしろから、原稿にあったぶんの本文ブロックを数えて終端の行を返す
161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 161 def body_end(lines, image_idx, blocks) i = image_idx + 1 last = image_idx blocks.times do i += 1 while i < lines.size && lines[i].strip.empty? break if i >= lines.size || STOP_LINE.match?(lines[i]) i += 1 while i < lines.size && !lines[i].strip.empty? last = i - 1 end last end |
.build_directive(match, body) ⇒ Object
133 134 135 136 137 138 139 140 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 133 def build_directive(match, body) { image: ImageFilenameSanitizer.sanitize(match[1].to_s.strip), width_mm: Units.length_to_mm(match[2].to_s.strip), klass: match[3].to_s.include?('side=R') ? 'sideimage-right' : 'sideimage', blocks: text_block_count(body) } end |
.find_image_line(lines, image, from) ⇒ Object
画像行を探す。取り込み時と同じ正規化を通した名前で照合する
155 156 157 158 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 155 def find_image_line(lines, image, from) needle = "](#{image}.webp)" (from...lines.size).find { lines[it].include?(needle) && lines[it].lstrip.start_with?('![') } end |
.image_line_with_width(line, directive, text_mm) ⇒ Object
画像行へ {width=NN%} を添える。Vivlio ではこの値がそのまま画像列の比率になる
177 178 179 180 181 182 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 177 def image_line_with_width(line, directive, text_mm) percent = width_percent(directive[:width_mm], text_mm) return line unless percent "#{line.chomp}{width=#{percent}%}\n" end |
.locate_spans(lines, directives, md_path) ⇒ Object
.re の並び順に、Markdown 側の [画像行, 本文の最終行, 指示] を求める
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 98 def locate_spans(lines, directives, md_path) cursor = 0 directives.filter_map do |directive| image_idx = find_image_line(lines, directive[:image], cursor) next warn_unplaced(md_path, directive) unless image_idx last_idx = body_end(lines, image_idx, directive[:blocks]) cursor = last_idx + 1 [image_idx, last_idx, directive] end end |
.parse_directives(re_lines) ⇒ Object
.re から sideimage の指示を出現順に取り出す
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 112 def parse_directives(re_lines) directives = [] i = 0 while i < re_lines.size match = SIDEIMAGE_OPEN.match(re_lines[i].to_s.chomp) if match body = [] i += 1 while i < re_lines.size && !BLOCK_CLOSE.match?(re_lines[i].to_s.chomp) body << re_lines[i].to_s.chomp i += 1 end directives << build_directive(match, body) end i += 1 end directives end |
.restore!(temp_dir, starter_dir) ⇒ void
This method returns an undefined value.
temp/ の Markdown に対して sideimage の囲みを復元する
63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 63 def restore!(temp_dir, starter_dir) re_dir = review_contents_dir(starter_dir) return unless Dir.exist?(re_dir) text_mm = text_area_width_mm(starter_dir) restored = Dir.glob(File.join(temp_dir, '*.md')).sum do |md_path| re_path = File.join(re_dir, "#{File.basename(md_path, '.md')}.re") File.exist?(re_path) ? restore_chapter!(md_path, re_path, text_mm) : 0 end Common.log_info(" sideimage の囲みを #{restored} 件復元しました") if restored.positive? end |
.restore_chapter!(md_path, re_path, text_mm) ⇒ Object
1 章ぶんを復元し、復元できた件数を返す
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 78 def restore_chapter!(md_path, re_path, text_mm) directives = parse_directives(File.readlines(re_path, encoding: 'utf-8')) return 0 if directives.empty? lines = File.readlines(md_path, encoding: 'utf-8') spans = locate_spans(lines, directives, md_path) return 0 if spans.empty? # 行番号がずれないよう後ろから書き換える spans.reverse_each do |image_idx, last_idx, directive| lines[last_idx] = "#{lines[last_idx].chomp}\n:::\n" lines[image_idx] = image_line_with_width(lines[image_idx], directive, text_mm) lines.insert(image_idx, ":::{.#{directive[:klass]}}\n") end File.write(md_path, lines.join, encoding: 'utf-8') spans.size end |
.review_contents_dir(starter_dir) ⇒ Object
Re:VIEW の原稿ディレクトリ(config.yml の contentdir。既定は contents)
217 218 219 220 221 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 217 def review_contents_dir(starter_dir) config = File.join(starter_dir, 'config.yml') dir = (YAML.safe_load_file(config, permitted_classes: [Symbol])['contentdir'] if File.exist?(config)) File.join(starter_dir, dir.to_s.strip.empty? ? 'contents' : dir.to_s.strip) end |
.target_page_preset(starter_dir) ⇒ Object
取り込み先で使う判型プリセットの中身
204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 204 def target_page_preset(starter_dir) starter_config = File.join(starter_dir, 'config-starter.yml') return nil unless File.exist?(starter_config) && File.exist?(PAGE_PRESETS_FILE) pagesize = YAML.safe_load_file(starter_config, permitted_classes: [Symbol]).dig('starter', 'pagesize') name = YamlProcessor::PAGE_PRESETS[pagesize.to_s.strip.upcase] return nil unless name # プリセットは YAML アンカー(`<<: *b5_std`)で共通部を引くため aliases が要る YAML.safe_load_file(PAGE_PRESETS_FILE, aliases: true)[name] end |
.text_area_width_mm(starter_dir) ⇒ Object
版面幅(mm)= 紙幅 − ノド − 小口。Re:VIEW の mm 指定を比率へ直す基準
191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 191 def text_area_width_mm(starter_dir) preset = target_page_preset(starter_dir) return DEFAULT_TEXT_WIDTH_MM unless preset width = Units.length_to_mm(Common::PAGE_SIZES.dig(preset['size'].to_s.upcase, :width)) inner = Units.length_to_mm(preset['margin_inner']) outer = Units.length_to_mm(preset['margin_outer']) return DEFAULT_TEXT_WIDTH_MM unless width&.positive? && inner && outer [width - inner - outer, 1.0].max end |
.text_block_count(body) ⇒ Object
本文のブロック数。//blankline のように「Markdown では空行にしかならない」
命令だけのブロックは数えない——数えると本文を 1 つ多く巻き込む。
144 145 146 147 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 144 def text_block_count(body) body.join("\n").split(/\n[ \t]*\n/) .count { |block| block.lines.any? { text_line?(it) } } end |
.text_line?(line) ⇒ Boolean
149 150 151 152 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 149 def text_line?(line) stripped = line.strip !stripped.empty? && !stripped.start_with?('//') end |
.warn_unplaced(md_path, directive) ⇒ Object
置き場所が決まらなかった指示は、著者が手で直せるように名指しで知らせる
224 225 226 227 228 229 230 231 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 224 def warn_unplaced(md_path, directive) Common.log_warn( " #{File.basename(md_path)}: sideimage の画像 #{directive[:image]} が見つからず、囲みを復元できませんでした。", detail: "対処: 該当箇所を :::{.#{directive[:klass]}} … ::: で囲んでください" \ '(22 章「サイドイメージ」)。' ) nil end |
.width_percent(width_mm, text_mm) ⇒ Object
184 185 186 187 188 |
# File 'lib/vivlio_starter/cli/import/sideimage_restorer.rb', line 184 def width_percent(width_mm, text_mm) return nil unless width_mm&.positive? && text_mm.positive? ((width_mm / text_mm) * 100).round.clamp(WIDTH_PERCENT_RANGE.begin, WIDTH_PERCENT_RANGE.end) end |