asciidoctor 1.5.8 → 2.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.adoc +628 -45
  4. data/LICENSE +2 -1
  5. data/README-de.adoc +28 -38
  6. data/README-fr.adoc +30 -43
  7. data/README-jp.adoc +255 -201
  8. data/README-zh_CN.adoc +40 -44
  9. data/README.adoc +170 -143
  10. data/asciidoctor.gemspec +22 -34
  11. data/bin/asciidoctor +5 -4
  12. data/data/locale/attributes-ar.adoc +4 -3
  13. data/data/locale/attributes-be.adoc +23 -0
  14. data/data/locale/attributes-bg.adoc +4 -3
  15. data/data/locale/attributes-ca.adoc +6 -5
  16. data/data/locale/attributes-cs.adoc +4 -3
  17. data/data/locale/attributes-da.adoc +6 -5
  18. data/data/locale/attributes-de.adoc +6 -5
  19. data/data/locale/attributes-en.adoc +4 -4
  20. data/data/locale/attributes-es.adoc +6 -5
  21. data/data/locale/attributes-fa.adoc +4 -3
  22. data/data/locale/attributes-fi.adoc +4 -3
  23. data/data/locale/attributes-fr.adoc +8 -7
  24. data/data/locale/attributes-hu.adoc +4 -3
  25. data/data/locale/attributes-id.adoc +4 -3
  26. data/data/locale/attributes-it.adoc +6 -5
  27. data/data/locale/attributes-ja.adoc +4 -3
  28. data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
  29. data/data/locale/attributes-nb.adoc +4 -3
  30. data/data/locale/attributes-nl.adoc +6 -5
  31. data/data/locale/attributes-nn.adoc +4 -3
  32. data/data/locale/attributes-pl.adoc +8 -7
  33. data/data/locale/attributes-pt.adoc +6 -5
  34. data/data/locale/attributes-pt_BR.adoc +6 -5
  35. data/data/locale/attributes-ro.adoc +4 -3
  36. data/data/locale/attributes-ru.adoc +6 -5
  37. data/data/locale/attributes-sr.adoc +4 -4
  38. data/data/locale/attributes-sr_Latn.adoc +4 -4
  39. data/data/locale/attributes-sv.adoc +4 -4
  40. data/data/locale/attributes-th.adoc +23 -0
  41. data/data/locale/attributes-tr.adoc +4 -3
  42. data/data/locale/attributes-uk.adoc +6 -5
  43. data/data/locale/attributes-vi.adoc +23 -0
  44. data/data/locale/attributes-zh_CN.adoc +4 -3
  45. data/data/locale/attributes-zh_TW.adoc +4 -3
  46. data/data/reference/syntax.adoc +296 -0
  47. data/data/stylesheets/asciidoctor-default.css +120 -114
  48. data/data/stylesheets/coderay-asciidoctor.css +15 -17
  49. data/lib/asciidoctor/abstract_block.rb +146 -140
  50. data/lib/asciidoctor/abstract_node.rb +152 -170
  51. data/lib/asciidoctor/attribute_list.rb +77 -89
  52. data/lib/asciidoctor/block.rb +29 -28
  53. data/lib/asciidoctor/callouts.rb +4 -2
  54. data/lib/asciidoctor/cli/invoker.rb +20 -24
  55. data/lib/asciidoctor/cli/options.rb +107 -96
  56. data/lib/asciidoctor/cli.rb +3 -2
  57. data/lib/asciidoctor/convert.rb +199 -0
  58. data/lib/asciidoctor/converter/composite.rb +40 -48
  59. data/lib/asciidoctor/converter/docbook5.rb +627 -644
  60. data/lib/asciidoctor/converter/html5.rb +1053 -951
  61. data/lib/asciidoctor/converter/manpage.rb +581 -532
  62. data/lib/asciidoctor/converter/template.rb +232 -271
  63. data/lib/asciidoctor/converter.rb +370 -185
  64. data/lib/asciidoctor/core_ext/float/truncate.rb +20 -0
  65. data/lib/asciidoctor/core_ext/hash/merge.rb +8 -0
  66. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  67. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  68. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  69. data/lib/asciidoctor/core_ext.rb +8 -17
  70. data/lib/asciidoctor/document.rb +503 -461
  71. data/lib/asciidoctor/extensions.rb +127 -174
  72. data/lib/asciidoctor/helpers.rb +184 -107
  73. data/lib/asciidoctor/inline.rb +9 -12
  74. data/lib/asciidoctor/list.rb +11 -29
  75. data/lib/asciidoctor/load.rb +119 -0
  76. data/lib/asciidoctor/logging.rb +22 -17
  77. data/lib/asciidoctor/parser.rb +673 -719
  78. data/lib/asciidoctor/path_resolver.rb +48 -33
  79. data/lib/asciidoctor/reader.rb +383 -338
  80. data/lib/asciidoctor/rouge_ext.rb +39 -0
  81. data/lib/asciidoctor/rx.rb +723 -0
  82. data/lib/asciidoctor/section.rb +17 -16
  83. data/lib/asciidoctor/stylesheets.rb +19 -37
  84. data/lib/asciidoctor/substitutors.rb +926 -1022
  85. data/lib/asciidoctor/syntax_highlighter/coderay.rb +88 -0
  86. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +34 -0
  87. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  88. data/lib/asciidoctor/syntax_highlighter/prettify.rb +30 -0
  89. data/lib/asciidoctor/syntax_highlighter/pygments.rb +157 -0
  90. data/lib/asciidoctor/syntax_highlighter/rouge.rb +143 -0
  91. data/lib/asciidoctor/syntax_highlighter.rb +253 -0
  92. data/lib/asciidoctor/table.rb +152 -114
  93. data/lib/asciidoctor/timings.rb +7 -5
  94. data/lib/asciidoctor/version.rb +2 -1
  95. data/lib/asciidoctor/writer.rb +30 -0
  96. data/lib/asciidoctor.rb +266 -1340
  97. data/man/asciidoctor.1 +49 -47
  98. data/man/asciidoctor.adoc +54 -45
  99. metadata +50 -245
  100. data/CONTRIBUTING.adoc +0 -185
  101. data/Gemfile +0 -60
  102. data/Rakefile +0 -129
  103. data/bin/asciidoctor-safe +0 -15
  104. data/features/open_block.feature +0 -92
  105. data/features/pass_block.feature +0 -66
  106. data/features/step_definitions.rb +0 -49
  107. data/features/text_formatting.feature +0 -57
  108. data/features/xref.feature +0 -1039
  109. data/lib/asciidoctor/converter/base.rb +0 -59
  110. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  111. data/lib/asciidoctor/converter/factory.rb +0 -226
  112. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  113. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  114. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  115. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  116. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  117. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  118. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  119. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  120. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  121. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  122. data/test/api_test.rb +0 -1240
  123. data/test/attribute_list_test.rb +0 -242
  124. data/test/attributes_test.rb +0 -1623
  125. data/test/blocks_test.rb +0 -3870
  126. data/test/converter_test.rb +0 -470
  127. data/test/document_test.rb +0 -1853
  128. data/test/extensions_test.rb +0 -1560
  129. data/test/fixtures/asciidoc_index.txt +0 -521
  130. data/test/fixtures/basic-docinfo-footer.html +0 -6
  131. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  132. data/test/fixtures/basic-docinfo.html +0 -1
  133. data/test/fixtures/basic-docinfo.xml +0 -4
  134. data/test/fixtures/basic.asciidoc +0 -5
  135. data/test/fixtures/chapter-a.adoc +0 -3
  136. data/test/fixtures/child-include.adoc +0 -5
  137. data/test/fixtures/circle.svg +0 -9
  138. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  139. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  140. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  141. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  142. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  143. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  144. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  145. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  146. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  147. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  148. data/test/fixtures/docinfo-footer.html +0 -1
  149. data/test/fixtures/docinfo-footer.xml +0 -9
  150. data/test/fixtures/docinfo.html +0 -1
  151. data/test/fixtures/docinfo.xml +0 -3
  152. data/test/fixtures/doctime-localtime.adoc +0 -2
  153. data/test/fixtures/dot.gif +0 -0
  154. data/test/fixtures/encoding.asciidoc +0 -13
  155. data/test/fixtures/file-with-missing-include.adoc +0 -1
  156. data/test/fixtures/grandchild-include.adoc +0 -3
  157. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  158. data/test/fixtures/include-file.asciidoc +0 -24
  159. data/test/fixtures/include-file.jsx +0 -8
  160. data/test/fixtures/include-file.ml +0 -3
  161. data/test/fixtures/include-file.xml +0 -5
  162. data/test/fixtures/lists.adoc +0 -96
  163. data/test/fixtures/master.adoc +0 -5
  164. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  165. data/test/fixtures/other-chapters.adoc +0 -11
  166. data/test/fixtures/outer-include.adoc +0 -5
  167. data/test/fixtures/parent-include-restricted.adoc +0 -5
  168. data/test/fixtures/parent-include.adoc +0 -5
  169. data/test/fixtures/sample.asciidoc +0 -30
  170. data/test/fixtures/section-a.adoc +0 -4
  171. data/test/fixtures/stylesheets/custom.css +0 -3
  172. data/test/fixtures/subdir/index.adoc +0 -3
  173. data/test/fixtures/subdir/inner-include.adoc +0 -3
  174. data/test/fixtures/subdir/middle-include.adoc +0 -5
  175. data/test/fixtures/subs-docinfo.html +0 -2
  176. data/test/fixtures/subs.adoc +0 -6
  177. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  178. data/test/fixtures/tagged-class.rb +0 -23
  179. data/test/fixtures/tip.gif +0 -0
  180. data/test/fixtures/unclosed-tag.adoc +0 -3
  181. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  182. data/test/invoker_test.rb +0 -745
  183. data/test/links_test.rb +0 -855
  184. data/test/lists_test.rb +0 -5151
  185. data/test/logger_test.rb +0 -211
  186. data/test/manpage_test.rb +0 -660
  187. data/test/options_test.rb +0 -262
  188. data/test/paragraphs_test.rb +0 -562
  189. data/test/parser_test.rb +0 -742
  190. data/test/paths_test.rb +0 -395
  191. data/test/preamble_test.rb +0 -173
  192. data/test/reader_test.rb +0 -2161
  193. data/test/sections_test.rb +0 -3575
  194. data/test/substitutions_test.rb +0 -2066
  195. data/test/tables_test.rb +0 -2036
  196. data/test/test_helper.rb +0 -447
  197. data/test/text_test.rb +0 -309
