asciidoctor-pdf 1.5.0.alpha.17 → 1.5.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +75 -2
  3. data/NOTICE.adoc +14 -11
  4. data/README.adoc +105 -27
  5. data/asciidoctor-pdf.gemspec +4 -1
  6. data/data/themes/base-theme.yml +4 -0
  7. data/data/themes/default-theme.yml +17 -34
  8. data/data/themes/default-with-fallback-font-theme.yml +22 -0
  9. data/docs/theming-guide.adoc +1057 -867
  10. data/lib/asciidoctor-pdf/asciidoctor_ext/abstract_block.rb +5 -0
  11. data/lib/asciidoctor-pdf/asciidoctor_ext/document.rb +3 -0
  12. data/lib/asciidoctor-pdf/asciidoctor_ext/image.rb +4 -4
  13. data/lib/asciidoctor-pdf/asciidoctor_ext/logging_shim.rb +8 -2
  14. data/lib/asciidoctor-pdf/asciidoctor_ext/section.rb +16 -8
  15. data/lib/asciidoctor-pdf/asciidoctor_ext.rb +3 -1
  16. data/lib/asciidoctor-pdf/converter.rb +758 -499
  17. data/lib/asciidoctor-pdf/core_ext/hash.rb +5 -0
  18. data/lib/asciidoctor-pdf/core_ext/regexp.rb +3 -0
  19. data/lib/asciidoctor-pdf/core_ext.rb +2 -0
  20. data/lib/asciidoctor-pdf/formatted_text/formatter.rb +8 -1
  21. data/lib/asciidoctor-pdf/formatted_text/inline_image_arranger.rb +3 -1
  22. data/lib/asciidoctor-pdf/formatted_text/parser.rb +24 -12
  23. data/lib/asciidoctor-pdf/formatted_text/parser.treetop +1 -1
  24. data/lib/asciidoctor-pdf/formatted_text/text_background_and_border_renderer.rb +45 -0
  25. data/lib/asciidoctor-pdf/formatted_text/transform.rb +44 -21
  26. data/lib/asciidoctor-pdf/formatted_text.rb +1 -0
  27. data/lib/asciidoctor-pdf/index_catalog.rb +9 -3
  28. data/lib/asciidoctor-pdf/measurements.rb +1 -1
  29. data/lib/asciidoctor-pdf/prawn_ext/extensions.rb +37 -21
  30. data/lib/asciidoctor-pdf/prawn_ext/images.rb +18 -7
  31. data/lib/asciidoctor-pdf/roman_numeral.rb +12 -0
  32. data/lib/asciidoctor-pdf/theme_loader.rb +99 -69
  33. data/lib/asciidoctor-pdf/version.rb +1 -1
  34. metadata +45 -5
@@ -19,9 +19,9 @@ class ThemeLoader
19
19
  DefaultThemePath = ::File.expand_path 'default-theme.yml', ThemesDir
20
20
  BaseThemePath = ::File.expand_path 'base-theme.yml', ThemesDir
21
21
 
