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,309 +1,270 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
- # A {Converter} implementation that uses templates composed in template
4
- # languages supported by {https://github.com/rtomayko/tilt Tilt} to convert
5
- # {AbstractNode} objects from a parsed AsciiDoc document tree to the backend
6
- # format.
7
- #
8
- # The converter scans the specified directories for template files that are
9
- # supported by Tilt. If an engine name (e.g., "slim") is specified in the
10
- # options Hash passed to the constructor, the scan is restricted to template
11
- # files that have a matching extension (e.g., ".slim"). The scanner trims any
12
- # extensions from the basename of the file and uses the resulting name as the
13
- # key under which to store the template. When the {Converter#convert} method
14
- # is invoked, the transform argument is used to select the template from this
15
- # table and use it to convert the node.
16
- #
17
- # For example, the template file "path/to/templates/paragraph.html.slim" will
18
- # be registered as the "paragraph" transform. The template is then used to
19
- # convert a paragraph {Block} object from the parsed AsciiDoc tree to an HTML
20
- # backend format (e.g., "html5").
21
- #
22
- # As an optimization, scan results and templates are cached for the lifetime
23
- # of the Ruby process. If the {https://rubygems.org/gems/concurrent-ruby
24
- # concurrent-ruby} gem is installed, these caches are guaranteed to be thread
25
- # safe. If this gem is not present, there is no such guarantee and a warning
26
- # will be issued.
27
- class Converter::TemplateConverter < Converter::Base
28
- DEFAULT_ENGINE_OPTIONS = {
29
- :erb => { :trim => '<' },
30
- # TODO line 466 of haml/compiler.rb sorts the attributes; file an issue to make this configurable
31
- # NOTE AsciiDoc syntax expects HTML/XML output to use double quotes around attribute values
32
- :haml => { :format => :xhtml, :attr_wrapper => '"', :escape_attrs => false, :ugly => true },
33
- :slim => { :disable_escape => true, :sort_attrs => false, :pretty => false }
34
- }
3
+ # A {Converter} implementation that uses templates composed in template
4
+ # languages supported by {https://github.com/rtomayko/tilt Tilt} to convert
5
+ # {AbstractNode} objects from a parsed AsciiDoc document tree to the backend
6
+ # format.
7
+ #
8
+ # The converter scans the specified directories for template files that are
9
+ # supported by Tilt. If an engine name (e.g., "slim") is specified in the
10
+ # options Hash passed to the constructor, the scan is restricted to template
11
+ # files that have a matching extension (e.g., ".slim"). The scanner trims any
12
+ # extensions from the basename of the file and uses the resulting name as the
13
+ # key under which to store the template. When the {Converter#convert} method
14
+ # is invoked, the transform argument is used to select the template from this
15
+ # table and use it to convert the node.
16
+ #
17
+ # For example, the template file "path/to/templates/paragraph.html.slim" will
18
+ # be registered as the "paragraph" transform. The template is then used to
19
+ # convert a paragraph {Block} object from the parsed AsciiDoc tree to an HTML
20
+ # backend format (e.g., "html5").
21
+ #
22
+ # As an optimization, scan results and templates are cached for the lifetime
23
+ # of the Ruby process. If the {https://rubygems.org/gems/concurrent-ruby
24
+ # concurrent-ruby} gem is installed, these caches are guaranteed to be thread
25
+ # safe. If this gem is not present, there is no such guarantee and a warning
26
+ # will be issued.
27
+ class Converter::TemplateConverter < Converter::Base
28
+ DEFAULT_ENGINE_OPTIONS = {
29
+ erb: { trim: 0 },
30
+ # TODO line 466 of haml/compiler.rb sorts the attributes; file an issue to make this configurable
31
+ # NOTE AsciiDoc syntax expects HTML/XML output to use double quotes around attribute values
32
+ haml: { format: :xhtml, attr_wrapper: '"', escape_attrs: false, ugly: true },
33
+ slim: { disable_escape: true, sort_attrs: false, pretty: false },
34
+ }
35
35
 
