class Pandocomatic::ConvertFileCommand
Command
to convert a file
@!attribute config
@return [Configuration] the configuration of pandocomatic used to convert the file
@!attribute src
@return [String] the path to the file to convert
@!attribute dst
@return [String] the path to the output file
Constants
- INTERNAL_TEMPLATE
Attributes
Public Class Methods
Create a new ConvertFileCommand
@param config [Configuration] pandocomatic’s configuration @param src [String] the path to the file to convert @param dst [String] the path to save the output of the conversion @param template_name [String = nil] the template to use while converting
this file
Pandocomatic::Command::new
# File lib/pandocomatic/command/convert_file_command.rb, line 92 def initialize(config, src, dst, template_name = nil) super() @config = config @src = src @dst = dst @template_name = if template_name.nil? || template_name.empty? @config.determine_template @src else template_name end @metadata = @config.get_metadata @src, @template_name @dst = @config.set_destination @dst, @template_name, @metadata @errors.push IOError.new(:file_does_not_exist, nil, @src) unless File.exist? @src @errors.push IOError.new(:file_is_not_a_file, nil, @src) unless File.file? @src @errors.push IOError.new(:file_is_not_readable, nil, @src) unless File.readable? @src end
Public Instance Methods
Execute this ConvertFileCommand
# File lib/pandocomatic/command/convert_file_command.rb, line 113 def run convert_file end
Create a string representation of this ConvertFileCommand
@return [String]
# File lib/pandocomatic/command/convert_file_command.rb, line 120 def to_s str = "convert #{File.basename @src} #{"-> #{File.basename @dst}" unless @dst.nil?}" unless @metadata.unique? str += "\n\t encountered multiple YAML metadata blocks with a pandocomatic property. " \ 'Only the pandocomatic property in the first YAML metadata block is being used; ' \ 'the others are discarded.' end str end
Private Instance Methods
Run cleanup scripts
@param template [Template] template
# File lib/pandocomatic/command/convert_file_command.rb, line 300 def cleanup(template) process '', Template::CLEANUP, template end
# File lib/pandocomatic/command/convert_file_command.rb, line 134 def convert_file pandoc_options = @metadata.pandoc_options || {} template = nil # Determine the actual options and settings to use when converting this # file. if !@template_name.nil? && !@template_name.empty? unless @config.template? @template_name raise ConfigurationError.new(:no_such_template, nil, @template_name) end template = @config.get_template @template_name pandoc_options = Template.extend_value(pandoc_options, template.pandoc) else template = Template.new INTERNAL_TEMPLATE end if template.name == INTERNAL_TEMPLATE Pandocomatic::LOG.debug ' # Using internal template.' else Pandocomatic::LOG.debug " # Using template '#{template.name}'." end # Ignore the `--verbose` option, and warn about ignoring it if pandoc_options.key?('verbose') && !@config.feature_enabled?(:pandoc_verbose) pandoc_options.delete 'verbose' warn 'WARNING: Ignoring the pandoc option "--verbose" because it ' \ 'might interfere with the working of pandocomatic. If you want to use ' \ '"--verbose" anyway, use pandocomatic\'s feature toggle ' \ '"--enable pandoc-verbose".' end template.merge! Template.new(INTERNAL_TEMPLATE, @metadata.pandocomatic) if @metadata.pandocomatic? Pandocomatic::LOG.debug ' # Selected template mixed with internal template and pandocomatic metadata ' \ "gives final template:#{Pandocomatic::LOG.indent(YAML.dump(template.to_h).sub('---', ''), 34)}" # Write out the results of the conversion process to file. @dst = @metadata.pandoc_options['output'] if @dst.to_s.empty? && @metadata.pandoc_options.key?('output') # Run setup scripts setup template # Read in the file to convert Pandocomatic::LOG.debug " → Reading source file: '#{@src}'" input = File.read @src # Run the default preprocessors to mix-in information about the file # that is being converted and mix-in the template's metadata section as # well input = FileInfoPreprocessor.run input, @src, src_root, pandoc_options input = MetadataPreprocessor.run input, template.metadata if template.metadata? # Convert the file by preprocessing it, run pandoc on it, and # postprocessing the output input = preprocess input, template input = pandoc input, pandoc_options, File.dirname(@src) output = postprocess input, template begin # Either output to file or to STDOUT. if @config.stdout? Pandocomatic::LOG.debug ' ← Writing output to STDOUT.' puts output @dst.close! else unless use_output_option @dst Pandocomatic::LOG.debug " ← Writing output to '#{@dst}'." File.open(@dst, 'w') do |file| raise IOError.new(:file_is_not_a_file, nil, @dst) unless File.file? @dst raise IOError.new(:file_is_not_writable, nil, @dst) unless File.writable? @dst file << output end end end rescue StandardError => e raise IOError.new(:error_writing_file, e, @dst) end # run cleanup scripts cleanup template end
Pandoc version 2 supports multiple pdf engines. Determine which to use given the options.
@param options [Hash] the options to a paru pandoc converter @return [String] the output format for the pdf engine to use.
# File lib/pandocomatic/command/convert_file_command.rb, line 352 def determine_output_for_pdf(options) if options.key? 'pdf-engine' engine = options['pdf-engine'] case engine when 'context' 'context' when 'pdfroff' 'ms' when 'wkhtmltopdf', 'weasyprint', 'prince' 'html' else 'latex' end else # According to pandoc's manual, the default is LaTeX 'latex' end end
# File lib/pandocomatic/command/convert_file_command.rb, line 220 def pandoc(input, options, src_dir) absolute_dst = File.expand_path @dst Dir.chdir(src_dir) do Pandocomatic::LOG.debug " # Changing directory to '#{src_dir}'" converter = Paru::Pandoc.new options.each do |option, value| # Options come from a YAML string. In YAML, properties without a value get value nil. # Interpret these empty properties as "skip this property" next if value.nil? if PANDOC_OPTIONS_WITH_PATH.include? option executable = option == 'filter' value = if value.is_a? Array value.map { |v| Path.update_path(@config, v, absolute_dst, check_executable: executable) } else Path.update_path(@config, value, @dst, check_executable: executable) end end # There is no "pdf" output format; change it to latex but keep the # extension. value = determine_output_for_pdf(options) if (option == 'to') && (value == 'pdf') begin # Pandoc multi-word options can have the multiple words separated by # both underscore (_) and dash (-). option = option.gsub '-', '_' converter.send option, value unless (option == 'output') || (option == 'use_extension') || (option == 'rename') # don't let pandoc write the output to enable postprocessing rescue StandardError Pandocomatic::LOG.warn "WARNING: The pandoc option '#{option}'" " (with value '#{value}') is not recognized by paru. This option is skipped." end end converter.send 'output', absolute_dst if use_output_option absolute_dst begin Pandocomatic::LOG.debug ' # Running pandoc' Pandocomatic::LOG.debug " | #{Pandocomatic::LOG.indent(converter.to_command, 43)}" converter << input rescue Paru::Error => e raise PandocError.new(:error_running_pandoc, e, input) end end end
Postprocess the input
@param input [String] the input to postprocess @param template [Template] template
@return [String] the generated output
# File lib/pandocomatic/command/convert_file_command.rb, line 286 def postprocess(input, template) process input, Template::POSTPROCESSORS, template end
Preprocess the input
@param input [String] the input to preprocess @param template [Template] template
@return [String] the generated output
# File lib/pandocomatic/command/convert_file_command.rb, line 276 def preprocess(input, template) process input, Template::PREPROCESSORS, template end
Run the input string through a list of filters called processors. There are various types: preprocessors and postprocessors, setup and cleanup, and rename
# File lib/pandocomatic/command/convert_file_command.rb, line 307 def process(input, type, template) if template.send "#{type}?" processors = template.send type Pandocomatic::LOG.debug " # Running #{type}:" unless processors.empty? output = input processors.each do |processor| script = if Path.local_path? processor processor else Path.update_path(@config, processor, @dst, check_executable: true) end command, *parameters = script.shellsplit # split on spaces unless it is preceded by a backslash unless File.exist? command command = Path.which(command) script = "#{command} #{parameters.join(' ')}" raise ProcessorError.new(:script_does_not_exist, nil, command) if command.nil? end raise ProcessorError.new(:script_is_not_executable, nil, command) unless File.executable? command begin Pandocomatic::LOG.debug " | #{script}" output = Processor.run(script, output) rescue StandardError => e ProcessorError.new(:error_processing_script, e, [script, @src]) end end output else input end end
Run setup scripts
@param template [Template] template
# File lib/pandocomatic/command/convert_file_command.rb, line 293 def setup(template) process '', Template::SETUP, template end
# File lib/pandocomatic/command/convert_file_command.rb, line 343 def use_output_option(dst) OUTPUT_FORMATS.include?(File.extname(dst).slice(1..-1)) end