require 'optparse' require 'epub/parser' using EPUB::Parser::XMLDocument::Refinements options = {:format => :line} navigation_types = { :toc => "table of contents", :"page-list" => "page list", :landmarks => "landmarks" } opt = OptionParser.new do |opt| opt.banner = < book.title} data.merge!(book.metadata.to_h) data['modified'] = book.modified data['unique identifier'] = book.metadata.unique_identifier data['epub version'] = book.package.version nav = book.manifest.navs.first data["navigations"] = nav ? nav&.content_document&.navigations&.collect(&:type)&.join(", ") : [] data.each_pair do |(key, value)| data[key] = value.respond_to?(:join) ? value.join(", ") : value.to_s end counts = {:chars => 0, :words => 0} if options[:words] or options[:chars] namespaces = {"xhtml" => "http://www.w3.org/1999/xhtml"} book.resources.select(&:xhtml?).each do |xhtml| begin doc = EPUB::Parser::XMLDocument.new(xhtml.read) body = doc.each_element_by_xpath('//xhtml:body', namespaces).first if body content = body.content counts[:words] += content.scan(/\S+/).length counts[:chars] += content.gsub(/\r|\n/, '').length end rescue => error warn "#{xhtml.href}: #{error}" end end end data['words'] = counts[:words] if options[:words] data['characters'] = counts[:chars] if options[:chars] if options[:format] == :line key_width = data.keys.map {|k| k.length}.max + 3 data.each_pair do |k, v| puts (k.to_s.capitalize + ':').ljust(key_width) + v.to_s end navigation_types.each_pair do |key, name| if options[key] puts "" puts "=== #{name} ===" nav_item = book.manifest.nav if nav_item nav = nav_item.content_document.navigations.find {|nav| nav.type == key.to_s.sub("-", "_")} if nav nav.traverse do |item, depth| text = item.text || "(No heading)" text += "(#{item.types.sort.join(', ')})" unless item.types.empty? puts "#{' ' * depth}#{text}" end else puts "(No #{name})" end else puts "(No #{name})" end end end else require options[:format].to_s puts data.__send__("to_#{options[:format]}") end