36
- begin
37
- unless defined? ::Concurrent::Hash
38
- require ::RUBY_MIN_VERSION_1_9 ? 'concurrent/hash' : 'asciidoctor/core_ext/1.8.7/concurrent/hash'
39
- end
40
- @caches = { :scans => ::Concurrent::Hash.new, :templates => ::Concurrent::Hash.new }
41
- rescue ::LoadError
42
- @caches = { :scans => {}, :templates => {} }
43
- end
36
+ begin
37
+ require 'concurrent/map' unless defined? ::Concurrent::Map
38
+ @caches = { scans: ::Concurrent::Map.new, templates: ::Concurrent::Map.new }
39
+ rescue ::LoadError
40
+ @caches = { scans: {}, templates: {} }
41
+ end
44
42
 
45
- def self.caches
46
- @caches
47
- end
43
+ class << self
44
+ attr_reader :caches
48
45
 
49
- def self.clear_caches
50
- @caches[:scans].clear if @caches[:scans]
51
- @caches[:templates].clear if @caches[:templates]
46
+ def clear_caches
47
+ @caches[:scans].clear
48
+ @caches[:templates].clear
52
49
  end
50
+ end
53
51
 
54
- def initialize backend, template_dirs, opts = {}
55
- Helpers.require_library 'tilt' unless defined? ::Tilt
56
- @backend = backend
57
- @templates = {}
58
- @template_dirs = template_dirs
59
- @eruby = opts[:eruby]
60
- @safe = opts[:safe]
61
- @active_engines = {}
62
- @engine = opts[:template_engine]
63
- @engine_options = DEFAULT_ENGINE_OPTIONS.inject({}) do |accum, (engine, default_opts)|
64
- accum[engine] = default_opts.dup
65
- accum
66
- end
67
- if opts[:htmlsyntax] == 'html'
68
- @engine_options[:haml][:format] = :html5
69
- @engine_options[:slim][:format] = :html
70
- end
71
- @engine_options[:slim][:include_dirs] = template_dirs.reverse.map {|dir| ::File.expand_path dir }
72
- if (overrides = opts[:template_engine_options])
73
- overrides.each do |engine, override_opts|
74
- (@engine_options[engine] ||= {}).update override_opts
75
- end
76
- end
77
- case opts[:template_cache]
78
- when true
79
- logger.warn 'gem \'concurrent-ruby\' is not installed. This gem is recommended when using the built-in template cache.' unless defined? ::Concurrent::Hash
80
- @caches = self.class.caches
81
- when ::Hash
82
- @caches = opts[:template_cache]
83
- else
84
- @caches = {} # the empty Hash effectively disables caching
52
+ def initialize backend, template_dirs, opts = {}
53
+ Helpers.require_library 'tilt' unless defined? ::Tilt.new
54
+ @backend = backend
55
+ @templates = {}
56
+ @template_dirs = template_dirs
57
+ @eruby = opts[:eruby]
58
+ @safe = opts[:safe]
59
+ @active_engines = {}
60
+ @engine = opts[:template_engine]
61
+ @engine_options = {}.tap {|accum| DEFAULT_ENGINE_OPTIONS.each {|engine, engine_opts| accum[engine] = engine_opts.merge } }
62
+ if opts[:htmlsyntax] == 'html' # if not set, assume xml since this converter is also used for DocBook (which doesn't specify htmlsyntax)
63
+ @engine_options[:haml][:format] = :html5
64
+ @engine_options[:slim][:format] = :html
65
+ end
66
+ @engine_options[:slim][:include_dirs] = template_dirs.reverse.map {|dir| ::File.expand_path dir }
67
+ if (overrides = opts[:template_engine_options])
68
+ overrides.each do |engine, override_opts|
69
+ (@engine_options[engine] ||= {}).update override_opts
85
70
  end
86
- scan
87
- #create_handlers
88
71
  end
