lib/epubmaker/epubcommon.rb in review-2.3.0 vs lib/epubmaker/epubcommon.rb in review-2.4.0

- old
+ new

@@ -1,7 +1,5 @@ -# encoding: utf-8 - # = epubcommon.rb -- super class for EPUBv2 and EPUBv3 # # Copyright (c) 2010-2017 Kenshi Muto and Masayoshi Takahashi # # This program is free software. @@ -13,89 +11,88 @@ require 'review/i18n' require 'review/template' require 'cgi' module EPUBMaker - # EPUBCommon is the common class for EPUB producer. class EPUBCommon - # Construct object with parameter hash +params+ and message resource hash +res+. + # Construct object with parameter hash +config+ and message resource hash +res+. def initialize(producer) @body_ext = '' @producer = producer @body_ext = nil end # Return mimetype content. def mimetype - "application/epub+zip" + 'application/epub+zip' end def opf_path - "OEBPS/#{@producer.params["bookname"]}.opf" + "OEBPS/#{@producer.config['bookname']}.opf" end def opf_coverimage - s = "" - if @producer.params["coverimage"] + s = '' + if @producer.config['coverimage'] file = nil @producer.contents.each do |item| - if item.media.start_with?('image') && item.file =~ /#{@producer.params["coverimage"]}\Z/ - s << %Q[ <meta name="cover" content="#{item.id}"/>\n] - file = item.file - break - end + next if !item.media.start_with?('image') || item.file !~ /#{@producer.config["coverimage"]}\Z/ + + s << %Q( <meta name="cover" content="#{item.id}"/>\n) + file = item.file + break end - raise "coverimage #{@producer.params["coverimage"]} not found. Abort." if file.nil? + raise "coverimage #{@producer.config['coverimage']} not found. Abort." if file.nil? end s end def ncx_isbn - uid = @producer.params["isbn"] || @producer.params["urnid"] - %Q[ <meta name="dtb:uid" content="#{uid}"/>\n] + uid = @producer.config['isbn'] || @producer.config['urnid'] + %Q( <meta name="dtb:uid" content="#{uid}"/>\n) end def ncx_doctitle <<EOT <docTitle> - <text>#{CGI.escapeHTML(@producer.params["title"])}</text> + <text>#{CGI.escapeHTML(@producer.config['title'])}</text> </docTitle> <docAuthor> - <text>#{@producer.params["aut"].nil? ? "" : CGI.escapeHTML(join_with_separator(@producer.params["aut"], ReVIEW::I18n.t("names_splitter")))}</text> + <text>#{@producer.config['aut'].nil? ? '' : CGI.escapeHTML(join_with_separator(@producer.config['aut'], ReVIEW::I18n.t('names_splitter')))}</text> </docAuthor> EOT end def ncx_navmap(indentarray) s = <<EOT <navMap> <navPoint id="top" playOrder="1"> <navLabel> - <text>#{CGI.escapeHTML(@producer.params["title"])}</text> + <text>#{CGI.escapeHTML(@producer.config['title'])}</text> </navLabel> - <content src="#{@producer.params["cover"]}"/> + <content src="#{@producer.config['cover']}"/> </navPoint> EOT nav_count = 2 - unless @producer.params["mytoc"].nil? + unless @producer.config['mytoc'].nil? s << <<EOT <navPoint id="toc" playOrder="#{nav_count}"> <navLabel> - <text>#{CGI.escapeHTML(@producer.res.v("toctitle"))}</text> + <text>#{CGI.escapeHTML(@producer.res.v('toctitle'))}</text> </navLabel> - <content src="#{@producer.params["bookname"]}-toc.#{@producer.params["htmlext"]}"/> + <content src="#{@producer.config['bookname']}-toc.#{@producer.config['htmlext']}"/> </navPoint> EOT nav_count += 1 end @producer.contents.each do |item| next if item.title.nil? - indent = indentarray.nil? ? [""] : indentarray + indent = indentarray.nil? ? [''] : indentarray level = item.level.nil? ? 0 : (item.level - 1) level = indent.size - 1 if level >= indent.size s << <<EOT <navPoint id="nav-#{nav_count}" playOrder="#{nav_count}"> <navLabel> @@ -120,294 +117,284 @@ tmpl = ReVIEW::Template.load(tmplfile) tmpl.result(binding) end # Return cover content. - def cover(type=nil) - @body_ext = type.nil? ? "" : " epub:type=\"#{type}\"" + def cover(type = nil) + @body_ext = type.nil? ? '' : %Q( epub:type="#{type}") - if @producer.params["coverimage"] + if @producer.config['coverimage'] file = @producer.coverimage - if !file - raise "coverimage #{@producer.params["coverimage"]} not found. Abort." - end + raise "coverimage #{@producer.config['coverimage']} not found. Abort." unless file @body = <<-EOT <div id="cover-image" class="cover-image"> - <img src="#{file}" alt="#{CGI.escapeHTML(@producer.params.name_of("title"))}" class="max"/> + <img src="#{file}" alt="#{CGI.escapeHTML(@producer.config.name_of('title'))}" class="max"/> </div> EOT else @body = <<-EOT -<h1 class="cover-title">#{CGI.escapeHTML(@producer.params.name_of("title"))}</h1> +<h1 class="cover-title">#{CGI.escapeHTML(@producer.config.name_of('title'))}</h1> EOT - if @producer.params["subtitle"] + if @producer.config['subtitle'] @body << <<-EOT -<h2 class="cover-subtitle">#{CGI.escapeHTML(@producer.params.name_of("subtitle"))}</h2> +<h2 class="cover-subtitle">#{CGI.escapeHTML(@producer.config.name_of('subtitle'))}</h2> EOT end end - @title = CGI.escapeHTML(@producer.params.name_of("title")) - @language = @producer.params['language'] - @stylesheets = @producer.params["stylesheet"] - if @producer.params["htmlversion"].to_i == 5 - tmplfile = File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) - else - tmplfile = File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) - end + @title = CGI.escapeHTML(@producer.config.name_of('title')) + @language = @producer.config['language'] + @stylesheets = @producer.config['stylesheet'] + tmplfile = if @producer.config['htmlversion'].to_i == 5 + File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) + else + File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) + end tmpl = ReVIEW::Template.load(tmplfile) tmpl.result(binding) end # Return title (copying) content. # NOTE: this method is not used yet. # see lib/review/epubmaker.rb#build_titlepage def titlepage - @title = CGI.escapeHTML(@producer.params.name_of("title")) + @title = CGI.escapeHTML(@producer.config.name_of('title')) @body = <<EOT <h1 class="tp-title">#{@title}</h1> EOT - if @producer.params["subtitle"] + if @producer.config['subtitle'] @body << <<EOT - <h2 class="tp-subtitle">#{CGI.escapeHTML(@producer.params.name_of("subtitle"))}</h2> + <h2 class="tp-subtitle">#{CGI.escapeHTML(@producer.config.name_of('subtitle'))}</h2> EOT end - if @producer.params["aut"] + if @producer.config['aut'] @body << <<EOT <p> <br /> <br /> </p> - <h2 class="tp-author">#{CGI.escapeHTML(join_with_separator(@producer.params.names_of("aut"), ReVIEW::I18n.t("names_splitter")))}</h2> + <h2 class="tp-author">#{CGI.escapeHTML(join_with_separator(@producer.config.names_of('aut'), ReVIEW::I18n.t('names_splitter')))}</h2> EOT end - publisher = @producer.params.names_of("pbl") + publisher = @producer.config.names_of('pbl') if publisher @body << <<EOT <p> <br /> <br /> <br /> <br /> </p> - <h3 class="tp-publisher">#{CGI.escapeHTML(join_with_separator(publisher, ReVIEW::I18n.t("names_splitter")))}</h3> + <h3 class="tp-publisher">#{CGI.escapeHTML(join_with_separator(publisher, ReVIEW::I18n.t('names_splitter')))}</h3> EOT end - @language = @producer.params['language'] - @stylesheets = @producer.params["stylesheet"] - if @producer.params["htmlversion"].to_i == 5 - tmplfile = File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) - else - tmplfile = File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) - end + @language = @producer.config['language'] + @stylesheets = @producer.config['stylesheet'] + tmplfile = if @producer.config['htmlversion'].to_i == 5 + File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) + else + File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) + end tmpl = ReVIEW::Template.load(tmplfile) tmpl.result(binding) end # Return colophon content. def colophon - @title = CGI.escapeHTML(@producer.res.v("colophontitle")) + @title = CGI.escapeHTML(@producer.res.v('colophontitle')) @body = <<EOT <div class="colophon"> EOT - if @producer.params["subtitle"].nil? + if @producer.config['subtitle'].nil? @body << <<EOT - <p class="title">#{CGI.escapeHTML(@producer.params.name_of("title"))}</p> + <p class="title">#{CGI.escapeHTML(@producer.config.name_of('title'))}</p> EOT else @body << <<EOT - <p class="title">#{CGI.escapeHTML(@producer.params.name_of("title"))}<br /><span class="subtitle">#{CGI.escapeHTML(@producer.params.name_of("subtitle"))}</span></p> + <p class="title">#{CGI.escapeHTML(@producer.config.name_of('title'))}<br /><span class="subtitle">#{CGI.escapeHTML(@producer.config.name_of('subtitle'))}</span></p> EOT end - if @producer.params["date"] || @producer.params["history"] - @body << colophon_history - end + @body << colophon_history if @producer.config['date'] || @producer.config['history'] - @body << %Q[ <table class="colophon">\n] - @body << @producer.params["colophon_order"].map{ |role| - if @producer.params[role] - %Q[ <tr><th>#{CGI.escapeHTML(@producer.res.v(role))}</th><td>#{CGI.escapeHTML(join_with_separator(@producer.params.names_of(role), ReVIEW::I18n.t("names_splitter")))}</td></tr>\n] + @body << %Q( <table class="colophon">\n) + @body << @producer.config['colophon_order'].map do |role| + if @producer.config[role] + %Q( <tr><th>#{CGI.escapeHTML(@producer.res.v(role))}</th><td>#{CGI.escapeHTML(join_with_separator(@producer.config.names_of(role), ReVIEW::I18n.t('names_splitter')))}</td></tr>\n) else - "" + '' end - }.join("") + end.join - if @producer.isbn_hyphen - @body << %Q[ <tr><th>ISBN</th><td>#{@producer.isbn_hyphen}</td></tr>\n] - end - @body << %Q[ </table>\n] - if !@producer.params["rights"].nil? && @producer.params["rights"].size > 0 - @body << %Q[ <p class="copyright">#{join_with_separator(@producer.params.names_of("rights").map {|m| CGI.escapeHTML(m)}, "<br />")}</p>\n] - end - @body << %Q[ </div>\n] + @body << %Q( <tr><th>ISBN</th><td>#{@producer.isbn_hyphen}</td></tr>\n) if @producer.isbn_hyphen + @body << %Q( </table>\n) + @body << %Q( <p class="copyright">#{join_with_separator(@producer.config.names_of('rights').map { |m| CGI.escapeHTML(m) }, '<br />')}</p>\n) if @producer.config['rights'] && !@producer.config['rights'].empty? + @body << %Q( </div>\n) - @language = @producer.params['language'] - @stylesheets = @producer.params["stylesheet"] - if @producer.params["htmlversion"].to_i == 5 - tmplfile = File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) - else - tmplfile = File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) - end + @language = @producer.config['language'] + @stylesheets = @producer.config['stylesheet'] + tmplfile = if @producer.config['htmlversion'].to_i == 5 + File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) + else + File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) + end tmpl = ReVIEW::Template.load(tmplfile) tmpl.result(binding) end def colophon_history - buf = "" - buf << %Q[ <div class="pubhistory">\n] - if @producer.params["history"] - @producer.params["history"].each_with_index do |items, edit| + buf = '' + buf << %Q( <div class="pubhistory">\n) + if @producer.config['history'] + @producer.config['history'].each_with_index do |items, edit| items.each_with_index do |item, rev| - editstr = (edit == 0) ? ReVIEW::I18n.t("first_edition") : ReVIEW::I18n.t("nth_edition","#{edit+1}") - revstr = ReVIEW::I18n.t("nth_impression", "#{rev+1}") + editstr = edit == 0 ? ReVIEW::I18n.t('first_edition') : ReVIEW::I18n.t('nth_edition', (edit + 1).to_s) + revstr = ReVIEW::I18n.t('nth_impression', (rev + 1).to_s) if item =~ /\A\d+\-\d+\-\d+\Z/ - buf << %Q[ <p>#{ReVIEW::I18n.t("published_by1", [date_to_s(item), editstr+revstr])}</p>\n] + buf << %Q( <p>#{ReVIEW::I18n.t('published_by1', [date_to_s(item), editstr + revstr])}</p>\n) elsif item =~ /\A(\d+\-\d+\-\d+)[\s ](.+)/ # custom date with string item.match(/\A(\d+\-\d+\-\d+)[\s ](.+)/) do |m| - buf << %Q[ <p>#{ReVIEW::I18n.t("published_by3", [date_to_s(m[1]), m[2]])}</p>\n] + buf << %Q( <p>#{ReVIEW::I18n.t('published_by3', [date_to_s(m[1]), m[2]])}</p>\n) end else # free format - buf << %Q[ <p>#{item}</p>\n] + buf << %Q( <p>#{item}</p>\n) end end end else - buf << %Q[ <p>#{ReVIEW::I18n.t("published_by2", date_to_s(@producer.params["date"]))}</p>\n] + buf << %Q( <p>#{ReVIEW::I18n.t('published_by2', date_to_s(@producer.config['date']))}</p>\n) end - buf << %Q[ </div>\n] + buf << %Q( </div>\n) buf end def date_to_s(date) require 'date' d = Date.parse(date) - d.strftime(ReVIEW::I18n.t("date_format")) + d.strftime(ReVIEW::I18n.t('date_format')) end # Return own toc content. def mytoc - @title = CGI.escapeHTML(@producer.res.v("toctitle")) + @title = CGI.escapeHTML(@producer.res.v('toctitle')) - @body = %Q[ <h1 class="toc-title">#{CGI.escapeHTML(@producer.res.v("toctitle"))}</h1>\n] - if @producer.params["epubmaker"]["flattoc"].nil? - @body << hierarchy_ncx("ul") + @body = %Q( <h1 class="toc-title">#{CGI.escapeHTML(@producer.res.v('toctitle'))}</h1>\n) + if @producer.config['epubmaker']['flattoc'].nil? + @body << hierarchy_ncx('ul') else - @body << flat_ncx("ul", @producer.params["epubmaker"]["flattocindent"]) + @body << flat_ncx('ul', @producer.config['epubmaker']['flattocindent']) end - @language = @producer.params['language'] - @stylesheets = @producer.params["stylesheet"] - if @producer.params["htmlversion"].to_i == 5 - tmplfile = File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) - else - tmplfile = File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) - end + @language = @producer.config['language'] + @stylesheets = @producer.config['stylesheet'] + tmplfile = if @producer.config['htmlversion'].to_i == 5 + File.expand_path('./html/layout-html5.html.erb', ReVIEW::Template::TEMPLATE_DIR) + else + File.expand_path('./html/layout-xhtml1.html.erb', ReVIEW::Template::TEMPLATE_DIR) + end tmpl = ReVIEW::Template.load(tmplfile) tmpl.result(binding) end def hierarchy_ncx(type) require 'rexml/document' level = 1 find_jump = nil has_part = nil - toclevel = @producer.params["toclevel"].to_i + toclevel = @producer.config['toclevel'].to_i # check part existance @producer.contents.each do |item| - if item.notoc.nil? && item.chaptype == "part" - has_part = true - break - end + next if item.notoc || item.chaptype != 'part' + + has_part = true + break end - if !has_part.nil? + if has_part @producer.contents.each do |item| - item.level += 1 if item.chaptype == "part" || item.chaptype == "body" - item.notoc = true if (item.chaptype == "pre" || item.chaptype == "post") && !item.level.nil? && (item.level + 1 == toclevel) # FIXME: 部があるときに前後の処理が困難 + item.level += 1 if item.chaptype == 'part' || item.chaptype == 'body' + item.notoc = true if (item.chaptype == 'pre' || item.chaptype == 'post') && !item.level.nil? && (item.level + 1 == toclevel) # FIXME: part processing end toclevel += 1 end - doc = REXML::Document.new(%Q[<#{type} class="toc-h#{level}"><li /></#{type}>]) + doc = REXML::Document.new(%Q(<#{type} class="toc-h#{level}"><li /></#{type}>)) doc.context[:attribute_quote] = :quote e = doc.root.elements[1] # first <li/> @producer.contents.each do |item| next if !item.notoc.nil? || item.level.nil? || item.file.nil? || item.title.nil? || item.level > toclevel if item.level == level - e2 = e.parent.add_element("li") + e2 = e.parent.add_element('li') e = e2 elsif item.level > level find_jump = true if (item.level - level) > 1 # deeper (level + 1).upto(item.level) do |n| if e.size == 0 # empty span for epubcheck - e.attributes["style"] = "list-style-type: none;" - es = e.add_element("span", {"style"=>"display:none;"}) - es.add_text(REXML::Text.new("&#xa0;", false, nil, true)) + e.attributes['style'] = 'list-style-type: none;' + es = e.add_element('span', 'style' => 'display:none;') + es.add_text(REXML::Text.new('&#xa0;', false, nil, true)) end - e2 = e.add_element(type, {"class" => "toc-h#{n}"}) - e3 = e2.add_element("li") + e2 = e.add_element(type, 'class' => "toc-h#{n}") + e3 = e2.add_element('li') e = e3 end level = item.level elsif item.level < level # shallower - (level - 1).downto(item.level) do |n| - e = e.parent.parent - end - e2 = e.parent.add_element("li") + (level - 1).downto(item.level) { e = e.parent.parent } + e2 = e.parent.add_element('li') e = e2 level = item.level end - e2 = e.add_element("a", {"href" => item.file}) + e2 = e.add_element('a', 'href' => item.file) e2.add_text(REXML::Text.new(item.title, true)) end - warn "found level jumping in table of contents. consider to use 'epubmaker:flattoc: true' for strict ePUB validator." unless find_jump.nil? + warn %Q(found level jumping in table of contents. consider to use 'epubmaker:flattoc: true' for strict ePUB validator.) unless find_jump.nil? - doc.to_s.gsub("<li/>", "").gsub("</li>", "</li>\n").gsub("<#{type} ", "\n" + '\&') # ugly + doc.to_s.gsub('<li/>', '').gsub('</li>', "</li>\n").gsub("<#{type} ", "\n" + '\&') # ugly end - def flat_ncx(type, indent=nil) - s = %Q[<#{type} class="toc-h1">\n] + def flat_ncx(type, indent = nil) + s = %Q(<#{type} class="toc-h1">\n) @producer.contents.each do |item| - next if !item.notoc.nil? || item.level.nil? || item.file.nil? || item.title.nil? || item.level > @producer.params["toclevel"].to_i - is = indent == true ? " " * item.level : "" - s << %Q[<li><a href="#{item.file}">#{is}#{CGI.escapeHTML(item.title)}</a></li>\n] + next if !item.notoc.nil? || item.level.nil? || item.file.nil? || item.title.nil? || item.level > @producer.config['toclevel'].to_i + is = indent == true ? ' ' * item.level : '' + s << %Q(<li><a href="#{item.file}">#{is}#{CGI.escapeHTML(item.title)}</a></li>\n) end - s << %Q[</#{type}>\n] + s << %Q(</#{type}>\n) s end def produce_write_common(basedir, tmpdir) - File.open("#{tmpdir}/mimetype", "w") {|f| @producer.mimetype(f) } + File.open("#{tmpdir}/mimetype", 'w') { |f| @producer.mimetype(f) } FileUtils.mkdir_p("#{tmpdir}/META-INF") - File.open("#{tmpdir}/META-INF/container.xml", "w") {|f| @producer.container(f) } + File.open("#{tmpdir}/META-INF/container.xml", 'w') { |f| @producer.container(f) } FileUtils.mkdir_p("#{tmpdir}/OEBPS") - File.open(File.join(tmpdir, opf_path), "w") {|f| @producer.opf(f) } + File.open(File.join(tmpdir, opf_path), 'w') { |f| @producer.opf(f) } - if File.exist?("#{basedir}/#{@producer.params["cover"]}") - FileUtils.cp("#{basedir}/#{@producer.params["cover"]}", "#{tmpdir}/OEBPS") + if File.exist?("#{basedir}/#{@producer.config['cover']}") + FileUtils.cp("#{basedir}/#{@producer.config['cover']}", "#{tmpdir}/OEBPS") else - File.open("#{tmpdir}/OEBPS/#{@producer.params["cover"]}", "w") {|f| @producer.cover(f) } + File.open("#{tmpdir}/OEBPS/#{@producer.config['cover']}", 'w') { |f| @producer.cover(f) } end @producer.contents.each do |item| next if item.file =~ /#/ # skip subgroup fname = "#{basedir}/#{item.file}" @@ -416,24 +403,24 @@ FileUtils.cp(fname, "#{tmpdir}/OEBPS/#{item.file}") end end def legacy_cover_and_title_file(loadfile, writefile) - @title = @producer.params["booktitle"] - s = "" + @title = @producer.config['booktitle'] + s = '' File.open(loadfile) do |f| f.each_line do |l| s << l end end - File.open(writefile, "w") do |f| + File.open(writefile, 'w') do |f| f.puts s end end def join_with_separator(value, sep) - if value.kind_of? Array + if value.is_a?(Array) value.join(sep) else value end end