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,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
3
  # Public: An abstract base class that provides state and methods for managing a
4
4
  # node of AsciiDoc content. The state and methods on this class are common to
@@ -16,30 +16,26 @@ class AbstractNode
16
16
  # Public: Get the Asciidoctor::Document to which this node belongs
17
17
  attr_reader :document
18
18
 
19
- # Public: Get/Set the id of this node
19
+ # Public: Get/Set the String id of this node
20
20
  attr_accessor :id
21
21
 
22
22
  # Public: Get the String name of this node
23
23
  attr_reader :node_name
24
24
 
25
- # Public: Get the element which is the parent of this node
25
+ # Public: Get the AbstractBlock parent element of this node
26
26
  attr_reader :parent
27
27
 
28
28
  def initialize parent, context, opts = {}
29
+ # document is a special case, should refer to itself
29
30
  if context == :document
30
- # document is a special case, should refer to itself
31
- @document, @parent = self, nil
32
- else
33
- if parent
34
- @document, @parent = parent.document, parent
35
- else
36
- @document = @parent = nil
37
- end
31
+ @document = self
32
+ elsif parent
33
+ @document = (@parent = parent).document
38
34
  end
39
35
  @node_name = (@context = context).to_s
40
- # QUESTION are we correct in duplicating the attributes (seems to be just as fast)
41
- @attributes = (opts.key? :attributes) ? opts[:attributes].dup : {}
42
- @passthroughs = {}
36
+ # NOTE the value of the :attributes option may be nil on an Inline node
37
+ @attributes = (attrs = opts[:attributes]) ? attrs.merge : {}
38
+ @passthroughs = []
43
39
  end
44
40
 
45
41
  # Public: Returns whether this {AbstractNode} is an instance of {Block}
@@ -70,56 +66,48 @@ class AbstractNode
70
66
  #
71
67
  # parent - The Block to set as the parent of this Block
72
68
  #
73
- # Returns the new parent Block associated with this Block
69
+ # Returns the the specified Block parent
74
70
  def parent= parent
75
71
  @parent, @document = parent, parent.document
76
72
  end
77
73
 