@@ -1,33 +1,30 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
3
  module Cli
4
- FS = '/'
5
- RS = '\\'
4
+ FS = ?/
5
+ RS = ?\\
6
6
 
7
7
  # Public: List of options that can be specified on the command line
8
8
  class Options < ::Hash
9
9
 
10
10
  def initialize(options = {})
11
11
  self[:attributes] = options[:attributes] || {}
12
- self[:input_files] = options[:input_files] || nil
13
- self[:output_file] = options[:output_file] || nil
12
+ self[:input_files] = options[:input_files]
13
+ self[:output_file] = options[:output_file]
14
14
  self[:safe] = options[:safe] || SafeMode::UNSAFE
15
- self[:header_footer] = options[:header_footer] || true
16
- self[:template_dirs] = options[:template_dirs] || nil
17
- self[:template_engine] = options[:template_engine] || nil
18
- if options[:doctype]
19
- self[:attributes]['doctype'] = options[:doctype]
20
- end
21
- if options[:backend]
22
- self[:attributes]['backend'] = options[:backend]
23
- end
24
- self[:eruby] = options[:eruby] || nil
25
- self[:verbose] = options[:verbose] || 1
26
- self[:load_paths] = options[:load_paths] || nil
27
- self[:requires] = options[:requires] || nil
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]
28
25
  self[:base_dir] = options[:base_dir]