22
- VariableRx = /\$([a-z0-9_]+)/
23
- LoneVariableRx = /^\$([a-z0-9_]+)$/
24
- HexColorEntryRx = /^(?<k>[[:blank:]]*[[:graph:]]+): +(?!null$)(?<q>["']?)#?(?<v>\w{3,6})\k<q> *(?:#.*)?$/
22
+ VariableRx = /\$([a-z0-9_-]+)/
23
+ LoneVariableRx = /^\$([a-z0-9_-]+)$/
24
+ HexColorEntryRx = /^(?<k> *\p{Graph}+): +(?!null$)(?<q>["']?)(?<h>#)?(?<v>[a-f0-9]{3,6})\k<q> *(?:#.*)?$/
25
25
  MultiplyDivideOpRx = /(-?\d+(?:\.\d+)?) +([*\/]) +(-?\d+(?:\.\d+)?)/
26
26
  AddSubtractOpRx = /(-?\d+(?:\.\d+)?) +([+\-]) +(-?\d+(?:\.\d+)?)/
27
27
  PrecisionFuncRx = /^(round|floor|ceil)\(/
@@ -35,7 +35,7 @@ class ThemeLoader
35
35
 
36
36
  # A marker module for a normalized CMYK array
37
37
  # Prevents normalizing CMYK value more than once
38
- module CmykColorValue
38
+ module CMYKColorValue
39
39
  include ColorValue
40
40
  def to_s
41
41
  %([#{join ', '}])
@@ -43,77 +43,89 @@ class ThemeLoader
43
43
  end
44
44
 
45
45
  def self.resolve_theme_file theme_name = nil, theme_path = nil
46
- theme_name ||= 'default'
47
- # if .yml extension is given, don't append -theme.yml
48
- if (theme_name.end_with? '.yml')
46
+ # if .yml extension is given, assume it's a path (don't append -theme.yml)
47
+ if ((theme_name ||= 'default').end_with? '.yml')
49
48
  # FIXME restrict to jail!
50
- # QUESTION why are we not using expand_path in this case?
51
- theme_path ? (::File.join theme_path, theme_name) : theme_name
49
+ theme_file = ::File.expand_path theme_name, theme_path
50
+ theme_path ||= ::File.dirname theme_file
52
51
  else
53
- # QUESTION should we append '-theme.yml' or just '.yml'?
54
- ::File.expand_path %(#{theme_name}-theme.yml), (theme_path || ThemesDir)
52
+ theme_file = ::File.expand_path %(#{theme_name}-theme.yml), (theme_path || (theme_path = ThemesDir))
55
53
  end
54
+ [theme_file, theme_path]
56
55
  end
57
56
 
58
- def self.resolve_theme_asset asset_path, theme_path = nil
57
+ def self.resolve_theme_asset asset_path, theme_path
59
58
  ::File.expand_path asset_path, (theme_path || ThemesDir)
60
59
  end
61
60
 
62
61
  # NOTE base theme is loaded "as is" (no post-processing)
63
62
  def self.load_base_theme
64
- ::OpenStruct.new(::SafeYAML.load_file BaseThemePath)
63
+ (::OpenStruct.new ::SafeYAML.load_file BaseThemePath).tap {|theme| theme.__dir__ = ThemesDir }
65
64
  end
66
65
 
67
- def self.load_theme theme_name = nil, theme_path = nil, opts = {}
68
- if (theme_file = resolve_theme_file theme_name, theme_path) == BaseThemePath ||
69
- (theme_file != DefaultThemePath && (opts.fetch :apply_base_theme, true))
70
- theme_data = load_base_theme
66
+ def self.load_theme theme_name = nil, theme_path = nil
67
+ theme_file, theme_path = resolve_theme_file theme_name, theme_path
68
+ if theme_file == BaseThemePath
69
+ load_base_theme
70
+ else
71
+ theme_data = load_file theme_file, nil, theme_path
72
+ unless theme_file == DefaultThemePath
73
+ # QUESTION should we enforce any other fallback values?
74
+ theme_data.base_align ||= 'left'
75
+ theme_data.code_font_family ||= (theme_data.literal_font_family || 'Courier')
76
+ theme_data.conum_font_family ||= (theme_data.literal_font_family || 'Courier')
77
+ end
78
+ theme_data.__dir__ = theme_path
79
+ theme_data
71
80
  end
72
-
73
- theme_file == BaseThemePath ? theme_data : (load_file theme_file, theme_data)
74
- end
75
-
76
- def self.load_file filename, theme_data = nil
77
- raw_data = (::File.read filename, encoding: ::Encoding::UTF_8).each_line.map {|l| l.sub HexColorEntryRx, '\k<k>: \'\k<v>\'' }.join
78
- self.new.load((::SafeYAML.load raw_data), theme_data)
79
81
  end
80
82
 
81
- def load hash, theme_data = nil
82
- theme_data ||= ::OpenStruct.new
83
- return theme_data unless ::Hash === hash
84
- base_code_font_family = theme_data.delete 'code_font_family'
85
- base_conum_font_family = theme_data.delete 'conum_font_family'
86
- hash.inject(theme_data) {|data, (key, val)| process_entry key, val, data }
87
- # NOTE remap legacy running content keys (e.g., header_recto_content_left => header_recto_left_content)
88
- %w(header_recto header_verso footer_recto footer_verso).each do |periphery_face|
89
- %w(left center right).each do |align|
90
- if (val = theme_data.delete %(#{periphery_face}_content_#{align}))
91
- theme_data[%(#{periphery_face}_#{align}_content)] = val
83
+ def self.load_file filename, theme_data = nil, theme_path = nil
84
+ data = ::File.read filename, encoding: ::Encoding::UTF_8
85
+ data = data.each_line.map {|l|
86
+ l.sub(HexColorEntryRx) { %(#{(m = $~)[:k]}: #{m[:h] || (m[:k].end_with? 'color') ? "'#{m[:v]}'" : m[:v]}) }
87
+ }.join unless filename == DefaultThemePath
88
+ yaml_data = ::SafeYAML.load data
89
+ if ::Hash === yaml_data && (yaml_data.key? 'extends')
90
+ if (extends = yaml_data.delete 'extends')
91
+ [*extends].each do |extend_file|
92
+ if extend_file == 'base'
93
+ theme_data = theme_data ? (::OpenStruct.new theme_data.to_h.merge load_base_theme.to_h) : load_base_theme
94
+ next
95
+ elsif extend_file == 'default' || extend_file == 'default-with-fallback-font'
96
+ extend_file, extend_theme_path = resolve_theme_file extend_file
97
+ elsif extend_file.start_with? './'
98
+ extend_file, extend_theme_path = resolve_theme_file extend_file, (::File.dirname filename)
99
+ else
100
+ extend_file, extend_theme_path = resolve_theme_file extend_file, theme_path
101
+ end
102
+ theme_data = load_file extend_file, theme_data, extend_theme_path
92
103
  end
93
104
  end
105
+ else
106
+ theme_data ||= (filename == DefaultThemePath ? nil : load_base_theme)
94
107
  end
95
- theme_data.base_align ||= 'left'
96
- theme_data.code_font_family ||= (theme_data.literal_font_family || base_code_font_family)
97
- theme_data.conum_font_family ||= (theme_data.literal_font_family || base_conum_font_family)
98
- # QUESTION should we do any other post-load calculations or defaults?
99
- theme_data
108
+ self.new.load yaml_data, theme_data, theme_path
109
+ end
110
+
111
+ def load hash, theme_data = nil, theme_path = nil
112
+ ::Hash === hash ? hash.reduce(theme_data || ::OpenStruct.new) {|data, (key, val)| process_entry key, val, data } : (theme_data || ::OpenStruct.new)
100
113
  end
101
114
 
102
115
  private
103
116
 
104
117
  def process_entry key, val, data
105
- if key.start_with? 'font_'
118
+ key = key.tr '-', '_' if key.include? '-'
119
+ if key == 'font_catalog' || key == 'font_fallbacks'
106
120
  data[key] = val
107
121
  elsif key.start_with? 'admonition_icon_'
108
122
  data[key] = (val || {}).map do |(key2, val2)|
109
123
  [key2.to_sym, (key2.end_with? '_color') ? to_color(evaluate val2, data) : (evaluate val2, data)]
110
124
  end.to_h
111
125
  elsif ::Hash === val
112
- val.each do |key2, val2|
113
- process_entry %(#{key}_#{key2.tr '-', '_'}), val2, data
114
- end
126
+ val.each {|subkey, subval| process_entry %(#{key}_#{subkey}), subval, data }
115
127
  elsif key.end_with? '_color'
116
- # QUESTION do we need to evaluate_math in this case?
128
+ # QUESTION do we really need to evaluate_math in this case?
117
129
  data[key] = to_color(evaluate val, data)
118
130
  elsif %(#{key.chomp '_'}_).include? '_content_'
119
131
  data[key] = (expand_vars val.to_s, data).to_s
@@ -138,21 +150,27 @@ class ThemeLoader
138
150
  def expand_vars expr, vars
139
151
  if (idx = (expr.index '$'))
140
152
  if idx == 0 && expr =~ LoneVariableRx
141
- if vars.respond_to? $1
142
- vars[$1]
153
+ if (key = $1).include? '-'
154
+ key = key.tr '-', '_'
155
+ end
156
+ if vars.respond_to? key
157
+ vars[key]
143
158
  else
144
159
  logger.warn %(unknown variable reference in PDF theme: $#{$1})
145
160
  expr
146
161
  end
147
162
  else
148
- expr.gsub(VariableRx) {
149
- if vars.respond_to? $1
150
- vars[$1]
163
+ expr.gsub(VariableRx) do
164
+ if (key = $1).include? '-'
165
+ key = key.tr '-', '_'
166
+ end
167
+ if vars.respond_to? key
168
+ vars[key]
151
169
  else
152
170
  logger.warn %(unknown variable reference in PDF theme: $#{$1})
153
171
  $&
154
172
  end
155
- }
173
+ end
156
174
  end
157
175
  else
158
176
  expr
@@ -166,16 +184,24 @@ class ThemeLoader
166
184
  # NOTE leave % as a string; handled by converter for now
167
185
  expr = resolve_measurement_values(original = expr)
168
186
  while true
169
- result = expr.gsub(MultiplyDivideOpRx) { $1.to_f.send $2.to_sym, $3.to_f }
170
- unchanged = (result == expr)
171
- expr = result
172
- break if unchanged
187
+ if (expr.count '*/') > 0
188
+ result = expr.gsub(MultiplyDivideOpRx) { $1.to_f.send $2.to_sym, $3.to_f }
189
+ unchanged = (result == expr)
190
+ expr = result
191
+ break if unchanged
192
+ else
193
+ break
194
+ end
173
195
  end
174
196
  while true
175
- result = expr.gsub(AddSubtractOpRx) { $1.to_f.send $2.to_sym, $3.to_f }
176
- unchanged = (result == expr)
177
- expr = result
178
- break if unchanged
197
+ if (expr.count '+-') > 0
198
+ result = expr.gsub(AddSubtractOpRx) { $1.to_f.send $2.to_sym, $3.to_f }
199
+ unchanged = (result == expr)
200
+ expr = result
201
+ break if unchanged
202
+ else
203
+ break
204
+ end
179
205
  end
180
206
  if (expr.end_with? ')') && expr =~ PrecisionFuncRx
181
207
  op = $1
@@ -194,13 +220,6 @@ class ThemeLoader
194
220
  when ColorValue
195
221
  # already converted
196
222
  return value
197
- when ::String
198
- if value == 'transparent'
199
- # FIXME should we have a TransparentColorValue class?
200
- return HexColorValue.new value
201
- elsif value.length == 6
202
- return HexColorValue.new value.upcase
203
- end
204
223
  when ::Array
205
224
  case value.length
206
225
  # CMYK value
@@ -219,7 +238,7 @@ class ThemeLoader
219
238
  when [100, 100, 100, 100]
220
239
  return HexColorValue.new '000000'
221
240
  else
222
- value.extend CmykColorValue
241
+ value.extend CMYKColorValue
223
242
  return value
224
243
  end
225
244
  # RGB value
@@ -229,9 +248,20 @@ class ThemeLoader
229
248
  else
230
249
  value = value.join
231
250
  end
251
+ when ::String
252
+ if value == 'transparent'
253
+ # FIXME should we have a TransparentColorValue class?
254
+ return HexColorValue.new value
255
+ elsif value.length == 6
256
+ return HexColorValue.new value.upcase
257
+ end
258
+ when ::NilClass
259
+ return nil
232
260
  else
233
- # Unknown type; coerce to a string
234
- value = value.to_s
261
+ # Unknown type (usually Integer); coerce to String
262
+ if (value = value.to_s).length == 6
263
+ return HexColorValue.new value.upcase
264
+ end
235
265
  end
236
266
  value = case value.length
237
267
  when 6
@@ -1,6 +1,6 @@
1
1
  module Asciidoctor
2
2
  module PDF
3
- VERSION = '1.5.0.alpha.17'
3
+ VERSION = '1.5.0.beta.1'
4
4
  end
5
5
  Pdf = PDF unless const_defined? :Pdf, false
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-pdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0.alpha.17
4
+ version: 1.5.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-04-23 00:00:00.000000000 Z
12
+ date: 2019-07-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: asciidoctor
@@ -17,7 +17,7 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 1.5.0
20
+ version: 1.5.3
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
23
  version: 3.0.0
@@ -27,7 +27,7 @@ dependencies:
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- version: 1.5.0
30
+ version: 1.5.3
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 3.0.0
@@ -171,6 +171,26 @@ dependencies:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
173
  version: 12.3.0
174
+ - !ruby/object:Gem::Dependency
175
+ name: rouge
176
+ requirement: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 3.4.0
181
+ - - "!="
182
+ - !ruby/object:Gem::Version
183
+ version: 3.4.1
184
+ type: :development
185
+ prerelease: false
186
+ version_requirements: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - "~>"
189
+ - !ruby/object:Gem::Version
190
+ version: 3.4.0
191
+ - - "!="
192
+ - !ruby/object:Gem::Version
193
+ version: 3.4.1
174
194
  - !ruby/object:Gem::Dependency
175
195
  name: rspec
176
196
  requirement: !ruby/object:Gem::Requirement
@@ -199,6 +219,20 @@ dependencies:
199
219
  - - "~>"
200
220
  - !ruby/object:Gem::Version
201
221
  version: 1.3.0
222
+ - !ruby/object:Gem::Dependency
223
+ name: chunky_png
224
+ requirement: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: 1.3.0
229
+ type: :development
230
+ prerelease: false
231
+ version_requirements: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - "~>"
234
+ - !ruby/object:Gem::Version
235
+ version: 1.3.0
202
236
  description: An extension for Asciidoctor that converts AsciiDoc documents to PDF
203
237
  using the Prawn PDF library.
204
238
  email: dan@opendevise.com
@@ -227,9 +261,12 @@ files:
227
261
  - data/fonts/notoserif-regular-subset.ttf
228
262
  - data/themes/base-theme.yml
229
263
  - data/themes/default-theme.yml
264
+ - data/themes/default-with-fallback-font-theme.yml
230
265
  - docs/theming-guide.adoc
231
266
  - lib/asciidoctor-pdf.rb
232
267
  - lib/asciidoctor-pdf/asciidoctor_ext.rb
268
+ - lib/asciidoctor-pdf/asciidoctor_ext/abstract_block.rb
269
+ - lib/asciidoctor-pdf/asciidoctor_ext/document.rb
233
270
  - lib/asciidoctor-pdf/asciidoctor_ext/image.rb
234
271
  - lib/asciidoctor-pdf/asciidoctor_ext/list.rb
235
272
  - lib/asciidoctor-pdf/asciidoctor_ext/list_item.rb
@@ -238,10 +275,12 @@ files:
238
275
  - lib/asciidoctor-pdf/converter.rb
239
276
  - lib/asciidoctor-pdf/core_ext.rb
240
277
  - lib/asciidoctor-pdf/core_ext/array.rb
278
+ - lib/asciidoctor-pdf/core_ext/hash.rb
241
279
  - lib/asciidoctor-pdf/core_ext/numeric.rb
242
280
  - lib/asciidoctor-pdf/core_ext/object.rb
243
281
  - lib/asciidoctor-pdf/core_ext/ostruct.rb
244
282
  - lib/asciidoctor-pdf/core_ext/quantifiable_stdout.rb
283
+ - lib/asciidoctor-pdf/core_ext/regexp.rb
245
284
  - lib/asciidoctor-pdf/core_ext/string.rb
246
285
  - lib/asciidoctor-pdf/formatted_text.rb
247
286
  - lib/asciidoctor-pdf/formatted_text/formatter.rb
@@ -251,6 +290,7 @@ files:
251
290
  - lib/asciidoctor-pdf/formatted_text/inline_text_aligner.rb
252
291
  - lib/asciidoctor-pdf/formatted_text/parser.rb
253
292
  - lib/asciidoctor-pdf/formatted_text/parser.treetop
293
+ - lib/asciidoctor-pdf/formatted_text/text_background_and_border_renderer.rb
254
294
  - lib/asciidoctor-pdf/formatted_text/transform.rb
255
295
  - lib/asciidoctor-pdf/implicit_header_processor.rb
256
296
  - lib/asciidoctor-pdf/index_catalog.rb
@@ -307,7 +347,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
307
347
  - !ruby/object:Gem::Version
308
348
  version: 1.3.1
309
349
  requirements: []
310
- rubygems_version: 3.0.3
350
+ rubygems_version: 3.0.4
311
351
  signing_key:
312
352
  specification_version: 4
313
353
  summary: Converts AsciiDoc documents to PDF using Asciidoctor and Prawn