78
- # Public: Get the value of the specified attribute
79
- #
80
- # Get the value for the specified attribute. First look in the attributes on
81
- # this node and return the value of the attribute if found. Otherwise, if
82
- # this node is a child of the Document node, look in the attributes of the
83
- # Document node and return the value of the attribute if found. Otherwise,
84
- # return the default value, which defaults to nil.
85
- #
86
- # name - the String or Symbol name of the attribute to lookup
87
- # default_val - the Object value to return if the attribute is not found (default: nil)
88
- # inherit - a Boolean indicating whether to check for the attribute on the
89
- # AsciiDoctor::Document if not found on this node (default: false)
90
- #
91
- # return the value of the attribute or the default value if the attribute
92
- # is not found in the attributes of this node or the document node
93
- def attr name, default_val = nil, inherit = true
94
- name = name.to_s
95
- # NOTE if @parent is set, it means @document is also set
96
- @attributes[name] || (inherit && @parent ? @document.attributes[name] || default_val : default_val)
97
- end
98
-
99
- # Public: Check if the attribute is defined, optionally performing a
100
- # comparison of its value if expected is not nil
101
- #
102
- # Check if the attribute is defined. First look in the attributes on this
103
- # node. If not found, and this node is a child of the Document node, look in
104
- # the attributes of the Document node. If the attribute is found and a
105
- # comparison value is specified (not nil), return whether the two values match.
106
- # Otherwise, return whether the attribute was found.
107
- #
108
- # name - the String or Symbol name of the attribute to lookup
109
- # expect_val - the expected Object value of the attribute (default: nil)
110
- # inherit - a Boolean indicating whether to check for the attribute on the
111
- # AsciiDoctor::Document if not found on this node (default: false)
112
- #
113
- # return a Boolean indicating whether the attribute exists and, if a
114
- # comparison value is specified, whether the value of the attribute matches
115
- # the comparison value
116
- def attr? name, expect_val = nil, inherit = true
117
- name = name.to_s
118
- # NOTE if @parent is set, it means @document is also set
119
- if expect_val.nil?
120
- (@attributes.key? name) || (inherit && @parent && (@document.attributes.key? name))
74
+ # Public: Get the value of the specified attribute. If the attribute is not found on this node, fallback_name is set,
75
+ # and this node is not the Document node, get the value of the specified attribute from the Document node.
76
+ #
77
+ # Look for the specified attribute in the attributes on this node and return the value of the attribute, if found.
78
+ # Otherwise, if fallback_name is set (default: same as name) and this node is not the Document node, look for that
79
+ # attribute on the Document node and return its value, if found. Otherwise, return the default value (default: nil).
80
+ #
81
+ # name - The String or Symbol name of the attribute to resolve.
82
+ # default_value - The Object value to return if the attribute is not found (default: nil).
83
+ # fallback_name - The String or Symbol of the attribute to resolve on the Document if the attribute is not found on
84
+ # this node (default: same as name).
85
+ #
86
+ # Returns the [Object] value (typically a String) of the attribute or default_value if the attribute is not found.
87
+ def attr name, default_value = nil, fallback_name = nil
88
+ @attributes[name.to_s] || (fallback_name && @parent && @document.attributes[(fallback_name == true ? name : fallback_name).to_s] || default_value)
89
+ end
90
+
91
+ # Public: Check if the specified attribute is defined using the same logic as {#attr}, optionally performing a
92
+ # comparison with the expected value if specified.
93
+ #
94
+ # Look for the specified attribute in the attributes on this node. If not found, fallback_name is specified (default:
95
+ # same as name), and this node is not the Document node, look for that attribute on the Document node. In either case,
96
+ # if the attribute is found, and the comparison value is truthy, return whether the two values match. Otherwise,
97
+ # return whether the attribute was found.
98
+ #
99
+ # name - The String or Symbol name of the attribute to resolve.
100
+ # expected_value - The expected Object value of the attribute (default: nil).
101
+ # fallback_name - The String or Symbol of the attribute to resolve on the Document if the attribute is not found on
102
+ # this node (default: same as name).
103
+ #
104
+ # Returns a [Boolean] indicating whether the attribute exists and, if a truthy comparison value is specified, whether
105
+ # the value of the attribute matches the comparison value.
106
+ def attr? name, expected_value = nil, fallback_name = nil
107
+ if expected_value
108
+ expected_value == (@attributes[name.to_s] || (fallback_name && @parent ? @document.attributes[(fallback_name == true ? name : fallback_name).to_s] : nil))
121
109
  else
122
- expect_val == (@attributes[name] || (inherit && @parent ? @document.attributes[name] : nil))
110
+ (@attributes.key? name.to_s) || (fallback_name && @parent ? (@document.attributes.key? (fallback_name == true ? name : fallback_name).to_s) : false)
123
111
  end
124
112
  end
125
113
 
@@ -153,34 +141,32 @@ class AbstractNode
153
141
  # enabled on the current node.
154
142
  #
155
143
  # Check if the option is enabled. This method simply checks to see if the
156
- # %name%-option attribute is defined on the current node.
144
+ # <name>-option attribute is defined on the current node.
157
145
  #
158
146
  # name - the String or Symbol name of the option
159
147
  #
160
148
  # return a Boolean indicating whether the option has been specified