29
- self[:source_dir] = options[:source_dir] || nil
30
- self[:destination_dir] = options[:destination_dir] || nil
26
+ self[:source_dir] = options[:source_dir]
27
+ self[:destination_dir] = options[:destination_dir]
31
28
  self[:failure_level] = ::Logger::Severity::FATAL
32
29
  self[:trace] = false
33
30
  self[:timings] = false
@@ -39,55 +36,61 @@ module Asciidoctor
39
36
 
40
37
  def parse!(args)
41
38
  opts_parser = ::OptionParser.new do |opts|
42
- opts.banner = <<-EOS
43
- Usage: asciidoctor [OPTION]... FILE...
44
- Translate the AsciiDoc source FILE or FILE(s) into the backend output format (e.g., HTML 5, DocBook 4.5, etc.)
45
- By default, the output is written to a file with the basename of the source file and the appropriate extension.
46
- Example: asciidoctor -b html5 source.asciidoc
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
+ Convert the AsciiDoc input FILE(s) to the backend output format (e.g., HTML 5, DocBook 5, etc.)
43
+ Unless specified otherwise, the output is written to a file whose name is derived from the input file.
44
+ Application log messages are printed to STDERR.
45
+ Example: asciidoctor input.adoc
47
46
 
48
47
  EOS
49
48
 
50
- opts.on('-b', '--backend BACKEND', 'set output format backend: [html5, xhtml5, docbook5, docbook45, manpage] (default: html5)',
51
- 'additional backends are supported via extensions (e.g., pdf, latex)') do |backend|
49
+ opts.on('-b', '--backend BACKEND', 'set backend output format: [html5, xhtml5, docbook5, manpage] (default: html5)',
50
+ 'additional backends are supported via extended converters (e.g., pdf, epub3)') do |backend|
52
51
  self[:attributes]['backend'] = backend
53
52
  end
54
53
  opts.on('-d', '--doctype DOCTYPE', ['article', 'book', 'manpage', 'inline'],
55
- 'document type to use when converting document: [article, book, manpage, inline] (default: article)') do |doc_type|
56
- self[:attributes]['doctype'] = doc_type
54
+ 'document type to use when converting document: [article, book, manpage, inline] (default: article)') do |doctype|
55
+ self[:attributes]['doctype'] = doctype
56
+ end
57
+ opts.on('-e', '--embedded', 'suppress enclosing document structure and output an embedded document (default: false)') do
58
+ self[:standalone] = false
57
59
  end
58
60
  opts.on('-o', '--out-file FILE', 'output file (default: based on path of input file); use - to output to STDOUT') do |output_file|
59
61
  self[:output_file] = output_file
60
62
  end