72
+ case opts[:template_cache]
73
+ when true
74
+ logger.warn 'optional gem \'concurrent-ruby\' is not available. This gem is recommended when using the default template cache.' unless defined? ::Concurrent::Map
75
+ @caches = self.class.caches
76
+ when ::Hash
77
+ @caches = opts[:template_cache]
78
+ else
79
+ @caches = {} # the empty Hash effectively disables caching
80
+ end
81
+ scan
82
+ end
89
83
 
90
- =begin
91
- # Public: Called when this converter is added to a composite converter.
92
- def composed parent
93
- # TODO set the backend info determined during the scan
84
+ # Public: Convert an {AbstractNode} to the backend format using the named template.
85
+ #
86
+ # Looks for a template that matches the value of the template name or, if the template name is not specified, the
87
+ # value of the {AbstractNode#node_name} property.
88
+ #
89
+ # node - the AbstractNode to convert
90
+ # template_name - the String name of the template to use, or the value of
91
+ # the node_name property on the node if a template name is
92
+ # not specified. (optional, default: nil)
93
+ # opts - an optional Hash that is passed as local variables to the
94
+ # template. (optional, default: nil)
95
+ #
96
+ # Returns the [String] result from rendering the template
97
+ def convert node, template_name = nil, opts = nil
98
+ unless (template = @templates[template_name ||= node.node_name])
99
+ raise %(Could not find a custom template to handle transform: #{template_name})
94
100
  end
95
- =end
96
101
 
97
- # Internal: Scans the template directories specified in the constructor for Tilt-supported
98
- # templates, loads the templates and stores the in a Hash that is accessible via the
99
- # {TemplateConverter#templates} method.
100
- #
101
- # Returns nothing
102
- def scan
103
- path_resolver = PathResolver.new
104
- backend = @backend
105
- engine = @engine
106
- @template_dirs.each do |template_dir|
107
- # FIXME need to think about safe mode restrictions here
108
- next unless ::File.directory?(template_dir = (path_resolver.system_path template_dir))
102
+ # Slim doesn't include helpers in the template's execution scope (like HAML), so do it ourselves
103
+ node.extend ::Slim::Helpers if (defined? ::Slim::Helpers) && (::Slim::Template === template)
109
104
 
110
- if engine
111
- file_pattern = %(*.#{engine})
112
- # example: templates/haml
113
- if ::File.directory?(engine_dir = %(#{template_dir}/#{engine}))
114
- template_dir = engine_dir
115
- end
116
- else
117
- # NOTE last matching template wins for template name if no engine is given
118
- file_pattern = '*'
119
- end
105
+ # NOTE opts become locals in the template
106
+ if template_name == 'document'
107
+ (template.render node, opts).strip
108
+ else
109
+ (template.render node, opts).rstrip
110
+ end
111
+ end
120
112
 
121
- # example: templates/html5 (engine not set) or templates/haml/html5 (engine set)
122
- if ::File.directory?(backend_dir = %(#{template_dir}/#{backend}))
123
- template_dir = backend_dir
124
- end
113
+ # Public: Checks whether there is a Tilt template registered with the specified name.
114
+ #
115
+ # name - the String template name
116
+ #
117
+ # Returns a [Boolean] that indicates whether a Tilt template is registered for the
118
+ # specified template name.
119
+ def handles? name
120
+ @templates.key? name
121
+ end
125
122
 
126
- pattern = %(#{template_dir}/#{file_pattern})
123
+ # Public: Retrieves the templates that this converter manages.
124
+ #
125
+ # Returns a [Hash] of Tilt template objects keyed by template name.
126
+ def templates
127
+ @templates.merge
128
+ end
127
129
 
128
- if (scan_cache = @caches[:scans])
129
- template_cache = @caches[:templates]
130
- unless (templates = scan_cache[pattern])
131
- templates = (scan_cache[pattern] = (scan_dir template_dir, pattern, template_cache))
132
- end
133
- templates.each do |name, template|
134
- @templates[name] = template_cache[template.file] = template
135
- end
136
- else
137
- @templates.update scan_dir(template_dir, pattern, @caches[:templates])
138
- end
139
- nil
140
- end
130
+ # Public: Registers a Tilt template with this converter.
131
+ #
132
+ # name - the String template name
133
+ # template - the Tilt template object to register
134
+ #
135
+ # Returns the Tilt template object
136
+ def register name, template
137
+ if (template_cache = @caches[:templates])
138
+ template_cache[template.file] = template
141
139
  end
140
+ @templates[name] = template
141
+ end
142
142
 
143
- =begin
144
- # Internal: Creates convert methods (e.g., inline_anchor) that delegate to the discovered templates.
145
- #
146
- # Returns nothing
147
- def create_handlers
148
- @templates.each do |name, template|
149
- create_handler name, template
150
- end
151
- nil
152
- end
143
+ private
153
144
 
154
- # Internal: Creates a convert method for the specified name that delegates to the specified template.
155
- #
156
- # Returns nothing
157
- def create_handler name, template
158
- metaclass = class << self; self; end
159
- if name == 'document'
160
- metaclass.send :define_method, name do |node|
161
- (template.render node).strip
145
+ # Internal: Scans the template directories specified in the constructor for Tilt-supported
146
+ # templates, loads the templates and stores the in a Hash that is accessible via the
147
+ # {TemplateConverter#templates} method.
148
+ #
149
+ # Returns nothing
150
+ def scan
151
+ path_resolver = PathResolver.new
152
+ backend = @backend
153
+ engine = @engine
154
+ @template_dirs.each do |template_dir|
155
+ # FIXME need to think about safe mode restrictions here
156
+ # Ruby 2.3 requires the extra brackets around the path_resolver.system_path method call
157
+ next unless ::File.directory?(template_dir = (path_resolver.system_path template_dir))
158
+
159
+ if engine
160
+ file_pattern = %(*.#{engine})
161
+ # example: templates/haml
162
+ if ::File.directory?(engine_dir = %(#{template_dir}/#{engine}))
163
+ template_dir = engine_dir
162
164
  end
163
165
  else
164
- metaclass.send :define_method, name do |node|
165
- (template.render node).rstrip
166
- end
166
+ # NOTE last matching template wins for template name if no engine is given
167
+ file_pattern = '*'
167
168
  end
168
- end
169
- =end
170
169
 
171
- # Public: Convert an {AbstractNode} to the backend format using the named template.
172
- #
173
- # Looks for a template that matches the value of the
174
- # {AbstractNode#node_name} property if a template name is not specified.
175
- #
176
- # node - the AbstractNode to convert
177
- # template_name - the String name of the template to use, or the value of
178
- # the node_name property on the node if a template name is
179
- # not specified. (optional, default: nil)
180
- # opts - an optional Hash that is passed as local variables to the
181
- # template. (optional, default: {})
182
- #
183
- # Returns the [String] result from rendering the template
184
- def convert node, template_name = nil, opts = {}
185
- template_name ||= node.node_name
186
- unless (template = @templates[template_name])
187
- raise %(Could not find a custom template to handle transform: #{template_name})
170
+ # example: templates/html5 (engine not set) or templates/haml/html5 (engine set)
171
+ if ::File.directory?(backend_dir = %(#{template_dir}/#{backend}))
172
+ template_dir = backend_dir
188
173
  end
189
174
 
190
- # Slim doesn't include helpers in the template's execution scope (like HAML), so do it ourselves
191
- node.extend ::Slim::Helpers if (defined? ::Slim::Helpers) && (::Slim::Template === template)
175
+ pattern = %(#{template_dir}/#{file_pattern})
192
176
 
193
- # NOTE opts become locals in the template
194
- if template_name == 'document'
195
- (template.render node, opts).strip
177
+ if (scan_cache = @caches[:scans])
178
+ template_cache = @caches[:templates]
179
+ unless (templates = scan_cache[pattern])
180
+ templates = scan_cache[pattern] = scan_dir template_dir, pattern, template_cache
181
+ end
182
+ templates.each do |name, template|
183
+ @templates[name] = template_cache[template.file] = template
184
+ end
196
185
  else
197
- (template.render node, opts).rstrip
186
+ @templates.update scan_dir(template_dir, pattern, @caches[:templates])
198
187
  end
199
188
  end
189
+ nil
190
+ end
200
191
 
201
- # Public: Checks whether there is a Tilt template registered with the specified name.
202
- #
203
- # name - the String template name
204
- #
205
- # Returns a [Boolean] that indicates whether a Tilt template is registered for the
206
- # specified template name.
207
- def handles? name
208
- @templates.key? name
209
- end
210
-
211
- # Public: Retrieves the templates that this converter manages.
212
- #
213
- # Returns a [Hash] of Tilt template objects keyed by template name.
214
- def templates
215
- @templates.dup
216
- end
217
-
218
- # Public: Registers a Tilt template with this converter.
219
- #
220
- # name - the String template name
221
- # template - the Tilt template object to register
222
- #
223
- # Returns the Tilt template object
224
- def register name, template
225
- @templates[name] = if (template_cache = @caches[:templates])
226
- template_cache[template.file] = template
227
- else
228
- template
192
+ # Internal: Scan the specified directory for template files matching pattern and instantiate
193
+ # a Tilt template for each matched file.
194
+ #
195
+ # Returns the scan result as a [Hash]
196
+ def scan_dir template_dir, pattern, template_cache = nil
197
+ result, helpers = {}, nil
198
+ # Grab the files in the top level of the directory (do not recurse)
199
+ ::Dir.glob(pattern).keep_if {|match| ::File.file? match }.each do |file|
200
+ if (basename = ::File.basename file) == 'helpers.rb'
201
+ helpers = file
202
+ next
203
+ elsif (path_segments = basename.split '.').size < 2
204
+ next
229
205
  end
230
- #create_handler name, template
231
- end
232
-
233
- # Internal: Scan the specified directory for template files matching pattern and instantiate
234
- # a Tilt template for each matched file.
235
- #
236
- # Returns the scan result as a [Hash]
237
- def scan_dir template_dir, pattern, template_cache = nil
238
- result, helpers = {}, nil
239
- # Grab the files in the top level of the directory (do not recurse)
240
- ::Dir.glob(pattern).select {|match| ::File.file? match }.each do |file|
241
- if (basename = ::File.basename file) == 'helpers.rb'
242
- helpers = file
243
- next
244
- elsif (path_segments = basename.split '.').size < 2
245
- next
246
- end
247
- if (name = path_segments[0]) == 'block_ruler'
248
- name = 'thematic_break'
249
- elsif name.start_with? 'block_'
250
- name = name.slice 6, name.length
251
- end
252
- unless template_cache && (template = template_cache[file])
253
- template_class, extra_engine_options, extsym = ::Tilt, {}, path_segments[-1].to_sym
254
- case extsym
255
- when :slim
256
- unless @active_engines[extsym]
257
- # NOTE slim doesn't get automatically loaded by Tilt
258
- Helpers.require_library 'slim' unless defined? ::Slim
259
- ::Slim::Engine.define_options :asciidoc => {}
260
- # align safe mode of AsciiDoc embedded in Slim template with safe mode of current document
261
- # NOTE safe mode won't get updated if using template cache and changing safe mode
262
- (@engine_options[extsym][:asciidoc] ||= {})[:safe] ||= @safe if @safe && ::Slim::VERSION >= '3.0'
263
- # load include plugin when using Slim >= 2.1
264
- require 'slim/include' unless (defined? ::Slim::Include) || ::Slim::VERSION < '2.1'
265
- @active_engines[extsym] = true
266
- end
267
- when :haml
268
- unless @active_engines[extsym]
269
- Helpers.require_library 'haml' unless defined? ::Haml
270
- # NOTE Haml 5 dropped support for pretty printing
271
- @engine_options[extsym].delete :ugly if defined? ::Haml::TempleEngine
272
- @active_engines[extsym] = true
273
- end
274
- when :erb
275
- template_class, extra_engine_options = (@active_engines[extsym] ||= (load_eruby @eruby))
276
- when :rb
277
- next
278
- else
279
- next unless ::Tilt.registered? extsym.to_s
206
+ if (name = path_segments[0]) == 'block_ruler'
207
+ name = 'thematic_break'
208
+ elsif name.start_with? 'block_'
209
+ name = name.slice 6, name.length
210
+ end
211
+ unless template_cache && (template = template_cache[file])
212
+ template_class, extra_engine_options, extsym = ::Tilt, {}, path_segments[-1].to_sym
213
+ case extsym
214
+ when :slim
215
+ unless @active_engines[extsym]
216
+ # NOTE slim doesn't get automatically loaded by Tilt
217
+ Helpers.require_library 'slim' unless defined? ::Slim::Engine
218
+ require 'slim/include' unless defined? ::Slim::Include
219
+ ::Slim::Engine.define_options asciidoc: {}
220
+ # align safe mode of AsciiDoc embedded in Slim template with safe mode of current document
221
+ # NOTE safe mode won't get updated if using template cache and changing safe mode
222
+ (@engine_options[extsym][:asciidoc] ||= {})[:safe] ||= @safe if @safe
223
+ @active_engines[extsym] = true
224
+ end
225
+ when :haml
226
+ unless @active_engines[extsym]
227
+ Helpers.require_library 'haml' unless defined? ::Haml::Engine
228
+ # NOTE Haml 5 dropped support for pretty printing
229
+ @engine_options[extsym].delete :ugly if defined? ::Haml::TempleEngine
230
+ @active_engines[extsym] = true
280
231
  end
281
- template = template_class.new file, 1, (@engine_options[extsym] ||= {}).merge(extra_engine_options)
232
+ when :erb
233
+ template_class, extra_engine_options = (@active_engines[extsym] ||= (load_eruby @eruby))
234
+ when :rb
235
+ next
236
+ else
237
+ next unless ::Tilt.registered? extsym.to_s
282
238
  end
283
- result[name] = template
239
+ template = template_class.new file, 1, (@engine_options[extsym] ||= {}).merge(extra_engine_options)
284
240
  end
285
- if helpers || ::File.file?(helpers = %(#{template_dir}/helpers.rb))
286
- require helpers
287
- end
288
- result
241
+ result[name] = template
242
+ end
243
+ if helpers || ::File.file?(helpers = %(#{template_dir}/helpers.rb))
244
+ require helpers
289
245
  end
246
+ result
247
+ end
290
248
 
291
- # Internal: Load the eRuby implementation
292
- #
293
- # name - the String name of the eRuby implementation
294
- #
295
- # Returns an [Array] containing the Tilt template Class for the eRuby implementation
296
- # and a Hash of additional options to pass to the initializer
297
- def load_eruby name
298
- if !name || name == 'erb'
299
- require 'erb' unless defined? ::ERB
300
- [::Tilt::ERBTemplate, {}]
301
- elsif name == 'erubis'
302
- Helpers.require_library 'erubis' unless defined? ::Erubis::FastEruby
303
- [::Tilt::ErubisTemplate, { :engine_class => ::Erubis::FastEruby }]
304
- else
305
- raise ::ArgumentError, %(Unknown ERB implementation: #{name})
306
- end
249
+ # Internal: Load the eRuby implementation
250
+ #
251
+ # name - the String name of the eRuby implementation
252
+ #
253
+ # Returns an [Array] containing the Tilt template Class for the eRuby implementation
254
+ # and a Hash of additional options to pass to the initializer
255
+ def load_eruby name
256
+ if !name || name == 'erb'
257
+ require 'erb' unless defined? ::ERB.version
258
+ [::Tilt::ERBTemplate, {}]
259
+ elsif name == 'erubi'
260
+ Helpers.require_library 'erubi' unless defined? ::Erubis::Engine
261
+ [::Tilt::ErubiTemplate, {}]
262
+ elsif name == 'erubis'
263
+ Helpers.require_library 'erubis' unless defined? ::Erubis::FastEruby
264
+ [::Tilt::ErubisTemplate, engine_class: ::Erubis::FastEruby]
265
+ else
266
+ raise ::ArgumentError, %(Unknown ERB implementation: #{name})
307
267
  end
308
268
  end
309
269
  end
270
+ end