161
- def option?(name)
162
- @attributes.key? %(#{name}-option)
149
+ def option? name
150
+ @attributes[%(#{name}-option)] ? true : false
163
151
  end
164
152
 
165
153
  # Public: Set the specified option on this node.
166
154
  #
167
- # This method sets the specified option on this node if not already set.
168
- # It will add the name to the options attribute and set the <name>-option
169
- # attribute.
155
+ # This method sets the specified option on this node by setting the <name>-option attribute.
170
156
  #
171
157
  # name - the String name of the option
172
158
  #
173
- # returns truthy if the option was set or falsey if the option was already set
174
- def set_option(name)
175
- if (attrs = @attributes)['options']
176
- unless attrs[key = %(#{name}-option)]
177
- attrs['options'] += %(,#{name})
178
- attrs[key] = ''
179
- end
180
- else
181
- attrs['options'] = name
182
- attrs[%(#{name}-option)] = ''
183
- end
159
+ # Returns nothing
160
+ def set_option name
161
+ @attributes[%(#{name}-option)] = ''
162
+ nil
163
+ end
164
+
165
+ # Public: Retrieve the Set of option names that are enabled on this node
166
+ #
167
+ # Returns a [Set] of option names
168
+ def enabled_options
169
+ ::Set.new.tap {|accum| @attributes.each_key {|k| accum << (k.slice 0, k.length - 7) if k.to_s.end_with? '-option' } }
184
170
  end
185
171
 
186
172
  # Public: Update the attributes of this node with the new values in
@@ -189,67 +175,82 @@ class AbstractNode
189
175
  # If an attribute already exists with the same key, it's value will
190
176
  # be overwritten.
191
177
  #
192
- # attributes - A Hash of attributes to assign to this node.
178
+ # new_attributes - A Hash of additional attributes to assign to this node.
193
179
  #
194
- # Returns nothing
195
- def update_attributes(attributes)
196
- @attributes.update(attributes)
197
- nil
180
+ # Returns the updated attributes [Hash] on this node.
181
+ def update_attributes new_attributes
182
+ @attributes.update new_attributes
198
183
  end
199
184
 
200
- # Public: A convenience method that returns the value of the role attribute
185
+ # Public: Retrieves the space-separated String role for this node.
186
+ #
187
+ # Returns the role as a space-separated [String].
201
188
  def role
202
- @attributes['role'] || @document.attributes['role']
189
+ @attributes['role']
203
190
  end
204
191
 
205
- # Public: A convenience method that returns the role names as an Array
192
+ # Public: Retrieves the String role names for this node as an Array.
206
193
  #
207
- # Returns the role names as an Array or an empty Array if the role attribute is absent.
194
+ # Returns the role names as a String [Array], which is empty if the role attribute is absent on this node.
208
195
  def roles
209
- (val = @attributes['role'] || @document.attributes['role']).nil_or_empty? ? [] : val.split
196
+ (val = @attributes['role']) ? val.split : []
210
197
  end
211
198
 
212
- # Public: A convenience method that checks if the role attribute is specified
213
- def role? expect_val = nil
214
- if expect_val
215
- expect_val == (@attributes['role'] || @document.attributes['role'])
216
- else
217
- @attributes.key?('role') || @document.attributes.key?('role')
218
- end
199
+ # Public: Checks if the role attribute is set on this node and, if an expected value is given, whether the
200
+ # space-separated role matches that value.
201
+ #
202
+ # expected_value - The expected String value of the role (optional, default: nil)
203
+ #
204
+ # Returns a [Boolean] indicating whether the role attribute is set on this node and, if an expected value is given,
205
+ # whether the space-separated role matches that value.
206
+ def role? expected_value = nil
207
+ expected_value ? expected_value == @attributes['role'] : (@attributes.key? 'role')
219
208
  end
220
209
 
221
- # Public: A convenience method that checks if the specified role is present
222
- # in the list of roles on this node
223
- def has_role?(name)
210
+ # Public: Checks if the specified role is present in the list of roles for this node.
211
+ #
212
+ # name - The String name of the role to find.
213
+ #
214
+ # Returns a [Boolean] indicating whether this node has the specified role.
215
+ def has_role? name
224
216
  # NOTE center + include? is faster than split + include?
225
- (val = @attributes['role'] || @document.attributes['role']) ? %( #{val} ).include?(%( #{name} )) : false
217
+ (val = @attributes['role']) ? (%( #{val} ).include? %( #{name} )) : false
226
218
  end
227
219
 
228
- # Public: A convenience method that adds the given role directly to this node
220
+ # Public: Sets the value of the role attribute on this node.
229
221
  #
230
- # Returns a Boolean indicating whether the role was added.
231
- def add_role(name)
232
- if (val = @attributes['role']).nil_or_empty?
233
- @attributes['role'] = name
234
- true
235
- # NOTE center + include? is faster than split + include?
236
- elsif %( #{val} ).include?(%( #{name} ))
237
- false
222
+ # names - A single role name, a space-separated String of role names, or an Array of role names
223
+ #
224
+ # Returns the specified String role name or Array of role names
225
+ def role= names
226
+ @attributes['role'] = (::Array === names) ? (names.join ' ') : names
227
+ end
228
+
229
+ # Public: Adds the given role directly to this node.
230
+ #
231
+ # Returns a [Boolean] indicating whether the role was added.
232
+ def add_role name
233
+ if (val = @attributes['role'])
234
+ # NOTE center + include? is faster than split + include?
235
+ if %( #{val} ).include? %( #{name} )
236
+ false
237
+ else
238
+ @attributes['role'] = %(#{val} #{name})
239
+ true
240
+ end
238
241
  else
239
- @attributes['role'] = %(#{val} #{name})
242
+ @attributes['role'] = name
240
243
  true
241
244
  end
242
245
  end
243
246
 
244
- # Public: A convenience method that removes the given role directly from this node
247
+ # Public: Removes the given role directly from this node.
245
248
  #
246
- # Returns a Boolean indicating whether the role was removed.
247
- def remove_role(name)
248
- if (val = @attributes['role']).nil_or_empty?
249
- false
250
- elsif (val = val.split).delete name
249
+ # Returns a [Boolean] indicating whether the role was removed.
250
+ def remove_role name
251
+ if (val = @attributes['role']) && ((val = val.split).delete name)
251
252
  if val.empty?
252
- @attributes.delete('role')
253
+ @attributes.delete 'role'
253
254
  else
254
255
  @attributes['role'] = val.join ' '
255
256
  end
@@ -273,12 +274,12 @@ class AbstractNode
273
274
  # specified icon name.
274
275
  #
275
276
  # If the 'icon' attribute is set on this block, the name is ignored and the
276
- # value of this attribute is used as the target image path. Otherwise,
277
+ # value of this attribute is used as the target image path. Otherwise,
277
278
  # construct a target image path by concatenating the value of the 'iconsdir'
278
- # attribute, the icon name and the value of the 'icontype' attribute
279
+ # attribute, the icon name, and the value of the 'icontype' attribute
279
280
  # (defaulting to 'png').
280
281
  #
281
- # The target image path is then passed through the #image_uri() method. If
282
+ # The target image path is then passed through the #image_uri() method. If
282
283
  # the 'data-uri' attribute is set on the document, the image will be
283
284
  # safely converted to a data URI.
284
285
  #
@@ -289,10 +290,9 @@ class AbstractNode
289
290
  # Returns A String reference or data URI for an icon image
290
291
  def icon_uri name
291
292
  if attr? 'icon'
292
- if ::File.extname(icon = (attr 'icon')).empty?
293
- # QUESTION should we be adding the extension if the icon is an absolute URI?
294
- icon = %(#{icon}.#{@document.attr 'icontype', 'png'})
295
- end
293
+ icon = attr 'icon'
294
+ # QUESTION should we be adding the extension if the icon is an absolute URI?
295
+ icon = %(#{icon}.#{@document.attr 'icontype', 'png'}) unless Helpers.extname? icon
296
296
  else
297
297
  icon = %(#{name}.#{@document.attr 'icontype', 'png'})
298
298
  end
@@ -320,14 +320,10 @@ class AbstractNode
320
320
  # Returns A String reference or data URI for the target image
321
321
  def image_uri(target_image, asset_dir_key = 'imagesdir')
322
322
  if (doc = @document).safe < SafeMode::SECURE && (doc.attr? 'data-uri')
323
- if ((Helpers.uriish? target_image) && (target_image = uri_encode_spaces target_image)) ||
323
+ if ((Helpers.uriish? target_image) && (target_image = Helpers.encode_spaces_in_uri target_image)) ||
324
324
  (asset_dir_key && (images_base = doc.attr asset_dir_key) && (Helpers.uriish? images_base) &&
325
325
  (target_image = normalize_web_path target_image, images_base, false))
326
- if doc.attr? 'allow-uri-read'
327
- generate_data_uri_from_uri target_image, (doc.attr? 'cache-uri')
328
- else
329
- target_image
330
- end
326
+ (doc.attr? 'allow-uri-read') ? (generate_data_uri_from_uri target_image, (doc.attr? 'cache-uri')) : target_image
331
327
  else
332
328
  generate_data_uri target_image, asset_dir_key
333
329
  end
@@ -367,18 +363,21 @@ class AbstractNode
367
363
  #
368
364
  # Returns A String data URI containing the content of the target image
369
365
  def generate_data_uri(target_image, asset_dir_key = nil)
370
- ext = ::File.extname target_image
371
- # QUESTION what if ext is empty?
372
- mimetype = (ext == '.svg' ? 'image/svg+xml' : %(image/#{ext.slice 1, ext.length}))
366
+ if (ext = Helpers.extname target_image, nil)
367
+ mimetype = ext == '.svg' ? 'image/svg+xml' : %(image/#{ext.slice 1, ext.length})
368
+ else
369
+ mimetype = 'application/octet-stream'
370
+ end
371
+
373
372
  if asset_dir_key
374
- image_path = normalize_system_path(target_image, @document.attr(asset_dir_key), nil, :target_name => 'image')
373
+ image_path = normalize_system_path(target_image, @document.attr(asset_dir_key), nil, target_name: 'image')
375
374
  else
376
375
  image_path = normalize_system_path(target_image)
377
376
  end
378
377
 
379
378
  if ::File.readable? image_path
380
379
  # NOTE base64 is autoloaded by reference to ::Base64
381
- %(data:#{mimetype};base64,#{::Base64.strict_encode64 ::IO.binread image_path})
380
+ %(data:#{mimetype};base64,#{::Base64.strict_encode64 ::File.binread image_path})
382
381
  else
383
382
  logger.warn %(image to embed not found or not readable: #{image_path})
384
383
  %(data:#{mimetype};base64,)
@@ -404,17 +403,13 @@ class AbstractNode
404
403
  # caching requires the open-uri-cached gem to be installed
405
404
  # processing will be automatically aborted if these libraries can't be opened
406
405
  Helpers.require_library 'open-uri/cached', 'open-uri-cached'
407
- elsif !::RUBY_ENGINE_OPAL
406
+ elsif !RUBY_ENGINE_OPAL
408
407
  # autoload open-uri
409
408
  ::OpenURI
410
409
  end
411
410
 
412
411
  begin
413
- mimetype = nil
414
- bindata = open image_uri, 'rb' do |f|
415
- mimetype = f.content_type
416
- f.read
417
- end
412
+ mimetype, bindata = ::OpenURI.open_uri(image_uri, URI_READ_MODE) {|f| [f.content_type, f.read] }
418
413
  # NOTE base64 is autoloaded by reference to ::Base64
419
414
  %(data:#{mimetype};base64,#{::Base64.strict_encode64 bindata})
420
415
  rescue
@@ -432,8 +427,7 @@ class AbstractNode
432
427
  # Delegates to normalize_system_path, with the start path set to the value of
433
428
  # the base_dir instance variable on the Document object.
434
429
  def normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true)
435
- normalize_system_path(asset_ref, @document.base_dir, nil,
436
- :target_name => asset_name, :recover => autocorrect)
430
+ normalize_system_path(asset_ref, @document.base_dir, nil, target_name: asset_name, recover: autocorrect)
437
431
  end
438
432
 
439
433
  # Public: Resolve and normalize a secure path from the target and start paths
@@ -469,8 +463,8 @@ class AbstractNode
469
463
  start = doc.base_dir
470
464
  end
471
465
  else
472
- start = doc.base_dir unless start
473
- jail = doc.base_dir unless jail
466
+ start ||= doc.base_dir
467
+ jail ||= doc.base_dir
474
468
  end
475
469
  doc.path_resolver.system_path target, start, jail, opts
476
470
  end
@@ -486,7 +480,7 @@ class AbstractNode
486
480
  # Returns the resolved [String] path
487
481
  def normalize_web_path(target, start = nil, preserve_uri_target = true)
488
482
  if preserve_uri_target && (Helpers.uriish? target)
489
- uri_encode_spaces target
483
+ Helpers.encode_spaces_in_uri target
490
484
  else
491
485
  @document.path_resolver.web_path target, start
492
486
  end
@@ -507,15 +501,10 @@ class AbstractNode
507
501
  # if the file does not exist.
508
502
  def read_asset path, opts = {}
509
503
  # remap opts for backwards compatibility
510
- opts = { :warn_on_failure => (opts != false) } unless ::Hash === opts
504
+ opts = { warn_on_failure: (opts != false) } unless ::Hash === opts
511
505
  if ::File.readable? path
512
- if opts[:normalize]
513
- # NOTE Opal does not yet support File#readlines
514
- (Helpers.normalize_lines_array ::File.open(path, 'rb') {|f| f.each_line.to_a }).join LF
515
- else
516
- # QUESTION should we chomp or rstrip content?
517
- ::IO.read path
518
- end
506
+ # QUESTION should we chomp content if normalize is false?
507
+ opts[:normalize] ? ((Helpers.prepare_source_string ::File.read path, mode: FILE_READ_MODE).join LF) : (::File.read path, mode: FILE_READ_MODE)
519
508
  elsif opts[:warn_on_failure]
520
509
  logger.warn %(#{(attr 'docfile') || '<stdin>'}: #{opts[:label] || 'file'} does not exist or cannot be read: #{path})
521
510
  nil
@@ -535,6 +524,7 @@ class AbstractNode
535
524
  # * :normalize a Boolean that indicates whether the data should be normalized (default: false)
536
525
  # * :start the String relative base path to use when resolving the target (default: nil)
537
526
  # * :warn_on_failure a Boolean that indicates whether warnings are issued if the target cannot be read (default: true)
527
+ # * :warn_if_empty a Boolean that indicates whether a warning is issued if contents of target is empty (default: false)
538
528
  # Returns the contents of the resolved target or nil if the resolved target cannot be read
539
529
  # --
540
530
  # TODO refactor other methods in this class to use this method were possible (repurposing if necessary)
@@ -546,37 +536,29 @@ class AbstractNode
546
536
  Helpers.require_library 'open-uri/cached', 'open-uri-cached' if doc.attr? 'cache-uri'
547
537
  begin
548
538
  if opts[:normalize]
549
- # NOTE Opal does not yet support File#readlines
550
- (Helpers.normalize_lines_array ::OpenURI.open_uri(target) {|f| f.each_line.to_a }).join LF
539
+ contents = (Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF
551
540
  else
552
- ::OpenURI.open_uri(target) {|f| f.read }
541
+ contents = ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }
553
542
  end
554
543
  rescue
555
544
  logger.warn %(could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true
556
- return
557
545
  end
558
- else
559
- logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled)) if opts.fetch :warn_on_failure, true
560
- return
546
+ elsif opts.fetch :warn_on_failure, true
547
+ logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled))
561
548
  end
562
549
  else
563
- target = normalize_system_path target, opts[:start], nil, :target_name => (opts[:label] || 'asset')
564
- read_asset target, :normalize => opts[:normalize], :warn_on_failure => (opts.fetch :warn_on_failure, true), :label => opts[:label]
550
+ target = normalize_system_path target, opts[:start], nil, target_name: (opts[:label] || 'asset')
551
+ contents = read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label]
565
552
  end
553
+ logger.warn %(contents of #{opts[:label] || 'asset'} is empty: #{target}) if contents && opts[:warn_if_empty] && contents.empty?
554
+ contents
566
555
  end
567
556
 
568
- # Internal: URI encode spaces in a String
569
- #
570
- # str - the String to encode
571
- #
572
- # Returns the String with all spaces replaced with %20.
573
- def uri_encode_spaces str
574
- (str.include? ' ') ? (str.gsub ' ', '%20') : str
575
- end
576
-
577
- # Public: Check whether the specified String is a URI by
557
+ # Deprecated: Check whether the specified String is a URI by
578
558
  # matching it against the Asciidoctor::UriSniffRx regex.
579
559
  #
560
+ # In use by Asciidoctor PDF
561
+ #
580
562
  # @deprecated Use Helpers.uriish? instead
581
563
  def is_uri? str
582
564
  Helpers.uriish? str