61
63
  opts.on('--safe',
62
- 'set safe mode level to safe (default: unsafe)',
63
- 'enables include directives, but prevents access to ancestor paths of source file',
64
- 'provided for compatibility with the asciidoc command') do
64
+ 'set safe mode level to safe (default: unsafe)',
65
+ 'enables include directives, but prevents access to ancestor paths of source file',
66
+ 'provided for compatibility with the asciidoc command') do
65
67
  self[:safe] = SafeMode::SAFE
66
68
  end
67
69
  opts.on('-S', '--safe-mode SAFE_MODE', (safe_mode_names = SafeMode.names),
68
- %(set safe mode level explicitly: [#{safe_mode_names.join ', '}] (default: unsafe)),
69
- 'disables potentially dangerous macros in source files, such as include::[]') do |name|
70
+ %(set safe mode level explicitly: [#{safe_mode_names.join ', '}] (default: unsafe)),
71
+ 'disables potentially dangerous macros in source files, such as include::[]') do |name|
70
72
  self[:safe] = SafeMode.value_for_name name
71
73
  end
72
- opts.on('-s', '--no-header-footer', 'suppress output of header and footer (default: false)') do
73
- self[:header_footer] = false
74
+ opts.on('-s', '--no-header-footer', 'suppress enclosing document structure and output an embedded document (default: false)') do
75
+ self[:standalone] = false
74
76
  end
75
77
  opts.on('-n', '--section-numbers', 'auto-number section titles in the HTML backend; disabled by default') do
76
78
  self[:attributes]['sectnums'] = ''
77
79
  end
78
- opts.on('-e', '--eruby ERUBY', ['erb', 'erubis'],
79
- 'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubis] (default: erb)') do |eruby|
80
+ opts.on('--eruby ERUBY', ['erb', 'erubi', 'erubis'],
81
+ 'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubi, erubis] (default: erb)') do |eruby|
80
82
  self[:eruby] = eruby
81
83
  end
82
- opts.on('-a', '--attribute key[=value]', 'a document attribute to set in the form of key, key! or key=value pair',
83
- 'unless @ is appended to the value, this attributes takes precedence over attributes',
84
- 'defined in the source document') do |attr|
85
- key, val = attr.split '=', 2
86
- val = val ? (FORCE_ENCODING ? (val.force_encoding ::Encoding::UTF_8) : val) : ''
87
- self[:attributes][key] = val
84
+ opts.on('-a', '--attribute name[=value]', 'a document attribute to set in the form of name, name!, or name=value pair',
85
+ 'this attribute takes precedence over the same attribute defined in the source document',
86
+ 'unless either the name or value ends in @ (i.e., name@=value or name=value@)') do |attr|
87
+ next if (attr = attr.rstrip).empty? || attr == '='
88
+ attr = attr.encode UTF_8 unless attr.encoding == UTF_8
89
+ name, _, val = attr.partition '='
90
+ self[:attributes][name] = val
88
91
  end
89
92
  opts.on('-T', '--template-dir DIR', 'a directory containing custom converter templates that override the built-in converter (requires tilt gem)',
90
- 'may be specified multiple times') do |template_dir|
93
+ 'may be specified multiple times') do |template_dir|
91
94
  if self[:template_dirs].nil?
92
95
  self[:template_dirs] = [template_dir]
93
96
  elsif ::Array === self[:template_dirs]
@@ -116,44 +119,49 @@ Example: asciidoctor -b html5 source.asciidoc
116
119
  'may be specified more than once') do |path|
117
120
  (self[:requires] ||= []).concat(path.split ',')
118
121
  end
119
- opts.on('--failure-level LEVEL', %w(warning WARNING error ERROR), 'set minimum logging level that triggers a non-zero exit code: [WARN, ERROR] (default: FATAL)') do |level|
122
+ opts.on('--failure-level LEVEL', %w(info INFO warning WARNING error ERROR fatal FATAL), 'set minimum log level that yields a non-zero exit code: [INFO, WARN, ERROR, FATAL] (default: FATAL)') do |level|
120
123
  level = 'WARN' if (level = level.upcase) == 'WARNING'
121
124
  self[:failure_level] = ::Logger::Severity.const_get level
122
125
  end
123
- opts.on('-q', '--quiet', 'suppress warnings (default: false)') do |verbose|
126
+ opts.on('-q', '--quiet', 'silence application log messages and script warnings (default: false)') do
124
127
  self[:verbose] = 0
125
128
  end
126
- opts.on('--trace', 'include backtrace information on errors (default: false)') do |trace|
129
+ opts.on('--trace', 'include backtrace information when reporting errors (default: false)') do
127
130
  self[:trace] = true
128
131
  end
129
- opts.on('-v', '--verbose', 'enable verbose mode (default: false)') do |verbose|
132
+ opts.on('-v', '--verbose', 'directs application messages logged at DEBUG or INFO level to STDERR (default: false)') do
130
133
  self[:verbose] = 2
131
134
  end
132
- opts.on('-t', '--timings', 'enable timings mode (default: false)') do |timing|
135
+ opts.on('-w', '--warnings', 'turn on script warnings (default: false)') do
136
+ self[:warnings] = true
137
+ end
138
+ opts.on('-t', '--timings', 'print timings report (default: false)') do
133
139
  self[:timings] = true
134
140
  end
135
-
136
- opts.on_tail('-h', '--help [TOPIC]', 'print the help message',
137
- 'show the command usage if TOPIC is not specified (or not recognized)',
141
+ opts.on_tail('-h', '--help [TOPIC]', 'print a help message',
142
+ 'show this usage if TOPIC is not specified or recognized',
143
+ 'show an overview of the AsciiDoc syntax if TOPIC is syntax',
138
144
  'dump the Asciidoctor man page (in troff/groff format) if TOPIC is manpage') do |topic|
139
- if topic == 'manpage'
140
- if (manpage_path = ENV['ASCIIDOCTOR_MANPAGE_PATH'])
145
+ case topic
146
+ # use `asciidoctor -h manpage | man -l -` to view with man pager
147
+ when 'manpage'
148
+ if (manpage_path = ::ENV['ASCIIDOCTOR_MANPAGE_PATH'])
141
149
  if ::File.exist? manpage_path
142
150
  if manpage_path.end_with? '.gz'
143
151
  require 'zlib' unless defined? ::Zlib::GzipReader
144
152
  $stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
145
153
  else
146
- $stdout.puts ::IO.read manpage_path
154
+ $stdout.puts ::File.read manpage_path
147
155
  end
148
156
  else
149
157
  $stderr.puts %(asciidoctor: FAILED: manual page not found: #{manpage_path})
150
158
  return 1
151
159
  end
152
- elsif ::File.exist?(manpage_path = (::File.join ::Asciidoctor::ROOT_PATH, 'man', 'asciidoctor.1'))
153
- $stdout.puts ::IO.read manpage_path
160
+ # Ruby 2.3 requires the extra brackets around the ::File.join method call
161
+ elsif ::File.exist? (manpage_path = (::File.join ROOT_DIR, 'man', 'asciidoctor.1'))
162
+ $stdout.puts ::File.read manpage_path
154
163
  else
155
- require 'open3' unless defined? ::Open3.popen3
156
- manpage_path = ::Open3.popen3('man -w asciidoctor') {|_, out| out.read }.chop rescue ''
164
+ manpage_path = %x(man -w asciidoctor).chop rescue ''
157
165
  if manpage_path.empty?
158
166
  $stderr.puts 'asciidoctor: FAILED: manual page not found; try `man asciidoctor`'
159
167
  return 1
@@ -161,26 +169,32 @@ Example: asciidoctor -b html5 source.asciidoc
161
169
  require 'zlib' unless defined? ::Zlib::GzipReader
162
170
  $stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
163
171
  else
164
- $stdout.puts ::IO.read manpage_path
172
+ $stdout.puts ::File.read manpage_path
165
173
  end
166
174
  end
175
+ when 'syntax'
176
+ # Ruby 2.3 requires the extra brackets around the ::File.join method call
177
+ if ::File.exist? (syntax_path = (::File.join ROOT_DIR, 'data', 'reference', 'syntax.adoc'))
178
+ $stdout.puts ::File.read syntax_path
179
+ else
180
+ $stderr.puts 'asciidoctor: FAILED: syntax page not found; visit https://asciidoctor.org/docs'
181
+ return 1
182
+ end
167
183
  else
168
184
  $stdout.puts opts
169
185
  end
170
186
  return 0
171
187
  end
172
-
173
188
  opts.on_tail('-V', '--version', 'display the version and runtime environment (or -v if no other flags or arguments)') do
174
189
  return print_version $stdout
175
190
  end
176
-
177
191
  end
178
192
 
179
- infiles = []
193
+ old_verbose, $VERBOSE = $VERBOSE, (args.include? '-w')
180
194
  opts_parser.parse! args
181
195
 
182
196
  if args.empty?
183
- if self[:verbose] == 2
197
+ if self[:verbose] == 2 # -v flag was specified
184
198
  return print_version $stdout
185
199
  else
186
200
  $stderr.puts opts_parser
@@ -188,29 +202,28 @@ Example: asciidoctor -b html5 source.asciidoc
188
202
  end
189
203
  end
190
204
 
205
+ infiles = []
191
206
  # shave off the file to process so that options errors appear correctly
192
207
  if args.size == 1 && args[0] == '-'
193
208
  infiles << args.pop
194
- elsif
209
+ else
195
210
  args.each do |file|
196
- if file == '-' || (file.start_with? '-')
211
+ if file.start_with? '-'
197
212
  # warn, but don't panic; we may have enough to proceed, so we won't force a failure
198
213
  $stderr.puts %(asciidoctor: WARNING: extra arguments detected (unparsed arguments: '#{args.join "', '"}') or incorrect usage of stdin)
214
+ elsif ::File.file? file
215
+ infiles << file
216
+ # NOTE only attempt to glob if file is not found
199
217
  else
200
- if ::File.file? file
218
+ # Tilt backslashes in Windows paths the Ruby-friendly way
219
+ if ::File::ALT_SEPARATOR == RS && (file.include? RS)
220
+ file = file.tr RS, FS
221
+ end
222
+ if (matches = ::Dir.glob file).empty?
223
+ # NOTE if no matches, assume it's just a missing file and proceed
201
224
  infiles << file
202
- # NOTE only attempt to glob if file is not found
203
225
  else
204
- # Tilt backslashes in Windows paths the Ruby-friendly way
205
- if ::File::ALT_SEPARATOR == RS && (file.include? RS)
206
- file = file.tr RS, FS
207
- end
208
- if (matches = ::Dir.glob file).empty?
209
- # NOTE if no matches, assume it's just a missing file and proceed
210
- infiles << file
211
- else
212
- infiles.concat matches
213
- end
226
+ infiles.concat matches
214
227
  end
215
228
  end
216
229
  end
@@ -236,16 +249,16 @@ Example: asciidoctor -b html5 source.asciidoc
236
249
 
237
250
  self[:input_files] = infiles
238
251
 
239
- self.delete(:attributes) if self[:attributes].empty?
252
+ delete :attributes if self[:attributes].empty?
240
253
 
241
254
  if self[:template_dirs]
242
255
  begin
243
- require 'tilt' unless defined? ::Tilt::VERSION
256
+ require 'tilt' unless defined? ::Tilt.new
244
257
  rescue ::LoadError
245
258
  raise $! if self[:trace]
246
259
  $stderr.puts 'asciidoctor: FAILED: \'tilt\' could not be loaded'
247
260
  $stderr.puts ' You must have the tilt gem installed (gem install tilt) to use custom backend templates'
248
- $stderr.puts ' Use --trace for backtrace'
261
+ $stderr.puts ' Use --trace to show backtrace'
249
262
  return 1
250
263
  rescue ::SystemExit
251
264
  # not permitted here
@@ -253,19 +266,19 @@ Example: asciidoctor -b html5 source.asciidoc
253
266
  end
254
267
 
255
268
  if (load_paths = self[:load_paths])
256
- (self[:load_paths] = load_paths.uniq).reverse_each do |path|
257
- $:.unshift ::File.expand_path(path)
258
- end
269
+ load_paths.uniq!
270
+ load_paths.reverse_each {|path| $:.unshift ::File.expand_path path }
259
271
  end
260
272
 
261
273
  if (requires = self[:requires])
262
- (self[:requires] = requires.uniq).each do |path|
274
+ requires.uniq!
275
+ requires.each do |path|
263
276
  begin
264
277
  require path
265
278
  rescue ::LoadError
266
279
  raise $! if self[:trace]
267
280
  $stderr.puts %(asciidoctor: FAILED: '#{path}' could not be loaded)
268
- $stderr.puts ' Use --trace for backtrace'
281
+ $stderr.puts ' Use --trace to show backtrace'
269
282
  return 1
270
283
  rescue ::SystemExit
271
284
  # not permitted here
@@ -277,23 +290,21 @@ Example: asciidoctor -b html5 source.asciidoc
277
290
  rescue ::OptionParser::MissingArgument
278
291
  $stderr.puts %(asciidoctor: option #{$!.message})
279
292
  $stdout.puts opts_parser
280
- return 1
293
+ 1
281
294
  rescue ::OptionParser::InvalidOption, ::OptionParser::InvalidArgument
282
295
  $stderr.puts %(asciidoctor: #{$!.message})
283
296
  $stdout.puts opts_parser
284
- return 1
297
+ 1
298
+ ensure
299
+ $VERBOSE = old_verbose
285
300
  end
286
301
 
287
302
  def print_version os = $stdout
288
303
  os.puts %(Asciidoctor #{::Asciidoctor::VERSION} [https://asciidoctor.org])
289
- if ::RUBY_MIN_VERSION_1_9
290
- encoding_info = { 'lc' => 'locale', 'fs' => 'filesystem', 'in' => 'internal', 'ex' => 'external' }.map do |k, v|
291
- %(#{k}:#{v == 'internal' ? (::File.open(__FILE__) {|f| f.getc }).encoding : (::Encoding.find v)})
292
- end
293
- os.puts %(Runtime Environment (#{::RUBY_DESCRIPTION}) (#{encoding_info.join ' '}))
294
- else
295
- os.puts %(Runtime Environment (#{::RUBY_DESCRIPTION}))
304
+ encoding_info = { 'lc' => 'locale', 'fs' => 'filesystem', 'in' => 'internal', 'ex' => 'external' }.map do |k, v|
305
+ %(#{k}:#{v == 'internal' ? (::File.open(__FILE__) {|f| f.getc.encoding }) : (::Encoding.find v)})
296
306
  end
307
+ os.puts %(Runtime Environment (#{::RUBY_DESCRIPTION}) (#{encoding_info.join ' '}))
297
308
  0
298
309
  end
299
310
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'optparse'
2
- require 'asciidoctor/cli/options'
3
- require 'asciidoctor/cli/invoker'
3
+ require_relative 'cli/options'
4
+ require_relative 'cli/invoker'
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+ module Asciidoctor
3
+ class << self
4
+ # Public: Parse the AsciiDoc source input into an Asciidoctor::Document and
5
+ # convert it to the specified backend format.
6
+ #
7
+ # Accepts input as an IO (or StringIO), String or String Array object. If the
8
+ # input is a File, the object is expected to be opened for reading and is not
9
+ # closed afterwards by this method. Information about the file (filename,
10
+ # directory name, etc) gets assigned to attributes on the Document object.
11
+ #
12
+ # If the :to_file option is true, and the input is a File, the output is
13
+ # written to a file adjacent to the input file, having an extension that
14
+ # corresponds to the backend format. Otherwise, if the :to_file option is
15
+ # specified, the file is written to that file. If :to_file is not an absolute
16
+ # path, it is resolved relative to :to_dir, if given, otherwise the
17
+ # Document#base_dir. If the target directory does not exist, it will not be
18
+ # created unless the :mkdirs option is set to true. If the file cannot be
19
+ # written because the target directory does not exist, or because it falls
20
+ # outside of the Document#base_dir in safe mode, an IOError is raised.
21
+ #
22
+ # If the output is going to be written to a file, the header and footer are
23
+ # included unless specified otherwise (writing to a file implies creating a
24
+ # standalone document). Otherwise, the header and footer are not included by
25
+ # default and the converted result is returned.
26
+ #
27
+ # input - the String AsciiDoc source filename
28
+ # options - a String, Array or Hash of options to control processing (default: {})
29
+ # String and Array values are converted into a Hash.
30
+ # See Asciidoctor::Document#initialize for details about options.
31
+ #
32
+ # Returns the Document object if the converted String is written to a
33
+ # file, otherwise the converted String
34
+ def convert input, options = {}
35
+ (options = options.merge).delete :parse
36
+ to_dir = options.delete :to_dir
37
+ mkdirs = options.delete :mkdirs
38
+
39
+ case (to_file = options.delete :to_file)
40
+ when true, nil
41
+ unless (write_to_target = to_dir)
42
+ sibling_path = ::File.absolute_path input.path if ::File === input
43
+ end
44
+ to_file = nil
45
+ when false
46
+ to_file = nil
47
+ when '/dev/null'
48
+ return load input, options
49
+ else
50
+ options[:to_file] = write_to_target = to_file unless (stream_output = to_file.respond_to? :write)
51
+ end
52
+
53
+ unless options.key? :standalone
54
+ if sibling_path || write_to_target
55
+ options[:standalone] = options.fetch :header_footer, true
56
+ elsif options.key? :header_footer
57
+ options[:standalone] = options[:header_footer]
58
+ end
59
+ end
60
+
61
+ # NOTE outfile may be controlled by document attributes, so resolve outfile after loading
62
+ if sibling_path
63
+ options[:to_dir] = outdir = ::File.dirname sibling_path
64
+ elsif write_to_target
65
+ if to_dir
66
+ if to_file
67
+ options[:to_dir] = ::File.dirname ::File.expand_path to_file, to_dir
68
+ else
69
+ options[:to_dir] = ::File.expand_path to_dir
70
+ end
71
+ elsif to_file
72
+ options[:to_dir] = ::File.dirname ::File.expand_path to_file
73
+ end
74
+ end
75
+
76
+ # NOTE :to_dir is always set when outputting to a file
77
+ # NOTE :to_file option only passed if assigned an explicit path
78
+ doc = load input, options
79
+
80
+ if sibling_path # write to file in same directory
81
+ outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
82
+ raise ::IOError, %(input file and output file cannot be the same: #{outfile}) if outfile == sibling_path
83
+ elsif write_to_target # write to explicit file or directory
84
+ working_dir = (options.key? :base_dir) ? (::File.expand_path options[:base_dir]) : ::Dir.pwd
85
+ # QUESTION should the jail be the working_dir or doc.base_dir???
86
+ jail = doc.safe >= SafeMode::SAFE ? working_dir : nil
87
+ if to_dir
88
+ outdir = doc.normalize_system_path(to_dir, working_dir, jail, target_name: 'to_dir', recover: false)
89
+ if to_file
90
+ outfile = doc.normalize_system_path(to_file, outdir, nil, target_name: 'to_dir', recover: false)
91
+ # reestablish outdir as the final target directory (in the case to_file had directory segments)
92
+ outdir = ::File.dirname outfile
93
+ else
94
+ outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
95
+ end
96
+ elsif to_file
97
+ outfile = doc.normalize_system_path(to_file, working_dir, jail, target_name: 'to_dir', recover: false)
98
+ # establish outdir as the final target directory (in the case to_file had directory segments)
99
+ outdir = ::File.dirname outfile
100
+ end
101
+
102
+ if ::File === input && outfile == (::File.absolute_path input.path)
103
+ raise ::IOError, %(input file and output file cannot be the same: #{outfile})
104
+ end
105
+
106
+ if mkdirs
107
+ Helpers.mkdir_p outdir
108
+ else
109
+ # NOTE we intentionally refer to the directory as it was passed to the API
110
+ raise ::IOError, %(target directory does not exist: #{to_dir} (hint: set :mkdirs option)) unless ::File.directory? outdir
111
+ end
112
+ else # write to stream
113
+ outfile = to_file
114
+ outdir = nil
115
+ end
116
+
117
+ if outfile && !stream_output
118
+ output = doc.convert 'outfile' => outfile, 'outdir' => outdir
119
+ else
120
+ output = doc.convert
121
+ end
122
+
123
+ if outfile
124
+ doc.write output, outfile
125
+
126
+ # NOTE document cannot control this behavior if safe >= SafeMode::SERVER
127
+ # NOTE skip if stylesdir is a URI
128
+ if !stream_output && doc.safe < SafeMode::SECURE && (doc.attr? 'linkcss') && (doc.attr? 'copycss') &&
129
+ (doc.basebackend? 'html') && !((stylesdir = (doc.attr 'stylesdir')) && (Helpers.uriish? stylesdir))
130
+ if (stylesheet = doc.attr 'stylesheet')
131
+ if DEFAULT_STYLESHEET_KEYS.include? stylesheet
132
+ copy_asciidoctor_stylesheet = true
133
+ elsif !(Helpers.uriish? stylesheet)
134
+ copy_user_stylesheet = true
135
+ end
136
+ end
137
+ copy_syntax_hl_stylesheet = (syntax_hl = doc.syntax_highlighter) && (syntax_hl.write_stylesheet? doc)
138
+ if copy_asciidoctor_stylesheet || copy_user_stylesheet || copy_syntax_hl_stylesheet
139
+ stylesoutdir = doc.normalize_system_path(stylesdir, outdir, doc.safe >= SafeMode::SAFE ? outdir : nil)
140
+ if mkdirs
141
+ Helpers.mkdir_p stylesoutdir
142
+ else
143
+ raise ::IOError, %(target stylesheet directory does not exist: #{stylesoutdir} (hint: set :mkdirs option)) unless ::File.directory? stylesoutdir
144
+ end
145
+
146
+ if copy_asciidoctor_stylesheet
147
+ Stylesheets.instance.write_primary_stylesheet stylesoutdir
148
+ # FIXME should Stylesheets also handle the user stylesheet?
149
+ elsif copy_user_stylesheet
150
+ if (stylesheet_src = doc.attr 'copycss') == '' || stylesheet_src == true
151
+ stylesheet_src = doc.normalize_system_path stylesheet
152
+ else
153
+ # NOTE in this case, copycss is a source location (but cannot be a URI)
154
+ stylesheet_src = doc.normalize_system_path stylesheet_src.to_s
155
+ end
156
+ stylesheet_dest = doc.normalize_system_path stylesheet, stylesoutdir, (doc.safe >= SafeMode::SAFE ? outdir : nil)
157
+ # NOTE don't warn if src can't be read and dest already exists (see #2323)
158
+ if stylesheet_src != stylesheet_dest && (stylesheet_data = doc.read_asset stylesheet_src,
159
+ warn_on_failure: !(::File.file? stylesheet_dest), label: 'stylesheet')
160
+ if (stylesheet_outdir = ::File.dirname stylesheet_dest) != stylesoutdir && !(::File.directory? stylesheet_outdir)
161
+ if mkdirs
162
+ Helpers.mkdir_p stylesheet_outdir
163
+ else
164
+ raise ::IOError, %(target stylesheet directory does not exist: #{stylesheet_outdir} (hint: set :mkdirs option))
165
+ end
166
+ end
167
+ ::File.write stylesheet_dest, stylesheet_data, mode: FILE_WRITE_MODE
168
+ end
169
+ end
170
+ syntax_hl.write_stylesheet doc, stylesoutdir if copy_syntax_hl_stylesheet
171
+ end
172
+ end
173
+ doc
174
+ else
175
+ output
176
+ end
177
+ end
178
+
179
+ # Public: Parse the contents of the AsciiDoc source file into an
180
+ # Asciidoctor::Document and convert it to the specified backend format.
181
+ #
182
+ # input - the String AsciiDoc source filename
183
+ # options - a String, Array or Hash of options to control processing (default: {})
184
+ # String and Array values are converted into a Hash.
185
+ # See Asciidoctor::Document#initialize for details about options.
186
+ #
187
+ # Returns the Document object if the converted String is written to a
188
+ # file, otherwise the converted String
189
+ def convert_file filename, options = {}
190
+ ::File.open(filename, FILE_READ_MODE) {|file| convert file, options }
191
+ end
192
+
193
+ # Deprecated: Use {Asciidoctor.convert} instead.
194
+ alias render convert
195
+
196
+ # Deprecated: Use {Asciidoctor.convert_file} instead.
197
+ alias render_file convert_file
198
+ end
199
+ end