Module: VivlioStarter::CLI::PreProcessCommands::DataImageResolver
- Defined in:
- lib/vivlio_starter/cli/pre_process/data_image_resolver.rb
Overview
QueryStream 展開結果内の素ファイル名画像を data/ 配下から解決するモジュール
Constant Summary collapse
- VARIANT_EXTS =
変種解決の優先順(ImagePathNormalizer.image_exists_for? と同ポリシー)。
%w[.webp .png .jpg .jpeg].freeze
- DATA_REL_ROOT =
ビルド生成物参照の共通プレフィックス(ImagePathNormalizer の carve-out と対応)。
'images/data'
Class Method Summary collapse
-
.plain_filename?(src) ⇒ Boolean
素のファイル名か("/" を含まず・スキーム付きでも絶対パスでもなく・images/ 始まりでもない)。.
-
.resolve_src(src, data_base, chapter_slug, context) ⇒ String?
単一の src を解決する。書き換えるべき新 src を返し、対象外・章ローカル該当・ ミス時は nil を返す(呼び出し元は nil のとき元の記法を保つ)。.
-
.rewrite(text, context, chapter_slug:) ⇒ String
QueryStream 1 記法の展開結果内の画像参照を data/ 配下から解決して書き換える。 Markdown 画像(
attrs)と HTML
の両方を対象とする。.
-
.stage_into_workspace!(source, rel) ⇒ Object
data/ 配下の実体をワークスペース html/images/data/
へコピーする。 既存の宛先が同一 size・同 mtime 以降なら再コピーしない(冪等・再ビルド高速化)。. -
.variant_exists?(base_path) ⇒ Boolean
変種込みで実在するか(真偽のみ)。.
-
.variant_path(base_path) ⇒ String?
変種込みで実在パスを返す(無ければ nil)。.svg は完全一致、他は VARIANT_EXTS 優先順。.
-
.warn_missing(src, data_base, chapter_slug, context) ⇒ Object
探索 3 箇所を列挙した親切な警告を出す(最終的な 🔴+プレースホルダーは normalizer が担う)。.
Class Method Details
.plain_filename?(src) ⇒ Boolean
素のファイル名か("/" を含まず・スキーム付きでも絶対パスでもなく・images/ 始まりでもない)。
94 95 96 97 98 99 100 |
# File 'lib/vivlio_starter/cli/pre_process/data_image_resolver.rb', line 94 def plain_filename?(src) return false if src.nil? || src.empty? return false if src.include?('/') # パス・URL・images/… を一括除外 return false if src.match?(%r{\A[a-zA-Z][a-zA-Z0-9+.-]*:}) # スキーム付き(data: 等) true end |
.resolve_src(src, data_base, chapter_slug, context) ⇒ String?
単一の src を解決する。書き換えるべき新 src を返し、対象外・章ローカル該当・ ミス時は nil を返す(呼び出し元は nil のとき元の記法を保つ)。
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/vivlio_starter/cli/pre_process/data_image_resolver.rb', line 73 def resolve_src(src, data_base, chapter_slug, context) return nil unless plain_filename?(src) # 章ローカルが最優先。実在すれば従来経路に委ねるため書き換えない。 return nil if variant_exists?(File.join(Common.images_dir, chapter_slug, src)) data_dir = Common.data_dir hit = variant_path(File.join(data_dir, data_base, src)) || variant_path(File.join(data_dir, 'images', src)) unless hit warn_missing(src, data_base, chapter_slug, context) return nil end rel = hit.delete_prefix("#{data_dir}/") # 例: "physics_books/relativity.webp" stage_into_workspace!(hit, rel) "#{DATA_REL_ROOT}/#{rel}" end |
.rewrite(text, context, chapter_slug:) ⇒ String
QueryStream 1 記法の展開結果内の画像参照を data/ 配下から解決して書き換える。
Markdown 画像(attrs)と HTML
の両方を対象とする。
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/vivlio_starter/cli/pre_process/data_image_resolver.rb', line 51 def rewrite(text, context, chapter_slug:) data_base = File.basename(context[:data_file].to_s, '.*') # --- Phase: Markdown 画像 {attrs} --- result = text.gsub(/!\[(?<alt>[^\]]*)\]\((?<src>[^)\s]+)\)(?<attr>\{[^}]*\})?/) do md = ::Regexp.last_match resolved = resolve_src(md[:src], data_base, chapter_slug, context) resolved ? "![#{md[:alt]}](#{resolved})#{md[:attr]}" : md[0] end # --- Phase: HTML <img src="src"> --- result.gsub(/<img\b[^>]*?\ssrc="(?<src>[^"]+)"[^>]*>/i) do tag = ::Regexp.last_match[0] src = ::Regexp.last_match[:src] resolved = resolve_src(src, data_base, chapter_slug, context) resolved ? tag.sub(/(\ssrc=")[^"]*(")/i, "\\1#{resolved}\\2") : tag end end |
.stage_into_workspace!(source, rel) ⇒ Object
data/ 配下の実体をワークスペース html/images/data/
116 117 118 119 120 121 122 123 |
# File 'lib/vivlio_starter/cli/pre_process/data_image_resolver.rb', line 116 def stage_into_workspace!(source, rel) dest = File.join(Common::BUILD_HTML_DIR, 'images', 'data', rel) return if File.exist?(dest) && File.size(dest) == File.size(source) && File.mtime(dest) >= File.mtime(source) FileUtils.mkdir_p(File.dirname(dest)) FileUtils.cp(source, dest) end |
.variant_exists?(base_path) ⇒ Boolean
変種込みで実在するか(真偽のみ)。
112 |
# File 'lib/vivlio_starter/cli/pre_process/data_image_resolver.rb', line 112 def variant_exists?(base_path) = !variant_path(base_path).nil? |
.variant_path(base_path) ⇒ String?
変種込みで実在パスを返す(無ければ nil)。.svg は完全一致、他は VARIANT_EXTS 優先順。
104 105 106 107 108 109 |
# File 'lib/vivlio_starter/cli/pre_process/data_image_resolver.rb', line 104 def variant_path(base_path) return (File.exist?(base_path) ? base_path : nil) if base_path.end_with?('.svg') base_without_ext = base_path.sub(/\.(webp|png|jpe?g)\z/i, '') VARIANT_EXTS.map { "#{base_without_ext}#{it}" }.find { File.exist?(it) } end |
.warn_missing(src, data_base, chapter_slug, context) ⇒ Object
探索 3 箇所を列挙した親切な警告を出す(最終的な 🔴+プレースホルダーは normalizer が担う)。
126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/vivlio_starter/cli/pre_process/data_image_resolver.rb', line 126 def warn_missing(src, data_base, chapter_slug, context) searched = [ "#{File.join(Common.images_dir, chapter_slug, src)}(章ローカル)", "#{File.join(Common.data_dir, data_base, src)}(データ単位フォルダ)", "#{File.join(Common.data_dir, 'images', src)}(共有プール)" ] Common.log_warn( "#{context[:location]} - データ画像 '#{src}' が見つかりません(記法: #{context[:query]})", detail: "探索した場所:\n - #{searched.join("\n - ")}\n" \ "ヒント: #{File.join(Common.data_dir, data_base, src)} に置くとデータ一式が自己完結します" ) end |