"Fossies" - the Fresh Open Source Software Archive

Member "asciidoctor-2.0.10/lib/asciidoctor/cli/options.rb" (1 Jun 2019, 14568 Bytes) of package /linux/www/asciidoctor-2.0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "options.rb": 2.0.6_vs_2.0.7.

    1 # frozen_string_literal: true
    2 module Asciidoctor
    3   module Cli
    4     FS = ?/
    5     RS = ?\\
    6 
    7     # Public: List of options that can be specified on the command line
    8     class Options < ::Hash
    9 
   10       def initialize(options = {})
   11         self[:attributes] = options[:attributes] || {}
   12         self[:input_files] = options[:input_files]
   13         self[:output_file] = options[:output_file]
   14         self[:safe] = options[:safe] || SafeMode::UNSAFE
   15         self[:standalone] = options.fetch :standalone, true
   16         self[:template_dirs] = options[:template_dirs]
   17         self[:template_engine] = options[:template_engine]
   18         self[:attributes]['doctype'] = options[:doctype] if options[:doctype]
   19         self[:attributes]['backend'] = options[:backend] if options[:backend]
   20         self[:eruby] = options[:eruby]
   21         self[:verbose] = options.fetch :verbose, 1
   22         self[:warnings] = options.fetch :warnings, false
   23         self[:load_paths] = options[:load_paths]
   24         self[:requires] = options[:requires]
   25         self[:base_dir] = options[:base_dir]
   26         self[:source_dir] = options[:source_dir]
   27         self[:destination_dir] = options[:destination_dir]
   28         self[:failure_level] = ::Logger::Severity::FATAL
   29         self[:trace] = false
   30         self[:timings] = false
   31       end
   32 
   33       def self.parse!(args)
   34         Options.new.parse! args
   35       end
   36 
   37       def parse!(args)
   38         opts_parser = ::OptionParser.new do |opts|
   39           # NOTE don't use squiggly heredoc to maintain compatibility with Ruby < 2.3
   40           opts.banner = <<-'EOS'.gsub '          ', ''
   41           Usage: asciidoctor [OPTION]... FILE...
   42           Translate the AsciiDoc source FILE or FILE(s) into the backend output format (e.g., HTML 5, DocBook 5, etc.)
   43           By default, the output is written to a file with the basename of the source file and the appropriate extension.
   44           Example: asciidoctor -b html5 source.asciidoc
   45 
   46           EOS
   47 
   48           opts.on('-b', '--backend BACKEND', 'set output format backend: [html5, xhtml5, docbook5, manpage] (default: html5)',
   49                   'additional backends are supported via extensions (e.g., pdf, latex)') do |backend|
   50             self[:attributes]['backend'] = backend
   51           end
   52           opts.on('-d', '--doctype DOCTYPE', ['article', 'book', 'manpage', 'inline'],
   53                   'document type to use when converting document: [article, book, manpage, inline] (default: article)') do |doc_type|
   54             self[:attributes]['doctype'] = doc_type
   55           end
   56           opts.on('-e', '--embedded', 'suppress enclosing document structure and output an embedded document (default: false)') do
   57             self[:standalone] = false
   58           end
   59           opts.on('-o', '--out-file FILE', 'output file (default: based on path of input file); use - to output to STDOUT') do |output_file|
   60             self[:output_file] = output_file
   61           end
   62           opts.on('--safe',
   63                   'set safe mode level to safe (default: unsafe)',
   64                   'enables include directives, but prevents access to ancestor paths of source file',
   65                   'provided for compatibility with the asciidoc command') do
   66             self[:safe] = SafeMode::SAFE
   67           end
   68           opts.on('-S', '--safe-mode SAFE_MODE', (safe_mode_names = SafeMode.names),
   69                   %(set safe mode level explicitly: [#{safe_mode_names.join ', '}] (default: unsafe)),
   70                   'disables potentially dangerous macros in source files, such as include::[]') do |name|
   71             self[:safe] = SafeMode.value_for_name name
   72           end
   73           opts.on('-s', '--no-header-footer', 'suppress enclosing document structure and output an embedded document (default: false)') do
   74             self[:standalone] = false
   75           end
   76           opts.on('-n', '--section-numbers', 'auto-number section titles in the HTML backend; disabled by default') do
   77             self[:attributes]['sectnums'] = ''
   78           end
   79           opts.on('--eruby ERUBY', ['erb', 'erubis'],
   80                   'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubis] (default: erb)') do |eruby|
   81             self[:eruby] = eruby
   82           end
   83           opts.on('-a', '--attribute name[=value]', 'a document attribute to set in the form of name, name!, or name=value pair',
   84                   'this attribute takes precedence over the same attribute defined in the source document',
   85                   'unless either the name or value ends in @ (i.e., name@=value or name=value@)') do |attr|
   86             next if (attr = attr.rstrip).empty? || attr == '='
   87             attr = attr.encode UTF_8 unless attr.encoding == UTF_8
   88             name, _, val = attr.partition '='
   89             self[:attributes][name] = val
   90           end
   91           opts.on('-T', '--template-dir DIR', 'a directory containing custom converter templates that override the built-in converter (requires tilt gem)',
   92                   'may be specified multiple times') do |template_dir|
   93             if self[:template_dirs].nil?
   94               self[:template_dirs] = [template_dir]
   95             elsif ::Array === self[:template_dirs]
   96               self[:template_dirs] << template_dir
   97             else
   98               self[:template_dirs] = [self[:template_dirs], template_dir]
   99             end
  100           end
  101           opts.on('-E', '--template-engine NAME', 'template engine to use for the custom converter templates (loads gem on demand)') do |template_engine|
  102             self[:template_engine] = template_engine
  103           end
  104           opts.on('-B', '--base-dir DIR', 'base directory containing the document and resources (default: directory of source file)') do |base_dir|
  105             self[:base_dir] = base_dir
  106           end
  107           opts.on('-R', '--source-dir DIR', 'source root directory (used for calculating path in destination directory)') do |src_dir|
  108             self[:source_dir] = src_dir
  109           end
  110           opts.on('-D', '--destination-dir DIR', 'destination output directory (default: directory of source file)') do |dest_dir|
  111             self[:destination_dir] = dest_dir
  112           end
  113           opts.on('-IDIRECTORY', '--load-path DIRECTORY', 'add a directory to the $LOAD_PATH',
  114               'may be specified more than once') do |path|
  115             (self[:load_paths] ||= []).concat(path.split ::File::PATH_SEPARATOR)
  116           end
  117           opts.on('-rLIBRARY', '--require LIBRARY', 'require the specified library before executing the processor (using require)',
  118               'may be specified more than once') do |path|
  119             (self[:requires] ||= []).concat(path.split ',')
  120           end
  121           opts.on('--failure-level LEVEL', %w(warning WARNING error ERROR info INFO), 'set minimum logging level that triggers non-zero exit code: [WARN, ERROR, INFO] (default: FATAL)') do |level|
  122             level = 'WARN' if (level = level.upcase) == 'WARNING'
  123             self[:failure_level] = ::Logger::Severity.const_get level, false
  124           end
  125           opts.on('-q', '--quiet', 'silence application log messages and script warnings (default: false)') do |verbose|
  126             self[:verbose] = 0
  127           end
  128           opts.on('--trace', 'include backtrace information when reporting errors (default: false)') do |trace|
  129             self[:trace] = true
  130           end
  131           opts.on('-v', '--verbose', 'enable verbose mode (default: false)') do |verbose|
  132             self[:verbose] = 2
  133           end
  134           opts.on('-w', '--warnings', 'turn on script warnings (default: false)') do |warnings|
  135             self[:warnings] = true
  136           end
  137           opts.on('-t', '--timings', 'print timings report (default: false)') do |timing|
  138             self[:timings] = true
  139           end
  140           opts.on_tail('-h', '--help [TOPIC]', 'print a help message',
  141               'show this usage if TOPIC is not specified or recognized',
  142               'show an overview of the AsciiDoc syntax if TOPIC is syntax',
  143               'dump the Asciidoctor man page (in troff/groff format) if TOPIC is manpage') do |topic|
  144             case topic
  145             # use `asciidoctor -h manpage | man -l -` to view with man pager
  146             when 'manpage'
  147               if (manpage_path = ::ENV['ASCIIDOCTOR_MANPAGE_PATH'])
  148                 if ::File.exist? manpage_path
  149                   if manpage_path.end_with? '.gz'
  150                     require 'zlib' unless defined? ::Zlib::GzipReader
  151                     $stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
  152                   else
  153                     $stdout.puts ::File.read manpage_path
  154                   end
  155                 else
  156                   $stderr.puts %(asciidoctor: FAILED: manual page not found: #{manpage_path})
  157                   return 1
  158                 end
  159               # Ruby 2.3 requires the extra brackets around the ::File.join method call
  160               elsif ::File.exist? (manpage_path = (::File.join ROOT_DIR, 'man', 'asciidoctor.1'))
  161                 $stdout.puts ::File.read manpage_path
  162               else
  163                 manpage_path = `man -w asciidoctor`.chop rescue ''
  164                 if manpage_path.empty?
  165                   $stderr.puts 'asciidoctor: FAILED: manual page not found; try `man asciidoctor`'
  166                   return 1
  167                 elsif manpage_path.end_with? '.gz'
  168                   require 'zlib' unless defined? ::Zlib::GzipReader
  169                   $stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
  170                 else
  171                   $stdout.puts ::File.read manpage_path
  172                 end
  173               end
  174             when 'syntax'
  175               # Ruby 2.3 requires the extra brackets around the ::File.join method call
  176               if ::File.exist? (syntax_path = (::File.join ROOT_DIR, 'data', 'reference', 'syntax.adoc'))
  177                 $stdout.puts ::File.read syntax_path
  178               else
  179                 $stderr.puts 'asciidoctor: FAILED: syntax page not found; visit https://asciidoctor.org/docs'
  180                 return 1
  181               end
  182             else
  183               $stdout.puts opts
  184             end
  185             return 0
  186           end
  187           opts.on_tail('-V', '--version', 'display the version and runtime environment (or -v if no other flags or arguments)') do
  188             return print_version $stdout
  189           end
  190         end
  191 
  192         old_verbose, $VERBOSE = $VERBOSE, (args.include? '-w')
  193         opts_parser.parse! args
  194 
  195         if args.empty?
  196           if self[:verbose] == 2 # -v flag was specified
  197             return print_version $stdout
  198           else
  199             $stderr.puts opts_parser
  200             return 1
  201           end
  202         end
  203 
  204         infiles = []
  205         # shave off the file to process so that options errors appear correctly
  206         if args.size == 1 && args[0] == '-'
  207           infiles << args.pop
  208         elsif
  209           args.each do |file|
  210             if file.start_with? '-'
  211               # warn, but don't panic; we may have enough to proceed, so we won't force a failure
  212               $stderr.puts %(asciidoctor: WARNING: extra arguments detected (unparsed arguments: '#{args.join "', '"}') or incorrect usage of stdin)
  213             elsif ::File.file? file
  214               infiles << file
  215             # NOTE only attempt to glob if file is not found
  216             else
  217               # Tilt backslashes in Windows paths the Ruby-friendly way
  218               if ::File::ALT_SEPARATOR == RS && (file.include? RS)
  219                 file = file.tr RS, FS
  220               end
  221               if (matches = ::Dir.glob file).empty?
  222                 # NOTE if no matches, assume it's just a missing file and proceed
  223                 infiles << file
  224               else
  225                 infiles.concat matches
  226               end
  227             end
  228           end
  229         end
  230 
  231         infiles.reject {|file| file == '-' }.each do |file|
  232           begin
  233             fstat = ::File.stat file
  234             if fstat.file? || fstat.pipe?
  235               unless fstat.readable?
  236                 $stderr.puts %(asciidoctor: FAILED: input file #{file} is not readable)
  237                 return 1
  238               end
  239             else
  240               $stderr.puts %(asciidoctor: FAILED: input path #{file} is a #{fstat.ftype}, not a file)
  241               return 1
  242             end
  243           rescue ::Errno::ENOENT
  244             $stderr.puts %(asciidoctor: FAILED: input file #{file} is missing)
  245             return 1
  246           end
  247         end
  248 
  249         self[:input_files] = infiles
  250 
  251         self.delete :attributes if self[:attributes].empty?
  252 
  253         if self[:template_dirs]
  254           begin
  255             require 'tilt' unless defined? ::Tilt.new
  256           rescue ::LoadError
  257             raise $! if self[:trace]
  258             $stderr.puts 'asciidoctor: FAILED: \'tilt\' could not be loaded'
  259             $stderr.puts '  You must have the tilt gem installed (gem install tilt) to use custom backend templates'
  260             $stderr.puts '  Use --trace for backtrace'
  261             return 1
  262           rescue ::SystemExit
  263             # not permitted here
  264           end
  265         end
  266 
  267         if (load_paths = self[:load_paths])
  268           load_paths.uniq!
  269           load_paths.reverse_each {|path| $:.unshift ::File.expand_path path }
  270         end
  271 
  272         if (requires = self[:requires])
  273           requires.uniq!
  274           requires.each do |path|
  275             begin
  276               require path
  277             rescue ::LoadError
  278               raise $! if self[:trace]
  279               $stderr.puts %(asciidoctor: FAILED: '#{path}' could not be loaded)
  280               $stderr.puts '  Use --trace for backtrace'
  281               return 1
  282             rescue ::SystemExit
  283               # not permitted here
  284             end
  285           end
  286         end
  287 
  288         self
  289       rescue ::OptionParser::MissingArgument
  290         $stderr.puts %(asciidoctor: option #{$!.message})
  291         $stdout.puts opts_parser
  292         return 1
  293       rescue ::OptionParser::InvalidOption, ::OptionParser::InvalidArgument
  294         $stderr.puts %(asciidoctor: #{$!.message})
  295         $stdout.puts opts_parser
  296         return 1
  297       ensure
  298         $VERBOSE = old_verbose
  299       end
  300 
  301       def print_version os = $stdout
  302         os.puts %(Asciidoctor #{::Asciidoctor::VERSION} [https://asciidoctor.org])
  303         encoding_info = { 'lc' => 'locale', 'fs' => 'filesystem', 'in' => 'internal', 'ex' => 'external' }.map do |k, v|
  304           %(#{k}:#{v == 'internal' ? (::File.open(__FILE__) {|f| f.getc.encoding }) : (::Encoding.find v)})
  305         end
  306         os.puts %(Runtime Environment (#{::RUBY_DESCRIPTION}) (#{encoding_info.join ' '}))
  307         0
  308       end
  309     end
  310   end
  311 end